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