Remove RemoveLastCapture action which duplicates remove-last-capture.
[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::transport_record (bool roll)
1576 {
1577
1578         if (_session) {
1579                 switch (_session->record_status()) {
1580                 case Session::Disabled:
1581                         if (_session->ntracks() == 0) {
1582                                 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."));
1583                                 msg.run ();
1584                                 return;
1585                         }
1586                         _session->maybe_enable_record ();
1587                         if (roll) {
1588                                 transport_roll ();
1589                         }
1590                         break;
1591                 case Session::Recording:
1592                         if (roll) {
1593                                 _session->request_stop();
1594                         } else {
1595                                 _session->disable_record (false, true);
1596                         }
1597                         break;
1598
1599                 case Session::Enabled:
1600                         _session->disable_record (false, true);
1601                 }
1602         }
1603         //cerr << "ARDOUR_UI::transport_record () called roll = " << roll << " _session->record_status() = " << _session->record_status() << endl;
1604 }
1605
1606 void
1607 ARDOUR_UI::transport_roll ()
1608 {
1609         if (!_session) {
1610                 return;
1611         }
1612
1613         if (_session->is_auditioning()) {
1614                 return;
1615         }
1616
1617 #if 0
1618         if (_session->config.get_external_sync()) {
1619                 switch (_session->config.get_sync_source()) {
1620                 case JACK:
1621                         break;
1622                 default:
1623                         /* transport controlled by the master */
1624                         return;
1625                 }
1626         }
1627 #endif
1628
1629         bool rolling = _session->transport_rolling();
1630
1631         if (_session->get_play_loop()) {
1632                 /* XXX it is not possible to just leave seamless loop and keep
1633                    playing at present (nov 4th 2009)
1634                 */
1635                 if (!Config->get_seamless_loop()) {
1636                         _session->request_play_loop (false, true);
1637                 }
1638         } else if (_session->get_play_range () && !Config->get_always_play_range()) {
1639                 /* stop playing a range if we currently are */
1640                 _session->request_play_range (0, true);
1641         }
1642
1643         if (Config->get_always_play_range()) {
1644                 _session->request_play_range (&editor->get_selection().time, true);
1645         }
1646
1647         if (!rolling) {
1648                 _session->request_transport_speed (1.0f);
1649         }
1650 }
1651
1652 void
1653 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
1654 {
1655
1656         if (!_session) {
1657                 return;
1658         }
1659
1660         if (_session->is_auditioning()) {
1661                 _session->cancel_audition ();
1662                 return;
1663         }
1664
1665         if (_session->config.get_external_sync()) {
1666                 switch (_session->config.get_sync_source()) {
1667                 case JACK:
1668                         break;
1669                 default:
1670                         /* transport controlled by the master */
1671                         return;
1672                 }
1673         }
1674
1675         bool rolling = _session->transport_rolling();
1676         bool affect_transport = true;
1677
1678         if (rolling && roll_out_of_bounded_mode) {
1679                 /* drop out of loop/range playback but leave transport rolling */
1680                 if (_session->get_play_loop()) {
1681                         if (Config->get_seamless_loop()) {
1682                                 /* the disk buffers contain copies of the loop - we can't
1683                                    just keep playing, so stop the transport. the user
1684                                    can restart as they wish.
1685                                 */
1686                                 affect_transport = true;
1687                         } else {
1688                                 /* disk buffers are normal, so we can keep playing */
1689                                 affect_transport = false;
1690                         }
1691                         _session->request_play_loop (false, true);
1692                 } else if (_session->get_play_range ()) {
1693                         affect_transport = false;
1694                         _session->request_play_range (0, true);
1695                 }
1696         }
1697
1698         if (affect_transport) {
1699                 if (rolling) {
1700                         _session->request_stop (with_abort, true);
1701                 } else {
1702                         if (Config->get_always_play_range ()) {
1703                                 _session->request_play_range (&editor->get_selection().time, true);
1704                         }
1705
1706                         _session->request_transport_speed (1.0f);
1707                 }
1708         }
1709 }
1710
1711 void
1712 ARDOUR_UI::toggle_session_auto_loop ()
1713 {
1714         Location * looploc = _session->locations()->auto_loop_location();
1715
1716         if (!_session || !looploc) {
1717                 return;
1718         }
1719
1720         if (_session->get_play_loop()) {
1721
1722                 if (_session->transport_rolling()) {
1723
1724                         _session->request_locate (looploc->start(), true);
1725                         _session->request_play_loop (false);
1726
1727                 } else {
1728                         _session->request_play_loop (false);
1729                 }
1730         } else {
1731                 _session->request_play_loop (true);
1732         }
1733         
1734         //show the loop markers
1735         looploc->set_hidden (false, this);
1736 }
1737
1738 void
1739 ARDOUR_UI::transport_play_selection ()
1740 {
1741         if (!_session) {
1742                 return;
1743         }
1744
1745         editor->play_selection ();
1746 }
1747
1748 void
1749 ARDOUR_UI::transport_rewind (int option)
1750 {
1751         float current_transport_speed;
1752
1753         if (_session) {
1754                 current_transport_speed = _session->transport_speed();
1755
1756                 if (current_transport_speed >= 0.0f) {
1757                         switch (option) {
1758                         case 0:
1759                                 _session->request_transport_speed (-1.0f);
1760                                 break;
1761                         case 1:
1762                                 _session->request_transport_speed (-4.0f);
1763                                 break;
1764                         case -1:
1765                                 _session->request_transport_speed (-0.5f);
1766                                 break;
1767                         }
1768                 } else {
1769                         /* speed up */
1770                         _session->request_transport_speed (current_transport_speed * 1.5f);
1771                 }
1772         }
1773 }
1774
1775 void
1776 ARDOUR_UI::transport_forward (int option)
1777 {
1778         float current_transport_speed;
1779
1780         if (_session) {
1781                 current_transport_speed = _session->transport_speed();
1782
1783                 if (current_transport_speed <= 0.0f) {
1784                         switch (option) {
1785                         case 0:
1786                                 _session->request_transport_speed (1.0f);
1787                                 break;
1788                         case 1:
1789                                 _session->request_transport_speed (4.0f);
1790                                 break;
1791                         case -1:
1792                                 _session->request_transport_speed (0.5f);
1793                                 break;
1794                         }
1795                 } else {
1796                         /* speed up */
1797                         _session->request_transport_speed (current_transport_speed * 1.5f);
1798                 }
1799
1800         }
1801 }
1802
1803 void
1804 ARDOUR_UI::toggle_record_enable (uint32_t rid)
1805 {
1806         if (_session == 0) {
1807                 return;
1808         }
1809
1810         boost::shared_ptr<Route> r;
1811
1812         if ((r = _session->route_by_remote_id (rid)) != 0) {
1813
1814                 Track* t;
1815
1816                 if ((t = dynamic_cast<Track*>(r.get())) != 0) {
1817                         t->set_record_enabled (!t->record_enabled(), this);
1818                 }
1819         }
1820         if (_session == 0) {
1821                 return;
1822         }
1823 }
1824
1825 void
1826 ARDOUR_UI::map_transport_state ()
1827 {
1828         if (!_session) {
1829                 auto_loop_button.unset_active_state ();
1830                 play_selection_button.unset_active_state ();
1831                 roll_button.unset_active_state ();
1832                 stop_button.set_active_state (Gtkmm2ext::ExplicitActive);
1833                 return;
1834         }
1835
1836         shuttle_box->map_transport_state ();
1837
1838         float sp = _session->transport_speed();
1839
1840         if (sp != 0.0f) {
1841
1842                 /* we're rolling */
1843
1844                 if (_session->get_play_range()) {
1845
1846                         play_selection_button.set_active_state (Gtkmm2ext::ExplicitActive);
1847                         roll_button.unset_active_state ();
1848                         auto_loop_button.unset_active_state ();
1849
1850                 } else if (_session->get_play_loop ()) {
1851
1852                         auto_loop_button.set_active (true);
1853                         play_selection_button.set_active (false);
1854                         roll_button.set_active (false);
1855
1856                 } else {
1857
1858                         roll_button.set_active (true);
1859                         play_selection_button.set_active (false);
1860                         auto_loop_button.set_active (false);
1861                 }
1862
1863                 if (Config->get_always_play_range()) {
1864                         /* light up both roll and play-selection if they are joined */
1865                         roll_button.set_active (true);
1866                         play_selection_button.set_active (true);
1867                 }
1868
1869                 stop_button.set_active (false);
1870
1871         } else {
1872
1873                 stop_button.set_active (true);
1874                 roll_button.set_active (false);
1875                 play_selection_button.set_active (false);
1876                 auto_loop_button.set_active (false);
1877                 update_disk_space ();
1878         }
1879 }
1880
1881 void
1882 ARDOUR_UI::engine_stopped ()
1883 {
1884         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
1885         ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1886         ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1887 }
1888
1889 void
1890 ARDOUR_UI::engine_running ()
1891 {
1892         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
1893         ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, true);
1894         ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, false);
1895
1896         Glib::RefPtr<Action> action;
1897         const char* action_name = 0;
1898
1899         switch (engine->frames_per_cycle()) {
1900         case 32:
1901                 action_name = X_("JACKLatency32");
1902                 break;
1903         case 64:
1904                 action_name = X_("JACKLatency64");
1905                 break;
1906         case 128:
1907                 action_name = X_("JACKLatency128");
1908                 break;
1909         case 512:
1910                 action_name = X_("JACKLatency512");
1911                 break;
1912         case 1024:
1913                 action_name = X_("JACKLatency1024");
1914                 break;
1915         case 2048:
1916                 action_name = X_("JACKLatency2048");
1917                 break;
1918         case 4096:
1919                 action_name = X_("JACKLatency4096");
1920                 break;
1921         case 8192:
1922                 action_name = X_("JACKLatency8192");
1923                 break;
1924         default:
1925                 /* XXX can we do anything useful ? */
1926                 break;
1927         }
1928
1929         if (action_name) {
1930
1931                 action = ActionManager::get_action (X_("JACK"), action_name);
1932
1933                 if (action) {
1934                         Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (action);
1935                         ract->set_active ();
1936                 }
1937         }
1938 }
1939
1940 void
1941 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
1942 {
1943         if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
1944                 /* we can't rely on the original string continuing to exist when we are called
1945                    again in the GUI thread, so make a copy and note that we need to
1946                    free it later.
1947                 */
1948                 char *copy = strdup (reason);
1949                 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
1950                 return;
1951         }
1952
1953         ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1954         ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1955
1956         update_sample_rate (0);
1957
1958         string msgstr;
1959
1960         /* if the reason is a non-empty string, it means that the backend was shutdown
1961            rather than just Ardour.
1962         */
1963
1964         if (strlen (reason)) {
1965                 msgstr = string_compose (_("The audio backend (JACK) was shutdown because:\n\n%1"), reason);
1966         } else {
1967                 msgstr = string_compose (_("\
1968 JACK has either been shutdown or it\n\
1969 disconnected %1 because %1\n\
1970 was not fast enough. Try to restart\n\
1971 JACK, reconnect and save the session."), PROGRAM_NAME);
1972         }
1973
1974         MessageDialog msg (*editor, msgstr);
1975         pop_back_splash (msg);
1976         msg.run ();
1977
1978         if (free_reason) {
1979                 free ((char*) reason);
1980         }
1981 }
1982
1983 int32_t
1984 ARDOUR_UI::do_engine_start ()
1985 {
1986         try {
1987                 engine->start();
1988         }
1989
1990         catch (...) {
1991                 engine->stop ();
1992                 error << _("Unable to start the session running")
1993                       << endmsg;
1994                 unload_session ();
1995                 return -2;
1996         }
1997
1998         return 0;
1999 }
2000
2001 void
2002 ARDOUR_UI::update_clocks ()
2003 {
2004         if (!editor || !editor->dragging_playhead()) {
2005                 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position()); /* EMIT_SIGNAL */
2006         }
2007 }
2008
2009 void
2010 ARDOUR_UI::start_clocking ()
2011 {
2012         clock_signal_connection = RapidScreenUpdate.connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2013 }
2014
2015 void
2016 ARDOUR_UI::stop_clocking ()
2017 {
2018         clock_signal_connection.disconnect ();
2019 }
2020
2021 gint
2022 ARDOUR_UI::_blink (void *arg)
2023
2024 {
2025         ((ARDOUR_UI *) arg)->blink ();
2026         return TRUE;
2027 }
2028
2029 void
2030 ARDOUR_UI::blink ()
2031 {
2032         Blink (blink_on = !blink_on); /* EMIT_SIGNAL */
2033 }
2034
2035 void
2036 ARDOUR_UI::start_blinking ()
2037 {
2038         /* Start the blink signal. Everybody with a blinking widget
2039            uses Blink to drive the widget's state.
2040         */
2041
2042         if (blink_timeout_tag < 0) {
2043                 blink_on = false;
2044                 blink_timeout_tag = g_timeout_add (240, _blink, this);
2045         }
2046 }
2047
2048 void
2049 ARDOUR_UI::stop_blinking ()
2050 {
2051         if (blink_timeout_tag >= 0) {
2052                 g_source_remove (blink_timeout_tag);
2053                 blink_timeout_tag = -1;
2054         }
2055 }
2056
2057
2058 /** Ask the user for the name of a new snapshot and then take it.
2059  */
2060
2061 void
2062 ARDOUR_UI::snapshot_session (bool switch_to_it)
2063 {
2064         ArdourPrompter prompter (true);
2065         string snapname;
2066
2067         prompter.set_name ("Prompter");
2068         prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2069         prompter.set_title (_("Take Snapshot"));
2070         prompter.set_prompt (_("Name of new snapshot"));
2071
2072         if (!switch_to_it) {
2073                 char timebuf[128];
2074                 time_t n;
2075                 struct tm local_time;
2076
2077                 time (&n);
2078                 localtime_r (&n, &local_time);
2079                 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2080                 prompter.set_initial_text (timebuf);
2081         }
2082
2083   again:
2084         switch (prompter.run()) {
2085         case RESPONSE_ACCEPT:
2086         {
2087                 prompter.get_result (snapname);
2088
2089                 bool do_save = (snapname.length() != 0);
2090
2091                 if (do_save) {
2092                         char illegal = Session::session_name_is_legal(snapname);
2093                         if (illegal) {
2094                                 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2095                                                      "snapshot names may not contain a '%1' character"), illegal));
2096                                 msg.run ();
2097                                 goto again;
2098                         }
2099                 }
2100
2101                 vector<sys::path> p;
2102                 get_state_files_in_directory (_session->session_directory().root_path(), p);
2103                 vector<string> n = get_file_names_no_extension (p);
2104                 if (find (n.begin(), n.end(), snapname) != n.end()) {
2105
2106                         ArdourDialog confirm (_("Confirm Snapshot Overwrite"), true);
2107                         Label m (_("A snapshot already exists with that name.  Do you want to overwrite it?"));
2108                         confirm.get_vbox()->pack_start (m, true, true);
2109                         confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2110                         confirm.add_button (_("Overwrite"), Gtk::RESPONSE_ACCEPT);
2111                         confirm.show_all ();
2112                         switch (confirm.run()) {
2113                         case RESPONSE_CANCEL:
2114                                 do_save = false;
2115                         }
2116                 }
2117
2118                 if (do_save) {
2119                         save_state (snapname, switch_to_it);
2120                 }
2121                 break;
2122         }
2123
2124         default:
2125                 break;
2126         }
2127 }
2128
2129 /** Ask the user for a new session name and then rename the session to it.
2130  */
2131
2132 void
2133 ARDOUR_UI::rename_session ()
2134 {
2135         if (!_session) {
2136                 return;
2137         }
2138
2139         ArdourPrompter prompter (true);
2140         string name;
2141
2142         prompter.set_name ("Prompter");
2143         prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2144         prompter.set_title (_("Rename Session"));
2145         prompter.set_prompt (_("New session name"));
2146
2147   again:
2148         switch (prompter.run()) {
2149         case RESPONSE_ACCEPT:
2150         {
2151                 prompter.get_result (name);
2152
2153                 bool do_rename = (name.length() != 0);
2154
2155                 if (do_rename) {
2156                         char illegal = Session::session_name_is_legal (name);
2157
2158                         if (illegal) {
2159                                 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2160                                                                      "session names may not contain a '%1' character"), illegal));
2161                                 msg.run ();
2162                                 goto again;
2163                         }
2164
2165                         switch (_session->rename (name)) {
2166                         case -1: {
2167                                 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
2168                                 msg.set_position (WIN_POS_MOUSE);
2169                                 msg.run ();
2170                                 goto again;
2171                                 break;
2172                         }
2173                         case 0:
2174                                 break;
2175                         default: {
2176                                 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
2177                                 msg.set_position (WIN_POS_MOUSE);
2178                                 msg.run ();
2179                                 break;
2180                         }
2181                         }
2182                 }
2183                 
2184                 break;
2185         }
2186
2187         default:
2188                 break;
2189         }
2190 }
2191
2192 void
2193 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2194 {
2195         XMLNode* node = new XMLNode (X_("UI"));
2196
2197         for (list<WindowProxyBase*>::iterator i = _window_proxies.begin(); i != _window_proxies.end(); ++i) {
2198                 if (!(*i)->rc_configured()) {
2199                         node->add_child_nocopy (*((*i)->get_state ()));
2200                 }
2201         }
2202
2203         node->add_child_nocopy (gui_object_state->get_state());
2204
2205         _session->add_extra_xml (*node);
2206
2207         save_state_canfail (name, switch_to_it);
2208 }
2209
2210 int
2211 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2212 {
2213         if (_session) {
2214                 int ret;
2215
2216                 if (name.length() == 0) {
2217                         name = _session->snap_name();
2218                 }
2219
2220                 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2221                         return ret;
2222                 }
2223         }
2224
2225         save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2226         return 0;
2227 }
2228
2229 void
2230 ARDOUR_UI::primary_clock_value_changed ()
2231 {
2232         if (_session) {
2233                 _session->request_locate (primary_clock->current_time ());
2234         }
2235 }
2236
2237 void
2238 ARDOUR_UI::big_clock_value_changed ()
2239 {
2240         if (_session) {
2241                 _session->request_locate (big_clock->current_time ());
2242         }
2243 }
2244
2245 void
2246 ARDOUR_UI::secondary_clock_value_changed ()
2247 {
2248         if (_session) {
2249                 _session->request_locate (secondary_clock->current_time ());
2250         }
2251 }
2252
2253 void
2254 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2255 {
2256         if (_session == 0) {
2257                 return;
2258         }
2259
2260         if (_session->step_editing()) {
2261                 return;
2262         }
2263
2264         Session::RecordState const r = _session->record_status ();
2265         bool const h = _session->have_rec_enabled_track ();
2266
2267         if (r == Session::Enabled || (r == Session::Recording && !h)) {
2268                 if (onoff) {
2269                         rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2270                 } else {
2271                         rec_button.set_active_state (Gtkmm2ext::ImplicitActive);
2272                 }
2273         } else if (r == Session::Recording && h) {
2274                 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2275         } else {
2276                 rec_button.unset_active_state ();
2277         }
2278 }
2279
2280 void
2281 ARDOUR_UI::save_template ()
2282 {
2283         ArdourPrompter prompter (true);
2284         string name;
2285
2286         if (!check_audioengine()) {
2287                 return;
2288         }
2289
2290         prompter.set_name (X_("Prompter"));
2291         prompter.set_title (_("Save Template"));
2292         prompter.set_prompt (_("Name for template:"));
2293         prompter.set_initial_text(_session->name() + _("-template"));
2294         prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2295
2296         switch (prompter.run()) {
2297         case RESPONSE_ACCEPT:
2298                 prompter.get_result (name);
2299
2300                 if (name.length()) {
2301                         _session->save_template (name);
2302                 }
2303                 break;
2304
2305         default:
2306                 break;
2307         }
2308 }
2309
2310 void
2311 ARDOUR_UI::edit_metadata ()
2312 {
2313         SessionMetadataEditor dialog;
2314         dialog.set_session (_session);
2315         editor->ensure_float (dialog);
2316         dialog.run ();
2317 }
2318
2319 void
2320 ARDOUR_UI::import_metadata ()
2321 {
2322         SessionMetadataImporter dialog;
2323         dialog.set_session (_session);
2324         editor->ensure_float (dialog);
2325         dialog.run ();
2326 }
2327
2328 bool
2329 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
2330 {
2331         std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2332
2333         MessageDialog msg (str,
2334                            false,
2335                            Gtk::MESSAGE_WARNING,
2336                            Gtk::BUTTONS_YES_NO,
2337                            true);
2338
2339
2340         msg.set_name (X_("OpenExistingDialog"));
2341         msg.set_title (_("Open Existing Session"));
2342         msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
2343         msg.set_position (Gtk::WIN_POS_MOUSE);
2344         pop_back_splash (msg);
2345
2346         switch (msg.run()) {
2347         case RESPONSE_YES:
2348                 return true;
2349                 break;
2350         }
2351         return false;
2352 }
2353
2354 int
2355 ARDOUR_UI::build_session_from_nsd (const std::string& session_path, const std::string& session_name)
2356 {
2357         BusProfile bus_profile;
2358
2359         if (Profile->get_sae()) {
2360
2361                 bus_profile.master_out_channels = 2;
2362                 bus_profile.input_ac = AutoConnectPhysical;
2363                 bus_profile.output_ac = AutoConnectMaster;
2364                 bus_profile.requested_physical_in = 0; // use all available
2365                 bus_profile.requested_physical_out = 0; // use all available
2366
2367         } else {
2368
2369                 /* get settings from advanced section of NSD */
2370
2371                 if (_startup->create_master_bus()) {
2372                         bus_profile.master_out_channels = (uint32_t) _startup->master_channel_count();
2373                 } else {
2374                         bus_profile.master_out_channels = 0;
2375                 }
2376
2377                 if (_startup->connect_inputs()) {
2378                         bus_profile.input_ac = AutoConnectPhysical;
2379                 } else {
2380                         bus_profile.input_ac = AutoConnectOption (0);
2381                 }
2382
2383                 bus_profile.output_ac = AutoConnectOption (0);
2384
2385                 if (_startup->connect_outputs ()) {
2386                         if (_startup->connect_outs_to_master()) {
2387                                 bus_profile.output_ac = AutoConnectMaster;
2388                         } else if (_startup->connect_outs_to_physical()) {
2389                                 bus_profile.output_ac = AutoConnectPhysical;
2390                         }
2391                 }
2392
2393                 bus_profile.requested_physical_in = (uint32_t) _startup->input_limit_count();
2394                 bus_profile.requested_physical_out = (uint32_t) _startup->output_limit_count();
2395         }
2396
2397         if (build_session (session_path, session_name, bus_profile)) {
2398                 return -1;
2399         }
2400
2401         return 0;
2402 }
2403
2404 void
2405 ARDOUR_UI::idle_load (const std::string& path)
2406 {
2407         if (_session) {
2408                 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2409                         /* /path/to/foo => /path/to/foo, foo */
2410                         load_session (path, basename_nosuffix (path));
2411                 } else {
2412                         /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2413                         load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2414                 }
2415         } else {
2416
2417                 ARDOUR_COMMAND_LINE::session_name = path;
2418
2419                 /*
2420                  * new_session_dialog doens't exist in A3
2421                  * Try to remove all references to it to
2422                  * see if it will compile.  NOTE: this will
2423                  * likely cause a runtime issue is my somewhat
2424                  * uneducated guess.
2425                  */
2426
2427                 //if (new_session_dialog) {
2428
2429
2430                         /* make it break out of Dialog::run() and
2431                            start again.
2432                          */
2433
2434                         //new_session_dialog->response (1);
2435                 //}
2436         }
2437 }
2438
2439 void
2440 ARDOUR_UI::loading_message (const std::string& msg)
2441 {
2442         if (ARDOUR_COMMAND_LINE::no_splash) {
2443                 return;
2444         }
2445
2446         show_splash ();
2447         if (splash) {
2448                 splash->message (msg);
2449                 flush_pending ();
2450         }
2451 }
2452
2453 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
2454 int
2455 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
2456 {
2457         string session_name;
2458         string session_path;
2459         string template_name;
2460         int ret = -1;
2461         bool likely_new = false;
2462
2463         if (!load_template.empty()) {
2464                 should_be_new = true;
2465                 template_name = load_template;
2466         }
2467
2468         while (ret != 0) {
2469
2470                 if (!should_be_new && !ARDOUR_COMMAND_LINE::session_name.empty()) {
2471
2472                         /* if they named a specific statefile, use it, otherwise they are
2473                            just giving a session folder, and we want to use it as is
2474                            to find the session.
2475                         */
2476
2477                         string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
2478
2479                         if (suffix != string::npos) {
2480                                 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
2481                                 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
2482                                 session_name = Glib::path_get_basename (session_name);
2483                         } else {
2484                                 session_path = ARDOUR_COMMAND_LINE::session_name;
2485                                 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
2486                         }
2487
2488                 } else {
2489
2490                         bool const apply = run_startup (should_be_new, load_template);
2491
2492                         if (!apply) {
2493                                 if (quit_on_cancel) {
2494                                         exit (1);
2495                                 } else {
2496                                         return ret;
2497                                 }
2498                         }
2499
2500                         /* if we run the startup dialog again, offer more than just "new session" */
2501
2502                         should_be_new = false;
2503
2504                         session_name = _startup->session_name (likely_new);
2505
2506                         string::size_type suffix = session_name.find (statefile_suffix);
2507
2508                         if (suffix != string::npos) {
2509                                 session_name = session_name.substr (0, suffix);
2510                         }
2511
2512                         /* this shouldn't happen, but we catch it just in case it does */
2513
2514                         if (session_name.empty()) {
2515                                 continue;
2516                         }
2517
2518                         if (_startup->use_session_template()) {
2519                                 template_name = _startup->session_template_name();
2520                                 _session_is_new = true;
2521                         }
2522
2523                         if (session_name[0] == G_DIR_SEPARATOR ||
2524                             (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
2525                             (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)) {
2526
2527                                 /* absolute path or cwd-relative path specified for session name: infer session folder
2528                                    from what was given.
2529                                 */
2530
2531                                 session_path = Glib::path_get_dirname (session_name);
2532                                 session_name = Glib::path_get_basename (session_name);
2533
2534                         } else {
2535
2536                                 session_path = _startup->session_folder();
2537
2538                                 char illegal = Session::session_name_is_legal (session_name);
2539
2540                                 if (illegal) {
2541                                         MessageDialog msg (*_startup,
2542                                                            string_compose (_("To ensure compatibility with various systems\n"
2543                                                                              "session names may not contain a '%1' character"),
2544                                                                            illegal));
2545                                         msg.run ();
2546                                         ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2547                                         continue;
2548                                 }
2549                         }
2550                 }
2551
2552                 if (create_engine ()) {
2553                         break;
2554                 }
2555
2556                 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
2557
2558                         if (likely_new) {
2559
2560                                 std::string existing = Glib::build_filename (session_path, session_name);
2561
2562                                 if (!ask_about_loading_existing_session (existing)) {
2563                                         ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2564                                         continue;
2565                                 }
2566                         }
2567
2568                         _session_is_new = false;
2569
2570                 } else {
2571
2572                         if (!likely_new) {
2573                                 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
2574                                 msg.run ();
2575                                 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2576                                 continue;
2577                         }
2578
2579                         if (session_name.find ('/') != std::string::npos) {
2580                                 MessageDialog msg (*_startup,
2581                                                    _("To ensure compatibility with various systems\n"
2582                                                      "session names may not contain a '/' character"));
2583                                 msg.run ();
2584                                 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2585                                 continue;
2586                         }
2587
2588                         if (session_name.find ('\\') != std::string::npos) {
2589                                 MessageDialog msg (*_startup,
2590                                                    _("To ensure compatibility with various systems\n"
2591                                                      "session names may not contain a '\\' character"));
2592                                 msg.run ();
2593                                 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2594                                 continue;
2595                         }
2596
2597                         _session_is_new = true;
2598                 }
2599
2600                 if (likely_new && template_name.empty()) {
2601
2602                         ret = build_session_from_nsd (session_path, session_name);
2603
2604                 } else {
2605
2606                         ret = load_session (session_path, session_name, template_name);
2607
2608                         if (ret == -2) {
2609                                 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
2610                                 exit (1);
2611                         }
2612
2613                         if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
2614                                 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
2615                                 exit (1);
2616                         }
2617                 }
2618         }
2619
2620         return ret;
2621 }
2622
2623 void
2624 ARDOUR_UI::close_session()
2625 {
2626         if (!check_audioengine()) {
2627                 return;
2628         }
2629
2630         if (unload_session (true)) {
2631                 return;
2632         }
2633
2634         ARDOUR_COMMAND_LINE::session_name = "";
2635
2636         if (get_session_parameters (true, false)) {
2637                 exit (1);
2638         }
2639
2640         goto_editor_window ();
2641 }
2642
2643 /** @param snap_name Snapshot name (without .ardour suffix).
2644  *  @return -2 if the load failed because we are not connected to the AudioEngine.
2645  */
2646 int
2647 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
2648 {
2649         Session *new_session;
2650         int unload_status;
2651         int retval = -1;
2652
2653         session_loaded = false;
2654
2655         if (!check_audioengine()) {
2656                 return -2;
2657         }
2658
2659         unload_status = unload_session ();
2660
2661         if (unload_status < 0) {
2662                 goto out;
2663         } else if (unload_status > 0) {
2664                 retval = 0;
2665                 goto out;
2666         }
2667
2668         loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
2669
2670         try {
2671                 new_session = new Session (*engine, path, snap_name, 0, mix_template);
2672         }
2673
2674         /* this one is special */
2675
2676         catch (AudioEngine::PortRegistrationFailure& err) {
2677
2678                 MessageDialog msg (err.what(),
2679                                    true,
2680                                    Gtk::MESSAGE_INFO,
2681                                    Gtk::BUTTONS_CLOSE);
2682
2683                 msg.set_title (_("Port Registration Error"));
2684                 msg.set_secondary_text (_("Click the Close button to try again."));
2685                 msg.set_position (Gtk::WIN_POS_CENTER);
2686                 pop_back_splash (msg);
2687                 msg.present ();
2688
2689                 int response = msg.run ();
2690
2691                 msg.hide ();
2692
2693                 switch (response) {
2694                 case RESPONSE_CANCEL:
2695                         exit (1);
2696                 default:
2697                         break;
2698                 }
2699                 goto out;
2700         }
2701
2702         catch (...) {
2703
2704                 MessageDialog msg (string_compose(
2705                                            _("Session \"%1 (snapshot %2)\" did not load successfully"),
2706                                            path, snap_name),
2707                                    true,
2708                                    Gtk::MESSAGE_INFO,
2709                                    BUTTONS_OK);
2710
2711                 msg.set_title (_("Loading Error"));
2712                 msg.set_secondary_text (_("Click the Refresh button to try again."));
2713                 msg.add_button (Stock::REFRESH, 1);
2714                 msg.set_position (Gtk::WIN_POS_CENTER);
2715                 pop_back_splash (msg);
2716                 msg.present ();
2717
2718                 int response = msg.run ();
2719
2720                 switch (response) {
2721                 case 1:
2722                         break;
2723                 default:
2724                         exit (1);
2725                 }
2726
2727                 msg.hide ();
2728
2729                 goto out;
2730         }
2731
2732         {
2733                 list<string> const u = new_session->unknown_processors ();
2734                 if (!u.empty()) {
2735                         MissingPluginDialog d (_session, u);
2736                         d.run ();
2737                 }
2738         }
2739
2740         /* Now the session been created, add the transport controls */
2741         new_session->add_controllable(roll_controllable);
2742         new_session->add_controllable(stop_controllable);
2743         new_session->add_controllable(goto_start_controllable);
2744         new_session->add_controllable(goto_end_controllable);
2745         new_session->add_controllable(auto_loop_controllable);
2746         new_session->add_controllable(play_selection_controllable);
2747         new_session->add_controllable(rec_controllable);
2748
2749         set_session (new_session);
2750
2751         session_loaded = true;
2752
2753         goto_editor_window ();
2754
2755         if (_session) {
2756                 _session->set_clean ();
2757         }
2758
2759         flush_pending ();
2760         retval = 0;
2761
2762   out:
2763         return retval;
2764 }
2765
2766 int
2767 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
2768 {
2769         Session *new_session;
2770         int x;
2771
2772         if (!check_audioengine()) {
2773                 return -1;
2774         }
2775
2776         session_loaded = false;
2777
2778         x = unload_session ();
2779
2780         if (x < 0) {
2781                 return -1;
2782         } else if (x > 0) {
2783                 return 0;
2784         }
2785
2786         _session_is_new = true;
2787
2788         try {
2789                 new_session = new Session (*engine, path, snap_name, &bus_profile);
2790         }
2791
2792         catch (...) {
2793
2794                 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
2795                 pop_back_splash (msg);
2796                 msg.run ();
2797                 return -1;
2798         }
2799
2800         /* Give the new session the default GUI state, if such things exist */
2801
2802         XMLNode* n;
2803         n = Config->instant_xml (X_("Editor"));
2804         if (n) {
2805                 new_session->add_instant_xml (*n, false);
2806         }
2807         n = Config->instant_xml (X_("Mixer"));
2808         if (n) {
2809                 new_session->add_instant_xml (*n, false);
2810         }
2811
2812         /* Put the playhead at 0 and scroll fully left */
2813         n = new_session->instant_xml (X_("Editor"));
2814         if (n) {
2815                 n->add_property (X_("playhead"), X_("0"));
2816                 n->add_property (X_("left-frame"), X_("0"));
2817         }
2818
2819         set_session (new_session);
2820
2821         session_loaded = true;
2822
2823         new_session->save_state(new_session->name());
2824
2825         return 0;
2826 }
2827
2828 void
2829 ARDOUR_UI::launch_chat ()
2830 {
2831 #ifdef __APPLE__
2832         open_uri("http://webchat.freenode.net/?channels=ardour-osx");
2833 #else
2834         open_uri("http://webchat.freenode.net/?channels=ardour");
2835 #endif
2836 }
2837
2838 void
2839 ARDOUR_UI::show_about ()
2840 {
2841         if (about == 0) {
2842                 about = new About;
2843                 about->signal_response().connect(sigc::mem_fun (*this, &ARDOUR_UI::about_signal_response) );
2844         }
2845
2846         about->set_transient_for(*editor);
2847         about->show_all ();
2848 }
2849
2850 void
2851 ARDOUR_UI::launch_manual ()
2852 {
2853         PBD::open_uri("http://ardour.org/flossmanual");
2854 }
2855
2856 void
2857 ARDOUR_UI::launch_reference ()
2858 {
2859         PBD::open_uri("http://ardour.org/refmanual");
2860 }
2861
2862 void
2863 ARDOUR_UI::hide_about ()
2864 {
2865         if (about) {
2866                 about->get_window()->set_cursor ();
2867                 about->hide ();
2868         }
2869 }
2870
2871 void
2872 ARDOUR_UI::about_signal_response (int /*response*/)
2873 {
2874         hide_about();
2875 }
2876
2877 void
2878 ARDOUR_UI::show_splash ()
2879 {
2880         if (splash == 0) {
2881                 try {
2882                         splash = new Splash;
2883                 } catch (...) {
2884                         cerr << "Splash could not be created\n";
2885                         return;
2886                 }
2887         }
2888
2889         splash->present ();
2890         splash->pop_front ();
2891         splash->queue_draw ();
2892         splash->get_window()->process_updates (true);
2893         flush_pending ();
2894 }
2895
2896 void
2897 ARDOUR_UI::hide_splash ()
2898 {
2899         if (splash) {
2900                 splash->hide();
2901         }
2902 }
2903
2904 void
2905 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title,
2906                                     const string& plural_msg, const string& singular_msg)
2907 {
2908         size_t removed;
2909
2910         removed = rep.paths.size();
2911
2912         if (removed == 0) {
2913                 MessageDialog msgd (*editor,
2914                                     _("No files were ready for clean-up"),
2915                                     true,
2916                                     Gtk::MESSAGE_INFO,
2917                                     Gtk::BUTTONS_OK);
2918                 msgd.set_title (_("Clean-up"));
2919                 msgd.set_secondary_text (_("If this seems suprising, \n\
2920 check for any existing snapshots.\n\
2921 These may still include regions that\n\
2922 require some unused files to continue to exist."));
2923
2924                 msgd.run ();
2925                 return;
2926         }
2927
2928         ArdourDialog results (_("Clean-up"), true, false);
2929
2930         struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
2931             CleanupResultsModelColumns() {
2932                     add (visible_name);
2933                     add (fullpath);
2934             }
2935             Gtk::TreeModelColumn<std::string> visible_name;
2936             Gtk::TreeModelColumn<std::string> fullpath;
2937         };
2938
2939
2940         CleanupResultsModelColumns results_columns;
2941         Glib::RefPtr<Gtk::ListStore> results_model;
2942         Gtk::TreeView results_display;
2943
2944         results_model = ListStore::create (results_columns);
2945         results_display.set_model (results_model);
2946         results_display.append_column (list_title, results_columns.visible_name);
2947
2948         results_display.set_name ("CleanupResultsList");
2949         results_display.set_headers_visible (true);
2950         results_display.set_headers_clickable (false);
2951         results_display.set_reorderable (false);
2952
2953         Gtk::ScrolledWindow list_scroller;
2954         Gtk::Label txt;
2955         Gtk::VBox dvbox;
2956         Gtk::HBox dhbox;  // the hbox for the image and text
2957         Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
2958         Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO,  Gtk::ICON_SIZE_DIALOG));
2959
2960         dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
2961
2962         const string dead_directory = _session->session_directory().dead_path().to_string();
2963
2964         /* subst:
2965            %1 - number of files removed
2966            %2 - location of "dead"
2967            %3 - size of files affected
2968            %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
2969         */
2970
2971         const char* bprefix;
2972         double space_adjusted = 0;
2973
2974         if (rep.space < 1000) {
2975                 bprefix = X_("");
2976                 space_adjusted = rep.space;
2977         } else if (rep.space < 1000000) {
2978                 bprefix = X_("kilo");
2979                 space_adjusted = truncf((float)rep.space / 1000.0);
2980         } else if (rep.space < 1000000 * 1000) {
2981                 bprefix = X_("mega");
2982                 space_adjusted = truncf((float)rep.space / (1000.0 * 1000.0));
2983         } else {
2984                 bprefix = X_("giga");
2985                 space_adjusted = truncf((float)rep.space / (1000.0 * 1000 * 1000.0));
2986         }
2987
2988         if (removed > 1) {
2989                 txt.set_text (string_compose (plural_msg, removed, dead_directory, space_adjusted, bprefix, PROGRAM_NAME));
2990         } else {
2991                 txt.set_text (string_compose (singular_msg, removed, dead_directory, space_adjusted, bprefix, PROGRAM_NAME));
2992         }
2993
2994         dhbox.pack_start (*dimage, true, false, 5);
2995         dhbox.pack_start (txt, true, false, 5);
2996
2997         for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
2998                 TreeModel::Row row = *(results_model->append());
2999                 row[results_columns.visible_name] = *i;
3000                 row[results_columns.fullpath] = *i;
3001         }
3002
3003         list_scroller.add (results_display);
3004         list_scroller.set_size_request (-1, 150);
3005         list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
3006
3007         dvbox.pack_start (dhbox, true, false, 5);
3008         dvbox.pack_start (list_scroller, true, false, 5);
3009         ddhbox.pack_start (dvbox, true, false, 5);
3010
3011         results.get_vbox()->pack_start (ddhbox, true, false, 5);
3012         results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
3013         results.set_default_response (RESPONSE_CLOSE);
3014         results.set_position (Gtk::WIN_POS_MOUSE);
3015
3016         results_display.show();
3017         list_scroller.show();
3018         txt.show();
3019         dvbox.show();
3020         dhbox.show();
3021         ddhbox.show();
3022         dimage->show();
3023
3024         //results.get_vbox()->show();
3025         results.set_resizable (false);
3026
3027         results.run ();
3028
3029 }
3030
3031 void
3032 ARDOUR_UI::cleanup ()
3033 {
3034         if (_session == 0) {
3035                 /* shouldn't happen: menu item is insensitive */
3036                 return;
3037         }
3038
3039
3040         MessageDialog checker (_("Are you sure you want to clean-up?"),
3041                                 true,
3042                                 Gtk::MESSAGE_QUESTION,
3043                                 Gtk::BUTTONS_NONE);
3044
3045         checker.set_title (_("Clean-up"));
3046
3047         checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
3048 ALL undo/redo information will be lost if you clean-up.\n\
3049 Clean-up will move all unused files to a \"dead\" location."));
3050
3051         checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3052         checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
3053         checker.set_default_response (RESPONSE_CANCEL);
3054
3055         checker.set_name (_("CleanupDialog"));
3056         checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3057         checker.set_position (Gtk::WIN_POS_MOUSE);
3058
3059         switch (checker.run()) {
3060         case RESPONSE_ACCEPT:
3061                 break;
3062         default:
3063                 return;
3064         }
3065
3066         ARDOUR::CleanupReport rep;
3067
3068         editor->prepare_for_cleanup ();
3069
3070         /* do not allow flush until a session is reloaded */
3071
3072         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3073         if (act) {
3074                 act->set_sensitive (false);
3075         }
3076
3077         if (_session->cleanup_sources (rep)) {
3078                 editor->finish_cleanup ();
3079                 return;
3080         }
3081
3082         editor->finish_cleanup ();
3083
3084         checker.hide();
3085         display_cleanup_results (rep,
3086                                  _("Cleaned Files"),
3087                                  _("\
3088 The following %1 files were not in use and \n\
3089 have been moved to:\n\n\
3090 %2\n\n\
3091 After a restart of %5,\n\n\
3092 Session -> Clean-up -> Flush Wastebasket\n\n\
3093 will release an additional\n\
3094 %3 %4bytes of disk space.\n"),
3095                                  _("\
3096 The following file was not in use and \n\
3097 has been moved to:\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
3105 }
3106
3107 void
3108 ARDOUR_UI::flush_trash ()
3109 {
3110         if (_session == 0) {
3111                 /* shouldn't happen: menu item is insensitive */
3112                 return;
3113         }
3114
3115         ARDOUR::CleanupReport rep;
3116
3117         if (_session->cleanup_trash_sources (rep)) {
3118                 return;
3119         }
3120
3121         display_cleanup_results (rep,
3122                                  _("deleted file"),
3123                                  _("The following %1 files were deleted from\n\
3124 %2,\n\
3125 releasing %3 %4bytes of disk space"),
3126                                  _("The following file was deleted from\n\
3127 %2,\n\
3128 releasing %3 %4bytes of disk space"));
3129 }
3130
3131 void
3132 ARDOUR_UI::add_route (Gtk::Window* float_window)
3133 {
3134         int count;
3135
3136         if (!_session) {
3137                 return;
3138         }
3139
3140         if (add_route_dialog == 0) {
3141                 add_route_dialog = new AddRouteDialog (_session);
3142                 add_route_dialog->set_position (WIN_POS_MOUSE);
3143                 if (float_window) {
3144                         add_route_dialog->set_transient_for (*float_window);
3145                 }
3146         }
3147
3148         if (add_route_dialog->is_visible()) {
3149                 /* we're already doing this */
3150                 return;
3151         }
3152
3153         ResponseType r = (ResponseType) add_route_dialog->run ();
3154
3155         add_route_dialog->hide();
3156
3157         switch (r) {
3158                 case RESPONSE_ACCEPT:
3159                         break;
3160                 default:
3161                         return;
3162                         break;
3163         }
3164
3165         if ((count = add_route_dialog->count()) <= 0) {
3166                 return;
3167         }
3168
3169         string template_path = add_route_dialog->track_template();
3170
3171         if (!template_path.empty()) {
3172                 _session->new_route_from_template (count, template_path);
3173                 return;
3174         }
3175
3176         uint32_t input_chan = add_route_dialog->channels ();
3177         uint32_t output_chan;
3178         string name_template = add_route_dialog->name_template ();
3179         PluginInfoPtr instrument = add_route_dialog->requested_instrument ();
3180         RouteGroup* route_group = add_route_dialog->route_group ();
3181
3182         AutoConnectOption oac = Config->get_output_auto_connect();
3183
3184         if (oac & AutoConnectMaster) {
3185                 output_chan = (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan);
3186         } else {
3187                 output_chan = input_chan;
3188         }
3189
3190         /* XXX do something with name template */
3191
3192         if (add_route_dialog->midi_tracks_wanted()) {
3193                 session_add_midi_track (route_group, count, name_template, instrument);
3194         } else if (add_route_dialog->audio_tracks_wanted()) {
3195                 session_add_audio_track (input_chan, output_chan, add_route_dialog->mode(), route_group, count, name_template);
3196         } else {
3197                 session_add_audio_bus (input_chan, output_chan, route_group, count, name_template);
3198         }
3199 }
3200
3201 XMLNode*
3202 ARDOUR_UI::mixer_settings () const
3203 {
3204         XMLNode* node = 0;
3205
3206         if (_session) {
3207                 node = _session->instant_xml(X_("Mixer"));
3208         } else {
3209                 node = Config->instant_xml(X_("Mixer"));
3210         }
3211
3212         if (!node) {
3213                 node = new XMLNode (X_("Mixer"));
3214         }
3215
3216         return node;
3217 }
3218
3219 XMLNode*
3220 ARDOUR_UI::editor_settings () const
3221 {
3222         XMLNode* node = 0;
3223
3224         if (_session) {
3225                 node = _session->instant_xml(X_("Editor"));
3226         } else {
3227                 node = Config->instant_xml(X_("Editor"));
3228         }
3229
3230         if (!node) {
3231                 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
3232                         node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
3233                 }
3234         }
3235
3236         if (!node) {
3237                 node = new XMLNode (X_("Editor"));
3238         }
3239
3240         return node;
3241 }
3242
3243 XMLNode*
3244 ARDOUR_UI::keyboard_settings () const
3245 {
3246         XMLNode* node = 0;
3247
3248         node = Config->extra_xml(X_("Keyboard"));
3249
3250         if (!node) {
3251                 node = new XMLNode (X_("Keyboard"));
3252         }
3253
3254         return node;
3255 }
3256
3257 void
3258 ARDOUR_UI::create_xrun_marker (framepos_t where)
3259 {
3260         editor->mouse_add_new_marker (where, false, true);
3261 }
3262
3263 void
3264 ARDOUR_UI::halt_on_xrun_message ()
3265 {
3266         MessageDialog msg (*editor,
3267                            _("Recording was stopped because your system could not keep up."));
3268         msg.run ();
3269 }
3270
3271 void
3272 ARDOUR_UI::xrun_handler (framepos_t where)
3273 {
3274         if (!_session) {
3275                 return;
3276         }
3277
3278         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
3279
3280         if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
3281                 create_xrun_marker(where);
3282         }
3283
3284         if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
3285                 halt_on_xrun_message ();
3286         }
3287 }
3288
3289 void
3290 ARDOUR_UI::disk_overrun_handler ()
3291 {
3292         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
3293
3294         if (!have_disk_speed_dialog_displayed) {
3295                 have_disk_speed_dialog_displayed = true;
3296                 MessageDialog* msg = new MessageDialog (*editor, string_compose (_("\
3297 The disk system on your computer\n\
3298 was not able to keep up with %1.\n\
3299 \n\
3300 Specifically, it failed to write data to disk\n\
3301 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
3302                 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3303                 msg->show ();
3304         }
3305 }
3306
3307 void
3308 ARDOUR_UI::disk_underrun_handler ()
3309 {
3310         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
3311
3312         if (!have_disk_speed_dialog_displayed) {
3313                 have_disk_speed_dialog_displayed = true;
3314                 MessageDialog* msg = new MessageDialog (
3315                         *editor, string_compose (_("The disk system on your computer\n\
3316 was not able to keep up with %1.\n\
3317 \n\
3318 Specifically, it failed to read data from disk\n\
3319 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
3320                 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3321                 msg->show ();
3322         }
3323 }
3324
3325 void
3326 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
3327 {
3328         have_disk_speed_dialog_displayed = false;
3329         delete msg;
3330 }
3331
3332 void
3333 ARDOUR_UI::session_dialog (std::string msg)
3334 {
3335         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
3336
3337         MessageDialog* d;
3338
3339         if (editor) {
3340                 d = new MessageDialog (*editor, msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3341         } else {
3342                 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3343         }
3344
3345         d->show_all ();
3346         d->run ();
3347         delete d;
3348 }
3349
3350 int
3351 ARDOUR_UI::pending_state_dialog ()
3352 {
3353         HBox* hbox = new HBox();
3354         Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3355         ArdourDialog dialog (_("Crash Recovery"), true);
3356         Label  message (_("\
3357 This session appears to have been in\n\
3358 middle of recording when ardour or\n\
3359 the computer was shutdown.\n\
3360 \n\
3361 Ardour can recover any captured audio for\n\
3362 you, or it can ignore it. Please decide\n\
3363 what you would like to do.\n"));
3364         image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3365         hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3366         hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3367         dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3368         dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
3369         dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
3370         dialog.set_default_response (RESPONSE_ACCEPT);
3371         dialog.set_position (WIN_POS_CENTER);
3372         message.show();
3373         image->show();
3374         hbox->show();
3375
3376         switch (dialog.run ()) {
3377         case RESPONSE_ACCEPT:
3378                 return 1;
3379         default:
3380                 return 0;
3381         }
3382 }
3383
3384 int
3385 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
3386 {
3387         HBox* hbox = new HBox();
3388         Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3389         ArdourDialog dialog (_("Sample Rate Mismatch"), true);
3390         Label  message (string_compose (_("\
3391 This session was created with a sample rate of %1 Hz\n\
3392 \n\
3393 The audioengine is currently running at %2 Hz\n"), desired, actual));
3394
3395         image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3396         hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3397         hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3398         dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3399         dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
3400         dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
3401         dialog.set_default_response (RESPONSE_ACCEPT);
3402         dialog.set_position (WIN_POS_CENTER);
3403         message.show();
3404         image->show();
3405         hbox->show();
3406
3407         switch (dialog.run ()) {
3408         case RESPONSE_ACCEPT:
3409                 return 0;
3410         default:
3411                 return 1;
3412         }
3413 }
3414
3415
3416 void
3417 ARDOUR_UI::disconnect_from_jack ()
3418 {
3419         if (engine) {
3420                 if( engine->disconnect_from_jack ()) {
3421                         MessageDialog msg (*editor, _("Could not disconnect from JACK"));
3422                         msg.run ();
3423                 }
3424
3425                 update_sample_rate (0);
3426         }
3427 }
3428
3429 void
3430 ARDOUR_UI::reconnect_to_jack ()
3431 {
3432         if (engine) {
3433                 if (engine->reconnect_to_jack ()) {
3434                         MessageDialog msg (*editor,  _("Could not reconnect to JACK"));
3435                         msg.run ();
3436                 }
3437
3438                 update_sample_rate (0);
3439         }
3440 }
3441
3442 void
3443 ARDOUR_UI::use_config ()
3444 {
3445         XMLNode* node = Config->extra_xml (X_("TransportControllables"));
3446         if (node) {
3447                 set_transport_controllable_state (*node);
3448         }
3449 }
3450
3451 void
3452 ARDOUR_UI::update_transport_clocks (framepos_t pos)
3453 {
3454         if (Config->get_primary_clock_delta_edit_cursor()) {
3455                 primary_clock->set (pos, false, editor->get_preferred_edit_position());
3456         } else {
3457                 primary_clock->set (pos);
3458         }
3459
3460         if (Config->get_secondary_clock_delta_edit_cursor()) {
3461                 secondary_clock->set (pos, false, editor->get_preferred_edit_position());
3462         } else {
3463                 secondary_clock->set (pos);
3464         }
3465
3466         if (big_clock_window->get()) {
3467                 big_clock->set (pos);
3468         }
3469 }
3470
3471
3472 void
3473 ARDOUR_UI::step_edit_status_change (bool yn)
3474 {
3475         // XXX should really store pre-step edit status of things
3476         // we make insensitive
3477
3478         if (yn) {
3479                 rec_button.set_active_state (Gtkmm2ext::ImplicitActive);
3480                 rec_button.set_sensitive (false);
3481         } else {
3482                 rec_button.unset_active_state ();;
3483                 rec_button.set_sensitive (true);
3484         }
3485 }
3486
3487 void
3488 ARDOUR_UI::record_state_changed ()
3489 {
3490         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
3491
3492         if (!_session || !big_clock_window->get()) {
3493                 /* why bother - the clock isn't visible */
3494                 return;
3495         }
3496
3497         if (_session->record_status () == Session::Recording && _session->have_rec_enabled_track ()) {
3498                 big_clock->set_active (true);
3499         } else {
3500                 big_clock->set_active (false);
3501         }
3502 }
3503
3504 bool
3505 ARDOUR_UI::first_idle ()
3506 {
3507         if (_session) {
3508                 _session->allow_auto_play (true);
3509         }
3510
3511         if (editor) {
3512                 editor->first_idle();
3513         }
3514
3515         Keyboard::set_can_save_keybindings (true);
3516         return false;
3517 }
3518
3519 void
3520 ARDOUR_UI::store_clock_modes ()
3521 {
3522         XMLNode* node = new XMLNode(X_("ClockModes"));
3523
3524         for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
3525                 XMLNode* child = new XMLNode (X_("Clock"));
3526                 
3527                 child->add_property (X_("name"), (*x)->name());
3528                 child->add_property (X_("mode"), enum_2_string ((*x)->mode()));
3529                 child->add_property (X_("on"), ((*x)->off() ? X_("no") : X_("yes")));
3530
3531                 node->add_child_nocopy (*child);
3532         }
3533
3534         _session->add_extra_xml (*node);
3535         _session->set_dirty ();
3536 }
3537
3538 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
3539         : Controllable (name), ui (u), type(tp)
3540 {
3541
3542 }
3543
3544 void
3545 ARDOUR_UI::TransportControllable::set_value (double val)
3546 {
3547         if (val < 0.5) {
3548                 /* do nothing: these are radio-style actions */
3549                 return;
3550         }
3551
3552         const char *action = 0;
3553
3554         switch (type) {
3555         case Roll:
3556                 action = X_("Roll");
3557                 break;
3558         case Stop:
3559                 action = X_("Stop");
3560                 break;
3561         case GotoStart:
3562                 action = X_("Goto Start");
3563                 break;
3564         case GotoEnd:
3565                 action = X_("Goto End");
3566                 break;
3567         case AutoLoop:
3568                 action = X_("Loop");
3569                 break;
3570         case PlaySelection:
3571                 action = X_("Play Selection");
3572                 break;
3573         case RecordEnable:
3574                 action = X_("Record");
3575                 break;
3576         default:
3577                 break;
3578         }
3579
3580         if (action == 0) {
3581                 return;
3582         }
3583
3584         Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
3585
3586         if (act) {
3587                 act->activate ();
3588         }
3589 }
3590
3591 double
3592 ARDOUR_UI::TransportControllable::get_value (void) const
3593 {
3594         float val = 0.0;
3595
3596         switch (type) {
3597         case Roll:
3598                 break;
3599         case Stop:
3600                 break;
3601         case GotoStart:
3602                 break;
3603         case GotoEnd:
3604                 break;
3605         case AutoLoop:
3606                 break;
3607         case PlaySelection:
3608                 break;
3609         case RecordEnable:
3610                 break;
3611         default:
3612                 break;
3613         }
3614
3615         return val;
3616 }
3617
3618 void
3619 ARDOUR_UI::setup_profile ()
3620 {
3621         if (gdk_screen_width() < 1200) {
3622                 Profile->set_small_screen ();
3623         }
3624
3625
3626         if (getenv ("ARDOUR_SAE")) {
3627                 Profile->set_sae ();
3628                 Profile->set_single_package ();
3629         }
3630 }
3631
3632 void
3633 ARDOUR_UI::toggle_translations ()
3634 {
3635         using namespace Glib;
3636
3637         RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("EnableTranslation"));
3638         if (act) {
3639                 RefPtr<ToggleAction> ract = RefPtr<ToggleAction>::cast_dynamic (act);
3640                 if (ract) {
3641
3642                         string i18n_killer = ARDOUR::translation_kill_path();
3643
3644                         bool already_enabled = !ARDOUR::translations_are_disabled ();
3645
3646                         if (ract->get_active ()) {
3647 /* we don't care about errors */
3648                                 int fd = ::open (i18n_killer.c_str(), O_RDONLY|O_CREAT, 0644);
3649                                 close (fd);
3650                         } else {
3651 /* we don't care about errors */
3652                                 unlink (i18n_killer.c_str());
3653                         }
3654
3655                         if (already_enabled != ract->get_active()) {
3656                                 MessageDialog win (already_enabled ? _("Translations disabled") : _("Translations enabled"),
3657                                                    false,
3658                                                    Gtk::MESSAGE_WARNING,
3659                                                    Gtk::BUTTONS_OK);
3660                                 win.set_secondary_text (string_compose (_("You must restart %1 for this to take effect."), PROGRAM_NAME));
3661                                 win.set_position (Gtk::WIN_POS_CENTER);
3662                                 win.present ();
3663                                 win.run ();
3664                         }
3665                 }
3666         }
3667 }
3668
3669 /** Add a window proxy to our list, so that its state will be saved.
3670  *  This call also causes the window to be created and opened if its
3671  *  state was saved as `visible'.
3672  */
3673 void
3674 ARDOUR_UI::add_window_proxy (WindowProxyBase* p)
3675 {
3676         _window_proxies.push_back (p);
3677         p->maybe_show ();
3678 }
3679
3680 /** Remove a window proxy from our list.  Must be called if a WindowProxy
3681  *  is deleted, to prevent hanging pointers.
3682  */
3683 void
3684 ARDOUR_UI::remove_window_proxy (WindowProxyBase* p)
3685 {
3686         _window_proxies.remove (p);
3687 }
3688
3689 int
3690 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
3691 {
3692         MissingFileDialog dialog (s, str, type);
3693
3694         dialog.show ();
3695         dialog.present ();
3696
3697         int result = dialog.run ();
3698         dialog.hide ();
3699
3700         switch (result) {
3701         case RESPONSE_OK:
3702                 break;
3703         default:
3704                 return 1; // quit entire session load
3705         }
3706
3707         result = dialog.get_action ();
3708
3709         return result;
3710 }
3711
3712 int
3713 ARDOUR_UI::ambiguous_file (std::string file, std::string /*path*/, std::vector<std::string> hits)
3714 {
3715         AmbiguousFileDialog dialog (file, hits);
3716
3717         dialog.show ();
3718         dialog.present ();
3719
3720         dialog.run ();
3721         return dialog.get_which ();
3722 }
3723
3724 /** Allocate our thread-local buffers */
3725 void
3726 ARDOUR_UI::get_process_buffers ()
3727 {
3728         _process_thread->get_buffers ();
3729 }
3730
3731 /** Drop our thread-local buffers */
3732 void
3733 ARDOUR_UI::drop_process_buffers ()
3734 {
3735         _process_thread->drop_buffers ();
3736 }
3737
3738 void
3739 ARDOUR_UI::feedback_detected ()
3740 {
3741         _feedback_exists = true;
3742 }
3743
3744 void
3745 ARDOUR_UI::successful_graph_sort ()
3746 {
3747         _feedback_exists = false;
3748 }
3749
3750 void
3751 ARDOUR_UI::midi_panic ()
3752 {
3753         if (_session) {
3754                 _session->midi_panic();
3755         }
3756 }