Special case JACK, sample-rate cannot be changed for new sessions
[ardour.git] / gtk2_ardour / ardour_ui_session.cc
1 /*
2  * Copyright (C) 2005-2007 Doug McLain <doug@nostar.net>
3  * Copyright (C) 2005-2017 Tim Mayberry <mojofunk@gmail.com>
4  * Copyright (C) 2005-2019 Paul Davis <paul@linuxaudiosystems.com>
5  * Copyright (C) 2005 Karsten Wiese <fzuuzf@googlemail.com>
6  * Copyright (C) 2005 Taybin Rutkin <taybin@taybin.com>
7  * Copyright (C) 2006-2015 David Robillard <d@drobilla.net>
8  * Copyright (C) 2007-2012 Carl Hetherington <carl@carlh.net>
9  * Copyright (C) 2008-2010 Sakari Bergen <sakari.bergen@beatwaves.net>
10  * Copyright (C) 2012-2019 Robin Gareus <robin@gareus.org>
11  * Copyright (C) 2013-2015 Colin Fletcher <colin.m.fletcher@googlemail.com>
12  * Copyright (C) 2013-2016 John Emmas <john@creativepost.co.uk>
13  * Copyright (C) 2013-2016 Nick Mainsbridge <mainsbridge@gmail.com>
14  * Copyright (C) 2014-2018 Ben Loftis <ben@harrisonconsoles.com>
15  * Copyright (C) 2015 AndrĂ© Nusser <andre.nusser@googlemail.com>
16  * Copyright (C) 2016-2018 Len Ovens <len@ovenwerks.net>
17  * Copyright (C) 2017 Johannes Mueller <github@johannes-mueller.org>
18  *
19  * This program is free software; you can redistribute it and/or modify
20  * it under the terms of the GNU General Public License as published by
21  * the Free Software Foundation; either version 2 of the License, or
22  * (at your option) any later version.
23  *
24  * This program is distributed in the hope that it will be useful,
25  * but WITHOUT ANY WARRANTY; without even the implied warranty of
26  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
27  * GNU General Public License for more details.
28  *
29  * You should have received a copy of the GNU General Public License along
30  * with this program; if not, write to the Free Software Foundation, Inc.,
31  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
32  */
33
34 #ifdef WAF_BUILD
35 #include "gtk2ardour-config.h"
36 #include "gtk2ardour-version.h"
37 #endif
38
39 #include <gtkmm/progressbar.h>
40 #include <gtkmm/stock.h>
41
42 #include "pbd/basename.h"
43 #include "pbd/localtime_r.h"
44 #include "pbd/unwind.h"
45
46 #include "gtkmm2ext/application.h"
47 #include "gtkmm2ext/doi.h"
48
49 #include "widgets/prompter.h"
50
51 #include "ardour/audioengine.h"
52 #include "ardour/filename_extensions.h"
53 #include "ardour/profile.h"
54 #include "ardour/session.h"
55 #include "ardour/session_utils.h"
56 #include "ardour/session_state_utils.h"
57 #include "ardour/session_directory.h"
58
59 #include "ardour_message.h"
60 #include "ardour_ui.h"
61 #include "engine_dialog.h"
62 #include "missing_plugin_dialog.h"
63 #include "opts.h"
64 #include "public_editor.h"
65 #include "save_as_dialog.h"
66 #include "session_dialog.h"
67 #include "session_archive_dialog.h"
68 #include "timers.h"
69 #include "utils.h"
70
71 #ifdef WINDOWS_VST_SUPPORT
72 #include <fst.h>
73 #endif
74
75 #include "pbd/i18n.h"
76
77 using namespace ARDOUR;
78 using namespace ARDOUR_UI_UTILS;
79 using namespace PBD;
80 using namespace Gtk;
81 using namespace std;
82 using namespace ArdourWidgets;
83
84 bool
85 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
86 {
87         std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
88
89         ArdourMessageDialog msg (str,
90                                  false,
91                                  Gtk::MESSAGE_WARNING,
92                                  Gtk::BUTTONS_YES_NO,
93                                  true);
94
95         msg.set_name (X_("OpenExistingDialog"));
96         msg.set_title (_("Open Existing Session"));
97         msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
98         msg.set_position (Gtk::WIN_POS_CENTER);
99
100         switch (msg.run()) {
101         case RESPONSE_YES:
102                 return true;
103                 break;
104         }
105         return false;
106 }
107
108 void
109 ARDOUR_UI::build_session_from_dialog (SessionDialog& sd, const std::string& session_path, const std::string& session_name, std::string const& session_template)
110 {
111         BusProfile bus_profile;
112
113         if (nsm) {
114                 bus_profile.master_out_channels = 2;
115         } else if ( Profile->get_mixbus()) {
116                 bus_profile.master_out_channels = 2;
117         } else {
118                 /* get settings from advanced section of NSD */
119                 bus_profile.master_out_channels = (uint32_t) sd.master_channel_count();
120         }
121
122         build_session (session_path, session_name, session_template, bus_profile);
123 }
124
125 /** This is only ever used once Ardour is already running with a session
126  * loaded. The startup case is handled by StartupFSM
127  */
128 void
129 ARDOUR_UI::start_session_load (bool create_new)
130 {
131         /* deal with any existing DIRTY session now, rather than later. don't
132          * treat a non-dirty session this way, so that it stays visible
133          * as we bring up the new session dialog.
134          */
135
136         if (_session && ARDOUR_UI::instance()->video_timeline) {
137                 ARDOUR_UI::instance()->video_timeline->sync_session_state();
138         }
139
140         if (_session && _session->dirty()) {
141                 if (unload_session (false)) {
142                         /* unload cancelled by user */
143                         return;
144                 }
145         }
146
147         SessionDialog* session_dialog = new SessionDialog (create_new, string(), Config->get_default_session_parent_dir(), string(), true);
148         session_dialog->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::session_dialog_response_handler), session_dialog));
149         session_dialog->present ();
150 }
151
152 void
153 ARDOUR_UI::session_dialog_response_handler (int response, SessionDialog* session_dialog)
154 {
155         string session_name;
156         string session_path;
157         string template_name;
158         bool likely_new = false;
159
160         session_path = "";
161         session_name = "";
162
163         switch (response) {
164         case RESPONSE_ACCEPT:
165                 break;
166         default:
167                 return; /* back to main event loop */
168         }
169
170         session_name = session_dialog->session_name (likely_new);
171         session_path = session_dialog->session_folder ();
172
173         if (nsm) {
174                 likely_new = true;
175         }
176
177         /* could be an archived session, so test for that and use the
178          * result if it was
179          */
180
181         if (!likely_new) {
182                 int rv = ARDOUR::inflate_session (session_name, Config->get_default_session_parent_dir(), session_path, session_name);
183
184                 if (rv < 0) {
185                         ArdourMessageDialog msg (*session_dialog, string_compose (_("Extracting session-archive failed: %1"), inflate_error (rv)));
186                         msg.run ();
187                         return; /* back to main event loop */
188                 } else if (rv == 0) {
189                         session_dialog->set_provided_session (session_name, session_path);
190                 }
191         }
192
193         string::size_type suffix = session_name.find (statefile_suffix);
194
195         if (suffix != string::npos) {
196                 session_name = session_name.substr (0, suffix);
197         }
198
199         /* this shouldn't happen, but we catch it just in case it does */
200
201         if (session_name.empty()) {
202                 return; /* back to main event loop */
203         }
204
205         if (session_dialog->use_session_template()) {
206                 template_name = session_dialog->session_template_name();
207                 _session_is_new = true;
208         }
209
210         if (session_name[0] == G_DIR_SEPARATOR ||
211 #ifdef PLATFORM_WINDOWS
212             (session_name.length() > 3 && session_name[1] == ':' && session_name[2] == G_DIR_SEPARATOR)
213 #else
214             (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
215             (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)
216 #endif
217                 )
218         {
219
220                 /* absolute path or cwd-relative path specified for session name: infer session folder
221                    from what was given.
222                 */
223
224                 session_path = Glib::path_get_dirname (session_name);
225                 session_name = Glib::path_get_basename (session_name);
226
227         } else {
228
229                 session_path = session_dialog->session_folder();
230
231                 char illegal = Session::session_name_is_legal (session_name);
232
233                 if (illegal) {
234                         ArdourMessageDialog msg (*session_dialog,
235                                                  string_compose (_("To ensure compatibility with various systems\n"
236                                                                    "session names may not contain a '%1' character"),
237                                                                  illegal));
238                         msg.run ();
239                         return; /* back to main event loop */
240                 }
241         }
242
243         if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
244
245
246                 if (likely_new && !nsm) {
247
248                         std::string existing = Glib::build_filename (session_path, session_name);
249
250                         if (!ask_about_loading_existing_session (existing)) {
251                                 return; /* back to main event loop */
252                         }
253                 }
254
255                 _session_is_new = false;
256
257         } else {
258
259                 if (!likely_new) {
260                         ArdourMessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
261                         msg.run ();
262                         return; /* back to main event loop */
263                 }
264
265                 char illegal = Session::session_name_is_legal(session_name);
266
267                 if (illegal) {
268                         ArdourMessageDialog msg (*session_dialog, string_compose(_("To ensure compatibility with various systems\n"
269                                                                                    "session names may not contain a '%1' character"), illegal));
270                         msg.run ();
271                         return; /* back to main event loop */
272
273                 }
274
275                 _session_is_new = true;
276         }
277
278
279         /* OK, parameters provided ... good to go. */
280
281         session_dialog->hide ();
282         delete_when_idle (session_dialog);
283
284         if (!template_name.empty() || likely_new) {
285
286                 build_session_from_dialog (*session_dialog, session_path, session_name, template_name);
287
288         } else {
289
290                 load_session (session_path, session_name, template_name);
291         }
292 }
293
294 void
295 ARDOUR_UI::close_session()
296 {
297         if (!check_audioengine (_main_window)) {
298                 return;
299         }
300
301         if (unload_session (true)) {
302                 return;
303         }
304
305         start_session_load (false);
306 }
307
308
309 /** @param snap_name Snapshot name (without .ardour suffix).
310  *  @return -2 if the load failed because we are not connected to the AudioEngine.
311  */
312 int
313 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
314 {
315         /* load_session calls flush_pending() which allows
316          * GUI interaction and potentially loading another session
317          * (that was easy via snapshot sidebar).
318          * Recursing into load_session() from load_session() and recusive
319          * event loops causes all kind of crashes.
320          */
321         assert (!session_load_in_progress);
322         if (session_load_in_progress) {
323                 return -1;
324         }
325         PBD::Unwinder<bool> lsu (session_load_in_progress, true);
326
327         int unload_status;
328         bool had_session = false;
329
330         if (_session) {
331                 had_session = true;
332
333                 unload_status = unload_session ();
334
335                 if (unload_status != 0) {
336                         hide_splash ();
337                         return -1;
338                 }
339         }
340
341         if (had_session) {
342                 float sr;
343                 SampleFormat sf;
344                 string pv;
345
346                 Session::get_info_from_path (Glib::build_filename (path, snap_name + statefile_suffix), sr, sf, pv);
347
348                 /* this will stop the engine if the SR is different */
349
350                 audio_midi_setup->set_desired_sample_rate (sr);
351
352                 if (!AudioEngine::instance()->running()) {
353                         audio_midi_setup->set_position (WIN_POS_CENTER);
354                         audio_midi_setup->present ();
355                         _engine_dialog_connection.disconnect ();
356                         _engine_dialog_connection = audio_midi_setup->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::audio_midi_setup_reconfigure_done), path, snap_name, mix_template));
357                         /* not done yet, but we're avoiding modal dialogs */
358                         return 0;
359                 }
360         }
361
362         return load_session_stage_two (path, snap_name, mix_template);
363 }
364
365 void
366 ARDOUR_UI::audio_midi_setup_reconfigure_done (int response, std::string path, std::string snap_name, std::string mix_template)
367 {
368         switch (response) {
369         case Gtk::RESPONSE_DELETE_EVENT:
370                 break;
371         default:
372                 if (!AudioEngine::instance()->running()) {
373                         return; // keep dialog visible, maybe try again
374                 }
375         }
376
377         audio_midi_setup->hide();
378
379         (void) load_session_stage_two (path, snap_name, mix_template);
380 }
381
382 int
383 ARDOUR_UI::load_session_stage_two (const std::string& path, const std::string& snap_name, std::string mix_template)
384 {
385         Session *new_session;
386         int retval = -1;
387
388         BootMessage (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
389
390         try {
391                 new_session = new Session (*AudioEngine::instance(), path, snap_name, 0, mix_template);
392         }
393
394         /* this one is special */
395
396         catch (AudioEngine::PortRegistrationFailure const& err) {
397
398                 ArdourMessageDialog msg (err.what(),
399                                          true,
400                                          Gtk::MESSAGE_INFO,
401                                          Gtk::BUTTONS_CLOSE);
402
403                 msg.set_title (_("Port Registration Error"));
404                 msg.set_secondary_text (_("Click the Close button to try again."));
405                 msg.set_position (Gtk::WIN_POS_CENTER);
406
407                 int response = msg.run ();
408                 msg.hide ();
409
410                 switch (response) {
411                 case RESPONSE_CANCEL:
412                         exit (EXIT_FAILURE);
413                 default:
414                         break;
415                 }
416                 goto out;
417         }
418         catch (SessionException const& e) {
419                 ArdourMessageDialog msg (string_compose(
420                                                  _("Session \"%1 (snapshot %2)\" did not load successfully:\n%3"),
421                                                  path, snap_name, e.what()),
422                                          true,
423                                          Gtk::MESSAGE_INFO,
424                                          BUTTONS_OK);
425
426                 msg.set_title (_("Loading Error"));
427                 msg.set_position (Gtk::WIN_POS_CENTER);
428
429                 dump_errors (cerr);
430
431                 (void) msg.run ();
432                 msg.hide ();
433
434                 goto out;
435         }
436         catch (...) {
437
438                 ArdourMessageDialog msg (string_compose(
439                                            _("Session \"%1 (snapshot %2)\" did not load successfully."),
440                                            path, snap_name),
441                                          true,
442                                          Gtk::MESSAGE_INFO,
443                                          BUTTONS_OK);
444
445                 msg.set_title (_("Loading Error"));
446                 msg.set_position (Gtk::WIN_POS_CENTER);
447
448                 dump_errors (cerr);
449
450                 (void) msg.run ();
451                 msg.hide ();
452
453                 goto out;
454         }
455
456         {
457                 list<string> const u = new_session->unknown_processors ();
458                 if (!u.empty()) {
459                         MissingPluginDialog d (_session, u);
460                         d.run ();
461                 }
462         }
463
464         if (!new_session->writable()) {
465                 ArdourMessageDialog msg (_("This session has been opened in read-only mode.\n\nYou will not be able to record or save."),
466                                          true,
467                                          Gtk::MESSAGE_INFO,
468                                          BUTTONS_OK);
469
470                 msg.set_title (_("Read-only Session"));
471                 msg.set_position (Gtk::WIN_POS_CENTER);
472                 (void) msg.run ();
473                 msg.hide ();
474         }
475
476
477         /* Now the session been created, add the transport controls */
478         new_session->add_controllable(roll_controllable);
479         new_session->add_controllable(stop_controllable);
480         new_session->add_controllable(goto_start_controllable);
481         new_session->add_controllable(goto_end_controllable);
482         new_session->add_controllable(auto_loop_controllable);
483         new_session->add_controllable(play_selection_controllable);
484         new_session->add_controllable(rec_controllable);
485
486         set_session (new_session);
487
488         if (_session) {
489                 _session->set_clean ();
490         }
491
492 #ifdef WINDOWS_VST_SUPPORT
493         fst_stop_threading();
494 #endif
495
496         {
497                 Timers::TimerSuspender t;
498                 flush_pending (10);
499         }
500
501 #ifdef WINDOWS_VST_SUPPORT
502         fst_start_threading();
503 #endif
504         retval = 0;
505
506         if (!mix_template.empty ()) {
507                 /* if mix_template is given, assume this is a new session */
508                 string metascript = Glib::build_filename (mix_template, "template.lua");
509                 meta_session_setup (metascript);
510         }
511
512
513   out:
514         /* For successful session load the splash is hidden by ARDOUR_UI::first_idle,
515          * which is queued by set_session().
516          * If session-loading fails we hide it explicitly.
517          * This covers both cases in a central place.
518          */
519         if (retval) {
520                 hide_splash ();
521         }
522         return retval;
523 }
524
525 int
526 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, const std::string& session_template, BusProfile const& bus_profile, bool from_startup_fsm)
527 {
528         int x;
529
530         x = unload_session ();
531
532         if (x < 0) {
533                 return -1;
534         } else if (x > 0) {
535                 return 0;
536         }
537
538         _session_is_new = true;
539
540         /* when running from startup FSM all is fine,
541          * engine should be running and the FSM will also have
542          * asked for the SR (even if try-autostart-engine is set)
543          */
544         if (from_startup_fsm && AudioEngine::instance()->running ()) {
545                 return build_session_stage_two (path, snap_name, session_template, bus_profile);
546         }
547         /* Sample-rate cannot be changed when JACK is running */
548         if (!ARDOUR::AudioEngine::instance()->setup_required () && AudioEngine::instance()->running ()) {
549                 return build_session_stage_two (path, snap_name, session_template, bus_profile);
550         }
551
552         /* Ask for the Sample-rate to use with the new session */
553         audio_midi_setup->set_position (WIN_POS_CENTER);
554         audio_midi_setup->set_modal ();
555         audio_midi_setup->present ();
556         _engine_dialog_connection.disconnect ();
557         _engine_dialog_connection = audio_midi_setup->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::audio_midi_setup_for_new_session_done), path, snap_name, session_template, bus_profile));
558
559         /* not done yet, but we're avoiding modal dialogs */
560         return 0;
561 }
562
563
564 void
565 ARDOUR_UI::audio_midi_setup_for_new_session_done (int response, std::string path, std::string snap_name, std::string template_name, BusProfile const& bus_profile)
566 {
567         switch (response) {
568                 case Gtk::RESPONSE_DELETE_EVENT:
569                         audio_midi_setup->set_modal (false);
570                         break;
571                 default:
572                         break;
573         }
574
575         if (!AudioEngine::instance()->running()) {
576                 return; // keep dialog visible, maybe try again
577         }
578         audio_midi_setup->set_modal (false);
579         audio_midi_setup->hide();
580
581         build_session_stage_two (path, snap_name, template_name, bus_profile);
582 }
583
584 int
585 ARDOUR_UI::build_session_stage_two (std::string const& path, std::string const& snap_name, std::string const& session_template, BusProfile const& bus_profile)
586 {
587         Session* new_session;
588
589         try {
590                 new_session = new Session (*AudioEngine::instance(), path, snap_name, bus_profile.master_out_channels > 0 ? &bus_profile : NULL);
591         }
592         catch (SessionException const& e) {
593                 cerr << "Here are the errors associated with this failed session:\n";
594                 dump_errors (cerr);
595                 cerr << "---------\n";
596                 ArdourMessageDialog msg (string_compose(_("Could not create session in \"%1\": %2"), path, e.what()));
597                 msg.set_title (_("Loading Error"));
598                 msg.set_position (Gtk::WIN_POS_CENTER);
599                 msg.run ();
600                 return -1;
601         }
602         catch (...) {
603                 cerr << "Here are the errors associated with this failed session:\n";
604                 dump_errors (cerr);
605                 cerr << "---------\n";
606                 ArdourMessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
607                 msg.set_title (_("Loading Error"));
608                 msg.set_position (Gtk::WIN_POS_CENTER);
609                 msg.run ();
610                 return -1;
611         }
612
613         /* Give the new session the default GUI state, if such things exist */
614
615         XMLNode* n;
616         n = Config->instant_xml (X_("Editor"));
617         if (n) {
618                 n->remove_nodes_and_delete ("Selection"); // no not apply selection to new sessions.
619                 new_session->add_instant_xml (*n, false);
620         }
621         n = Config->instant_xml (X_("Mixer"));
622         if (n) {
623                 new_session->add_instant_xml (*n, false);
624         }
625
626         n = Config->instant_xml (X_("Preferences"));
627         if (n) {
628                 new_session->add_instant_xml (*n, false);
629         }
630
631         /* Put the playhead at 0 and scroll fully left */
632         n = new_session->instant_xml (X_("Editor"));
633         if (n) {
634                 n->set_property (X_("playhead"), X_("0"));
635                 n->set_property (X_("left-frame"), X_("0"));
636         }
637
638         set_session (new_session);
639
640         new_session->save_state(new_session->name());
641
642         if (!session_template.empty() && session_template.substr (0, 11) == "urn:ardour:") {
643                 meta_session_setup (session_template.substr (11));
644         }
645
646         return 0;
647 }
648
649 /** Ask the user for the name of a new snapshot and then take it.
650  */
651
652 void
653 ARDOUR_UI::snapshot_session (bool switch_to_it)
654 {
655         if (switch_to_it && _session->dirty()) {
656                 vector<string> actions;
657                 actions.push_back (_("Abort saving snapshot"));
658                 actions.push_back (_("Don't save now, just snapshot"));
659                 actions.push_back (_("Save it first"));
660                 switch (ask_about_saving_session(actions)) {
661                         case -1:
662                                 return;
663                                 break;
664                         case 1:
665                                 if (save_state_canfail ("")) {
666                                         ArdourMessageDialog msg (_main_window,
667                                                         string_compose (_("\
668 %1 was unable to save your session.\n\n\
669 If you still wish to proceed, please use the\n\n\
670 \"Don't save now\" option."), PROGRAM_NAME));
671                                         msg.run ();
672                                         return;
673                                 }
674                                 /* fallthrough */
675                         case 0:
676                                 _session->remove_pending_capture_state ();
677                                 break;
678                 }
679         }
680
681         Prompter prompter (true);
682         prompter.set_name ("Prompter");
683         prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
684         if (switch_to_it) {
685                 prompter.set_title (_("Snapshot and switch"));
686                 prompter.set_prompt (_("New session name"));
687         } else {
688                 prompter.set_title (_("Take Snapshot"));
689                 prompter.set_prompt (_("Name of new snapshot"));
690         }
691
692         if (switch_to_it) {
693                 prompter.set_initial_text (_session->snap_name());
694         } else {
695                 Glib::DateTime tm (g_date_time_new_now_local ());
696                 prompter.set_initial_text (tm.format ("%FT%H.%M.%S"));
697         }
698
699         bool finished = false;
700         while (!finished) {
701                 switch (prompter.run()) {
702                 case RESPONSE_ACCEPT:
703                 {
704                         finished = process_snapshot_session_prompter (prompter, switch_to_it);
705                         break;
706                 }
707
708                 default:
709                         finished = true;
710                         break;
711                 }
712         }
713 }
714
715 /** Ask the user for a new session name and then rename the session to it.
716  */
717
718 void
719 ARDOUR_UI::rename_session ()
720 {
721         if (!_session) {
722                 return;
723         }
724
725         Prompter prompter (true);
726         string name;
727
728         prompter.set_name ("Prompter");
729         prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
730         prompter.set_title (_("Rename Session"));
731         prompter.set_prompt (_("New session name"));
732
733   again:
734         switch (prompter.run()) {
735         case RESPONSE_ACCEPT:
736         {
737                 prompter.get_result (name);
738
739                 bool do_rename = (name.length() != 0);
740
741                 if (do_rename) {
742                         char illegal = Session::session_name_is_legal (name);
743
744                         if (illegal) {
745                                 ArdourMessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
746                                                                      "session names may not contain a '%1' character"), illegal));
747                                 msg.run ();
748                                 goto again;
749                         }
750
751                         switch (_session->rename (name)) {
752                         case -1: {
753                                 ArdourMessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
754                                 msg.run ();
755                                 goto again;
756                                 break;
757                         }
758                         case 0:
759                                 break;
760                         default: {
761                                 ArdourMessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
762                                 msg.run ();
763                                 break;
764                         }
765                         }
766                 }
767
768                 break;
769         }
770
771         default:
772                 break;
773         }
774 }
775
776 bool
777 ARDOUR_UI::save_as_progress_update (float fraction, int64_t cnt, int64_t total, Gtk::Label* label, Gtk::ProgressBar* bar)
778 {
779         char buf[256];
780
781         snprintf (buf, sizeof (buf), _("Copied %" PRId64 " of %" PRId64), cnt, total);
782
783         label->set_text (buf);
784         bar->set_fraction (fraction);
785
786         /* process events, redraws, etc. */
787
788         while (gtk_events_pending()) {
789                 gtk_main_iteration ();
790         }
791
792         return true; /* continue with save-as */
793 }
794
795 void
796 ARDOUR_UI::save_session_as ()
797 {
798         if (!_session) {
799                 return;
800         }
801
802         if (_session->dirty()) {
803                 vector<string> actions;
804                 actions.push_back (_("Abort save-as"));
805                 actions.push_back (_("Don't save now, just save-as"));
806                 actions.push_back (_("Save it first"));
807                 switch (ask_about_saving_session(actions)) {
808                         case -1:
809                                 return;
810                                 break;
811                         case 1:
812                                 if (save_state_canfail ("")) {
813                                         ArdourMessageDialog msg (_main_window,
814                                                         string_compose (_("\
815 %1 was unable to save your session.\n\n\
816 If you still wish to proceed, please use the\n\n\
817 \"Don't save now\" option."), PROGRAM_NAME));
818                                         msg.run ();
819                                         return;
820                                 }
821                                 /* fallthrough */
822                         case 0:
823                                 _session->remove_pending_capture_state ();
824                                 break;
825                 }
826         }
827
828         if (!save_as_dialog) {
829                 save_as_dialog = new SaveAsDialog;
830         }
831
832         save_as_dialog->set_name (_session->name());
833
834         int response = save_as_dialog->run ();
835
836         save_as_dialog->hide ();
837
838         switch (response) {
839         case Gtk::RESPONSE_OK:
840                 break;
841         default:
842                 return;
843         }
844
845
846         Session::SaveAs sa;
847
848         sa.new_parent_folder = save_as_dialog->new_parent_folder ();
849         sa.new_name = save_as_dialog->new_name ();
850         sa.switch_to = save_as_dialog->switch_to();
851         sa.copy_media = save_as_dialog->copy_media();
852         sa.copy_external = save_as_dialog->copy_external();
853         sa.include_media = save_as_dialog->include_media ();
854
855         /* Only bother with a progress dialog if we're going to copy
856            media into the save-as target. Without that choice, this
857            will be very fast because we're only talking about a few kB's to
858            perhaps a couple of MB's of data.
859         */
860
861         ArdourDialog progress_dialog (_("Save As"), true);
862         ScopedConnection c;
863
864         if (sa.include_media && sa.copy_media) {
865
866                 Gtk::Label* label = manage (new Gtk::Label());
867                 Gtk::ProgressBar* progress_bar = manage (new Gtk::ProgressBar ());
868
869                 progress_dialog.get_vbox()->pack_start (*label);
870                 progress_dialog.get_vbox()->pack_start (*progress_bar);
871                 label->show ();
872                 progress_bar->show ();
873
874                 /* this signal will be emitted from within this, the calling thread,
875                  * after every file is copied. It provides information on percentage
876                  * complete (in terms of total data to copy), the number of files
877                  * copied so far, and the total number to copy.
878                  */
879
880                 sa.Progress.connect_same_thread (c, boost::bind (&ARDOUR_UI::save_as_progress_update, this, _1, _2, _3, label, progress_bar));
881
882                 progress_dialog.show_all ();
883                 progress_dialog.present ();
884         }
885
886         if (_session->save_as (sa)) {
887                 /* ERROR MESSAGE */
888                 ArdourMessageDialog msg (string_compose (_("Save As failed: %1"), sa.failure_message));
889                 msg.run ();
890         }
891
892         /* the logic here may seem odd: why isn't the condition sa.switch_to ?
893          * the trick is this: if the new session was copy with media included,
894          * then Session::save_as() will have already done a neat trick to avoid
895          * us having to unload and load the new state. But if the media was not
896          * included, then this is required (it avoids us having to otherwise
897          * drop all references to media (sources).
898          */
899
900         if (!sa.include_media && sa.switch_to) {
901                 unload_session (false);
902                 load_session (sa.final_session_folder_name, sa.new_name);
903         }
904 }
905
906 void
907 ARDOUR_UI::archive_session ()
908 {
909         if (!_session) {
910                 return;
911         }
912
913         time_t n;
914         time (&n);
915         Glib::DateTime gdt (Glib::DateTime::create_now_local (n));
916
917         SessionArchiveDialog sad;
918         sad.set_name (_session->name() + gdt.format ("_%F_%H%M%S"));
919         int response = sad.run ();
920
921         if (response != Gtk::RESPONSE_OK) {
922                 sad.hide ();
923                 return;
924         }
925
926         if (_session->archive_session (sad.target_folder(), sad.name(), sad.encode_option (), sad.compression_level (), sad.only_used_sources (), &sad)) {
927                 ArdourMessageDialog msg (_("Session Archiving failed."));
928                 msg.run ();
929         }
930 }
931
932 void
933 ARDOUR_UI::quick_snapshot_session (bool switch_to_it)
934 {
935                 char timebuf[128];
936                 time_t n;
937                 struct tm local_time;
938
939                 time (&n);
940                 localtime_r (&n, &local_time);
941                 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
942                 if (switch_to_it && _session->dirty ()) {
943                         save_state_canfail ("");
944                 }
945
946                 save_state (timebuf, switch_to_it);
947 }
948
949
950 bool
951 ARDOUR_UI::process_snapshot_session_prompter (Prompter& prompter, bool switch_to_it)
952 {
953         string snapname;
954
955         prompter.get_result (snapname);
956
957         bool do_save = (snapname.length() != 0);
958
959         if (do_save) {
960                 char illegal = Session::session_name_is_legal(snapname);
961                 if (illegal) {
962                         ArdourMessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
963                                                                    "snapshot names may not contain a '%1' character"), illegal));
964                         msg.run ();
965                         return false;
966                 }
967         }
968
969         vector<std::string> p;
970         get_state_files_in_directory (_session->session_directory().root_path(), p);
971         vector<string> n = get_file_names_no_extension (p);
972
973         if (find (n.begin(), n.end(), snapname) != n.end()) {
974
975                 do_save = overwrite_file_dialog (prompter,
976                                                  _("Confirm Snapshot Overwrite"),
977                                                  _("A snapshot already exists with that name. Do you want to overwrite it?"));
978         }
979
980         if (do_save) {
981                 save_state (snapname, switch_to_it);
982         }
983         else {
984                 return false;
985         }
986
987         return true;
988 }
989
990
991 void
992 ARDOUR_UI::open_session ()
993 {
994         if (!check_audioengine (_main_window)) {
995                 return;
996         }
997
998         /* ardour sessions are folders */
999         Gtk::FileChooserDialog open_session_selector(_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1000         open_session_selector.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1001         open_session_selector.add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1002         open_session_selector.set_default_response(Gtk::RESPONSE_ACCEPT);
1003
1004         if (_session) {
1005                 string session_parent_dir = Glib::path_get_dirname(_session->path());
1006                 open_session_selector.set_current_folder(session_parent_dir);
1007         } else {
1008                 open_session_selector.set_current_folder(Config->get_default_session_parent_dir());
1009         }
1010
1011         Gtkmm2ext::add_volume_shortcuts (open_session_selector);
1012         try {
1013                 /* add_shortcut_folder throws an exception if the folder being added already has a shortcut */
1014                 string default_session_folder = Config->get_default_session_parent_dir();
1015                 open_session_selector.add_shortcut_folder (default_session_folder);
1016         }
1017         catch (Glib::Error const& e) {
1018                 std::cerr << "open_session_selector.add_shortcut_folder() threw Glib::Error " << e.what() << std::endl;
1019         }
1020
1021         FileFilter session_filter;
1022         session_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::statefile_suffix));
1023         session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1024         open_session_selector.add_filter (session_filter);
1025
1026         FileFilter archive_filter;
1027         archive_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::session_archive_suffix));
1028         archive_filter.set_name (_("Session Archives"));
1029
1030         open_session_selector.add_filter (archive_filter);
1031
1032         open_session_selector.set_filter (session_filter);
1033
1034         int response = open_session_selector.run();
1035         open_session_selector.hide ();
1036
1037         if (response == Gtk::RESPONSE_CANCEL) {
1038                 return;
1039         }
1040
1041         string session_path = open_session_selector.get_filename();
1042         string path, name;
1043         bool isnew;
1044
1045         if (session_path.length() > 0) {
1046                 int rv = ARDOUR::inflate_session (session_path,
1047                                 Config->get_default_session_parent_dir(), path, name);
1048                 if (rv == 0) {
1049                         _session_is_new = false;
1050                         load_session (path, name);
1051                 }
1052                 else if (rv < 0) {
1053                         ArdourMessageDialog msg (_main_window,
1054                                                  string_compose (_("Extracting session-archive failed: %1"), inflate_error (rv)));
1055                         msg.run ();
1056                 }
1057                 else if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1058                         _session_is_new = isnew;
1059                         load_session (path, name);
1060                 }
1061         }
1062 }
1063
1064 void
1065 ARDOUR_UI::open_recent_session ()
1066 {
1067         bool can_return = (_session != 0);
1068
1069         SessionDialog recent_session_dialog;
1070
1071         while (true) {
1072
1073                 ResponseType r = (ResponseType) recent_session_dialog.run ();
1074
1075                 switch (r) {
1076                 case RESPONSE_ACCEPT:
1077                         break;
1078                 default:
1079                         if (can_return) {
1080                                 recent_session_dialog.hide();
1081                                 return;
1082                         } else {
1083                                 exit (EXIT_FAILURE);
1084                         }
1085                 }
1086
1087                 recent_session_dialog.hide();
1088
1089                 bool should_be_new;
1090
1091                 std::string path = recent_session_dialog.session_folder();
1092                 std::string state = recent_session_dialog.session_name (should_be_new);
1093
1094                 if (should_be_new == true) {
1095                         continue;
1096                 }
1097
1098                 _session_is_new = false;
1099
1100                 if (load_session (path, state) == 0) {
1101                         break;
1102                 }
1103
1104                 can_return = false;
1105         }
1106 }
1107
1108 int
1109 ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
1110 {
1111         ArdourDialog window (_("Unsaved Session"));
1112         Gtk::HBox dhbox;  // the hbox for the image and text
1113         Gtk::Label  prompt_label;
1114         Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING,  Gtk::ICON_SIZE_DIALOG));
1115
1116         string msg;
1117
1118         assert (actions.size() >= 3);
1119
1120         window.add_button (actions[0], RESPONSE_REJECT);
1121         window.add_button (actions[1], RESPONSE_APPLY);
1122         window.add_button (actions[2], RESPONSE_ACCEPT);
1123
1124         window.set_default_response (RESPONSE_ACCEPT);
1125
1126         Gtk::Button noquit_button (msg);
1127         noquit_button.set_name ("EditorGTKButton");
1128
1129         string prompt;
1130
1131         if (_session->snap_name() == _session->name()) {
1132                 prompt = string_compose(_("The session \"%1\"\nhas not been saved.\n\nAny changes made this time\nwill be lost unless you save it.\n\nWhat do you want to do?"),
1133                                         _session->snap_name());
1134         } else {
1135                 prompt = string_compose(_("The snapshot \"%1\"\nhas not been saved.\n\nAny changes made this time\nwill be lost unless you save it.\n\nWhat do you want to do?"),
1136                                         _session->snap_name());
1137         }
1138
1139         prompt_label.set_text (prompt);
1140         prompt_label.set_name (X_("PrompterLabel"));
1141         prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
1142
1143         dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
1144         dhbox.set_homogeneous (false);
1145         dhbox.pack_start (*dimage, false, false, 5);
1146         dhbox.pack_start (prompt_label, true, false, 5);
1147         window.get_vbox()->pack_start (dhbox);
1148
1149         window.set_name (_("Prompter"));
1150         window.set_modal (true);
1151         window.set_resizable (false);
1152
1153         dhbox.show();
1154         prompt_label.show();
1155         dimage->show();
1156         window.show();
1157         window.present ();
1158
1159         ResponseType r = (ResponseType) window.run();
1160
1161         window.hide ();
1162
1163         switch (r) {
1164         case RESPONSE_ACCEPT: // save and get out of here
1165                 return 1;
1166         case RESPONSE_APPLY:  // get out of here
1167                 return 0;
1168         default:
1169                 break;
1170         }
1171
1172         return -1;
1173 }
1174
1175
1176 void
1177 ARDOUR_UI::save_session_at_its_request (std::string snapshot_name)
1178 {
1179         if (_session) {
1180                 _session->save_state (snapshot_name);
1181         }
1182 }
1183
1184 gint
1185 ARDOUR_UI::autosave_session ()
1186 {
1187         if (g_main_depth() > 1) {
1188                 /* inside a recursive main loop,
1189                    give up because we may not be able to
1190                    take a lock.
1191                 */
1192                 return 1;
1193         }
1194
1195         if (!Config->get_periodic_safety_backups()) {
1196                 return 1;
1197         }
1198
1199         if (_session) {
1200                 _session->maybe_write_autosave();
1201         }
1202
1203         return 1;
1204 }