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