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