156125e01c4b35e7d8183efd534df0eedd41dd84
[ardour.git] / gtk2_ardour / ardour_ui.cc
1 /*
2     Copyright (C) 1999-2007 Paul Davis
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #ifdef WAF_BUILD
21 #include "gtk2ardour-config.h"
22 #endif
23
24 #include <stdint.h>
25
26 #include <algorithm>
27 #include <cmath>
28 #include <fcntl.h>
29 #include <signal.h>
30 #include <unistd.h>
31 #include <time.h>
32 #include <cerrno>
33 #include <fstream>
34
35 #include <iostream>
36
37 #include <sys/resource.h>
38
39 #include <gtkmm/messagedialog.h>
40 #include <gtkmm/accelmap.h>
41
42 #include "pbd/error.h"
43 #include "pbd/basename.h"
44 #include "pbd/compose.h"
45 #include "pbd/failed_constructor.h"
46 #include "pbd/enumwriter.h"
47 #include "pbd/memento_command.h"
48 #include "pbd/openuri.h"
49 #include "pbd/file_utils.h"
50
51 #include "gtkmm2ext/application.h"
52 #include "gtkmm2ext/bindings.h"
53 #include "gtkmm2ext/gtk_ui.h"
54 #include "gtkmm2ext/utils.h"
55 #include "gtkmm2ext/click_box.h"
56 #include "gtkmm2ext/fastmeter.h"
57 #include "gtkmm2ext/popup.h"
58 #include "gtkmm2ext/window_title.h"
59
60 #include "midi++/manager.h"
61
62 #include "ardour/ardour.h"
63 #include "ardour/callback.h"
64 #include "ardour/profile.h"
65 #include "ardour/session_directory.h"
66 #include "ardour/session_route.h"
67 #include "ardour/session_state_utils.h"
68 #include "ardour/session_utils.h"
69 #include "ardour/port.h"
70 #include "ardour/audioengine.h"
71 #include "ardour/playlist.h"
72 #include "ardour/utils.h"
73 #include "ardour/audio_diskstream.h"
74 #include "ardour/audiofilesource.h"
75 #include "ardour/recent_sessions.h"
76 #include "ardour/port.h"
77 #include "ardour/audio_track.h"
78 #include "ardour/midi_track.h"
79 #include "ardour/filesystem_paths.h"
80 #include "ardour/filename_extensions.h"
81 #include "ardour/process_thread.h"
82
83 typedef uint64_t microseconds_t;
84
85 #include "about.h"
86 #include "actions.h"
87 #include "add_route_dialog.h"
88 #include "ambiguous_file_dialog.h"
89 #include "ardour_ui.h"
90 #include "audio_clock.h"
91 #include "bundle_manager.h"
92 #include "engine_dialog.h"
93 #include "gain_meter.h"
94 #include "global_port_matrix.h"
95 #include "gui_object.h"
96 #include "gui_thread.h"
97 #include "keyboard.h"
98 #include "location_ui.h"
99 #include "missing_file_dialog.h"
100 #include "missing_plugin_dialog.h"
101 #include "mixer_ui.h"
102 #include "opts.h"
103 #include "processor_box.h"
104 #include "prompter.h"
105 #include "public_editor.h"
106 #include "route_time_axis.h"
107 #include "session_metadata_dialog.h"
108 #include "shuttle_control.h"
109 #include "speaker_dialog.h"
110 #include "splash.h"
111 #include "startup.h"
112 #include "theme_manager.h"
113 #include "time_axis_view_item.h"
114 #include "utils.h"
115 #include "window_proxy.h"
116
117 #include "i18n.h"
118
119 using namespace ARDOUR;
120 using namespace PBD;
121 using namespace Gtkmm2ext;
122 using namespace Gtk;
123
124 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
125 UIConfiguration *ARDOUR_UI::ui_config = 0;
126
127 sigc::signal<void,bool> ARDOUR_UI::Blink;
128 sigc::signal<void>      ARDOUR_UI::RapidScreenUpdate;
129 sigc::signal<void>      ARDOUR_UI::SuperRapidScreenUpdate;
130 sigc::signal<void, framepos_t, bool, framepos_t> ARDOUR_UI::Clock;
131
132 bool could_be_a_valid_path (const string& path);
133
134 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[])
135
136         : Gtkmm2ext::UI (PROGRAM_NAME, argcp, argvp)
137
138         , gui_object_state (new GUIObjectState)
139         , primary_clock (new AudioClock (X_("primary"), false, X_("TransportClockDisplay"), true, true, false, true))
140         , secondary_clock (new AudioClock (X_("secondary"), false, X_("SecondaryClockDisplay"), true, true, false, true))
141
142           /* big clock */
143
144         , big_clock (new AudioClock (X_("bigclock"), false, "BigClockNonRecording", true, true, false, false))
145
146           /* transport */
147
148         , roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll))
149         , stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop))
150         , goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart))
151         , goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd))
152         , auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop))
153         , play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection))
154         , rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable))
155
156         , auto_return_button (ArdourButton::led_default_elements)
157         , auto_play_button (ArdourButton::led_default_elements)
158         , auto_input_button (ArdourButton::led_default_elements)
159
160         , time_master_button (_("time\nmaster"))
161
162         , auditioning_alert_button (_("AUDITION"))
163         , solo_alert_button (_("SOLO"))
164
165         , error_log_button (_("Errors"))
166
167         , _status_bar_visibility (X_("status-bar"))
168
169 {
170         using namespace Gtk::Menu_Helpers;
171
172         Gtkmm2ext::init();
173
174
175 #ifdef TOP_MENUBAR
176         // _auto_display_errors = false;
177         /*
178          * This was commented out as it wasn't defined
179          * in A3 IIRC.  If this is not needed it should
180          * be completely removed.
181          */
182 #endif
183
184         about = 0;
185         splash = 0;
186         _startup = 0;
187
188         if (theArdourUI == 0) {
189                 theArdourUI = this;
190         }
191
192         ui_config = new UIConfiguration();
193         theme_manager = new ThemeManager();
194
195         key_editor = 0;
196
197         editor = 0;
198         mixer = 0;
199         editor = 0;
200         engine = 0;
201         _session_is_new = false;
202         big_clock_window = 0;
203         big_clock_height = 0;
204         big_clock_resize_in_progress = false;
205         session_selector_window = 0;
206         last_key_press_time = 0;
207         _will_create_new_session_automatically = false;
208         add_route_dialog = 0;
209         route_params = 0;
210         bundle_manager = 0;
211         rc_option_editor = 0;
212         session_option_editor = 0;
213         location_ui = 0;
214         open_session_selector = 0;
215         have_configure_timeout = false;
216         have_disk_speed_dialog_displayed = false;
217         session_loaded = false;
218         ignore_dual_punch = false;
219         original_big_clock_width = -1;
220         original_big_clock_height = -1;
221         original_big_clock_font_size = 0;
222
223         roll_button.set_controllable (roll_controllable);
224         stop_button.set_controllable (stop_controllable);
225         goto_start_button.set_controllable (goto_start_controllable);
226         goto_end_button.set_controllable (goto_end_controllable);
227         auto_loop_button.set_controllable (auto_loop_controllable);
228         play_selection_button.set_controllable (play_selection_controllable);
229         rec_button.set_controllable (rec_controllable);
230
231         roll_button.set_name ("transport button");
232         stop_button.set_name ("transport button");
233         goto_start_button.set_name ("transport button");
234         goto_end_button.set_name ("transport button");
235         auto_loop_button.set_name ("transport button");
236         play_selection_button.set_name ("transport button");
237         rec_button.set_name ("transport recenable button");
238         join_play_range_button.set_name ("transport button");
239
240         roll_button.set_tweaks (ArdourButton::ShowHover);
241         stop_button.set_tweaks (ArdourButton::ShowHover);
242         auto_loop_button.set_tweaks (ArdourButton::ShowHover);
243         play_selection_button.set_tweaks (ArdourButton::ShowHover);
244         rec_button.set_tweaks (ArdourButton::ShowHover);
245         join_play_range_button.set_tweaks (ArdourButton::ShowHover);
246
247         goto_start_button.set_tweaks (ArdourButton::Tweaks(ArdourButton::ShowClick|ArdourButton::ShowHover));
248         goto_end_button.set_tweaks (ArdourButton::Tweaks(ArdourButton::ShowClick|ArdourButton::ShowHover));
249         
250         last_configure_time= 0;
251         last_peak_grab = 0;
252
253         ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
254         ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
255
256         /* handle dialog requests */
257
258         ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
259
260         /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
261
262         ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
263
264         /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
265
266         ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
267
268         /* handle requests to quit (coming from JACK session) */
269
270         ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::finish, this), gui_context ());
271
272         /* tell the user about feedback */
273
274         ARDOUR::Session::FeedbackDetected.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::feedback_detected, this), gui_context ());
275
276         /* handle requests to deal with missing files */
277
278         ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
279
280         /* and ambiguous files */
281
282         ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2, _3));
283
284         /* lets get this party started */
285
286         try {
287                 if (ARDOUR::init (ARDOUR_COMMAND_LINE::use_vst, ARDOUR_COMMAND_LINE::try_hw_optimization)) {
288                         throw failed_constructor ();
289                 }
290
291                 setup_gtk_ardour_enums ();
292                 setup_profile ();
293
294                 GainMeter::setup_slider_pix ();
295                 RouteTimeAxisView::setup_slider_pix ();
296                 SendProcessorEntry::setup_slider_pix ();
297                 SessionEvent::create_per_thread_pool ("GUI", 512);
298
299         } catch (failed_constructor& err) {
300                 error << string_compose (_("could not initialize %1."), PROGRAM_NAME) << endmsg;
301                 // pass it on up
302                 throw;
303         }
304
305         /* we like keyboards */
306
307         keyboard = new ArdourKeyboard(*this);
308
309         XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
310         if (node) {
311                 keyboard->set_state (*node, Stateful::loading_state_version);
312         }
313
314         /* we don't like certain modifiers */
315         Bindings::set_ignored_state (GDK_LOCK_MASK|GDK_MOD2_MASK|GDK_MOD3_MASK);
316
317         reset_dpi();
318
319         TimeAxisViewItem::set_constant_heights ();
320
321         /* The following must happen after ARDOUR::init() so that Config is set up */
322
323         location_ui = new ActionWindowProxy<LocationUIWindow> (X_("locations"), Config->extra_xml (X_("UI")), X_("ToggleLocations"));
324         big_clock_window = new ActionWindowProxy<Gtk::Window> (X_("bigclock"), Config->extra_xml (X_("UI")), X_("ToggleBigClock"));
325         speaker_config_window = new ActionWindowProxy<SpeakerDialog> (X_("speakerconf"), Config->extra_xml (X_("UI")), X_("toggle-speaker-config"));
326
327         for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) {
328                 _global_port_matrix[*i] = new ActionWindowProxy<GlobalPortMatrixWindow> (
329                         string_compose ("GlobalPortMatrix-%1", (*i).to_string()),
330                         Config->extra_xml (X_("UI")),
331                         string_compose ("toggle-%1-connection-manager", (*i).to_string())
332                         );
333         }
334
335         setup_clock ();
336
337         SpeakerDialog* s = new SpeakerDialog ();
338         s->signal_unmap().connect (sigc::bind (sigc::ptr_fun (&ActionManager::uncheck_toggleaction), X_("<Actions>/Common/toggle-speaker-config")));
339         speaker_config_window->set (s);
340
341         starting.connect (sigc::mem_fun(*this, &ARDOUR_UI::startup));
342         stopping.connect (sigc::mem_fun(*this, &ARDOUR_UI::shutdown));
343
344         _process_thread = new ProcessThread ();
345         _process_thread->init ();
346 }
347
348 /** @return true if a session was chosen and `apply' clicked, otherwise false if `cancel' was clicked */
349 bool
350 ARDOUR_UI::run_startup (bool should_be_new, string load_template)
351 {
352         delete _startup;
353         _startup = new ArdourStartup ();
354
355         XMLNode* audio_setup = Config->extra_xml ("AudioSetup");
356
357         if (audio_setup && _startup->engine_control()) {
358                 _startup->engine_control()->set_state (*audio_setup);
359         }
360
361         _startup->set_new_only (should_be_new);
362         if (!load_template.empty()) {
363                 _startup->set_load_template( load_template );
364         }
365         _startup->present ();
366
367         main().run();
368
369         _startup->hide ();
370
371         switch (_startup->response()) {
372         case RESPONSE_OK:
373                 return true;
374         default:
375                 return false;
376         }
377 }
378
379 int
380 ARDOUR_UI::create_engine ()
381 {
382         // this gets called every time by new_session()
383
384         if (engine) {
385                 return 0;
386         }
387
388         loading_message (_("Starting audio engine"));
389
390         try {
391                 engine = new ARDOUR::AudioEngine (ARDOUR_COMMAND_LINE::jack_client_name, ARDOUR_COMMAND_LINE::jack_session_uuid);
392
393         } catch (...) {
394
395                 return -1;
396         }
397
398         engine->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
399         engine->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
400         engine->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
401
402         engine->Halted.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
403
404         ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
405
406         post_engine ();
407
408         return 0;
409 }
410
411 void
412 ARDOUR_UI::post_engine ()
413 {
414         /* Things to be done once we create the AudioEngine
415          */
416
417         ARDOUR::init_post_engine ();
418
419         ActionManager::init ();
420         _tooltips.enable();
421
422         if (setup_windows ()) {
423                 throw failed_constructor ();
424         }
425
426         /* Do this after setup_windows (), as that's when the _status_bar_visibility is created */
427         XMLNode* n = Config->extra_xml (X_("UI"));
428         if (n) {
429                 _status_bar_visibility.set_state (*n);
430         }
431         
432         check_memory_locking();
433
434         /* this is the first point at which all the keybindings are available */
435
436         if (ARDOUR_COMMAND_LINE::show_key_actions) {
437                 vector<string> names;
438                 vector<string> paths;
439                 vector<string> tooltips;
440                 vector<string> keys;
441                 vector<AccelKey> bindings;
442
443                 ActionManager::get_all_actions (names, paths, tooltips, keys, bindings);
444
445                 vector<string>::iterator n;
446                 vector<string>::iterator k;
447                 for (n = names.begin(), k = keys.begin(); n != names.end(); ++n, ++k) {
448                         cerr << "Action: " << (*n) << " bound to " << (*k) << endl;
449                 }
450
451                 exit (0);
452         }
453
454         blink_timeout_tag = -1;
455
456         /* this being a GUI and all, we want peakfiles */
457
458         AudioFileSource::set_build_peakfiles (true);
459         AudioFileSource::set_build_missing_peakfiles (true);
460
461         /* set default clock modes */
462
463         if (Profile->get_sae()) {
464                 primary_clock->set_mode (AudioClock::BBT);
465                 secondary_clock->set_mode (AudioClock::MinSec);
466         }  else {
467                 primary_clock->set_mode (AudioClock::Timecode);
468                 secondary_clock->set_mode (AudioClock::BBT);
469         }
470
471         /* start the time-of-day-clock */
472
473 #ifndef GTKOSX
474         /* OS X provides a nearly-always visible wallclock, so don't be stupid */
475         update_wall_clock ();
476         Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 60000);
477 #endif
478
479         update_disk_space ();
480         update_cpu_load ();
481         update_sample_rate (engine->frame_rate());
482
483         Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
484         boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
485         Config->map_parameters (pc);
486
487         /* now start and maybe save state */
488
489         if (do_engine_start () == 0) {
490                 if (_session && _session_is_new) {
491                         /* we need to retain initial visual
492                            settings for a new session
493                         */
494                         _session->save_state ("");
495                 }
496         }
497 }
498
499 ARDOUR_UI::~ARDOUR_UI ()
500 {
501         delete keyboard;
502         delete editor;
503         delete mixer;
504         delete add_route_dialog;
505 }
506
507 void
508 ARDOUR_UI::pop_back_splash ()
509 {
510         if (Splash::instance()) {
511                 // Splash::instance()->pop_back();
512                 Splash::instance()->hide ();
513         }
514 }
515
516 gint
517 ARDOUR_UI::configure_timeout ()
518 {
519         if (last_configure_time == 0) {
520                 /* no configure events yet */
521                 return true;
522         }
523
524         /* force a gap of 0.5 seconds since the last configure event
525          */
526
527         if (get_microseconds() - last_configure_time < 500000) {
528                 return true;
529         } else {
530                 have_configure_timeout = false;
531                 cerr << "config event-driven save\n";
532                 save_ardour_state ();
533                 return false;
534         }
535 }
536
537 gboolean
538 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
539 {
540         if (have_configure_timeout) {
541                 last_configure_time = get_microseconds();
542         } else {
543                 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
544                 have_configure_timeout = true;
545         }
546
547         return FALSE;
548 }
549
550 void
551 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
552 {
553         const XMLProperty* prop;
554
555         if ((prop = node.property ("roll")) != 0) {
556                 roll_controllable->set_id (prop->value());
557         }
558         if ((prop = node.property ("stop")) != 0) {
559                 stop_controllable->set_id (prop->value());
560         }
561         if ((prop = node.property ("goto-start")) != 0) {
562                 goto_start_controllable->set_id (prop->value());
563         }
564         if ((prop = node.property ("goto-end")) != 0) {
565                 goto_end_controllable->set_id (prop->value());
566         }
567         if ((prop = node.property ("auto-loop")) != 0) {
568                 auto_loop_controllable->set_id (prop->value());
569         }
570         if ((prop = node.property ("play-selection")) != 0) {
571                 play_selection_controllable->set_id (prop->value());
572         }
573         if ((prop = node.property ("rec")) != 0) {
574                 rec_controllable->set_id (prop->value());
575         }
576         if ((prop = node.property ("shuttle")) != 0) {
577                 shuttle_box->controllable()->set_id (prop->value());
578         }
579
580 }
581
582 XMLNode&
583 ARDOUR_UI::get_transport_controllable_state ()
584 {
585         XMLNode* node = new XMLNode(X_("TransportControllables"));
586         char buf[64];
587
588         roll_controllable->id().print (buf, sizeof (buf));
589         node->add_property (X_("roll"), buf);
590         stop_controllable->id().print (buf, sizeof (buf));
591         node->add_property (X_("stop"), buf);
592         goto_start_controllable->id().print (buf, sizeof (buf));
593         node->add_property (X_("goto_start"), buf);
594         goto_end_controllable->id().print (buf, sizeof (buf));
595         node->add_property (X_("goto_end"), buf);
596         auto_loop_controllable->id().print (buf, sizeof (buf));
597         node->add_property (X_("auto_loop"), buf);
598         play_selection_controllable->id().print (buf, sizeof (buf));
599         node->add_property (X_("play_selection"), buf);
600         rec_controllable->id().print (buf, sizeof (buf));
601         node->add_property (X_("rec"), buf);
602         shuttle_box->controllable()->id().print (buf, sizeof (buf));
603         node->add_property (X_("shuttle"), buf);
604
605         return *node;
606 }
607
608
609 gint
610 ARDOUR_UI::autosave_session ()
611 {
612         if (g_main_depth() > 1) {
613                 /* inside a recursive main loop,
614                    give up because we may not be able to
615                    take a lock.
616                 */
617                 return 1;
618         }
619
620         if (!Config->get_periodic_safety_backups()) {
621                 return 1;
622         }
623
624         if (_session) {
625                 _session->maybe_write_autosave();
626         }
627
628         return 1;
629 }
630
631 void
632 ARDOUR_UI::update_autosave ()
633 {
634         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_autosave)
635
636         if (_session && _session->dirty()) {
637                 if (_autosave_connection.connected()) {
638                         _autosave_connection.disconnect();
639                 }
640
641                 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
642                                 Config->get_periodic_safety_backup_interval() * 1000);
643
644         } else {
645                 if (_autosave_connection.connected()) {
646                         _autosave_connection.disconnect();
647                 }
648         }
649 }
650
651 void
652 ARDOUR_UI::backend_audio_error (bool we_set_params, Gtk::Window* toplevel)
653 {
654         string title;
655         if (we_set_params) {
656                 title = string_compose (_("%1 could not start JACK"), PROGRAM_NAME);
657         } else {
658                 title = string_compose (_("%1 could not connect to JACK."), PROGRAM_NAME);
659         }
660
661         MessageDialog win (title,
662                            false,
663                            Gtk::MESSAGE_INFO,
664                            Gtk::BUTTONS_NONE);
665
666         if (we_set_params) {
667                 win.set_secondary_text(_("There are several possible reasons:\n\
668 \n\
669 1) You requested audio parameters that are not supported..\n\
670 2) JACK is running as another user.\n\
671 \n\
672 Please consider the possibilities, and perhaps try different parameters."));
673         } else {
674                 win.set_secondary_text(_("There are several possible reasons:\n\
675 \n\
676 1) JACK is not running.\n\
677 2) JACK is running as another user, perhaps root.\n\
678 3) There is already another client called \"ardour\".\n\
679 \n\
680 Please consider the possibilities, and perhaps (re)start JACK."));
681         }
682
683         if (toplevel) {
684                 win.set_transient_for (*toplevel);
685         }
686
687         if (we_set_params) {
688                 win.add_button (Stock::OK, RESPONSE_CLOSE);
689         } else {
690                 win.add_button (Stock::QUIT, RESPONSE_CLOSE);
691         }
692
693         win.set_default_response (RESPONSE_CLOSE);
694
695         win.show_all ();
696         win.set_position (Gtk::WIN_POS_CENTER);
697         pop_back_splash ();
698
699         /* we just don't care about the result, but we want to block */
700
701         win.run ();
702 }
703
704 void
705 ARDOUR_UI::startup ()
706 {
707         Application* app = Application::instance ();
708
709         app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
710         app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::idle_load));
711
712 #ifdef PHONE_HOME
713         call_the_mothership (VERSIONSTRING);
714 #endif
715
716         app->ready ();
717
718         if (get_session_parameters (true, ARDOUR_COMMAND_LINE::new_session, ARDOUR_COMMAND_LINE::load_template)) {
719                 exit (1);
720         }
721
722         use_config ();
723
724         goto_editor_window ();
725
726         /* Add the window proxies here; their addition may cause windows to be opened, and we want them
727            to be opened on top of the editor window that goto_editor_window() just opened.
728         */
729         add_window_proxy (location_ui);
730         add_window_proxy (big_clock_window);
731         for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) {
732                 add_window_proxy (_global_port_matrix[*i]);
733         }
734
735         /* We have to do this here since goto_editor_window() ends up calling show_all() on the
736          * editor window, and we may want stuff to be hidden.
737          */
738         _status_bar_visibility.update ();
739
740         BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
741 }
742
743 void
744 ARDOUR_UI::no_memory_warning ()
745 {
746         XMLNode node (X_("no-memory-warning"));
747         Config->add_instant_xml (node);
748 }
749
750 void
751 ARDOUR_UI::check_memory_locking ()
752 {
753 #ifdef __APPLE__
754         /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
755         return;
756 #else // !__APPLE__
757
758         XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
759
760         if (engine->is_realtime() && memory_warning_node == 0) {
761
762                 struct rlimit limits;
763                 int64_t ram;
764                 long pages, page_size;
765
766                 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0) {
767                         ram = 0;
768                 } else {
769                         ram = (int64_t) pages * (int64_t) page_size;
770                 }
771
772                 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
773                         return;
774                 }
775
776                 if (limits.rlim_cur != RLIM_INFINITY) {
777
778                         if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
779
780                                 MessageDialog msg (
781                                         string_compose (
782                                                 _("WARNING: Your system has a limit for maximum amount of locked memory. "
783                                                   "This might cause %1 to run out of memory before your system "
784                                                   "runs out of memory. \n\n"
785                                                   "You can view the memory limit with 'ulimit -l', "
786                                                   "and it is normally controlled by /etc/security/limits.conf"),
787                                                 PROGRAM_NAME).c_str());
788
789                                 VBox* vbox = msg.get_vbox();
790                                 HBox hbox;
791                                 CheckButton cb (_("Do not show this window again"));
792
793                                 cb.signal_toggled().connect (sigc::mem_fun (*this, &ARDOUR_UI::no_memory_warning));
794
795                                 hbox.pack_start (cb, true, false);
796                                 vbox->pack_start (hbox);
797                                 cb.show();
798                                 vbox->show();
799                                 hbox.show ();
800
801                                 pop_back_splash ();
802
803                                 editor->ensure_float (msg);
804                                 msg.run ();
805                         }
806                 }
807         }
808 #endif // !__APPLE__
809 }
810
811
812 void
813 ARDOUR_UI::queue_finish ()
814 {
815         Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
816 }
817
818 bool
819 ARDOUR_UI::idle_finish ()
820 {
821         finish ();
822         return false; /* do not call again */
823 }
824
825 void
826 ARDOUR_UI::finish()
827 {
828         if (_session) {
829                 int tries = 0;
830
831                 if (_session->transport_rolling() && (++tries < 8)) {
832                         _session->request_stop (false, true);
833                         usleep (10000);
834                 }
835
836                 if (_session->dirty()) {
837                         vector<string> actions;
838                         actions.push_back (_("Don't quit"));
839                         actions.push_back (_("Just quit"));
840                         actions.push_back (_("Save and quit"));
841                         switch (ask_about_saving_session(actions)) {
842                         case -1:
843                                 return;
844                                 break;
845                         case 1:
846                                 /* use the default name */
847                                 if (save_state_canfail ("")) {
848                                         /* failed - don't quit */
849                                         MessageDialog msg (*editor,
850                                                            _("\
851 Ardour was unable to save your session.\n\n\
852 If you still wish to quit, please use the\n\n\
853 \"Just quit\" option."));
854                                         pop_back_splash();
855                                         msg.run ();
856                                         return;
857                                 }
858                                 break;
859                         case 0:
860                                 break;
861                         }
862                 }
863
864                 second_connection.disconnect ();
865                 point_one_second_connection.disconnect ();
866                 point_oh_five_second_connection.disconnect ();
867                 point_zero_one_second_connection.disconnect();
868         }
869
870         /* Save state before deleting the session, as that causes some
871            windows to be destroyed before their visible state can be
872            saved.
873         */
874         save_ardour_state ();
875
876         if (_session) {
877                 // _session->set_deletion_in_progress ();
878                 _session->set_clean ();
879                 _session->remove_pending_capture_state ();
880                 delete _session;
881                 _session = 0;
882         }
883
884         ArdourDialog::close_all_dialogs ();
885         engine->stop (true);
886         quit ();
887 }
888
889 int
890 ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
891 {
892         ArdourDialog window (_("Unsaved Session"));
893         Gtk::HBox dhbox;  // the hbox for the image and text
894         Gtk::Label  prompt_label;
895         Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING,  Gtk::ICON_SIZE_DIALOG));
896
897         string msg;
898
899         assert (actions.size() >= 3);
900
901         window.add_button (actions[0], RESPONSE_REJECT);
902         window.add_button (actions[1], RESPONSE_APPLY);
903         window.add_button (actions[2], RESPONSE_ACCEPT);
904
905         window.set_default_response (RESPONSE_ACCEPT);
906
907         Gtk::Button noquit_button (msg);
908         noquit_button.set_name ("EditorGTKButton");
909
910         string prompt;
911
912         if (_session->snap_name() == _session->name()) {
913                 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?"),
914                                         _session->snap_name());
915         } else {
916                 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?"),
917                                         _session->snap_name());
918         }
919
920         prompt_label.set_text (prompt);
921         prompt_label.set_name (X_("PrompterLabel"));
922         prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
923
924         dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
925         dhbox.set_homogeneous (false);
926         dhbox.pack_start (*dimage, false, false, 5);
927         dhbox.pack_start (prompt_label, true, false, 5);
928         window.get_vbox()->pack_start (dhbox);
929
930         window.set_name (_("Prompter"));
931         window.set_position (Gtk::WIN_POS_MOUSE);
932         window.set_modal (true);
933         window.set_resizable (false);
934
935         dhbox.show();
936         prompt_label.show();
937         dimage->show();
938         window.show();
939         window.set_keep_above (true);
940         window.present ();
941
942         ResponseType r = (ResponseType) window.run();
943
944         window.hide ();
945
946         switch (r) {
947         case RESPONSE_ACCEPT: // save and get out of here
948                 return 1;
949         case RESPONSE_APPLY:  // get out of here
950                 return 0;
951         default:
952                 break;
953         }
954
955         return -1;
956 }
957
958 gint
959 ARDOUR_UI::every_second ()
960 {
961         update_cpu_load ();
962         update_buffer_load ();
963         update_disk_space ();
964         return TRUE;
965 }
966
967 gint
968 ARDOUR_UI::every_point_one_seconds ()
969 {
970         shuttle_box->update_speed_display ();
971         RapidScreenUpdate(); /* EMIT_SIGNAL */
972         return TRUE;
973 }
974
975 gint
976 ARDOUR_UI::every_point_zero_one_seconds ()
977 {
978         // august 2007: actual update frequency: 40Hz, not 100Hz
979
980         SuperRapidScreenUpdate(); /* EMIT_SIGNAL */
981         return TRUE;
982 }
983
984 void
985 ARDOUR_UI::update_sample_rate (framecnt_t)
986 {
987         char buf[64];
988
989         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
990
991         if (!engine->connected()) {
992
993                 snprintf (buf, sizeof (buf), _("disconnected"));
994
995         } else {
996
997                 framecnt_t rate = engine->frame_rate();
998
999                 if (fmod (rate, 1000.0) != 0.0) {
1000                         snprintf (buf, sizeof (buf), _("JACK: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
1001                                   (float) rate/1000.0f,
1002                                   (engine->frames_per_cycle() / (float) rate) * 1000.0f);
1003                 } else {
1004                         snprintf (buf, sizeof (buf), _("JACK: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
1005                                   rate/1000,
1006                                   (engine->frames_per_cycle() / (float) rate) * 1000.0f);
1007                 }
1008         }
1009
1010         sample_rate_label.set_markup (buf);
1011 }
1012
1013 void
1014 ARDOUR_UI::update_format ()
1015 {
1016         if (!_session) {
1017                 format_label.set_text ("");
1018                 return;
1019         }
1020
1021         stringstream s;
1022         s << "File: <span foreground=\"green\">";
1023
1024         switch (_session->config.get_native_file_header_format ()) {
1025         case BWF:
1026                 s << "BWF";
1027                 break;
1028         case WAVE:
1029                 s << "WAV";
1030                 break;
1031         case WAVE64:
1032                 s << "WAV64";
1033                 break;
1034         case CAF:
1035                 s << "CAF";
1036                 break;
1037         case AIFF:
1038                 s << "AIFF";
1039                 break;
1040         case iXML:
1041                 s << "iXML";
1042                 break;
1043         case RF64:
1044                 s << "RF64";
1045                 break;
1046         }
1047
1048         s << " ";
1049         
1050         switch (_session->config.get_native_file_data_format ()) {
1051         case FormatFloat:
1052                 s << "32-float";
1053                 break;
1054         case FormatInt24:
1055                 s << "24-int";
1056                 break;
1057         case FormatInt16:
1058                 s << "16-int";
1059                 break;
1060         }
1061
1062         s << "</span>";
1063
1064         format_label.set_markup (s.str ());
1065 }
1066
1067 void
1068 ARDOUR_UI::update_cpu_load ()
1069 {
1070         char buf[64];
1071
1072         /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::build_menu_bar
1073            should also be changed.
1074         */
1075
1076         float const c = engine->get_cpu_load ();
1077         snprintf (buf, sizeof (buf), _("DSP: <span foreground=\"%s\">%5.1f%%</span>"), c >= 90 ? X_("red") : X_("green"), c);
1078         cpu_load_label.set_markup (buf);
1079 }
1080
1081 void
1082 ARDOUR_UI::update_buffer_load ()
1083 {
1084         char buf[256];
1085
1086         uint32_t const playback = _session ? _session->playback_load () : 100;
1087         uint32_t const capture = _session ? _session->capture_load () : 100;
1088
1089         /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::build_menu_bar
1090            should also be changed.
1091         */
1092         
1093         if (_session) {
1094                 snprintf (
1095                         buf, sizeof (buf),
1096                         _("Buffers: <span foreground=\"green\">p:</span><span foreground=\"%s\">%" PRIu32 "%%</span> "
1097                                    "<span foreground=\"green\">c:</span><span foreground=\"%s\">%" PRIu32 "%%</span>"),
1098                         playback <= 5 ? X_("red") : X_("green"),
1099                         playback,
1100                         capture <= 5 ? X_("red") : X_("green"),
1101                         capture
1102                         );
1103
1104                 buffer_load_label.set_markup (buf);
1105         } else {
1106                 buffer_load_label.set_text ("");
1107         }
1108 }
1109
1110 void
1111 ARDOUR_UI::count_recenabled_streams (Route& route)
1112 {
1113         Track* track = dynamic_cast<Track*>(&route);
1114         if (track && track->record_enabled()) {
1115                 rec_enabled_streams += track->n_inputs().n_total();
1116         }
1117 }
1118
1119 void
1120 ARDOUR_UI::update_disk_space()
1121 {
1122         if (_session == 0) {
1123                 return;
1124         }
1125
1126         framecnt_t frames = _session->available_capture_duration();
1127         char buf[64];
1128         framecnt_t fr = _session->frame_rate();
1129
1130         if (frames == max_framecnt) {
1131                 snprintf (buf, sizeof (buf), _("Disk: <span foreground=\"green\">24hrs+</span>"));
1132         } else {
1133                 rec_enabled_streams = 0;
1134                 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams);
1135
1136                 if (rec_enabled_streams) {
1137                         frames /= rec_enabled_streams;
1138                 }
1139
1140                 int hrs;
1141                 int mins;
1142                 int secs;
1143
1144                 hrs  = frames / (fr * 3600);
1145
1146                 if (hrs > 24) {
1147                         snprintf (buf, sizeof (buf), _("Disk: <span foreground=\"green\">&gt;24 hrs</span>"));
1148                 } else {
1149                         frames -= hrs * fr * 3600;
1150                         mins = frames / (fr * 60);
1151                         frames -= mins * fr * 60;
1152                         secs = frames / fr;
1153                         
1154                         bool const low = (hrs == 0 && mins <= 30);
1155                         
1156                         snprintf (
1157                                 buf, sizeof(buf),
1158                                 _("Disk: <span foreground=\"%s\">%02dh:%02dm:%02ds</span>"),
1159                                 low ? X_("red") : X_("green"),
1160                                 hrs, mins, secs
1161                                 );
1162                 }
1163         }
1164
1165         disk_space_label.set_markup (buf);
1166
1167         // An attempt to make the disk space label flash red when space has run out.
1168
1169         if (frames < fr * 60 * 5) {
1170         /*      disk_space_box.style ("disk_space_label_empty"); */
1171         } else {
1172         /*      disk_space_box.style ("disk_space_label"); */
1173         }
1174
1175 }
1176
1177 gint
1178 ARDOUR_UI::update_wall_clock ()
1179 {
1180         time_t now;
1181         struct tm *tm_now;
1182         char buf[16];
1183
1184         time (&now);
1185         tm_now = localtime (&now);
1186
1187         sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1188         wall_clock_label.set_text (buf);
1189
1190         return TRUE;
1191 }
1192
1193 gint
1194 ARDOUR_UI::session_menu (GdkEventButton */*ev*/)
1195 {
1196         session_popup_menu->popup (0, 0);
1197         return TRUE;
1198 }
1199
1200 void
1201 ARDOUR_UI::redisplay_recent_sessions ()
1202 {
1203         std::vector<sys::path> session_directories;
1204         RecentSessionsSorter cmp;
1205
1206         recent_session_display.set_model (Glib::RefPtr<TreeModel>(0));
1207         recent_session_model->clear ();
1208
1209         ARDOUR::RecentSessions rs;
1210         ARDOUR::read_recent_sessions (rs);
1211
1212         if (rs.empty()) {
1213                 recent_session_display.set_model (recent_session_model);
1214                 return;
1215         }
1216         //
1217         // sort them alphabetically
1218         sort (rs.begin(), rs.end(), cmp);
1219
1220         for (ARDOUR::RecentSessions::iterator i = rs.begin(); i != rs.end(); ++i) {
1221                 session_directories.push_back ((*i).second);
1222         }
1223
1224         for (vector<sys::path>::const_iterator i = session_directories.begin();
1225                         i != session_directories.end(); ++i)
1226         {
1227                 std::vector<sys::path> state_file_paths;
1228
1229                 // now get available states for this session
1230
1231                 get_state_files_in_directory (*i, state_file_paths);
1232
1233                 vector<string*>* states;
1234                 vector<const gchar*> item;
1235                 string fullpath = (*i).to_string();
1236
1237                 /* remove any trailing / */
1238
1239                 if (fullpath[fullpath.length()-1] == '/') {
1240                         fullpath = fullpath.substr (0, fullpath.length()-1);
1241                 }
1242
1243                 /* check whether session still exists */
1244                 if (!Glib::file_test(fullpath.c_str(), Glib::FILE_TEST_EXISTS)) {
1245                         /* session doesn't exist */
1246                         cerr << "skipping non-existent session " << fullpath << endl;
1247                         continue;
1248                 }
1249
1250                 /* now get available states for this session */
1251
1252                 if ((states = Session::possible_states (fullpath)) == 0) {
1253                         /* no state file? */
1254                         continue;
1255                 }
1256
1257                 std::vector<string> state_file_names(get_file_names_no_extension (state_file_paths));
1258
1259                 Gtk::TreeModel::Row row = *(recent_session_model->append());
1260
1261                 row[recent_session_columns.visible_name] = Glib::path_get_basename (fullpath);
1262                 row[recent_session_columns.fullpath] = fullpath;
1263
1264                 if (state_file_names.size() > 1) {
1265
1266                         // add the children
1267
1268                         for (std::vector<std::string>::iterator i2 = state_file_names.begin();
1269                                         i2 != state_file_names.end(); ++i2)
1270                         {
1271
1272                                 Gtk::TreeModel::Row child_row = *(recent_session_model->append (row.children()));
1273
1274                                 child_row[recent_session_columns.visible_name] = *i2;
1275                                 child_row[recent_session_columns.fullpath] = fullpath;
1276                         }
1277                 }
1278         }
1279
1280         recent_session_display.set_model (recent_session_model);
1281 }
1282
1283 void
1284 ARDOUR_UI::build_session_selector ()
1285 {
1286         session_selector_window = new ArdourDialog (_("Recent Sessions"));
1287
1288         Gtk::ScrolledWindow *scroller = manage (new Gtk::ScrolledWindow);
1289
1290         session_selector_window->add_button (Stock::CANCEL, RESPONSE_CANCEL);
1291         session_selector_window->add_button (Stock::OPEN, RESPONSE_ACCEPT);
1292         session_selector_window->set_default_response (RESPONSE_ACCEPT);
1293         recent_session_model = TreeStore::create (recent_session_columns);
1294         recent_session_display.set_model (recent_session_model);
1295         recent_session_display.append_column (_("Recent Sessions"), recent_session_columns.visible_name);
1296         recent_session_display.set_headers_visible (false);
1297         recent_session_display.get_selection()->set_mode (SELECTION_BROWSE);
1298         recent_session_display.signal_row_activated().connect (sigc::mem_fun (*this, &ARDOUR_UI::recent_session_row_activated));
1299
1300         scroller->add (recent_session_display);
1301         scroller->set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
1302
1303         session_selector_window->set_name ("SessionSelectorWindow");
1304         session_selector_window->set_size_request (200, 400);
1305         session_selector_window->get_vbox()->pack_start (*scroller);
1306
1307         recent_session_display.show();
1308         scroller->show();
1309         //session_selector_window->get_vbox()->show();
1310 }
1311
1312 void
1313 ARDOUR_UI::recent_session_row_activated (const TreePath& /*path*/, TreeViewColumn* /*col*/)
1314 {
1315         session_selector_window->response (RESPONSE_ACCEPT);
1316 }
1317
1318 void
1319 ARDOUR_UI::open_recent_session ()
1320 {
1321         bool can_return = (_session != 0);
1322
1323         if (session_selector_window == 0) {
1324                 build_session_selector ();
1325         }
1326
1327         redisplay_recent_sessions ();
1328
1329         while (true) {
1330
1331                 session_selector_window->set_position (WIN_POS_MOUSE);
1332
1333                 ResponseType r = (ResponseType) session_selector_window->run ();
1334
1335                 switch (r) {
1336                 case RESPONSE_ACCEPT:
1337                         break;
1338                 default:
1339                         if (can_return) {
1340                                 session_selector_window->hide();
1341                                 return;
1342                         } else {
1343                                 exit (1);
1344                         }
1345                 }
1346
1347                 if (recent_session_display.get_selection()->count_selected_rows() == 0) {
1348                         continue;
1349                 }
1350
1351                 session_selector_window->hide();
1352
1353                 Gtk::TreeModel::iterator i = recent_session_display.get_selection()->get_selected();
1354
1355                 if (i == recent_session_model->children().end()) {
1356                         return;
1357                 }
1358
1359                 std::string path = (*i)[recent_session_columns.fullpath];
1360                 std::string state = (*i)[recent_session_columns.visible_name];
1361
1362                 _session_is_new = false;
1363
1364                 if (load_session (path, state) == 0) {
1365                         break;
1366                 }
1367
1368                 can_return = false;
1369         }
1370 }
1371
1372 bool
1373 ARDOUR_UI::check_audioengine ()
1374 {
1375         if (engine) {
1376                 if (!engine->connected()) {
1377                         MessageDialog msg (string_compose (
1378                                                    _("%1 is not connected to JACK\n"
1379                                                      "You cannot open or close sessions in this condition"),
1380                                                    PROGRAM_NAME));
1381                         pop_back_splash ();
1382                         msg.run ();
1383                         return false;
1384                 }
1385                 return true;
1386         } else {
1387                 return false;
1388         }
1389 }
1390
1391 void
1392 ARDOUR_UI::open_session ()
1393 {
1394         if (!check_audioengine()) {
1395                 return;
1396
1397         }
1398
1399         /* popup selector window */
1400
1401         if (open_session_selector == 0) {
1402
1403                 /* ardour sessions are folders */
1404
1405                 open_session_selector = new Gtk::FileChooserDialog (_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1406                 open_session_selector->add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1407                 open_session_selector->add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1408                 open_session_selector->set_default_response(Gtk::RESPONSE_ACCEPT);
1409
1410                 FileFilter session_filter;
1411                 session_filter.add_pattern ("*.ardour");
1412                 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1413                 open_session_selector->add_filter (session_filter);
1414                 open_session_selector->set_filter (session_filter);
1415         }
1416
1417         int response = open_session_selector->run();
1418         open_session_selector->hide ();
1419
1420         switch (response) {
1421         case RESPONSE_ACCEPT:
1422                 break;
1423         default:
1424                 open_session_selector->hide();
1425                 return;
1426         }
1427
1428         open_session_selector->hide();
1429         string session_path = open_session_selector->get_filename();
1430         string path, name;
1431         bool isnew;
1432
1433         if (session_path.length() > 0) {
1434                 if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1435                         _session_is_new = isnew;
1436                         load_session (path, name);
1437                 }
1438         }
1439 }
1440
1441
1442 void
1443 ARDOUR_UI::session_add_midi_route (bool disk, RouteGroup* route_group, uint32_t how_many, string const & name_template)
1444 {
1445         list<boost::shared_ptr<MidiTrack> > tracks;
1446
1447         if (_session == 0) {
1448                 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1449                 return;
1450         }
1451
1452         try {
1453                 if (disk) {
1454
1455                         tracks = _session->new_midi_track (ARDOUR::Normal, route_group, how_many, name_template);
1456
1457                         if (tracks.size() != how_many) {
1458                                 if (how_many == 1) {
1459                                         error << _("could not create a new midi track") << endmsg;
1460                                 } else {
1461                                         error << string_compose (_("could not create %1 new midi tracks"), how_many) << endmsg;
1462                                 }
1463                         }
1464                 } /*else {
1465                         if ((route = _session->new_midi_route ()) == 0) {
1466                                 error << _("could not create new midi bus") << endmsg;
1467                         }
1468                 }*/
1469         }
1470
1471         catch (...) {
1472                 MessageDialog msg (*editor,
1473                                    string_compose (_("There are insufficient JACK ports available\n\
1474 to create a new track or bus.\n\
1475 You should save %1, exit and\n\
1476 restart JACK with more ports."), PROGRAM_NAME));
1477                 msg.run ();
1478         }
1479 }
1480
1481
1482 void
1483 ARDOUR_UI::session_add_audio_route (
1484         bool track,
1485         int32_t input_channels,
1486         int32_t output_channels,
1487         ARDOUR::TrackMode mode,
1488         RouteGroup* route_group,
1489         uint32_t how_many,
1490         string const & name_template
1491         )
1492 {
1493         list<boost::shared_ptr<AudioTrack> > tracks;
1494         RouteList routes;
1495
1496         if (_session == 0) {
1497                 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1498                 return;
1499         }
1500
1501         try {
1502                 if (track) {
1503                         tracks = _session->new_audio_track (input_channels, output_channels, mode, route_group, how_many, name_template);
1504
1505                         if (tracks.size() != how_many) {
1506                                 if (how_many == 1) {
1507                                         error << _("could not create a new audio track") << endmsg;
1508                                 } else {
1509                                         error << string_compose (_("could only create %1 of %2 new audio %3"),
1510                                                                  tracks.size(), how_many, (track ? _("tracks") : _("busses"))) << endmsg;
1511                                 }
1512                         }
1513
1514                 } else {
1515
1516                         routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template);
1517
1518                         if (routes.size() != how_many) {
1519                                 if (how_many == 1) {
1520                                         error << _("could not create a new audio bus") << endmsg;
1521                                 } else {
1522                                         error << string_compose (_("could not create %1 new audio busses"), how_many) << endmsg;
1523                                 }
1524                         }
1525                 }
1526         }
1527
1528         catch (...) {
1529                 MessageDialog msg (*editor,
1530                                    string_compose (_("There are insufficient JACK ports available\n\
1531 to create a new track or bus.\n\
1532 You should save %1, exit and\n\
1533 restart JACK with more ports."), PROGRAM_NAME));
1534                 pop_back_splash ();
1535                 msg.run ();
1536         }
1537 }
1538
1539 void
1540 ARDOUR_UI::do_transport_locate (framepos_t new_position, bool with_roll)
1541 {
1542         framecnt_t _preroll = 0;
1543
1544         if (_session) {
1545                 // XXX CONFIG_CHANGE FIX - requires AnyTime handling
1546                 // _preroll = _session->convert_to_frames_at (new_position, Config->get_preroll());
1547
1548                 if (new_position > _preroll) {
1549                         new_position -= _preroll;
1550                 } else {
1551                         new_position = 0;
1552                 }
1553
1554                 _session->request_locate (new_position, with_roll);
1555         }
1556 }
1557
1558 void
1559 ARDOUR_UI::transport_goto_start ()
1560 {
1561         if (_session) {
1562                 _session->goto_start();
1563
1564                 /* force displayed area in editor to start no matter
1565                    what "follow playhead" setting is.
1566                 */
1567
1568                 if (editor) {
1569                         editor->center_screen (_session->current_start_frame ());
1570                 }
1571         }
1572 }
1573
1574 void
1575 ARDOUR_UI::transport_goto_zero ()
1576 {
1577         if (_session) {
1578                 _session->request_locate (0);
1579
1580                 /* force displayed area in editor to start no matter
1581                    what "follow playhead" setting is.
1582                 */
1583
1584                 if (editor) {
1585                         editor->reset_x_origin (0);
1586                 }
1587         }
1588 }
1589
1590 void
1591 ARDOUR_UI::transport_goto_wallclock ()
1592 {
1593         if (_session && editor) {
1594
1595                 time_t now;
1596                 struct tm tmnow;
1597                 framepos_t frames;
1598
1599                 time (&now);
1600                 localtime_r (&now, &tmnow);
1601
1602                 frames = tmnow.tm_hour * (60 * 60 * _session->frame_rate());
1603                 frames += tmnow.tm_min * (60 * _session->frame_rate());
1604                 frames += tmnow.tm_sec * _session->frame_rate();
1605
1606                 _session->request_locate (frames, _session->transport_rolling ());
1607
1608                 /* force displayed area in editor to start no matter
1609                    what "follow playhead" setting is.
1610                 */
1611
1612                 if (editor) {
1613                         editor->center_screen (frames);
1614                 }
1615         }
1616 }
1617
1618 void
1619 ARDOUR_UI::transport_goto_end ()
1620 {
1621         if (_session) {
1622                 framepos_t const frame = _session->current_end_frame();
1623                 _session->request_locate (frame);
1624
1625                 /* force displayed area in editor to start no matter
1626                    what "follow playhead" setting is.
1627                 */
1628
1629                 if (editor) {
1630                         editor->center_screen (frame);
1631                 }
1632         }
1633 }
1634
1635 void
1636 ARDOUR_UI::transport_stop ()
1637 {
1638         if (!_session) {
1639                 return;
1640         }
1641
1642         if (_session->is_auditioning()) {
1643                 _session->cancel_audition ();
1644                 return;
1645         }
1646
1647         _session->request_stop (false, true);
1648 }
1649
1650 void
1651 ARDOUR_UI::transport_stop_and_forget_capture ()
1652 {
1653         if (_session) {
1654                 _session->request_stop (true, true);
1655         }
1656 }
1657
1658 void
1659 ARDOUR_UI::remove_last_capture()
1660 {
1661         if (editor) {
1662                 editor->remove_last_capture();
1663         }
1664 }
1665
1666 void
1667 ARDOUR_UI::transport_record (bool roll)
1668 {
1669
1670         if (_session) {
1671                 switch (_session->record_status()) {
1672                 case Session::Disabled:
1673                         if (_session->ntracks() == 0) {
1674                                 MessageDialog msg (*editor, _("Please create 1 or more track\nbefore trying to record.\nCheck the Session menu."));
1675                                 msg.run ();
1676                                 return;
1677                         }
1678                         _session->maybe_enable_record ();
1679                         if (roll) {
1680                                 transport_roll ();
1681                         }
1682                         break;
1683                 case Session::Recording:
1684                         if (roll) {
1685                                 _session->request_stop();
1686                         } else {
1687                                 _session->disable_record (false, true);
1688                         }
1689                         break;
1690
1691                 case Session::Enabled:
1692                         _session->disable_record (false, true);
1693                 }
1694         }
1695         //cerr << "ARDOUR_UI::transport_record () called roll = " << roll << " _session->record_status() = " << _session->record_status() << endl;
1696 }
1697
1698 void
1699 ARDOUR_UI::transport_roll ()
1700 {
1701         if (!_session) {
1702                 return;
1703         }
1704
1705         if (_session->is_auditioning()) {
1706                 return;
1707         }
1708
1709 #if 0
1710         if (_session->config.get_external_sync()) {
1711                 switch (_session->config.get_sync_source()) {
1712                 case JACK:
1713                         break;
1714                 default:
1715                         /* transport controlled by the master */
1716                         return;
1717                 }
1718         }
1719 #endif
1720
1721         bool rolling = _session->transport_rolling();
1722
1723         if (_session->get_play_loop()) {
1724                 /* XXX it is not possible to just leave seamless loop and keep
1725                    playing at present (nov 4th 2009)
1726                 */
1727                 if (!Config->get_seamless_loop()) {
1728                         _session->request_play_loop (false, true);
1729                 }
1730         } else if (_session->get_play_range () && !join_play_range_button.active_state()) {
1731                 /* stop playing a range if we currently are */
1732                 _session->request_play_range (0, true);
1733         }
1734
1735         if (join_play_range_button.active_state()) {
1736                 _session->request_play_range (&editor->get_selection().time, true);
1737         }
1738
1739         if (!rolling) {
1740                 _session->request_transport_speed (1.0f);
1741         }
1742 }
1743
1744 void
1745 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
1746 {
1747
1748         if (!_session) {
1749                 return;
1750         }
1751
1752         if (_session->is_auditioning()) {
1753                 _session->cancel_audition ();
1754                 return;
1755         }
1756
1757         if (_session->config.get_external_sync()) {
1758                 switch (_session->config.get_sync_source()) {
1759                 case JACK:
1760                         break;
1761                 default:
1762                         /* transport controlled by the master */
1763                         return;
1764                 }
1765         }
1766
1767         bool rolling = _session->transport_rolling();
1768         bool affect_transport = true;
1769
1770         if (rolling && roll_out_of_bounded_mode) {
1771                 /* drop out of loop/range playback but leave transport rolling */
1772                 if (_session->get_play_loop()) {
1773                         if (Config->get_seamless_loop()) {
1774                                 /* the disk buffers contain copies of the loop - we can't
1775                                    just keep playing, so stop the transport. the user
1776                                    can restart as they wish.
1777                                 */
1778                                 affect_transport = true;
1779                         } else {
1780                                 /* disk buffers are normal, so we can keep playing */
1781                                 affect_transport = false;
1782                         }
1783                         _session->request_play_loop (false, true);
1784                 } else if (_session->get_play_range ()) {
1785                         affect_transport = false;
1786                         _session->request_play_range (0, true);
1787                 }
1788         }
1789
1790         if (affect_transport) {
1791                 if (rolling) {
1792                         _session->request_stop (with_abort, true);
1793                 } else {
1794                         if (join_play_range_button.active_state()) {
1795                                 _session->request_play_range (&editor->get_selection().time, true);
1796                         }
1797
1798                         _session->request_transport_speed (1.0f);
1799                 }
1800         }
1801 }
1802
1803 void
1804 ARDOUR_UI::toggle_session_auto_loop ()
1805 {
1806         if (!_session) {
1807                 return;
1808         }
1809
1810         if (_session->get_play_loop()) {
1811
1812                 if (_session->transport_rolling()) {
1813
1814                         Location * looploc = _session->locations()->auto_loop_location();
1815
1816                         if (looploc) {
1817                                 _session->request_locate (looploc->start(), true);
1818                                 _session->request_play_loop (false);
1819                         }
1820
1821                 } else {
1822                         _session->request_play_loop (false);
1823                 }
1824         } else {
1825
1826           Location * looploc = _session->locations()->auto_loop_location();
1827
1828                 if (looploc) {
1829                         _session->request_play_loop (true);
1830                 }
1831         }
1832 }
1833
1834 void
1835 ARDOUR_UI::transport_play_selection ()
1836 {
1837         if (!_session) {
1838                 return;
1839         }
1840
1841         editor->play_selection ();
1842 }
1843
1844 void
1845 ARDOUR_UI::transport_rewind (int option)
1846 {
1847         float current_transport_speed;
1848
1849         if (_session) {
1850                 current_transport_speed = _session->transport_speed();
1851
1852                 if (current_transport_speed >= 0.0f) {
1853                         switch (option) {
1854                         case 0:
1855                                 _session->request_transport_speed (-1.0f);
1856                                 break;
1857                         case 1:
1858                                 _session->request_transport_speed (-4.0f);
1859                                 break;
1860                         case -1:
1861                                 _session->request_transport_speed (-0.5f);
1862                                 break;
1863                         }
1864                 } else {
1865                         /* speed up */
1866                         _session->request_transport_speed (current_transport_speed * 1.5f);
1867                 }
1868         }
1869 }
1870
1871 void
1872 ARDOUR_UI::transport_forward (int option)
1873 {
1874         float current_transport_speed;
1875
1876         if (_session) {
1877                 current_transport_speed = _session->transport_speed();
1878
1879                 if (current_transport_speed <= 0.0f) {
1880                         switch (option) {
1881                         case 0:
1882                                 _session->request_transport_speed (1.0f);
1883                                 break;
1884                         case 1:
1885                                 _session->request_transport_speed (4.0f);
1886                                 break;
1887                         case -1:
1888                                 _session->request_transport_speed (0.5f);
1889                                 break;
1890                         }
1891                 } else {
1892                         /* speed up */
1893                         _session->request_transport_speed (current_transport_speed * 1.5f);
1894                 }
1895
1896         }
1897 }
1898
1899 void
1900 ARDOUR_UI::toggle_record_enable (uint32_t rid)
1901 {
1902         if (_session == 0) {
1903                 return;
1904         }
1905
1906         boost::shared_ptr<Route> r;
1907
1908         if ((r = _session->route_by_remote_id (rid)) != 0) {
1909
1910                 Track* t;
1911
1912                 if ((t = dynamic_cast<Track*>(r.get())) != 0) {
1913                         t->set_record_enabled (!t->record_enabled(), this);
1914                 }
1915         }
1916         if (_session == 0) {
1917                 return;
1918         }
1919 }
1920
1921 void
1922 ARDOUR_UI::map_transport_state ()
1923 {
1924         if (!_session) {
1925                 auto_loop_button.unset_active_state ();
1926                 play_selection_button.unset_active_state ();
1927                 roll_button.unset_active_state ();
1928                 stop_button.set_active_state (Gtkmm2ext::Active);
1929                 return;
1930         }
1931
1932         shuttle_box->map_transport_state ();
1933
1934         float sp = _session->transport_speed();
1935
1936         if (sp != 0.0f) {
1937
1938                 /* we're rolling */
1939
1940                 if (_session->get_play_range()) {
1941
1942                         play_selection_button.set_active_state (Gtkmm2ext::Active);
1943                         roll_button.unset_active_state ();
1944                         auto_loop_button.unset_active_state ();
1945
1946                 } else if (_session->get_play_loop ()) {
1947
1948                         auto_loop_button.set_active_state (Gtkmm2ext::Active);
1949                         play_selection_button.unset_active_state ();
1950                         roll_button.unset_active_state ();
1951
1952                 } else {
1953
1954                         roll_button.set_active_state (Gtkmm2ext::Active);
1955                         play_selection_button.unset_active_state ();
1956                         auto_loop_button.unset_active_state ();
1957                 }
1958
1959                 if (join_play_range_button.active_state()) {
1960                         /* light up both roll and play-selection if they are joined */
1961                         roll_button.set_active_state (Gtkmm2ext::Active);
1962                         play_selection_button.set_active_state (Gtkmm2ext::Active);
1963                 }
1964
1965                 stop_button.unset_active_state ();
1966
1967         } else {
1968
1969                 stop_button.set_active_state (Gtkmm2ext::Active);
1970                 roll_button.unset_active_state ();
1971                 play_selection_button.unset_active_state ();
1972                 auto_loop_button.unset_active_state ();
1973                 update_disk_space ();
1974         }
1975 }
1976
1977 void
1978 ARDOUR_UI::engine_stopped ()
1979 {
1980         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
1981         ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1982         ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1983 }
1984
1985 void
1986 ARDOUR_UI::engine_running ()
1987 {
1988         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
1989         ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, true);
1990         ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, false);
1991
1992         Glib::RefPtr<Action> action;
1993         const char* action_name = 0;
1994
1995         switch (engine->frames_per_cycle()) {
1996         case 32:
1997                 action_name = X_("JACKLatency32");
1998                 break;
1999         case 64:
2000                 action_name = X_("JACKLatency64");
2001                 break;
2002         case 128:
2003                 action_name = X_("JACKLatency128");
2004                 break;
2005         case 512:
2006                 action_name = X_("JACKLatency512");
2007                 break;
2008         case 1024:
2009                 action_name = X_("JACKLatency1024");
2010                 break;
2011         case 2048:
2012                 action_name = X_("JACKLatency2048");
2013                 break;
2014         case 4096:
2015                 action_name = X_("JACKLatency4096");
2016                 break;
2017         case 8192:
2018                 action_name = X_("JACKLatency8192");
2019                 break;
2020         default:
2021                 /* XXX can we do anything useful ? */
2022                 break;
2023         }
2024
2025         if (action_name) {
2026
2027                 action = ActionManager::get_action (X_("JACK"), action_name);
2028
2029                 if (action) {
2030                         Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (action);
2031                         ract->set_active ();
2032                 }
2033         }
2034 }
2035
2036 void
2037 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
2038 {
2039         if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
2040                 /* we can't rely on the original string continuing to exist when we are called
2041                    again in the GUI thread, so make a copy and note that we need to
2042                    free it later.
2043                 */
2044                 char *copy = strdup (reason);
2045                 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
2046                 return;
2047         }
2048
2049         ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
2050         ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
2051
2052         update_sample_rate (0);
2053
2054         string msgstr;
2055
2056         /* if the reason is a non-empty string, it means that the backend was shutdown
2057            rather than just Ardour.
2058         */
2059
2060         if (strlen (reason)) {
2061                 msgstr = string_compose (_("The audio backend (JACK) was shutdown because:\n\n%1"), reason);
2062         } else {
2063                 msgstr = string_compose (_("\
2064 JACK has either been shutdown or it\n\
2065 disconnected %1 because %1\n\
2066 was not fast enough. Try to restart\n\
2067 JACK, reconnect and save the session."), PROGRAM_NAME);
2068         }
2069
2070         MessageDialog msg (*editor, msgstr);
2071         pop_back_splash ();
2072         msg.run ();
2073
2074         if (free_reason) {
2075                 free ((char*) reason);
2076         }
2077 }
2078
2079 int32_t
2080 ARDOUR_UI::do_engine_start ()
2081 {
2082         try {
2083                 engine->start();
2084         }
2085
2086         catch (...) {
2087                 engine->stop ();
2088                 error << _("Unable to start the session running")
2089                       << endmsg;
2090                 unload_session ();
2091                 return -2;
2092         }
2093
2094         return 0;
2095 }
2096
2097 void
2098 ARDOUR_UI::setup_theme ()
2099 {
2100         theme_manager->setup_theme();
2101 }
2102
2103 void
2104 ARDOUR_UI::update_clocks ()
2105 {
2106         if (!editor || !editor->dragging_playhead()) {
2107                 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position()); /* EMIT_SIGNAL */
2108         }
2109 }
2110
2111 void
2112 ARDOUR_UI::start_clocking ()
2113 {
2114         clock_signal_connection = RapidScreenUpdate.connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2115 }
2116
2117 void
2118 ARDOUR_UI::stop_clocking ()
2119 {
2120         clock_signal_connection.disconnect ();
2121 }
2122
2123 void
2124 ARDOUR_UI::toggle_clocking ()
2125 {
2126 #if 0
2127         if (clock_button.get_active()) {
2128                 start_clocking ();
2129         } else {
2130                 stop_clocking ();
2131         }
2132 #endif
2133 }
2134
2135 gint
2136 ARDOUR_UI::_blink (void *arg)
2137
2138 {
2139         ((ARDOUR_UI *) arg)->blink ();
2140         return TRUE;
2141 }
2142
2143 void
2144 ARDOUR_UI::blink ()
2145 {
2146         Blink (blink_on = !blink_on); /* EMIT_SIGNAL */
2147 }
2148
2149 void
2150 ARDOUR_UI::start_blinking ()
2151 {
2152         /* Start the blink signal. Everybody with a blinking widget
2153            uses Blink to drive the widget's state.
2154         */
2155
2156         if (blink_timeout_tag < 0) {
2157                 blink_on = false;
2158                 blink_timeout_tag = g_timeout_add (240, _blink, this);
2159         }
2160 }
2161
2162 void
2163 ARDOUR_UI::stop_blinking ()
2164 {
2165         if (blink_timeout_tag >= 0) {
2166                 g_source_remove (blink_timeout_tag);
2167                 blink_timeout_tag = -1;
2168         }
2169 }
2170
2171
2172 /** Ask the user for the name of a new shapshot and then take it.
2173  */
2174
2175 void
2176 ARDOUR_UI::snapshot_session (bool switch_to_it)
2177 {
2178         ArdourPrompter prompter (true);
2179         string snapname;
2180
2181         prompter.set_name ("Prompter");
2182         prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2183         prompter.set_title (_("Take Snapshot"));
2184         prompter.set_prompt (_("Name of new snapshot"));
2185
2186         if (!switch_to_it) {
2187                 char timebuf[128];
2188                 time_t n;
2189                 struct tm local_time;
2190
2191                 time (&n);
2192                 localtime_r (&n, &local_time);
2193                 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2194                 prompter.set_initial_text (timebuf);
2195         }
2196
2197   again:
2198         switch (prompter.run()) {
2199         case RESPONSE_ACCEPT:
2200         {
2201                 prompter.get_result (snapname);
2202
2203                 bool do_save = (snapname.length() != 0);
2204
2205                 if (do_save) {
2206                         if (snapname.find ('/') != string::npos) {
2207                                 MessageDialog msg (_("To ensure compatibility with various systems\n"
2208                                                      "snapshot names may not contain a '/' character"));
2209                                 msg.run ();
2210                                 goto again;
2211                         }
2212                         if (snapname.find ('\\') != string::npos) {
2213                                 MessageDialog msg (_("To ensure compatibility with various systems\n"
2214                                                      "snapshot names may not contain a '\\' character"));
2215                                 msg.run ();
2216                                 goto again;
2217                         }
2218                         if (snapname.find (':') != string::npos) {
2219                                 MessageDialog msg (_("To ensure compatibility with various systems\n"
2220                                                      "snapshot names may not contain a ':' character"));
2221                                 msg.run ();
2222                                 goto again;
2223                         }
2224                 }
2225
2226                 vector<sys::path> p;
2227                 get_state_files_in_directory (_session->session_directory().root_path(), p);
2228                 vector<string> n = get_file_names_no_extension (p);
2229                 if (find (n.begin(), n.end(), snapname) != n.end()) {
2230
2231                         ArdourDialog confirm (_("Confirm Snapshot Overwrite"), true);
2232                         Label m (_("A snapshot already exists with that name.  Do you want to overwrite it?"));
2233                         confirm.get_vbox()->pack_start (m, true, true);
2234                         confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2235                         confirm.add_button (_("Overwrite"), Gtk::RESPONSE_ACCEPT);
2236                         confirm.show_all ();
2237                         switch (confirm.run()) {
2238                         case RESPONSE_CANCEL:
2239                                 do_save = false;
2240                         }
2241                 }
2242
2243                 if (do_save) {
2244                         save_state (snapname, switch_to_it);
2245                 }
2246                 break;
2247         }
2248
2249         default:
2250                 break;
2251         }
2252 }
2253
2254 /** Ask the user for the name of a new shapshot and then take it.
2255  */
2256
2257 void
2258 ARDOUR_UI::rename_session ()
2259 {
2260         if (!_session) {
2261                 return;
2262         }
2263
2264         ArdourPrompter prompter (true);
2265         string name;
2266
2267         prompter.set_name ("Prompter");
2268         prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2269         prompter.set_title (_("Rename Session"));
2270         prompter.set_prompt (_("New session name"));
2271
2272   again:
2273         switch (prompter.run()) {
2274         case RESPONSE_ACCEPT:
2275         {
2276                 prompter.get_result (name);
2277
2278                 bool do_rename = (name.length() != 0);
2279
2280                 if (do_rename) {
2281                         if (name.find ('/') != string::npos) {
2282                                 MessageDialog msg (_("To ensure compatibility with various systems\n"
2283                                                      "session names may not contain a '/' character"));
2284                                 msg.run ();
2285                                 goto again;
2286                         }
2287                         if (name.find ('\\') != string::npos) {
2288                                 MessageDialog msg (_("To ensure compatibility with various systems\n"
2289                                                      "session names may not contain a '\\' character"));
2290                                 msg.run ();
2291                                 goto again;
2292                         }
2293
2294                         switch (_session->rename (name)) {
2295                         case -1: {
2296                                 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
2297                                 msg.set_position (WIN_POS_MOUSE);
2298                                 msg.run ();
2299                                 goto again;
2300                                 break;
2301                         }
2302                         case 0:
2303                                 break;
2304                         default: {
2305                                 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
2306                                 msg.set_position (WIN_POS_MOUSE);
2307                                 msg.run ();
2308                                 break;
2309                         }
2310                         }
2311                 }
2312                 
2313                 break;
2314         }
2315
2316         default:
2317                 break;
2318         }
2319 }
2320
2321 void
2322 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2323 {
2324         XMLNode* node = new XMLNode (X_("UI"));
2325
2326         for (list<WindowProxyBase*>::iterator i = _window_proxies.begin(); i != _window_proxies.end(); ++i) {
2327                 if (!(*i)->rc_configured()) {
2328                         node->add_child_nocopy (*((*i)->get_state ()));
2329                 }
2330         }
2331
2332         node->add_child_nocopy (gui_object_state->get_state());
2333
2334         _session->add_extra_xml (*node);
2335
2336         save_state_canfail (name, switch_to_it);
2337 }
2338
2339 int
2340 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2341 {
2342         if (_session) {
2343                 int ret;
2344
2345                 if (name.length() == 0) {
2346                         name = _session->snap_name();
2347                 }
2348
2349                 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2350                         return ret;
2351                 }
2352         }
2353
2354         save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2355         return 0;
2356 }
2357
2358 void
2359 ARDOUR_UI::primary_clock_value_changed ()
2360 {
2361         if (_session) {
2362                 _session->request_locate (primary_clock->current_time ());
2363         }
2364 }
2365
2366 void
2367 ARDOUR_UI::big_clock_value_changed ()
2368 {
2369         if (_session) {
2370                 _session->request_locate (big_clock->current_time ());
2371         }
2372 }
2373
2374 void
2375 ARDOUR_UI::secondary_clock_value_changed ()
2376 {
2377         if (_session) {
2378                 _session->request_locate (secondary_clock->current_time ());
2379         }
2380 }
2381
2382 void
2383 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2384 {
2385         if (_session == 0) {
2386                 return;
2387         }
2388
2389         if (_session->step_editing()) {
2390                 return;
2391         }
2392
2393         Session::RecordState const r = _session->record_status ();
2394         bool const h = _session->have_rec_enabled_track ();
2395
2396         if (r == Session::Enabled || (r == Session::Recording && !h)) {
2397                 if (onoff) {
2398                         rec_button.set_active_state (Active);
2399                 } else {
2400                         rec_button.set_active_state (Mid);
2401                 }
2402         } else if (r == Session::Recording && h) {
2403                 rec_button.set_active_state (Mid);
2404         } else {
2405                 rec_button.unset_active_state ();
2406         }
2407 }
2408
2409 void
2410 ARDOUR_UI::save_template ()
2411 {
2412         ArdourPrompter prompter (true);
2413         string name;
2414
2415         if (!check_audioengine()) {
2416                 return;
2417         }
2418
2419         prompter.set_name (X_("Prompter"));
2420         prompter.set_title (_("Save Template"));
2421         prompter.set_prompt (_("Name for template:"));
2422         prompter.set_initial_text(_session->name() + _("-template"));
2423         prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2424
2425         switch (prompter.run()) {
2426         case RESPONSE_ACCEPT:
2427                 prompter.get_result (name);
2428
2429                 if (name.length()) {
2430                         _session->save_template (name);
2431                 }
2432                 break;
2433
2434         default:
2435                 break;
2436         }
2437 }
2438
2439 void
2440 ARDOUR_UI::edit_metadata ()
2441 {
2442         SessionMetadataEditor dialog;
2443         dialog.set_session (_session);
2444         editor->ensure_float (dialog);
2445         dialog.run ();
2446 }
2447
2448 void
2449 ARDOUR_UI::import_metadata ()
2450 {
2451         SessionMetadataImporter dialog;
2452         dialog.set_session (_session);
2453         editor->ensure_float (dialog);
2454         dialog.run ();
2455 }
2456
2457 bool
2458 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
2459 {
2460         std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2461
2462         MessageDialog msg (str,
2463                            false,
2464                            Gtk::MESSAGE_WARNING,
2465                            Gtk::BUTTONS_YES_NO,
2466                            true);
2467
2468
2469         msg.set_name (X_("OpenExistingDialog"));
2470         msg.set_title (_("Open Existing Session"));
2471         msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
2472         msg.set_position (Gtk::WIN_POS_MOUSE);
2473         pop_back_splash ();
2474
2475         switch (msg.run()) {
2476         case RESPONSE_YES:
2477                 return true;
2478                 break;
2479         }
2480         return false;
2481 }
2482
2483 int
2484 ARDOUR_UI::build_session_from_nsd (const std::string& session_path, const std::string& session_name)
2485 {
2486         BusProfile bus_profile;
2487
2488         if (Profile->get_sae()) {
2489
2490                 bus_profile.master_out_channels = 2;
2491                 bus_profile.input_ac = AutoConnectPhysical;
2492                 bus_profile.output_ac = AutoConnectMaster;
2493                 bus_profile.requested_physical_in = 0; // use all available
2494                 bus_profile.requested_physical_out = 0; // use all available
2495
2496         } else {
2497
2498                 /* get settings from advanced section of NSD */
2499
2500                 if (_startup->create_master_bus()) {
2501                         bus_profile.master_out_channels = (uint32_t) _startup->master_channel_count();
2502                 } else {
2503                         bus_profile.master_out_channels = 0;
2504                 }
2505
2506                 if (_startup->connect_inputs()) {
2507                         bus_profile.input_ac = AutoConnectPhysical;
2508                 } else {
2509                         bus_profile.input_ac = AutoConnectOption (0);
2510                 }
2511
2512                 /// @todo some minor tweaks.
2513
2514                 bus_profile.output_ac = AutoConnectOption (0);
2515
2516                 if (_startup->connect_outputs ()) {
2517                         if (_startup->connect_outs_to_master()) {
2518                                 bus_profile.output_ac = AutoConnectMaster;
2519                         } else if (_startup->connect_outs_to_physical()) {
2520                                 bus_profile.output_ac = AutoConnectPhysical;
2521                         }
2522                 }
2523
2524                 bus_profile.requested_physical_in = (uint32_t) _startup->input_limit_count();
2525                 bus_profile.requested_physical_out = (uint32_t) _startup->output_limit_count();
2526         }
2527
2528         if (build_session (session_path, session_name, bus_profile)) {
2529                 return -1;
2530         }
2531
2532         return 0;
2533 }
2534
2535 void
2536 ARDOUR_UI::idle_load (const std::string& path)
2537 {
2538         if (_session) {
2539                 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2540                         /* /path/to/foo => /path/to/foo, foo */
2541                         load_session (path, basename_nosuffix (path));
2542                 } else {
2543                         /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2544                         load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2545                 }
2546         } else {
2547
2548                 ARDOUR_COMMAND_LINE::session_name = path;
2549
2550                 /*
2551                  * new_session_dialog doens't exist in A3
2552                  * Try to remove all references to it to
2553                  * see if it will compile.  NOTE: this will
2554                  * likely cause a runtime issue is my somewhat
2555                  * uneducated guess.
2556                  */
2557
2558                 //if (new_session_dialog) {
2559
2560
2561                         /* make it break out of Dialog::run() and
2562                            start again.
2563                          */
2564
2565                         //new_session_dialog->response (1);
2566                 //}
2567         }
2568 }
2569
2570 void
2571 ARDOUR_UI::end_loading_messages ()
2572 {
2573         // hide_splash ();
2574 }
2575
2576 void
2577 ARDOUR_UI::loading_message (const std::string& /*msg*/)
2578 {
2579         // show_splash ();
2580         // splash->message (msg);
2581         flush_pending ();
2582 }
2583
2584 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
2585 int
2586 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
2587 {
2588         string session_name;
2589         string session_path;
2590         string template_name;
2591         int ret = -1;
2592         bool likely_new = false;
2593
2594         if (!load_template.empty()) {
2595                 should_be_new = true;
2596                 template_name = load_template;
2597         }
2598
2599         while (ret != 0) {
2600
2601                 if (!should_be_new && !ARDOUR_COMMAND_LINE::session_name.empty()) {
2602
2603                         /* if they named a specific statefile, use it, otherwise they are
2604                            just giving a session folder, and we want to use it as is
2605                            to find the session.
2606                         */
2607
2608                         string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
2609
2610                         if (suffix != string::npos) {
2611                                 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
2612                                 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
2613                                 session_name = Glib::path_get_basename (session_name);
2614                         } else {
2615                                 session_path = ARDOUR_COMMAND_LINE::session_name;
2616                                 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
2617                         }
2618
2619                 } else {
2620
2621                         bool const apply = run_startup (should_be_new, load_template);
2622
2623                         if (!apply) {
2624                                 if (quit_on_cancel) {
2625                                         exit (1);
2626                                 } else {
2627                                         return ret;
2628                                 }
2629                         }
2630
2631                         /* if we run the startup dialog again, offer more than just "new session" */
2632
2633                         should_be_new = false;
2634
2635                         session_name = _startup->session_name (likely_new);
2636
2637                         string::size_type suffix = session_name.find (statefile_suffix);
2638
2639                         if (suffix != string::npos) {
2640                                 session_name = session_name.substr (0, suffix);
2641                         }
2642
2643                         /* this shouldn't happen, but we catch it just in case it does */
2644
2645                         if (session_name.empty()) {
2646                                 continue;
2647                         }
2648
2649                         if (_startup->use_session_template()) {
2650                                 template_name = _startup->session_template_name();
2651                                 _session_is_new = true;
2652                         }
2653
2654                         if (session_name[0] == G_DIR_SEPARATOR ||
2655                             (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
2656                             (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)) {
2657
2658                                 /* absolute path or cwd-relative path specified for session name: infer session folder
2659                                    from what was given.
2660                                 */
2661
2662                                 session_path = Glib::path_get_dirname (session_name);
2663                                 session_name = Glib::path_get_basename (session_name);
2664
2665                         } else {
2666
2667                                 session_path = _startup->session_folder();
2668
2669                                 if (session_name.find ('/') != string::npos) {
2670                                         MessageDialog msg (*_startup,
2671                                                            _("To ensure compatibility with various systems\n"
2672                                                              "session names may not contain a '/' character"));
2673                                         msg.run ();
2674                                         ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2675                                         continue;
2676                                 }
2677
2678                                 if (session_name.find ('\\') != string::npos) {
2679                                         MessageDialog msg (*_startup,
2680                                                            _("To ensure compatibility with various systems\n"
2681                                                              "session names may not contain a '\\' character"));
2682                                         msg.run ();
2683                                         ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2684                                         continue;
2685                                 }
2686                         }
2687                 }
2688
2689                 if (create_engine ()) {
2690                         break;
2691                 }
2692
2693                 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
2694
2695                         if (likely_new) {
2696
2697                                 std::string existing = Glib::build_filename (session_path, session_name);
2698
2699                                 if (!ask_about_loading_existing_session (existing)) {
2700                                         ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2701                                         continue;
2702                                 }
2703                         }
2704
2705                         _session_is_new = false;
2706
2707                 } else {
2708
2709                         if (!likely_new) {
2710                                 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
2711                                 msg.run ();
2712                                 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2713                                 continue;
2714                         }
2715
2716                         if (session_name.find ('/') != std::string::npos) {
2717                                 MessageDialog msg (*_startup,
2718                                                    _("To ensure compatibility with various systems\n"
2719                                                      "session names may not contain a '/' character"));
2720                                 msg.run ();
2721                                 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2722                                 continue;
2723                         }
2724
2725                         if (session_name.find ('\\') != std::string::npos) {
2726                                 MessageDialog msg (*_startup,
2727                                                    _("To ensure compatibility with various systems\n"
2728                                                      "session names may not contain a '\\' character"));
2729                                 msg.run ();
2730                                 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2731                                 continue;
2732                         }
2733
2734                         _session_is_new = true;
2735                 }
2736
2737                 if (likely_new && template_name.empty()) {
2738
2739                         ret = build_session_from_nsd (session_path, session_name);
2740
2741                 } else {
2742
2743                         ret = load_session (session_path, session_name, template_name);
2744
2745                         if (ret == -2) {
2746                                 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
2747                                 exit (1);
2748                         }
2749
2750                         if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
2751                                 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
2752                                 exit (1);
2753                         }
2754                 }
2755         }
2756
2757         return ret;
2758 }
2759
2760 void
2761 ARDOUR_UI::close_session()
2762 {
2763         if (!check_audioengine()) {
2764                 return;
2765         }
2766
2767         if (unload_session (true)) {
2768                 return;
2769         }
2770
2771         ARDOUR_COMMAND_LINE::session_name = "";
2772
2773         if (get_session_parameters (true, false)) {
2774                 exit (1);
2775         }
2776
2777         goto_editor_window ();
2778 }
2779
2780 /** @param snap_name Snapshot name (without .ardour suffix).
2781  *  @return -2 if the load failed because we are not connected to the AudioEngine.
2782  */
2783 int
2784 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
2785 {
2786         Session *new_session;
2787         int unload_status;
2788         int retval = -1;
2789
2790         session_loaded = false;
2791
2792         if (!check_audioengine()) {
2793                 return -2;
2794         }
2795
2796         unload_status = unload_session ();
2797
2798         if (unload_status < 0) {
2799                 goto out;
2800         } else if (unload_status > 0) {
2801                 retval = 0;
2802                 goto out;
2803         }
2804
2805         loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
2806
2807         try {
2808                 new_session = new Session (*engine, path, snap_name, 0, mix_template);
2809         }
2810
2811         /* this one is special */
2812
2813         catch (AudioEngine::PortRegistrationFailure& err) {
2814
2815                 MessageDialog msg (err.what(),
2816                                    true,
2817                                    Gtk::MESSAGE_INFO,
2818                                    Gtk::BUTTONS_CLOSE);
2819
2820                 msg.set_title (_("Port Registration Error"));
2821                 msg.set_secondary_text (_("Click the Close button to try again."));
2822                 msg.set_position (Gtk::WIN_POS_CENTER);
2823                 pop_back_splash ();
2824                 msg.present ();
2825
2826                 int response = msg.run ();
2827
2828                 msg.hide ();
2829
2830                 switch (response) {
2831                 case RESPONSE_CANCEL:
2832                         exit (1);
2833                 default:
2834                         break;
2835                 }
2836                 goto out;
2837         }
2838
2839         catch (...) {
2840
2841                 MessageDialog msg (string_compose(
2842                                            _("Session \"%1 (snapshot %2)\" did not load successfully"),
2843                                            path, snap_name),
2844                                    true,
2845                                    Gtk::MESSAGE_INFO,
2846                                    BUTTONS_OK);
2847
2848                 msg.set_title (_("Loading Error"));
2849                 msg.set_secondary_text (_("Click the Refresh button to try again."));
2850                 msg.add_button (Stock::REFRESH, 1);
2851                 msg.set_position (Gtk::WIN_POS_CENTER);
2852                 pop_back_splash ();
2853                 msg.present ();
2854
2855                 int response = msg.run ();
2856
2857                 switch (response) {
2858                 case 1:
2859                         break;
2860                 default:
2861                         exit (1);
2862                 }
2863
2864                 msg.hide ();
2865
2866                 goto out;
2867         }
2868
2869         {
2870                 list<string> const u = new_session->unknown_processors ();
2871                 if (!u.empty()) {
2872                         MissingPluginDialog d (_session, u);
2873                         d.run ();
2874                 }
2875         }
2876
2877         /* Now the session been created, add the transport controls */
2878         new_session->add_controllable(roll_controllable);
2879         new_session->add_controllable(stop_controllable);
2880         new_session->add_controllable(goto_start_controllable);
2881         new_session->add_controllable(goto_end_controllable);
2882         new_session->add_controllable(auto_loop_controllable);
2883         new_session->add_controllable(play_selection_controllable);
2884         new_session->add_controllable(rec_controllable);
2885
2886         set_session (new_session);
2887
2888         session_loaded = true;
2889
2890         goto_editor_window ();
2891
2892         if (_session) {
2893                 _session->set_clean ();
2894         }
2895
2896         flush_pending ();
2897         retval = 0;
2898
2899   out:
2900         return retval;
2901 }
2902
2903 int
2904 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
2905 {
2906         Session *new_session;
2907         int x;
2908
2909         if (!check_audioengine()) {
2910                 return -1;
2911         }
2912
2913         session_loaded = false;
2914
2915         x = unload_session ();
2916
2917         if (x < 0) {
2918                 return -1;
2919         } else if (x > 0) {
2920                 return 0;
2921         }
2922
2923         _session_is_new = true;
2924
2925         try {
2926                 new_session = new Session (*engine, path, snap_name, &bus_profile);
2927         }
2928
2929         catch (...) {
2930
2931                 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
2932                 pop_back_splash ();
2933                 msg.run ();
2934                 return -1;
2935         }
2936
2937         /* Give the new session the default GUI state, if such things exist */
2938
2939         XMLNode* n;
2940         n = Config->instant_xml (X_("Editor"));
2941         if (n) {
2942                 new_session->add_instant_xml (*n, false);
2943         }
2944         n = Config->instant_xml (X_("Mixer"));
2945         if (n) {
2946                 new_session->add_instant_xml (*n, false);
2947         }
2948
2949         /* Put the playhead at 0 and scroll fully left */
2950         n = new_session->instant_xml (X_("Editor"));
2951         if (n) {
2952                 n->add_property (X_("playhead"), X_("0"));
2953                 n->add_property (X_("left-frame"), X_("0"));
2954         }
2955
2956         set_session (new_session);
2957
2958         session_loaded = true;
2959
2960         new_session->save_state(new_session->name());
2961
2962         return 0;
2963 }
2964
2965 void
2966 ARDOUR_UI::launch_chat ()
2967 {
2968 #ifdef __APPLE__
2969         open_uri("http://webchat.freenode.net/?channels=ardour-osx");
2970 #else
2971         open_uri("http://webchat.freenode.net/?channels=ardour");
2972 #endif
2973 }
2974
2975 void
2976 ARDOUR_UI::show_about ()
2977 {
2978         if (about == 0) {
2979                 about = new About;
2980                 about->signal_response().connect(sigc::mem_fun (*this, &ARDOUR_UI::about_signal_response) );
2981         }
2982
2983         about->set_transient_for(*editor);
2984         about->show_all ();
2985 }
2986
2987 void
2988 ARDOUR_UI::launch_manual ()
2989 {
2990         PBD::open_uri("http://ardour.org/flossmanual");
2991 }
2992
2993 void
2994 ARDOUR_UI::launch_reference ()
2995 {
2996         PBD::open_uri("http://ardour.org/refmanual");
2997 }
2998
2999 void
3000 ARDOUR_UI::hide_about ()
3001 {
3002         if (about) {
3003                 about->get_window()->set_cursor ();
3004                 about->hide ();
3005         }
3006 }
3007
3008 void
3009 ARDOUR_UI::about_signal_response (int /*response*/)
3010 {
3011         hide_about();
3012 }
3013
3014 void
3015 ARDOUR_UI::show_splash ()
3016 {
3017         if (splash == 0) {
3018                 try {
3019                         splash = new Splash;
3020                 } catch (...) {
3021                         return;
3022                 }
3023         }
3024
3025         splash->show ();
3026         splash->present ();
3027         splash->queue_draw ();
3028         splash->get_window()->process_updates (true);
3029         flush_pending ();
3030 }
3031
3032 void
3033 ARDOUR_UI::hide_splash ()
3034 {
3035         if (splash) {
3036                 splash->hide();
3037         }
3038 }
3039
3040 void
3041 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title,
3042                                     const string& plural_msg, const string& singular_msg)
3043 {
3044         size_t removed;
3045
3046         removed = rep.paths.size();
3047
3048         if (removed == 0) {
3049                 MessageDialog msgd (*editor,
3050                                     _("No files were ready for clean-up"),
3051                                     true,
3052                                     Gtk::MESSAGE_INFO,
3053                                     (Gtk::ButtonsType)(Gtk::BUTTONS_OK)  );
3054                 msgd.set_title (_("Clean-up"));
3055                 msgd.set_secondary_text (_("If this seems suprising, \n\
3056 check for any existing snapshots.\n\
3057 These may still include regions that\n\
3058 require some unused files to continue to exist."));
3059
3060                 msgd.run ();
3061                 return;
3062         }
3063
3064         ArdourDialog results (_("Clean-up"), true, false);
3065
3066         struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
3067             CleanupResultsModelColumns() {
3068                     add (visible_name);
3069                     add (fullpath);
3070             }
3071             Gtk::TreeModelColumn<std::string> visible_name;
3072             Gtk::TreeModelColumn<std::string> fullpath;
3073         };
3074
3075
3076         CleanupResultsModelColumns results_columns;
3077         Glib::RefPtr<Gtk::ListStore> results_model;
3078         Gtk::TreeView results_display;
3079
3080         results_model = ListStore::create (results_columns);
3081         results_display.set_model (results_model);
3082         results_display.append_column (list_title, results_columns.visible_name);
3083
3084         results_display.set_name ("CleanupResultsList");
3085         results_display.set_headers_visible (true);
3086         results_display.set_headers_clickable (false);
3087         results_display.set_reorderable (false);
3088
3089         Gtk::ScrolledWindow list_scroller;
3090         Gtk::Label txt;
3091         Gtk::VBox dvbox;
3092         Gtk::HBox dhbox;  // the hbox for the image and text
3093         Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
3094         Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO,  Gtk::ICON_SIZE_DIALOG));
3095
3096         dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
3097
3098         const string dead_directory = _session->session_directory().dead_path().to_string();
3099
3100         /* subst:
3101            %1 - number of files removed
3102            %2 - location of "dead"
3103            %3 - size of files affected
3104            %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
3105         */
3106
3107         const char* bprefix;
3108         double space_adjusted = 0;
3109
3110         if (rep.space < 1000) {
3111                 bprefix = X_("");
3112                 space_adjusted = rep.space;
3113         } else if (rep.space < 1000000) {
3114                 bprefix = X_("kilo");
3115                 space_adjusted = truncf((float)rep.space / 1000.0);
3116         } else if (rep.space < 1000000 * 1000) {
3117                 bprefix = X_("mega");
3118                 space_adjusted = truncf((float)rep.space / (1000.0 * 1000.0));
3119         } else {
3120                 bprefix = X_("giga");
3121                 space_adjusted = truncf((float)rep.space / (1000.0 * 1000 * 1000.0));
3122         }
3123
3124         if (removed > 1) {
3125                 txt.set_text (string_compose (plural_msg, removed, dead_directory, space_adjusted, bprefix));
3126         } else {
3127                 txt.set_text (string_compose (singular_msg, removed, dead_directory, space_adjusted, bprefix));
3128         }
3129
3130         dhbox.pack_start (*dimage, true, false, 5);
3131         dhbox.pack_start (txt, true, false, 5);
3132
3133         for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
3134                 TreeModel::Row row = *(results_model->append());
3135                 row[results_columns.visible_name] = *i;
3136                 row[results_columns.fullpath] = *i;
3137         }
3138
3139         list_scroller.add (results_display);
3140         list_scroller.set_size_request (-1, 150);
3141         list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
3142
3143         dvbox.pack_start (dhbox, true, false, 5);
3144         dvbox.pack_start (list_scroller, true, false, 5);
3145         ddhbox.pack_start (dvbox, true, false, 5);
3146
3147         results.get_vbox()->pack_start (ddhbox, true, false, 5);
3148         results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
3149         results.set_default_response (RESPONSE_CLOSE);
3150         results.set_position (Gtk::WIN_POS_MOUSE);
3151
3152         results_display.show();
3153         list_scroller.show();
3154         txt.show();
3155         dvbox.show();
3156         dhbox.show();
3157         ddhbox.show();
3158         dimage->show();
3159
3160         //results.get_vbox()->show();
3161         results.set_resizable (false);
3162
3163         results.run ();
3164
3165 }
3166
3167 void
3168 ARDOUR_UI::cleanup ()
3169 {
3170         if (_session == 0) {
3171                 /* shouldn't happen: menu item is insensitive */
3172                 return;
3173         }
3174
3175
3176         MessageDialog checker (_("Are you sure you want to clean-up?"),
3177                                 true,
3178                                 Gtk::MESSAGE_QUESTION,
3179                                 (Gtk::ButtonsType)(Gtk::BUTTONS_NONE));
3180
3181         checker.set_title (_("Clean-up"));
3182
3183         checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
3184 ALL undo/redo information will be lost if you clean-up.\n\
3185 Clean-up will move all unused files to a \"dead\" location."));
3186
3187         checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3188         checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
3189         checker.set_default_response (RESPONSE_CANCEL);
3190
3191         checker.set_name (_("CleanupDialog"));
3192         checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3193         checker.set_position (Gtk::WIN_POS_MOUSE);
3194
3195         switch (checker.run()) {
3196         case RESPONSE_ACCEPT:
3197                 break;
3198         default:
3199                 return;
3200         }
3201
3202         ARDOUR::CleanupReport rep;
3203
3204         editor->prepare_for_cleanup ();
3205
3206         /* do not allow flush until a session is reloaded */
3207
3208         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3209         if (act) {
3210                 act->set_sensitive (false);
3211         }
3212
3213         if (_session->cleanup_sources (rep)) {
3214                 editor->finish_cleanup ();
3215                 return;
3216         }
3217
3218         editor->finish_cleanup ();
3219
3220         checker.hide();
3221         display_cleanup_results (rep,
3222                                  _("Cleaned Files"),
3223                                  _("\
3224 The following %1 files were not in use and \n\
3225 have been moved to:\n\n\
3226 %2\n\n\
3227 After a restart of Ardour,\n\n\
3228 Session -> Clean-up -> Flush Wastebasket\n\n\
3229 will release an additional\n\
3230 %3 %4bytes of disk space.\n"),
3231                                  _("\
3232 The following file was not in use and \n\
3233 has been moved to:\n                            \
3234 %2\n\n\
3235 After a restart of Ardour,\n\n\
3236 Session -> Clean-up -> Flush Wastebasket\n\n\
3237 will release an additional\n\
3238 %3 %4bytes of disk space.\n"
3239                                          ));
3240
3241 }
3242
3243 void
3244 ARDOUR_UI::flush_trash ()
3245 {
3246         if (_session == 0) {
3247                 /* shouldn't happen: menu item is insensitive */
3248                 return;
3249         }
3250
3251         ARDOUR::CleanupReport rep;
3252
3253         if (_session->cleanup_trash_sources (rep)) {
3254                 return;
3255         }
3256
3257         display_cleanup_results (rep,
3258                                  _("deleted file"),
3259                                  _("The following %1 files were deleted from\n\
3260 %2,\n\
3261 releasing %3 %4bytes of disk space"),
3262                                  _("The following file was deleted from\n\
3263 %2,\n\
3264 releasing %3 %4bytes of disk space"));
3265 }
3266
3267 void
3268 ARDOUR_UI::add_route (Gtk::Window* float_window)
3269 {
3270         int count;
3271
3272         if (!_session) {
3273                 return;
3274         }
3275
3276         if (add_route_dialog == 0) {
3277                 add_route_dialog = new AddRouteDialog (_session);
3278                 if (float_window) {
3279                         add_route_dialog->set_transient_for (*float_window);
3280                 }
3281         }
3282
3283         if (add_route_dialog->is_visible()) {
3284                 /* we're already doing this */
3285                 return;
3286         }
3287
3288         ResponseType r = (ResponseType) add_route_dialog->run ();
3289
3290         add_route_dialog->hide();
3291
3292         switch (r) {
3293                 case RESPONSE_ACCEPT:
3294                         break;
3295                 default:
3296                         return;
3297                         break;
3298         }
3299
3300         if ((count = add_route_dialog->count()) <= 0) {
3301                 return;
3302         }
3303
3304         string template_path = add_route_dialog->track_template();
3305
3306         if (!template_path.empty()) {
3307                 _session->new_route_from_template (count, template_path);
3308                 return;
3309         }
3310
3311         uint32_t input_chan = add_route_dialog->channels ();
3312         uint32_t output_chan;
3313         string name_template = add_route_dialog->name_template ();
3314         bool track = add_route_dialog->track ();
3315         RouteGroup* route_group = add_route_dialog->route_group ();
3316
3317         AutoConnectOption oac = Config->get_output_auto_connect();
3318
3319         if (oac & AutoConnectMaster) {
3320                 output_chan = (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan);
3321         } else {
3322                 output_chan = input_chan;
3323         }
3324
3325         /* XXX do something with name template */
3326
3327         if (add_route_dialog->type() == ARDOUR::DataType::MIDI) {
3328                 if (track) {
3329                         session_add_midi_track (route_group, count, name_template);
3330                 } else  {
3331                         MessageDialog msg (*editor,
3332                                         _("Sorry, MIDI Busses are not supported at this time."));
3333                         msg.run ();
3334                         //session_add_midi_bus();
3335                 }
3336         } else {
3337                 if (track) {
3338                         session_add_audio_track (input_chan, output_chan, add_route_dialog->mode(), route_group, count, name_template);
3339                 } else {
3340                         session_add_audio_bus (input_chan, output_chan, route_group, count, name_template);
3341                 }
3342         }
3343 }
3344
3345 XMLNode*
3346 ARDOUR_UI::mixer_settings () const
3347 {
3348         XMLNode* node = 0;
3349
3350         if (_session) {
3351                 node = _session->instant_xml(X_("Mixer"));
3352         } else {
3353                 node = Config->instant_xml(X_("Mixer"));
3354         }
3355
3356         if (!node) {
3357                 node = new XMLNode (X_("Mixer"));
3358         }
3359
3360         return node;
3361 }
3362
3363 XMLNode*
3364 ARDOUR_UI::editor_settings () const
3365 {
3366         XMLNode* node = 0;
3367
3368         if (_session) {
3369                 node = _session->instant_xml(X_("Editor"));
3370         } else {
3371                 node = Config->instant_xml(X_("Editor"));
3372         }
3373
3374         if (!node) {
3375                 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
3376                         node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
3377                 }
3378         }
3379
3380         if (!node) {
3381                 node = new XMLNode (X_("Editor"));
3382         }
3383
3384         return node;
3385 }
3386
3387 XMLNode*
3388 ARDOUR_UI::keyboard_settings () const
3389 {
3390         XMLNode* node = 0;
3391
3392         node = Config->extra_xml(X_("Keyboard"));
3393
3394         if (!node) {
3395                 node = new XMLNode (X_("Keyboard"));
3396         }
3397
3398         return node;
3399 }
3400
3401 void
3402 ARDOUR_UI::create_xrun_marker (framepos_t where)
3403 {
3404         editor->mouse_add_new_marker (where, false, true);
3405 }
3406
3407 void
3408 ARDOUR_UI::halt_on_xrun_message ()
3409 {
3410         MessageDialog msg (*editor,
3411                            _("Recording was stopped because your system could not keep up."));
3412         msg.run ();
3413 }
3414
3415 void
3416 ARDOUR_UI::xrun_handler (framepos_t where)
3417 {
3418         if (!_session) {
3419                 return;
3420         }
3421
3422         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
3423
3424         if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
3425                 create_xrun_marker(where);
3426         }
3427
3428         if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
3429                 halt_on_xrun_message ();
3430         }
3431 }
3432
3433 void
3434 ARDOUR_UI::disk_overrun_handler ()
3435 {
3436         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
3437
3438         if (!have_disk_speed_dialog_displayed) {
3439                 have_disk_speed_dialog_displayed = true;
3440                 MessageDialog* msg = new MessageDialog (*editor, string_compose (_("\
3441 The disk system on your computer\n\
3442 was not able to keep up with %1.\n\
3443 \n\
3444 Specifically, it failed to write data to disk\n\
3445 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
3446                 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3447                 msg->show ();
3448         }
3449 }
3450
3451 void
3452 ARDOUR_UI::disk_underrun_handler ()
3453 {
3454         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
3455
3456         if (!have_disk_speed_dialog_displayed) {
3457                 have_disk_speed_dialog_displayed = true;
3458                 MessageDialog* msg = new MessageDialog (
3459                         *editor, string_compose (_("The disk system on your computer\n\
3460 was not able to keep up with %1.\n\
3461 \n\
3462 Specifically, it failed to read data from disk\n\
3463 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
3464                 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3465                 msg->show ();
3466         }
3467 }
3468
3469 void
3470 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
3471 {
3472         have_disk_speed_dialog_displayed = false;
3473         delete msg;
3474 }
3475
3476 void
3477 ARDOUR_UI::session_dialog (std::string msg)
3478 {
3479         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
3480
3481         MessageDialog* d;
3482
3483         if (editor) {
3484                 d = new MessageDialog (*editor, msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3485         } else {
3486                 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3487         }
3488
3489         d->show_all ();
3490         d->run ();
3491         delete d;
3492 }
3493
3494 int
3495 ARDOUR_UI::pending_state_dialog ()
3496 {
3497         HBox* hbox = new HBox();
3498         Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3499         ArdourDialog dialog (_("Crash Recovery"), true);
3500         Label  message (_("\
3501 This session appears to have been in\n\
3502 middle of recording when ardour or\n\
3503 the computer was shutdown.\n\
3504 \n\
3505 Ardour can recover any captured audio for\n\
3506 you, or it can ignore it. Please decide\n\
3507 what you would like to do.\n"));
3508         image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3509         hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3510         hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3511         dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3512         dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
3513         dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
3514         dialog.set_default_response (RESPONSE_ACCEPT);
3515         dialog.set_position (WIN_POS_CENTER);
3516         message.show();
3517         image->show();
3518         hbox->show();
3519
3520         switch (dialog.run ()) {
3521         case RESPONSE_ACCEPT:
3522                 return 1;
3523         default:
3524                 return 0;
3525         }
3526 }
3527
3528 int
3529 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
3530 {
3531         HBox* hbox = new HBox();
3532         Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3533         ArdourDialog dialog (_("Sample Rate Mismatch"), true);
3534         Label  message (string_compose (_("\
3535 This session was created with a sample rate of %1 Hz\n\
3536 \n\
3537 The audioengine is currently running at %2 Hz\n"), desired, actual));
3538
3539         image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3540         hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3541         hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3542         dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3543         dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
3544         dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
3545         dialog.set_default_response (RESPONSE_ACCEPT);
3546         dialog.set_position (WIN_POS_CENTER);
3547         message.show();
3548         image->show();
3549         hbox->show();
3550
3551         switch (dialog.run ()) {
3552         case RESPONSE_ACCEPT:
3553                 return 0;
3554         default:
3555                 return 1;
3556         }
3557 }
3558
3559
3560 void
3561 ARDOUR_UI::disconnect_from_jack ()
3562 {
3563         if (engine) {
3564                 if( engine->disconnect_from_jack ()) {
3565                         MessageDialog msg (*editor, _("Could not disconnect from JACK"));
3566                         msg.run ();
3567                 }
3568
3569                 update_sample_rate (0);
3570         }
3571 }
3572
3573 void
3574 ARDOUR_UI::reconnect_to_jack ()
3575 {
3576         if (engine) {
3577                 if (engine->reconnect_to_jack ()) {
3578                         MessageDialog msg (*editor,  _("Could not reconnect to JACK"));
3579                         msg.run ();
3580                 }
3581
3582                 update_sample_rate (0);
3583         }
3584 }
3585
3586 void
3587 ARDOUR_UI::use_config ()
3588 {
3589         XMLNode* node = Config->extra_xml (X_("TransportControllables"));
3590         if (node) {
3591                 set_transport_controllable_state (*node);
3592         }
3593 }
3594
3595 void
3596 ARDOUR_UI::update_transport_clocks (framepos_t pos)
3597 {
3598         if (Config->get_primary_clock_delta_edit_cursor()) {
3599                 primary_clock->set (pos, false, editor->get_preferred_edit_position(), 1);
3600         } else {
3601                 primary_clock->set (pos, 0, true);
3602         }
3603
3604         if (Config->get_secondary_clock_delta_edit_cursor()) {
3605                 secondary_clock->set (pos, false, editor->get_preferred_edit_position(), 2);
3606         } else {
3607                 secondary_clock->set (pos);
3608         }
3609
3610         if (big_clock_window->get()) {
3611                 big_clock->set (pos);
3612         }
3613 }
3614
3615
3616 void
3617 ARDOUR_UI::step_edit_status_change (bool yn)
3618 {
3619         // XXX should really store pre-step edit status of things
3620         // we make insensitive
3621
3622         if (yn) {
3623                 rec_button.set_active_state (Mid);
3624                 rec_button.set_sensitive (false);
3625         } else {
3626                 rec_button.unset_active_state ();;
3627                 rec_button.set_sensitive (true);
3628         }
3629 }
3630
3631 void
3632 ARDOUR_UI::record_state_changed ()
3633 {
3634         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
3635
3636         if (!_session || !big_clock_window->get()) {
3637                 /* why bother - the clock isn't visible */
3638                 return;
3639         }
3640
3641         Session::RecordState const r = _session->record_status ();
3642         bool const h = _session->have_rec_enabled_track ();
3643
3644         if (r == Session::Recording && h)  {
3645                 big_clock->set_widget_name ("BigClockRecording");
3646         } else {
3647                 big_clock->set_widget_name ("BigClockNonRecording");
3648         }
3649 }
3650
3651 bool
3652 ARDOUR_UI::first_idle ()
3653 {
3654         if (_session) {
3655                 _session->allow_auto_play (true);
3656         }
3657
3658         if (editor) {
3659                 editor->first_idle();
3660         }
3661
3662         Keyboard::set_can_save_keybindings (true);
3663         return false;
3664 }
3665
3666 void
3667 ARDOUR_UI::store_clock_modes ()
3668 {
3669         XMLNode* node = new XMLNode(X_("ClockModes"));
3670
3671         for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
3672                 XMLNode* child = new XMLNode (X_("Clock"));
3673                 
3674                 child->add_property (X_("name"), (*x)->name());
3675                 child->add_property (X_("mode"), enum_2_string ((*x)->mode()));
3676                 child->add_property (X_("on"), ((*x)->off() ? X_("no") : X_("yes")));
3677
3678                 node->add_child_nocopy (*child);
3679         }
3680
3681         _session->add_extra_xml (*node);
3682         _session->set_dirty ();
3683 }
3684
3685 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
3686         : Controllable (name), ui (u), type(tp)
3687 {
3688
3689 }
3690
3691 void
3692 ARDOUR_UI::TransportControllable::set_value (double val)
3693 {
3694         if (val < 0.5) {
3695                 /* do nothing: these are radio-style actions */
3696                 return;
3697         }
3698
3699         const char *action = 0;
3700
3701         switch (type) {
3702         case Roll:
3703                 action = X_("Roll");
3704                 break;
3705         case Stop:
3706                 action = X_("Stop");
3707                 break;
3708         case GotoStart:
3709                 action = X_("Goto Start");
3710                 break;
3711         case GotoEnd:
3712                 action = X_("Goto End");
3713                 break;
3714         case AutoLoop:
3715                 action = X_("Loop");
3716                 break;
3717         case PlaySelection:
3718                 action = X_("Play Selection");
3719                 break;
3720         case RecordEnable:
3721                 action = X_("Record");
3722                 break;
3723         default:
3724                 break;
3725         }
3726
3727         if (action == 0) {
3728                 return;
3729         }
3730
3731         Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
3732
3733         if (act) {
3734                 act->activate ();
3735         }
3736 }
3737
3738 double
3739 ARDOUR_UI::TransportControllable::get_value (void) const
3740 {
3741         float val = 0.0;
3742
3743         switch (type) {
3744         case Roll:
3745                 break;
3746         case Stop:
3747                 break;
3748         case GotoStart:
3749                 break;
3750         case GotoEnd:
3751                 break;
3752         case AutoLoop:
3753                 break;
3754         case PlaySelection:
3755                 break;
3756         case RecordEnable:
3757                 break;
3758         default:
3759                 break;
3760         }
3761
3762         return val;
3763 }
3764
3765 void
3766 ARDOUR_UI::setup_profile ()
3767 {
3768         if (gdk_screen_width() < 1200) {
3769                 Profile->set_small_screen ();
3770         }
3771
3772
3773         if (getenv ("ARDOUR_SAE")) {
3774                 Profile->set_sae ();
3775                 Profile->set_single_package ();
3776         }
3777 }
3778
3779 void
3780 ARDOUR_UI::toggle_translations ()
3781 {
3782         using namespace Glib;
3783
3784         RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("EnableTranslation"));
3785         if (act) {
3786                 RefPtr<ToggleAction> ract = RefPtr<ToggleAction>::cast_dynamic (act);
3787                 if (ract) {
3788
3789                         string i18n_killer = ARDOUR::translation_kill_path();
3790
3791                         bool already_enabled = !ARDOUR::translations_are_disabled ();
3792
3793                         if (ract->get_active ()) {
3794 /* we don't care about errors */
3795                                 int fd = ::open (i18n_killer.c_str(), O_RDONLY|O_CREAT, 0644);
3796                                 close (fd);
3797                         } else {
3798 /* we don't care about errors */
3799                                 unlink (i18n_killer.c_str());
3800                         }
3801
3802                         if (already_enabled != ract->get_active()) {
3803                                 MessageDialog win (already_enabled ? _("Translations disabled") : _("Translations enabled"),
3804                                                    false,
3805                                                    Gtk::MESSAGE_WARNING,
3806                                                    Gtk::BUTTONS_OK);
3807                                 win.set_secondary_text (string_compose (_("You must restart %1 for this to take effect."), PROGRAM_NAME));
3808                                 win.set_position (Gtk::WIN_POS_CENTER);
3809                                 win.present ();
3810                                 win.run ();
3811                         }
3812                 }
3813         }
3814 }
3815
3816 /** Add a window proxy to our list, so that its state will be saved.
3817  *  This call also causes the window to be created and opened if its
3818  *  state was saved as `visible'.
3819  */
3820 void
3821 ARDOUR_UI::add_window_proxy (WindowProxyBase* p)
3822 {
3823         _window_proxies.push_back (p);
3824         p->maybe_show ();
3825 }
3826
3827 /** Remove a window proxy from our list.  Must be called if a WindowProxy
3828  *  is deleted, to prevent hanging pointers.
3829  */
3830 void
3831 ARDOUR_UI::remove_window_proxy (WindowProxyBase* p)
3832 {
3833         _window_proxies.remove (p);
3834 }
3835
3836 int
3837 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
3838 {
3839         MissingFileDialog dialog (s, str, type);
3840
3841         dialog.show ();
3842         dialog.present ();
3843
3844         int result = dialog.run ();
3845         dialog.hide ();
3846
3847         switch (result) {
3848         case RESPONSE_OK:
3849                 break;
3850         default:
3851                 return 1; // quit entire session load
3852         }
3853
3854         result = dialog.get_action ();
3855
3856         return result;
3857 }
3858
3859 int
3860 ARDOUR_UI::ambiguous_file (std::string file, std::string /*path*/, std::vector<std::string> hits)
3861 {
3862         AmbiguousFileDialog dialog (file, hits);
3863
3864         dialog.show ();
3865         dialog.present ();
3866
3867         dialog.run ();
3868         return dialog.get_which ();
3869 }
3870
3871 /** Allocate our thread-local buffers */
3872 void
3873 ARDOUR_UI::get_process_buffers ()
3874 {
3875         _process_thread->get_buffers ();
3876 }
3877
3878 /** Drop our thread-local buffers */
3879 void
3880 ARDOUR_UI::drop_process_buffers ()
3881 {
3882         _process_thread->drop_buffers ();
3883 }
3884
3885 void
3886 ARDOUR_UI::feedback_detected ()
3887 {
3888         MessageDialog d (
3889                 _("Something you have just done has generated a feedback path within Ardour's "
3890                   "routing.  Until this feedback is removed, Ardour's output will be as it was "
3891                   "before you made the feedback-generating connection.")
3892                 );
3893
3894         d.run ();
3895 }