diff options
Diffstat (limited to 'gtk2_ardour/startup_fsm.cc')
-rw-r--r-- | gtk2_ardour/startup_fsm.cc | 324 |
1 files changed, 208 insertions, 116 deletions
diff --git a/gtk2_ardour/startup_fsm.cc b/gtk2_ardour/startup_fsm.cc index 596ed82c0d..d1951ec295 100644 --- a/gtk2_ardour/startup_fsm.cc +++ b/gtk2_ardour/startup_fsm.cc @@ -43,10 +43,13 @@ #include <gtkmm2ext/doi.h> #include "ardour_ui.h" +#include "debug.h" #include "engine_dialog.h" #include "new_user_wizard.h" #include "opts.h" +#include "plugin_scan_dialog.h" #include "session_dialog.h" +#include "splash.h" #include "startup_fsm.h" #ifdef WAF_BUILD @@ -65,17 +68,25 @@ StartupFSM::StartupFSM (EngineControl& amd) : session_existing_sample_rate (0) , session_is_new (false) , new_user (NewUserWizard::required()) - , new_session (true) - , _state (new_user ? NeedWizard : NeedSessionPath) - , new_user_wizard (0) + , new_session_required (ARDOUR_COMMAND_LINE::new_session || (!ARDOUR::Profile->get_mixbus() && new_user)) + , _state (new_user ? WaitingForNewUser : WaitingForSessionPath) , audiomidi_dialog (amd) + , new_user_dialog (0) , session_dialog (0) , pre_release_dialog (0) + , plugin_scan_dialog (0) { + /* note that our initial state can be any of: + * + * WaitingForPreRelease: if this is a pre-release build of Ardour and the user has not testified to their fidelity to our creed + * WaitingForNewUser: if this is the first time any version appears to have been run on this machine by this user + * WaitingForSessionPath: if the previous two conditions are not true + */ + if (string (VERSIONSTRING).find (".pre") != string::npos) { string fn = Glib::build_filename (user_config_directory(), ".i_swear_that_i_will_heed_the_guidelines_stated_in_the_pre_release_dialog"); if (!Glib::file_test (fn, Glib::FILE_TEST_EXISTS)) { - _state = NeedPreRelease; + set_state (WaitingForPreRelease); } } @@ -83,17 +94,14 @@ StartupFSM::StartupFSM (EngineControl& amd) app->ShouldQuit.connect (sigc::mem_fun (*this, &StartupFSM::queue_finish)); app->ShouldLoad.connect (sigc::mem_fun (*this, &StartupFSM::load_from_application_api)); - - /* this may cause the delivery of ShouldLoad etc if we were invoked in - * particular ways. It will happen when the event loop runs again. - */ - - app->ready (); } StartupFSM::~StartupFSM () { delete session_dialog; + delete pre_release_dialog; + delete plugin_scan_dialog; + delete new_user_dialog; } void @@ -105,116 +113,149 @@ StartupFSM::queue_finish () void StartupFSM::start () { - if (_state == NeedPreRelease) { + /* get the splash screen visible, if it isn't yet */ + Splash::instance()->pop_front(); + /* make it all happen on-screen */ + ARDOUR_UI::instance()->flush_pending (); + + DEBUG_TRACE (DEBUG::GuiStartup, string_compose (X_("State at startup: %1\n"), enum_2_string (_state))); + + switch (_state) { + case WaitingForPreRelease: show_pre_release_dialog (); - } else if (new_user) { - show_new_user_wizard (); - } else { - /* pretend we just showed the new user wizard and we're done - with it - */ - dialog_response_handler (RESPONSE_OK, NewUserDialog); + break; + case WaitingForNewUser: + show_new_user_dialog (); + break; + case WaitingForSessionPath: + if (ARDOUR_COMMAND_LINE::session_name.empty()) { + + /* nothing given on the command line ... show new session dialog */ + + show_session_dialog (new_session_required); + + } else { + + if (get_session_parameters_from_command_line (new_session_required)) { + + /* command line arguments all OK. Get engine parameters */ + + if (!new_session_required && session_existing_sample_rate > 0) { + audiomidi_dialog.set_desired_sample_rate (session_existing_sample_rate); + } + + start_audio_midi_setup (); + + } else { + + /* command line arguments not good. Use + * dialog, but prime the dialog with + * the information we set up in + * get_session_parameters_from_command_line() + */ + + show_session_dialog (new_session_required); + } + } + break; + default: + fatal << string_compose (_("Programming error: %1"), string_compose (X_("impossible starting state in StartupFSM (%1)"), enum_2_string (_state))) << endmsg; + std::cerr << string_compose (_("Programming error: %1"), string_compose (X_("impossible starting state in StartupFSM (%1)"), enum_2_string (_state))) << std::endl; + /* NOTREACHED */ + abort (); } + + DEBUG_TRACE (DEBUG::GuiStartup, string_compose (X_("State after startup: %1\n"), enum_2_string (_state))); + + /* this may cause the delivery of ShouldLoad etc if we were invoked in + * particular ways. It will happen when the event loop runs again. + */ + + Application::instance()->ready (); } +void +StartupFSM::reset() +{ + show_session_dialog (new_session_required); +} void -StartupFSM::end() +StartupFSM::set_state (MainState ms) { + DEBUG_TRACE (DEBUG::GuiStartup, string_compose (X_("new state: %1\n"), enum_2_string (ms))); + _state = ms; +} + +template<typename T> void +StartupFSM::end_dialog (T** d) +{ + assert (d); + assert (*d); + + end_dialog (**d); + delete_when_idle (*d); + *d = 0; +} +template<typename T> void +StartupFSM::end_dialog (T& d) +{ + d.hide (); + current_dialog_connection.disconnect (); } void StartupFSM::dialog_response_handler (int response, StartupFSM::DialogID dialog_id) { - const bool new_session_required = (ARDOUR_COMMAND_LINE::new_session || (!ARDOUR::Profile->get_mixbus() && new_user)); + 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)); - restart: + /* Notes: + * + * 1) yes, a brand new user might have specified a command line + * argument naming a new session. We ignore it. You're new to Ardour? + * We want to guide you through the startup. + */ switch (_state) { - case NeedPreRelease: + case WaitingForPreRelease: switch (dialog_id) { case PreReleaseDialog: default: /* any response value from the pre-release dialog means "move along now" */ - delete_when_idle (pre_release_dialog); - pre_release_dialog = 0; - _state = NeedSessionPath; + Gtk::Widget* w = pre_release_dialog; + end_dialog (&w); + if (NewUserWizard::required()) { - show_new_user_wizard (); + show_new_user_dialog (); } else { - /* act as if we had just finished with the new - user wizard. goto preferred over reentrancy. - */ - dialog_id = NewUserDialog; - response = RESPONSE_OK; - goto restart; + show_session_dialog (new_session_required); } break; } break; - case NeedSessionPath: + case WaitingForNewUser: switch (dialog_id) { case NewUserDialog: - - current_dialog_connection.disconnect (); - delete_when_idle (new_user_wizard); - switch (response) { case RESPONSE_OK: + end_dialog (&new_user_dialog); + show_session_dialog (new_session_required); break; default: - exit (1); - } - - /* new user wizard done, now lets get session params - * either from the command line (if given) or a dialog - * (if nothing given on the command line or if the - * command line arguments don't work for some reason - */ - - if (ARDOUR_COMMAND_LINE::session_name.empty()) { - - /* nothing given on the command line ... show new session dialog */ - - session_path = string(); - session_name = string(); - session_template = string(); - - _state = NeedSessionPath; - show_session_dialog (new_session_required); - - } else { - - if (get_session_parameters_from_command_line (new_session_required)) { - - /* command line arguments all OK. Get engine parameters */ - - _state = NeedEngineParams; - - if (!new_session_required && session_existing_sample_rate > 0) { - audiomidi_dialog.set_desired_sample_rate (session_existing_sample_rate); - } - - start_audio_midi_setup (); - - } else { - - /* command line arguments not good. Use - * dialog, but prime the dialog with - * the information we set up in - * get_session_parameters_from_command_line() - */ - - _state = NeedSessionPath; - show_session_dialog (new_session_required); - } + _signal_response (ExitProgram); } + default: + /* ERROR */ break; + } + break; + case WaitingForSessionPath: + switch (dialog_id) { case NewSessionDialog: switch (response) { case RESPONSE_OK: @@ -224,15 +265,16 @@ StartupFSM::dialog_response_handler (int response, StartupFSM::DialogID dialog_i /* Unrecoverable error */ _signal_response (ExitProgram); break; + case 0: + end_dialog (&session_dialog); + start_audio_midi_setup (); + break; case 1: /* do nothing - keep dialog up for a * retry. Errors were addressed by * ::check_session_parameters() */ break; - case 0: - start_audio_midi_setup (); - break; } break; @@ -248,16 +290,15 @@ StartupFSM::dialog_response_handler (int response, StartupFSM::DialogID dialog_i } break; - case NeedEngineParams: + case WaitingForEngineParams: switch (dialog_id) { case AudioMIDISetup: switch (response) { case RESPONSE_OK: case RESPONSE_ACCEPT: if (AudioEngine::instance()->running()) { - audiomidi_dialog.hide (); - current_dialog_connection.disconnect(); - _signal_response (LoadSession); + end_dialog (audiomidi_dialog); + engine_running (); } else { /* just keep going */ } @@ -272,25 +313,63 @@ StartupFSM::dialog_response_handler (int response, StartupFSM::DialogID dialog_i } break; - case NeedWizard: - show_new_user_wizard (); - _state = NeedSessionPath; - break; + case WaitingForPlugins: + switch (dialog_id) { + case PluginDialog: + end_dialog (&plugin_scan_dialog); + switch (response) { + case RESPONSE_OK: + _signal_response (LoadSession); + break; + default: + _signal_response (ExitProgram); + break; + } + default: + /* ERROR */ + break; + } } } void -StartupFSM::show_new_user_wizard () +StartupFSM::show_plugin_scan_dialog () +{ + set_state (WaitingForPlugins); + + /* if the user does not ask to discover VSTs at startup, or if this is Mixbus, then the plugin scan + that we run here, during startup, should only use the existing plugin cache (if any). + */ + + plugin_scan_dialog = new PluginScanDialog ((!Config->get_discover_vst_on_start() || Profile->get_mixbus()), new_user); + current_dialog_connection = plugin_scan_dialog->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &StartupFSM::dialog_response_handler), PluginDialog)); + plugin_scan_dialog->set_position (WIN_POS_CENTER); + + /* 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. + * + * See also comments in PluginScanDialog::start() to understand the absurd complexities behind this call. + */ + + DEBUG_TRACE (DEBUG::GuiStartup, string_compose ("starting plugin dialog, cache only ? %1\n", !Config->get_discover_vst_on_start())); + plugin_scan_dialog->start(); + DEBUG_TRACE (DEBUG::GuiStartup, "plugin dialog done\n"); +} + + +void +StartupFSM::show_new_user_dialog () { - new_user_wizard = new NewUserWizard; - current_dialog_connection = new_user_wizard->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &StartupFSM::dialog_response_handler), NewUserDialog)); - new_user_wizard->set_position (WIN_POS_CENTER); - new_user_wizard->present (); + set_state (WaitingForNewUser); + new_user_dialog = new NewUserWizard; + current_dialog_connection = new_user_dialog->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &StartupFSM::dialog_response_handler), NewUserDialog)); + new_user_dialog->set_position (WIN_POS_CENTER); + new_user_dialog->present (); } void StartupFSM::show_session_dialog (bool new_session_required) { + set_state (WaitingForSessionPath); session_dialog = new SessionDialog (new_session_required, session_name, session_path, session_template, false); current_dialog_connection = session_dialog->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &StartupFSM::dialog_response_handler), NewSessionDialog)); session_dialog->set_position (WIN_POS_CENTER); @@ -300,6 +379,7 @@ StartupFSM::show_session_dialog (bool new_session_required) void StartupFSM::show_audiomidi_dialog () { + set_state (WaitingForEngineParams); current_dialog_connection = audiomidi_dialog.signal_response().connect (sigc::bind (sigc::mem_fun (*this, &StartupFSM::dialog_response_handler), AudioMIDISetup)); audiomidi_dialog.set_position (WIN_POS_CENTER); audiomidi_dialog.present (); @@ -331,31 +411,43 @@ StartupFSM::start_audio_midi_setup () } if (setup_required) { - _state = NeedEngineParams; - if (session_dialog) { - session_dialog->hide (); - delete_when_idle (session_dialog); - session_dialog = 0; - } - current_dialog_connection.disconnect(); if (!session_is_new && session_existing_sample_rate > 0) { audiomidi_dialog.set_desired_sample_rate (session_existing_sample_rate); } show_audiomidi_dialog (); + DEBUG_TRACE (DEBUG::GuiStartup, "audiomidi shown and waiting\n"); } else { - /* XXX should we reset _state to something meaningul here (e.g. "Done")? */ - - if (session_dialog) { - session_dialog->hide (); - delete_when_idle (session_dialog); - session_dialog = 0; - } - current_dialog_connection.disconnect (); - _signal_response (LoadSession); + DEBUG_TRACE (DEBUG::GuiStartup, "engine already running, audio/MIDI setup dialog not required\n"); + engine_running (); } } +void +StartupFSM::engine_running () +{ + DEBUG_TRACE (DEBUG::GuiStartup, "engine running, start plugin scan then attach UI to engine\n"); + + /* This may be very slow. See comments in PluginScanDialog::start() */ + show_plugin_scan_dialog (); + + DEBUG_TRACE (DEBUG::GuiStartup, "attach UI to engine\n"); + + /* This may be very slow: it will run the GUI's post-engine + initialization which is essentially unbounded in time/scope of what + it can do. + */ + + ARDOUR_UI::instance()->attach_to_engine (); + + /* now that we've done the plugin scan AND attached the UI to the engine, we can + proceed with the next (final) steps of startup. This uses the same response + signal mechanism we use for the other dialogs. + */ + + plugin_scan_dialog->response (RESPONSE_OK); +} + bool StartupFSM::get_session_parameters_from_command_line (bool new_session_required) { @@ -739,7 +831,7 @@ StartupFSM::load_from_application_api (const std::string& path) * main event loop is doing. */ - _state = NeedSessionPath; + set_state (WaitingForSessionPath); } bool @@ -797,7 +889,7 @@ Full information on all the above can be found on the support page at\n\ "), PROGRAM_NAME, VERSIONSTRING)); - pre_release_dialog->signal_response().connect (sigc::bind (sigc::mem_fun (this, &StartupFSM::dialog_response_handler), PreReleaseDialog)); + current_dialog_connection = pre_release_dialog->signal_response().connect (sigc::bind (sigc::mem_fun (this, &StartupFSM::dialog_response_handler), PreReleaseDialog)); pre_release_dialog->get_vbox()->set_border_width (12); pre_release_dialog->get_vbox()->pack_start (*label, false, false, 12); |