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