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