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