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