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