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