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