fix two thinkos with startup sequence
[ardour.git] / gtk2_ardour / startup_fsm.cc
1 /*
2  * Copyright (C) 2019 Paul Davis <paul@linuxaudiosystems.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17  */
18
19 #include <vector>
20
21 #include <gtkmm/dialog.h>
22 #include <gtkmm/liststore.h>
23 #include <gtkmm/messagedialog.h>
24 #include <gtkmm/stock.h>
25
26 #include "pbd/basename.h"
27 #include "pbd/file_archive.h"
28 #include "pbd/file_utils.h"
29 #include "pbd/i18n.h"
30
31 #include "ardour/audioengine.h"
32 #include "ardour/filename_extensions.h"
33 #include "ardour/filesystem_paths.h"
34 #include "ardour/profile.h"
35 #include "ardour/recent_sessions.h"
36 #include "ardour/rc_configuration.h"
37 #include "ardour/search_paths.h"
38 #include "ardour/session.h"
39 #include "ardour/session_utils.h"
40 #include "ardour/template_utils.h"
41
42 #include "gtkmm2ext/application.h"
43 #include <gtkmm2ext/doi.h>
44
45 #include "ardour_ui.h"
46 #include "engine_dialog.h"
47 #include "new_user_wizard.h"
48 #include "opts.h"
49 #include "session_dialog.h"
50 #include "startup_fsm.h"
51
52 #ifdef WAF_BUILD
53 #include "gtk2ardour-version.h"
54 #endif
55
56 using namespace ARDOUR;
57 using namespace Gtk;
58 using namespace Gtkmm2ext;
59 using namespace PBD;
60
61 using std::string;
62 using std::vector;
63
64 StartupFSM::StartupFSM (EngineControl& amd)
65         : session_existing_sample_rate (0)
66         , session_is_new (false)
67         , new_user (NewUserWizard::required())
68         , new_session (true)
69         , _state (new_user ? NeedWizard : NeedSessionPath)
70         , new_user_wizard (0)
71         , audiomidi_dialog (amd)
72         , session_dialog (0)
73         , pre_release_dialog (0)
74 {
75         if (string (VERSIONSTRING).find (".pre") != string::npos) {
76                 string fn = Glib::build_filename (user_config_directory(), ".i_swear_that_i_will_heed_the_guidelines_stated_in_the_pre_release_dialog");
77                 if (!Glib::file_test (fn, Glib::FILE_TEST_EXISTS)) {
78                         _state = NeedPreRelease;
79                 }
80         }
81
82         Application* app = Application::instance ();
83
84         app->ShouldQuit.connect (sigc::mem_fun (*this, &StartupFSM::queue_finish));
85         app->ShouldLoad.connect (sigc::mem_fun (*this, &StartupFSM::load_from_application_api));
86
87         /* this may cause the delivery of ShouldLoad etc if we were invoked in
88          * particular ways. It will happen when the event loop runs again.
89          */
90
91         app->ready ();
92 }
93
94 StartupFSM::~StartupFSM ()
95 {
96         delete session_dialog;
97 }
98
99 void
100 StartupFSM::queue_finish ()
101 {
102         _signal_response (ExitProgram);
103 }
104
105 void
106 StartupFSM::start ()
107 {
108         if (_state == NeedPreRelease) {
109                 show_pre_release_dialog ();
110         } else if (new_user) {
111                 show_new_user_wizard ();
112         } else {
113                 /* pretend we just showed the new user wizard and we're done
114                    with it
115                 */
116                 dialog_response_handler (RESPONSE_OK, NewUserDialog);
117         }
118 }
119
120
121 void
122 StartupFSM::end()
123 {
124
125 }
126
127 void
128 StartupFSM::dialog_response_handler (int response, StartupFSM::DialogID dialog_id)
129 {
130         const bool new_session_required = (ARDOUR_COMMAND_LINE::new_session || (!ARDOUR::Profile->get_mixbus() && new_user));
131
132   restart:
133
134         switch (_state) {
135         case NeedPreRelease:
136                 switch (dialog_id) {
137                 case PreReleaseDialog:
138                 default:
139                         /* any response value from the pre-release dialog means
140                            "move along now"
141                         */
142                         delete_when_idle (pre_release_dialog);
143                         pre_release_dialog = 0;
144                         _state = NeedSessionPath;
145                         if (NewUserWizard::required()) {
146                                 show_new_user_wizard ();
147                         } else {
148                                 /* act as if we had just finished with the new
149                                    user wizard. goto preferred over reentrancy.
150                                 */
151                                 dialog_id = NewUserDialog;
152                                 response = RESPONSE_OK;
153                                 goto restart;
154                         }
155                         break;
156                 }
157                 break;
158
159         case NeedSessionPath:
160                 switch (dialog_id) {
161                 case NewUserDialog:
162
163                         current_dialog_connection.disconnect ();
164                         delete_when_idle (new_user_wizard);
165
166                         switch (response) {
167                         case RESPONSE_OK:
168                                 break;
169                         default:
170                                 exit (1);
171                         }
172
173                         /* new user wizard done, now lets get session params
174                          * either from the command line (if given) or a dialog
175                          * (if nothing given on the command line or if the
176                          * command line arguments don't work for some reason
177                          */
178
179                         if (ARDOUR_COMMAND_LINE::session_name.empty()) {
180
181                                 /* nothing given on the command line ... show new session dialog */
182
183                                 session_path = string();
184                                 session_name = string();
185                                 session_template = string();
186
187                                 _state = NeedSessionPath;
188                                 show_session_dialog (new_session_required);
189
190                         } else {
191
192                                 if (get_session_parameters_from_command_line (new_session_required)) {
193
194                                         /* command line arguments all OK. Get engine parameters */
195
196                                         _state = NeedEngineParams;
197
198                                         if (!new_session_required && session_existing_sample_rate > 0) {
199                                                 audiomidi_dialog.set_desired_sample_rate (session_existing_sample_rate);
200                                         }
201
202                                         start_audio_midi_setup ();
203
204                                 } else {
205
206                                         /* command line arguments not good. Use
207                                          * dialog, but prime the dialog with
208                                          * the information we set up in
209                                          * get_session_parameters_from_command_line()
210                                          */
211
212                                         _state = NeedSessionPath;
213                                         show_session_dialog (new_session_required);
214                                 }
215                         }
216                         break;
217
218                 case NewSessionDialog:
219                         switch (response) {
220                         case RESPONSE_OK:
221                         case RESPONSE_ACCEPT:
222                                 switch (check_session_parameters (new_session_required)) {
223                                 case -1:
224                                         /* Unrecoverable error */
225                                         _signal_response (ExitProgram);
226                                         break;
227                                 case 1:
228                                         /* do nothing - keep dialog up for a
229                                          * retry. Errors were addressed by
230                                          * ::check_session_parameters()
231                                          */
232                                         break;
233                                 case 0:
234                                         start_audio_midi_setup ();
235                                         break;
236                                 }
237                                 break;
238
239                         default:
240                                 _signal_response (ExitProgram);
241                                 break;
242                         }
243                         break;
244
245                 default:
246                         /* ERROR */
247                         break;
248                 }
249                 break;
250
251         case NeedEngineParams:
252                 switch (dialog_id) {
253                 case AudioMIDISetup:
254                         switch (response) {
255                         case RESPONSE_OK:
256                         case RESPONSE_ACCEPT:
257                                 if (AudioEngine::instance()->running()) {
258                                         audiomidi_dialog.hide ();
259                                         current_dialog_connection.disconnect();
260                                         _signal_response (LoadSession);
261                                 } else {
262                                         /* just keep going */
263                                 }
264                                 break;
265                         default:
266                                 _signal_response (ExitProgram);
267                         }
268                         break;
269                 default:
270                         /* ERROR */
271                         break;
272                 }
273                 break;
274
275         case NeedWizard:
276                 show_new_user_wizard ();
277                 _state = NeedSessionPath;
278                 break;
279         }
280 }
281
282 void
283 StartupFSM::show_new_user_wizard ()
284 {
285         new_user_wizard = new NewUserWizard;
286         current_dialog_connection = new_user_wizard->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &StartupFSM::dialog_response_handler), NewUserDialog));
287         new_user_wizard->set_position (WIN_POS_CENTER);
288         new_user_wizard->present ();
289 }
290
291 void
292 StartupFSM::show_session_dialog (bool new_session_required)
293 {
294         session_dialog = new SessionDialog (new_session_required, session_name, session_path, session_template, false);
295         current_dialog_connection = session_dialog->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &StartupFSM::dialog_response_handler), NewSessionDialog));
296         session_dialog->set_position (WIN_POS_CENTER);
297         session_dialog->present ();
298 }
299
300 void
301 StartupFSM::show_audiomidi_dialog ()
302 {
303         current_dialog_connection = audiomidi_dialog.signal_response().connect (sigc::bind (sigc::mem_fun (*this, &StartupFSM::dialog_response_handler), AudioMIDISetup));
304         audiomidi_dialog.set_position (WIN_POS_CENTER);
305         audiomidi_dialog.present ();
306 }
307
308 void
309 StartupFSM::start_audio_midi_setup ()
310 {
311         bool setup_required = false;
312
313         if (AudioEngine::instance()->current_backend() == 0) {
314                 /* backend is unknown ... */
315                 setup_required = true;
316
317         } else if (session_is_new && AudioEngine::instance()->running() && AudioEngine::instance()->sample_rate () == session_existing_sample_rate) {
318                 /* keep engine */
319
320                 warning << "A running engine should not be possible at this point" << endmsg;
321
322         } else if (AudioEngine::instance()->setup_required()) {
323                 /* backend is known, but setup is needed */
324                 setup_required = true;
325
326         } else if (!AudioEngine::instance()->running()) {
327                 /* should always be true during startup */
328                 if (AudioEngine::instance()->start()) {
329                         setup_required = true;
330                 }
331         }
332
333         if (setup_required) {
334                 _state = NeedEngineParams;
335                 if (session_dialog) {
336                         session_dialog->hide ();
337                         delete_when_idle (session_dialog);
338                         session_dialog = 0;
339                 }
340                 current_dialog_connection.disconnect();
341                 if (!session_is_new && session_existing_sample_rate > 0) {
342                         audiomidi_dialog.set_desired_sample_rate (session_existing_sample_rate);
343                 }
344                 show_audiomidi_dialog ();
345         } else {
346                 /* XXX should we reset _state to something meaningul here (e.g. "Done")? */
347
348                 if (session_dialog) {
349                         session_dialog->hide ();
350                         delete_when_idle (session_dialog);
351                         session_dialog = 0;
352                 }
353
354                 current_dialog_connection.disconnect ();
355                 _signal_response (LoadSession);
356         }
357 }
358
359 bool
360 StartupFSM::get_session_parameters_from_command_line (bool new_session_required)
361 {
362         return get_session_parameters_from_path (ARDOUR_COMMAND_LINE::session_name, ARDOUR_COMMAND_LINE::load_template, new_session_required);
363 }
364
365 bool
366 StartupFSM::get_session_parameters_from_path (string const & path, string const & template_name, bool new_session_required)
367 {
368         if (path.empty()) {
369                 /* use GUI to ask the user */
370                 return false;
371         }
372
373         if (Glib::file_test (path.c_str(), Glib::FILE_TEST_EXISTS)) {
374
375                 session_is_new = false;
376
377                 if (new_session_required) {
378                         /* wait! it already exists */
379
380                         if (!ask_about_loading_existing_session (path)) {
381                                 return false;
382                         } else {
383                                 /* load it anyway */
384                         }
385                 }
386
387                 session_name = basename_nosuffix (path);
388
389                 if (Glib::file_test (path.c_str(), Glib::FILE_TEST_IS_REGULAR)) {
390                         /* session/snapshot file, change path to be dir */
391                         session_path = Glib::path_get_dirname (path);
392                 } else {
393                         session_path = path;
394                 }
395
396                 float sr;
397                 SampleFormat fmt;
398                 string program_version;
399
400                 const string statefile_path = Glib::build_filename (session_path, session_name + ARDOUR::statefile_suffix);
401                 if (Session::get_info_from_path (statefile_path, sr, fmt, program_version)) {
402                         /* exists but we can't read it correctly */
403                         error << string_compose (_("Cannot get existing session information from %1"), statefile_path) << endmsg;
404                         return false;
405                 }
406
407                 session_existing_sample_rate = sr;
408                 return true;
409
410         }
411
412         /*  Everything after this involves a new session
413          *
414          *  ... did the  user give us a path or just a name?
415          */
416
417         if (path.find (G_DIR_SEPARATOR) == string::npos) {
418                 /* user gave session name with no path info, use
419                    default session folder.
420                 */
421                 session_name = ARDOUR_COMMAND_LINE::session_name;
422                 session_path = Glib::build_filename (Config->get_default_session_parent_dir (), session_name);
423         } else {
424                 session_name = basename_nosuffix (path);
425                 session_path = path;
426         }
427
428
429         if (!template_name.empty()) {
430
431                 /* Allow the user to specify a template via path or name on the
432                  * command line
433                  */
434
435                 bool have_resolved_template_name = false;
436
437                 /* compare by name (path may or may not be UTF-8) */
438
439                 vector<TemplateInfo> templates;
440                 find_session_templates (templates, false);
441                 for (vector<TemplateInfo>::iterator x = templates.begin(); x != templates.end(); ++x) {
442                         if ((*x).name == template_name) {
443                                 session_template = (*x).path;
444                                 have_resolved_template_name = true;
445                                 break;
446                         }
447                 }
448
449                 /* look up script by name */
450                 LuaScriptList scripts (LuaScripting::instance ().scripts (LuaScriptInfo::SessionInit));
451                 LuaScriptList& as (LuaScripting::instance ().scripts (LuaScriptInfo::EditorAction));
452                 for (LuaScriptList::const_iterator s = as.begin(); s != as.end(); ++s) {
453                         if ((*s)->subtype & LuaScriptInfo::SessionSetup) {
454                                 scripts.push_back (*s);
455                         }
456                 }
457                 std::sort (scripts.begin(), scripts.end(), LuaScripting::Sorter());
458                 for (LuaScriptList::const_iterator s = scripts.begin(); s != scripts.end(); ++s) {
459                         if ((*s)->name == template_name) {
460                                 session_template = "urn:ardour:" + (*s)->path;
461                                 have_resolved_template_name = true;
462                                 break;
463                         }
464                 }
465
466                 if (!have_resolved_template_name) {
467                         /* this will produce a more or less meaninful error later:
468                          * "ERROR: Could not open session template [abs-path to user-config dir]"
469                          */
470                         session_template = Glib::build_filename (ARDOUR::user_template_directory (), template_name);
471                 }
472         }
473
474         /* We don't know what this is, because the session is new and the
475          * command line doesn't let us specify it. The user will get to decide
476          * in the audio/MIDI dialog.
477          */
478
479         session_existing_sample_rate = 0;
480         session_is_new = true;
481
482         /* this is an arbitrary default value but since the user insists on
483          * starting a new session from the command line, it will do as well as
484          * any other possible value. I mean, seriously, what else could it be
485          * by default?
486          */
487
488         bus_profile.master_out_channels = 2;
489
490         return true;
491 }
492
493 /** return values:
494  * -1: failure
495  *  1: failure but user can retry
496  *  0: success, seesion parameters ready for use
497  */
498 int
499 StartupFSM::check_session_parameters (bool must_be_new)
500 {
501         bool requested_new = false;
502
503         session_name = session_dialog->session_name (requested_new);
504         session_path = session_dialog->session_folder ();
505
506         if (must_be_new) {
507                 assert (requested_new);
508         }
509
510         if (!must_be_new) {
511
512                 /* See if the specified session is a session archive */
513
514                 int rv = ARDOUR::inflate_session (session_name, Config->get_default_session_parent_dir(), session_path, session_name);
515                 if (rv < 0) {
516                         MessageDialog msg (*session_dialog, string_compose (_("Extracting session-archive failed: %1"), inflate_error (rv)));
517                         msg.run ();
518
519                         return 1;
520                 } else if (rv == 0) {
521                         /* names are good (and session is unarchived/inflated */
522                         return 0;
523                 }
524         }
525
526         /* check for ".ardour" in statefile name, because we don't want
527          * it
528          *
529          * XXX Note this wierd conflation of a
530          * file-name-without-a-suffix and the session name. It's not
531          * really a session name at all, but rather the suffix-free
532          * name of a statefile (snapshot).
533          */
534
535         const string::size_type suffix_at = session_name.find (statefile_suffix);
536
537         if (suffix_at != string::npos) {
538                 session_name = session_name.substr (0, suffix_at);
539         }
540
541         /* this shouldn't happen, but we catch it just in case it does */
542
543         if (session_name.empty()) {
544                 return 1; /* keep running dialog */
545         }
546
547         if (session_dialog->use_session_template()) {
548                 session_template = session_dialog->session_template_name();
549         }
550
551         if (session_name[0] == G_DIR_SEPARATOR ||
552 #ifdef PLATFORM_WINDOWS
553             // Windows file system .. detect absolute path
554             // C:/*
555             (session_name.length() > 3 && session_name[1] == ':' && session_name[2] == G_DIR_SEPARATOR)
556 #else
557             // Sensible file systems
558             // /* or ./* or ../*
559             (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
560             (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)
561 #endif
562                 )
563         {
564
565                 /* user typed absolute path or cwd-relative path
566                    specified into session name field. So ... infer
567                    session path and name from what was given.
568                 */
569
570                 session_path = Glib::path_get_dirname (session_name);
571                 session_name = Glib::path_get_basename (session_name);
572
573         } else {
574
575                 /* session name is just a name */
576         }
577
578         /* check if name is legal */
579
580         const char illegal = Session::session_name_is_legal (session_name);
581
582         if (illegal) {
583                 MessageDialog msg (*session_dialog,
584                                    string_compose (_("To ensure compatibility with various systems\n"
585                                                      "session names may not contain a '%1' character"),
586                                                    illegal));
587                 msg.run ();
588                 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
589                 return 1; /* keep running dialog */
590         }
591
592
593         /* check if the currently-exists status matches whether or not
594          * it should be new
595          */
596
597         if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
598
599                 if (requested_new /*&& !nsm*/) {
600
601                         std::string existing = Glib::build_filename (session_path, session_name);
602
603                         if (!ask_about_loading_existing_session (existing)) {
604                                 session_dialog->clear_name ();
605                                 return 1; /* try again */
606                         }
607                 }
608
609                 session_is_new = false;
610
611         } else {
612
613                 /* does not exist at present */
614
615                 if (!requested_new) {
616                         ARDOUR_UI::pop_back_splash (*session_dialog);
617                         MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
618                         msg.run ();
619                         session_dialog->clear_name();
620                         return 1;
621                 }
622
623                 session_is_new = true;
624         }
625
626         float sr;
627         SampleFormat fmt;
628         string program_version;
629         const string statefile_path = Glib::build_filename (session_path, session_name + ARDOUR::statefile_suffix);
630
631         if (!session_is_new) {
632
633                 if (Session::get_info_from_path (statefile_path, sr, fmt, program_version)) {
634                         /* exists but we can't read it */
635                         return -1;
636                 }
637
638                 session_existing_sample_rate = sr;
639
640         } else {
641
642                 bus_profile.master_out_channels = session_dialog->master_channel_count ();
643         }
644
645         return 0;
646 }
647
648 void
649 StartupFSM::copy_demo_sessions ()
650 {
651         // TODO: maybe IFF brand_new_user
652         if (ARDOUR::Profile->get_mixbus () && Config->get_copy_demo_sessions ()) {
653                 std::string dspd (Config->get_default_session_parent_dir());
654                 Searchpath ds (ARDOUR::ardour_data_search_path());
655                 ds.add_subdirectory_to_paths ("sessions");
656                 vector<string> demos;
657                 find_files_matching_pattern (demos, ds, ARDOUR::session_archive_suffix);
658
659                 ARDOUR::RecentSessions rs;
660                 ARDOUR::read_recent_sessions (rs);
661
662                 for (vector<string>::iterator i = demos.begin(); i != demos.end (); ++i) {
663                         /* "demo-session" must be inside "demo-session.<session_archive_suffix>" */
664                         std::string name = basename_nosuffix (basename_nosuffix (*i));
665                         std::string path = Glib::build_filename (dspd, name);
666                         /* skip if session-dir already exists */
667                         if (Glib::file_test(path.c_str(), Glib::FILE_TEST_IS_DIR)) {
668                                 continue;
669                         }
670                         /* skip sessions that are already in 'recent'.
671                          * eg. a new user changed <session-default-dir> shorly after installation
672                          */
673                         for (ARDOUR::RecentSessions::iterator r = rs.begin(); r != rs.end(); ++r) {
674                                 if ((*r).first == name) {
675                                         continue;
676                                 }
677                         }
678                         try {
679                                 PBD::FileArchive ar (*i);
680                                 if (0 == ar.inflate (dspd)) {
681                                         store_recent_sessions (name, path);
682                                         info << string_compose (_("Copied Demo Session %1."), name) << endmsg;
683                                 }
684                         } catch (...) {
685                                 /* relax ? */
686                         }
687                 }
688         }
689 }
690
691 void
692 StartupFSM::load_from_application_api (const std::string& path)
693 {
694         /* macOS El Capitan (and probably later) now somehow passes the command
695            line arguments to an app via the openFile delegate protocol. Ardour
696            already does its own command line processing, and having both
697            pathways active causes crashes. So, if the command line was already
698            set, do nothing here.
699         */
700
701         if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
702                 return;
703         }
704
705         /* Cancel SessionDialog if it's visible to make macOS delegates work.
706          *
707          * there's a race condition here: we connect to app->ShouldLoad
708          * and then at some point (might) show a session dialog. The race is
709          * caused by the non-deterministic interaction between the macOS event
710          * loop(s) and the GDK one(s).
711          *
712          *  - ShouldLoad does not arrive before we show the session dialog
713          *          -> here we should hide the session dialog, then use the
714          *             supplied path as if it was provided on the command line
715          *  - ShouldLoad signal arrives before we show a session dialog
716          *          -> don't bother showing the session dialog, just use the
717          *             supplied path as if it was provided on the command line
718          *
719          */
720
721         if (session_dialog) {
722                 session_dialog->hide ();
723                 delete_when_idle (session_dialog);
724                 session_dialog = 0;
725         }
726
727         /* no command line argument given ... must just be via
728          * desktop/finder/window manager API (e.g. double click on "foo.ardour"
729          * icon)
730          */
731
732         if (get_session_parameters_from_path (path, string(), false)) {
733                 _signal_response (LoadSession);
734                 return;
735         }
736
737         /* given parameters failed for some reason. This is probably true
738          * anyway, but force it to be true and then carry on with whatever the
739          * main event loop is doing.
740          */
741
742         _state = NeedSessionPath;
743 }
744
745 bool
746 StartupFSM::ask_about_loading_existing_session (const std::string& session_path)
747 {
748         std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
749
750         MessageDialog msg (str,
751                            false,
752                            Gtk::MESSAGE_WARNING,
753                            Gtk::BUTTONS_YES_NO,
754                            true);
755
756
757         msg.set_name (X_("OpenExistingDialog"));
758         msg.set_title (_("Open Existing Session"));
759         msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
760         msg.set_position (Gtk::WIN_POS_CENTER);
761         ARDOUR_UI::pop_back_splash (msg);
762
763         switch (msg.run()) {
764         case RESPONSE_YES:
765                 return true;
766                 break;
767         }
768         return false;
769 }
770
771 void
772 StartupFSM::show_pre_release_dialog ()
773 {
774         pre_release_dialog = new ArdourDialog  (_("Pre-Release Warning"), true, false);
775         pre_release_dialog->add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
776
777         Label* label = manage (new Label);
778         label->set_markup (string_compose (_("<span size=\"x-large\" weight=\"bold\">Welcome to this pre-release build of %1 %2</span>\n\n\
779 <span size=\"large\">There are still several issues and bugs to be worked on,\n\
780 as well as general workflow improvements, before this can be considered\n\
781 release software. So, a few guidelines:\n\
782 \n\
783 1) Please do <b>NOT</b> use this software with the expectation that it is stable or reliable\n\
784    though it may be so, depending on your workflow.\n\
785 2) Please wait for a helpful writeup of new features.\n\
786 3) <b>Please do NOT use the forums at ardour.org to report issues</b>.\n\
787 4) <b>Please do NOT file bugs for this alpha-development versions at this point in time</b>.\n\
788    There is no bug triaging before the initial development concludes and\n\
789    reporting issue for incomplete, ongoing work-in-progress is mostly useless.\n\
790 5) Please <b>DO</b> join us on IRC for real time discussions about %1 %2. You\n\
791    can get there directly from within the program via the Help->Chat menu option.\n\
792 6) Please <b>DO</b> submit patches for issues after discussing them on IRC.\n\
793 \n\
794 Full information on all the above can be found on the support page at\n\
795 \n\
796                 http://ardour.org/support</span>\n\
797 "), PROGRAM_NAME, VERSIONSTRING));
798
799
800         pre_release_dialog->signal_response().connect (sigc::bind (sigc::mem_fun (this, &StartupFSM::dialog_response_handler), PreReleaseDialog));
801
802         pre_release_dialog->get_vbox()->set_border_width (12);
803         pre_release_dialog->get_vbox()->pack_start (*label, false, false, 12);
804         pre_release_dialog->get_vbox()->show_all ();
805         pre_release_dialog->set_position (WIN_POS_CENTER);
806         pre_release_dialog->present ();
807 }