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