a5dafd6757a5e9cb3dba9ab5ce15bac02992386f
[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%T", &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                 }
2158
2159                 vector<sys::path> p;
2160                 get_state_files_in_directory (_session->session_directory().root_path(), p);
2161                 vector<string> n = get_file_names_no_extension (p);
2162                 if (find (n.begin(), n.end(), snapname) != n.end()) {
2163
2164                         ArdourDialog confirm (_("Confirm Snapshot Overwrite"), true);
2165                         Label m (_("A snapshot already exists with that name.  Do you want to overwrite it?"));
2166                         confirm.get_vbox()->pack_start (m, true, true);
2167                         confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2168                         confirm.add_button (_("Overwrite"), Gtk::RESPONSE_ACCEPT);
2169                         confirm.show_all ();
2170                         switch (confirm.run()) {
2171                         case RESPONSE_CANCEL:
2172                                 do_save = false;
2173                         }
2174                 }
2175
2176                 if (do_save) {
2177                         save_state (snapname, switch_to_it);
2178                 }
2179                 break;
2180         }
2181
2182         default:
2183                 break;
2184         }
2185 }
2186
2187 /** Ask the user for the name of a new shapshot and then take it.
2188  */
2189
2190 void
2191 ARDOUR_UI::rename_session ()
2192 {
2193         if (!_session) {
2194                 return;
2195         }
2196
2197         ArdourPrompter prompter (true);
2198         string name;
2199
2200         prompter.set_name ("Prompter");
2201         prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2202         prompter.set_title (_("Rename Session"));
2203         prompter.set_prompt (_("New session name"));
2204
2205   again:
2206         switch (prompter.run()) {
2207         case RESPONSE_ACCEPT:
2208         {
2209                 prompter.get_result (name);
2210
2211                 bool do_rename = (name.length() != 0);
2212
2213                 if (do_rename) {
2214                         if (name.find ('/') != string::npos) {
2215                                 MessageDialog msg (_("To ensure compatibility with various systems\n"
2216                                                      "session names may not contain a '/' character"));
2217                                 msg.run ();
2218                                 goto again;
2219                         }
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
2227                         switch (_session->rename (name)) {
2228                         case -1: {
2229                                 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
2230                                 msg.set_position (WIN_POS_MOUSE);
2231                                 msg.run ();
2232                                 goto again;
2233                                 break;
2234                         }
2235                         case 0:
2236                                 break;
2237                         default: {
2238                                 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
2239                                 msg.set_position (WIN_POS_MOUSE);
2240                                 msg.run ();
2241                                 break;
2242                         }
2243                         }
2244                 }
2245                 
2246                 break;
2247         }
2248
2249         default:
2250                 break;
2251         }
2252 }
2253
2254 void
2255 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2256 {
2257         XMLNode* node = new XMLNode (X_("UI"));
2258
2259         for (list<WindowProxyBase*>::iterator i = _window_proxies.begin(); i != _window_proxies.end(); ++i) {
2260                 if (!(*i)->rc_configured()) {
2261                         node->add_child_nocopy (*((*i)->get_state ()));
2262                 }
2263         }
2264
2265         node->add_child_nocopy (gui_object_state->get_state());
2266
2267         _session->add_extra_xml (*node);
2268
2269         save_state_canfail (name, switch_to_it);
2270 }
2271
2272 int
2273 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2274 {
2275         if (_session) {
2276                 int ret;
2277
2278                 if (name.length() == 0) {
2279                         name = _session->snap_name();
2280                 }
2281
2282                 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2283                         return ret;
2284                 }
2285         }
2286
2287         save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2288         return 0;
2289 }
2290
2291 void
2292 ARDOUR_UI::primary_clock_value_changed ()
2293 {
2294         if (_session) {
2295                 _session->request_locate (primary_clock->current_time ());
2296         }
2297 }
2298
2299 void
2300 ARDOUR_UI::big_clock_value_changed ()
2301 {
2302         if (_session) {
2303                 _session->request_locate (big_clock->current_time ());
2304         }
2305 }
2306
2307 void
2308 ARDOUR_UI::secondary_clock_value_changed ()
2309 {
2310         if (_session) {
2311                 _session->request_locate (secondary_clock->current_time ());
2312         }
2313 }
2314
2315 void
2316 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2317 {
2318         if (_session == 0) {
2319                 return;
2320         }
2321
2322         if (_session->step_editing()) {
2323                 return;
2324         }
2325
2326         Session::RecordState const r = _session->record_status ();
2327         bool const h = _session->have_rec_enabled_track ();
2328
2329         if (r == Session::Enabled || (r == Session::Recording && !h)) {
2330                 if (onoff) {
2331                         rec_button.set_visual_state (2);
2332                 } else {
2333                         rec_button.set_visual_state (0);
2334                 }
2335         } else if (r == Session::Recording && h) {
2336                 rec_button.set_visual_state (1);
2337         } else {
2338                 rec_button.set_visual_state (0);
2339         }
2340 }
2341
2342 void
2343 ARDOUR_UI::save_template ()
2344 {
2345         ArdourPrompter prompter (true);
2346         string name;
2347
2348         if (!check_audioengine()) {
2349                 return;
2350         }
2351
2352         prompter.set_name (X_("Prompter"));
2353         prompter.set_title (_("Save Template"));
2354         prompter.set_prompt (_("Name for template:"));
2355         prompter.set_initial_text(_session->name() + _("-template"));
2356         prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2357
2358         switch (prompter.run()) {
2359         case RESPONSE_ACCEPT:
2360                 prompter.get_result (name);
2361
2362                 if (name.length()) {
2363                         _session->save_template (name);
2364                 }
2365                 break;
2366
2367         default:
2368                 break;
2369         }
2370 }
2371
2372 void
2373 ARDOUR_UI::edit_metadata ()
2374 {
2375         SessionMetadataEditor dialog;
2376         dialog.set_session (_session);
2377         editor->ensure_float (dialog);
2378         dialog.run ();
2379 }
2380
2381 void
2382 ARDOUR_UI::import_metadata ()
2383 {
2384         SessionMetadataImporter dialog;
2385         dialog.set_session (_session);
2386         editor->ensure_float (dialog);
2387         dialog.run ();
2388 }
2389
2390 bool
2391 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
2392 {
2393         std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2394
2395         MessageDialog msg (str,
2396                            false,
2397                            Gtk::MESSAGE_WARNING,
2398                            Gtk::BUTTONS_YES_NO,
2399                            true);
2400
2401
2402         msg.set_name (X_("OpenExistingDialog"));
2403         msg.set_title (_("Open Existing Session"));
2404         msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
2405         msg.set_position (Gtk::WIN_POS_MOUSE);
2406         pop_back_splash ();
2407
2408         switch (msg.run()) {
2409         case RESPONSE_YES:
2410                 return true;
2411                 break;
2412         }
2413         return false;
2414 }
2415
2416 int
2417 ARDOUR_UI::build_session_from_nsd (const std::string& session_path, const std::string& session_name)
2418 {
2419         BusProfile bus_profile;
2420
2421         if (Profile->get_sae()) {
2422
2423                 bus_profile.master_out_channels = 2;
2424                 bus_profile.input_ac = AutoConnectPhysical;
2425                 bus_profile.output_ac = AutoConnectMaster;
2426                 bus_profile.requested_physical_in = 0; // use all available
2427                 bus_profile.requested_physical_out = 0; // use all available
2428
2429         } else {
2430
2431                 /* get settings from advanced section of NSD */
2432
2433                 if (_startup->create_master_bus()) {
2434                         bus_profile.master_out_channels = (uint32_t) _startup->master_channel_count();
2435                 } else {
2436                         bus_profile.master_out_channels = 0;
2437                 }
2438
2439                 if (_startup->connect_inputs()) {
2440                         bus_profile.input_ac = AutoConnectPhysical;
2441                 } else {
2442                         bus_profile.input_ac = AutoConnectOption (0);
2443                 }
2444
2445                 /// @todo some minor tweaks.
2446
2447                 bus_profile.output_ac = AutoConnectOption (0);
2448
2449                 if (_startup->connect_outputs ()) {
2450                         if (_startup->connect_outs_to_master()) {
2451                                 bus_profile.output_ac = AutoConnectMaster;
2452                         } else if (_startup->connect_outs_to_physical()) {
2453                                 bus_profile.output_ac = AutoConnectPhysical;
2454                         }
2455                 }
2456
2457                 bus_profile.requested_physical_in = (uint32_t) _startup->input_limit_count();
2458                 bus_profile.requested_physical_out = (uint32_t) _startup->output_limit_count();
2459         }
2460
2461         if (build_session (session_path, session_name, bus_profile)) {
2462                 return -1;
2463         }
2464
2465         return 0;
2466 }
2467
2468 void
2469 ARDOUR_UI::idle_load (const std::string& path)
2470 {
2471         if (_session) {
2472                 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2473                         /* /path/to/foo => /path/to/foo, foo */
2474                         load_session (path, basename_nosuffix (path));
2475                 } else {
2476                         /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2477                         load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2478                 }
2479         } else {
2480
2481                 ARDOUR_COMMAND_LINE::session_name = path;
2482
2483                 /*
2484                  * new_session_dialog doens't exist in A3
2485                  * Try to remove all references to it to
2486                  * see if it will compile.  NOTE: this will
2487                  * likely cause a runtime issue is my somewhat
2488                  * uneducated guess.
2489                  */
2490
2491                 //if (new_session_dialog) {
2492
2493
2494                         /* make it break out of Dialog::run() and
2495                            start again.
2496                          */
2497
2498                         //new_session_dialog->response (1);
2499                 //}
2500         }
2501 }
2502
2503 void
2504 ARDOUR_UI::end_loading_messages ()
2505 {
2506         // hide_splash ();
2507 }
2508
2509 void
2510 ARDOUR_UI::loading_message (const std::string& /*msg*/)
2511 {
2512         // show_splash ();
2513         // splash->message (msg);
2514         flush_pending ();
2515 }
2516
2517 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
2518 int
2519 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
2520 {
2521         string session_name;
2522         string session_path;
2523         string template_name;
2524         int ret = -1;
2525         bool likely_new = false;
2526
2527         if (!load_template.empty()) {
2528                 should_be_new = true;
2529                 template_name = load_template;
2530         }
2531
2532         while (ret != 0) {
2533
2534                 if (!should_be_new && !ARDOUR_COMMAND_LINE::session_name.empty()) {
2535
2536                         /* if they named a specific statefile, use it, otherwise they are
2537                            just giving a session folder, and we want to use it as is
2538                            to find the session.
2539                         */
2540
2541                         string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
2542
2543                         if (suffix != string::npos) {
2544                                 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
2545                                 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
2546                                 session_name = Glib::path_get_basename (session_name);
2547                         } else {
2548                                 session_path = ARDOUR_COMMAND_LINE::session_name;
2549                                 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
2550                         }
2551
2552                 } else {
2553
2554                         bool const apply = run_startup (should_be_new, load_template);
2555
2556                         if (!apply) {
2557                                 if (quit_on_cancel) {
2558                                         exit (1);
2559                                 } else {
2560                                         return ret;
2561                                 }
2562                         }
2563
2564                         /* if we run the startup dialog again, offer more than just "new session" */
2565
2566                         should_be_new = false;
2567
2568                         session_name = _startup->session_name (likely_new);
2569
2570                         string::size_type suffix = session_name.find (statefile_suffix);
2571
2572                         if (suffix != string::npos) {
2573                                 session_name = session_name.substr (0, suffix);
2574                         }
2575
2576                         /* this shouldn't happen, but we catch it just in case it does */
2577
2578                         if (session_name.empty()) {
2579                                 continue;
2580                         }
2581
2582                         if (_startup->use_session_template()) {
2583                                 template_name = _startup->session_template_name();
2584                                 _session_is_new = true;
2585                         }
2586
2587                         if (session_name[0] == G_DIR_SEPARATOR ||
2588                             (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
2589                             (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)) {
2590
2591                                 /* absolute path or cwd-relative path specified for session name: infer session folder
2592                                    from what was given.
2593                                 */
2594
2595                                 session_path = Glib::path_get_dirname (session_name);
2596                                 session_name = Glib::path_get_basename (session_name);
2597
2598                         } else {
2599
2600                                 session_path = _startup->session_folder();
2601
2602                                 if (session_name.find ('/') != string::npos) {
2603                                         MessageDialog msg (*_startup,
2604                                                            _("To ensure compatibility with various systems\n"
2605                                                              "session names may not contain a '/' character"));
2606                                         msg.run ();
2607                                         ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2608                                         continue;
2609                                 }
2610
2611                                 if (session_name.find ('\\') != string::npos) {
2612                                         MessageDialog msg (*_startup,
2613                                                            _("To ensure compatibility with various systems\n"
2614                                                              "session names may not contain a '\\' character"));
2615                                         msg.run ();
2616                                         ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2617                                         continue;
2618                                 }
2619                         }
2620                 }
2621
2622                 if (create_engine ()) {
2623                         break;
2624                 }
2625
2626                 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
2627
2628                         if (likely_new) {
2629
2630                                 std::string existing = Glib::build_filename (session_path, session_name);
2631
2632                                 if (!ask_about_loading_existing_session (existing)) {
2633                                         ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2634                                         continue;
2635                                 }
2636                         }
2637
2638                         _session_is_new = false;
2639
2640                 } else {
2641
2642                         if (!likely_new) {
2643                                 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
2644                                 msg.run ();
2645                                 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2646                                 continue;
2647                         }
2648
2649                         if (session_name.find ('/') != std::string::npos) {
2650                                 MessageDialog msg (*_startup,
2651                                                    _("To ensure compatibility with various systems\n"
2652                                                      "session names may not contain a '/' character"));
2653                                 msg.run ();
2654                                 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2655                                 continue;
2656                         }
2657
2658                         if (session_name.find ('\\') != std::string::npos) {
2659                                 MessageDialog msg (*_startup,
2660                                                    _("To ensure compatibility with various systems\n"
2661                                                      "session names may not contain a '\\' character"));
2662                                 msg.run ();
2663                                 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2664                                 continue;
2665                         }
2666
2667                         _session_is_new = true;
2668                 }
2669
2670                 if (likely_new && template_name.empty()) {
2671
2672                         ret = build_session_from_nsd (session_path, session_name);
2673
2674                 } else {
2675
2676                         ret = load_session (session_path, session_name, template_name);
2677
2678                         if (ret == -2) {
2679                                 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
2680                                 exit (1);
2681                         }
2682
2683                         if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
2684                                 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
2685                                 exit (1);
2686                         }
2687                 }
2688         }
2689
2690         return ret;
2691 }
2692
2693 void
2694 ARDOUR_UI::close_session()
2695 {
2696         if (!check_audioengine()) {
2697                 return;
2698         }
2699
2700         if (unload_session (true)) {
2701                 return;
2702         }
2703
2704         ARDOUR_COMMAND_LINE::session_name = "";
2705
2706         if (get_session_parameters (true, false)) {
2707                 exit (1);
2708         }
2709
2710         goto_editor_window ();
2711 }
2712
2713 /** @param snap_name Snapshot name (without .ardour suffix).
2714  *  @return -2 if the load failed because we are not connected to the AudioEngine.
2715  */
2716 int
2717 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
2718 {
2719         Session *new_session;
2720         int unload_status;
2721         int retval = -1;
2722
2723         session_loaded = false;
2724
2725         if (!check_audioengine()) {
2726                 return -2;
2727         }
2728
2729         unload_status = unload_session ();
2730
2731         if (unload_status < 0) {
2732                 goto out;
2733         } else if (unload_status > 0) {
2734                 retval = 0;
2735                 goto out;
2736         }
2737
2738         loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
2739
2740         try {
2741                 new_session = new Session (*engine, path, snap_name, 0, mix_template);
2742         }
2743
2744         /* this one is special */
2745
2746         catch (AudioEngine::PortRegistrationFailure& err) {
2747
2748                 MessageDialog msg (err.what(),
2749                                    true,
2750                                    Gtk::MESSAGE_INFO,
2751                                    Gtk::BUTTONS_CLOSE);
2752
2753                 msg.set_title (_("Port Registration Error"));
2754                 msg.set_secondary_text (_("Click the Close button to try again."));
2755                 msg.set_position (Gtk::WIN_POS_CENTER);
2756                 pop_back_splash ();
2757                 msg.present ();
2758
2759                 int response = msg.run ();
2760
2761                 msg.hide ();
2762
2763                 switch (response) {
2764                 case RESPONSE_CANCEL:
2765                         exit (1);
2766                 default:
2767                         break;
2768                 }
2769                 goto out;
2770         }
2771
2772         catch (...) {
2773
2774                 MessageDialog msg (string_compose(
2775                                            _("Session \"%1 (snapshot %2)\" did not load successfully"),
2776                                            path, snap_name),
2777                                    true,
2778                                    Gtk::MESSAGE_INFO,
2779                                    BUTTONS_OK);
2780
2781                 msg.set_title (_("Loading Error"));
2782                 msg.set_secondary_text (_("Click the Refresh button to try again."));
2783                 msg.add_button (Stock::REFRESH, 1);
2784                 msg.set_position (Gtk::WIN_POS_CENTER);
2785                 pop_back_splash ();
2786                 msg.present ();
2787
2788                 int response = msg.run ();
2789
2790                 switch (response) {
2791                 case 1:
2792                         break;
2793                 default:
2794                         exit (1);
2795                 }
2796
2797                 msg.hide ();
2798
2799                 goto out;
2800         }
2801
2802         {
2803                 list<string> const u = new_session->unknown_processors ();
2804                 if (!u.empty()) {
2805                         MissingPluginDialog d (_session, u);
2806                         d.run ();
2807                 }
2808         }
2809
2810         /* Now the session been created, add the transport controls */
2811         new_session->add_controllable(roll_controllable);
2812         new_session->add_controllable(stop_controllable);
2813         new_session->add_controllable(goto_start_controllable);
2814         new_session->add_controllable(goto_end_controllable);
2815         new_session->add_controllable(auto_loop_controllable);
2816         new_session->add_controllable(play_selection_controllable);
2817         new_session->add_controllable(rec_controllable);
2818
2819         set_session (new_session);
2820
2821         session_loaded = true;
2822
2823         goto_editor_window ();
2824
2825         if (_session) {
2826                 _session->set_clean ();
2827         }
2828
2829         flush_pending ();
2830         retval = 0;
2831
2832   out:
2833         return retval;
2834 }
2835
2836 int
2837 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
2838 {
2839         Session *new_session;
2840         int x;
2841
2842         if (!check_audioengine()) {
2843                 return -1;
2844         }
2845
2846         session_loaded = false;
2847
2848         x = unload_session ();
2849
2850         if (x < 0) {
2851                 return -1;
2852         } else if (x > 0) {
2853                 return 0;
2854         }
2855
2856         _session_is_new = true;
2857
2858         try {
2859                 new_session = new Session (*engine, path, snap_name, &bus_profile);
2860         }
2861
2862         catch (...) {
2863
2864                 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
2865                 pop_back_splash ();
2866                 msg.run ();
2867                 return -1;
2868         }
2869
2870         /* Give the new session the default GUI state, if such things exist */
2871
2872         XMLNode* n;
2873         n = Config->instant_xml (X_("Editor"));
2874         if (n) {
2875                 new_session->add_instant_xml (*n, false);
2876         }
2877         n = Config->instant_xml (X_("Mixer"));
2878         if (n) {
2879                 new_session->add_instant_xml (*n, false);
2880         }
2881
2882         /* Put the playhead at 0 and scroll fully left */
2883         n = new_session->instant_xml (X_("Editor"));
2884         if (n) {
2885                 n->add_property (X_("playhead"), X_("0"));
2886                 n->add_property (X_("left-frame"), X_("0"));
2887         }
2888
2889         set_session (new_session);
2890
2891         session_loaded = true;
2892
2893         new_session->save_state(new_session->name());
2894
2895         return 0;
2896 }
2897
2898 void
2899 ARDOUR_UI::launch_chat ()
2900 {
2901 #ifdef __APPLE__
2902         open_uri("http://webchat.freenode.net/?channels=ardour-osx");
2903 #else
2904         open_uri("http://webchat.freenode.net/?channels=ardour");
2905 #endif
2906 }
2907
2908 void
2909 ARDOUR_UI::show_about ()
2910 {
2911         if (about == 0) {
2912                 about = new About;
2913                 about->signal_response().connect(sigc::mem_fun (*this, &ARDOUR_UI::about_signal_response) );
2914         }
2915
2916         about->set_transient_for(*editor);
2917         about->show_all ();
2918 }
2919
2920 void
2921 ARDOUR_UI::launch_manual ()
2922 {
2923         PBD::open_uri("http://ardour.org/flossmanual");
2924 }
2925
2926 void
2927 ARDOUR_UI::launch_reference ()
2928 {
2929         PBD::open_uri("http://ardour.org/refmanual");
2930 }
2931
2932 void
2933 ARDOUR_UI::hide_about ()
2934 {
2935         if (about) {
2936                 about->get_window()->set_cursor ();
2937                 about->hide ();
2938         }
2939 }
2940
2941 void
2942 ARDOUR_UI::about_signal_response (int /*response*/)
2943 {
2944         hide_about();
2945 }
2946
2947 void
2948 ARDOUR_UI::show_splash ()
2949 {
2950         if (splash == 0) {
2951                 try {
2952                         splash = new Splash;
2953                 } catch (...) {
2954                         return;
2955                 }
2956         }
2957
2958         splash->show ();
2959         splash->present ();
2960         splash->queue_draw ();
2961         splash->get_window()->process_updates (true);
2962         flush_pending ();
2963 }
2964
2965 void
2966 ARDOUR_UI::hide_splash ()
2967 {
2968         if (splash) {
2969                 splash->hide();
2970         }
2971 }
2972
2973 void
2974 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title,
2975                                     const string& plural_msg, const string& singular_msg)
2976 {
2977         size_t removed;
2978
2979         removed = rep.paths.size();
2980
2981         if (removed == 0) {
2982                 MessageDialog msgd (*editor,
2983                                     _("No files were ready for clean-up"),
2984                                     true,
2985                                     Gtk::MESSAGE_INFO,
2986                                     (Gtk::ButtonsType)(Gtk::BUTTONS_OK)  );
2987                 msgd.set_title (_("Clean-up"));
2988                 msgd.set_secondary_text (_("If this seems suprising, \n\
2989 check for any existing snapshots.\n\
2990 These may still include regions that\n\
2991 require some unused files to continue to exist."));
2992
2993                 msgd.run ();
2994                 return;
2995         }
2996
2997         ArdourDialog results (_("Clean-up"), true, false);
2998
2999         struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
3000             CleanupResultsModelColumns() {
3001                     add (visible_name);
3002                     add (fullpath);
3003             }
3004             Gtk::TreeModelColumn<std::string> visible_name;
3005             Gtk::TreeModelColumn<std::string> fullpath;
3006         };
3007
3008
3009         CleanupResultsModelColumns results_columns;
3010         Glib::RefPtr<Gtk::ListStore> results_model;
3011         Gtk::TreeView results_display;
3012
3013         results_model = ListStore::create (results_columns);
3014         results_display.set_model (results_model);
3015         results_display.append_column (list_title, results_columns.visible_name);
3016
3017         results_display.set_name ("CleanupResultsList");
3018         results_display.set_headers_visible (true);
3019         results_display.set_headers_clickable (false);
3020         results_display.set_reorderable (false);
3021
3022         Gtk::ScrolledWindow list_scroller;
3023         Gtk::Label txt;
3024         Gtk::VBox dvbox;
3025         Gtk::HBox dhbox;  // the hbox for the image and text
3026         Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
3027         Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO,  Gtk::ICON_SIZE_DIALOG));
3028
3029         dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
3030
3031         const string dead_directory = _session->session_directory().dead_path().to_string();
3032
3033         /* subst:
3034            %1 - number of files removed
3035            %2 - location of "dead"
3036            %3 - size of files affected
3037            %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
3038         */
3039
3040         const char* bprefix;
3041         double space_adjusted = 0;
3042
3043         if (rep.space < 1000) {
3044                 bprefix = X_("");
3045                 space_adjusted = rep.space;
3046         } else if (rep.space < 1000000) {
3047                 bprefix = X_("kilo");
3048                 space_adjusted = truncf((float)rep.space / 1000.0);
3049         } else if (rep.space < 1000000 * 1000) {
3050                 bprefix = X_("mega");
3051                 space_adjusted = truncf((float)rep.space / (1000.0 * 1000.0));
3052         } else {
3053                 bprefix = X_("giga");
3054                 space_adjusted = truncf((float)rep.space / (1000.0 * 1000 * 1000.0));
3055         }
3056
3057         if (removed > 1) {
3058                 txt.set_text (string_compose (plural_msg, removed, dead_directory, space_adjusted, bprefix));
3059         } else {
3060                 txt.set_text (string_compose (singular_msg, removed, dead_directory, space_adjusted, bprefix));
3061         }
3062
3063         dhbox.pack_start (*dimage, true, false, 5);
3064         dhbox.pack_start (txt, true, false, 5);
3065
3066         for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
3067                 TreeModel::Row row = *(results_model->append());
3068                 row[results_columns.visible_name] = *i;
3069                 row[results_columns.fullpath] = *i;
3070         }
3071
3072         list_scroller.add (results_display);
3073         list_scroller.set_size_request (-1, 150);
3074         list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
3075
3076         dvbox.pack_start (dhbox, true, false, 5);
3077         dvbox.pack_start (list_scroller, true, false, 5);
3078         ddhbox.pack_start (dvbox, true, false, 5);
3079
3080         results.get_vbox()->pack_start (ddhbox, true, false, 5);
3081         results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
3082         results.set_default_response (RESPONSE_CLOSE);
3083         results.set_position (Gtk::WIN_POS_MOUSE);
3084
3085         results_display.show();
3086         list_scroller.show();
3087         txt.show();
3088         dvbox.show();
3089         dhbox.show();
3090         ddhbox.show();
3091         dimage->show();
3092
3093         //results.get_vbox()->show();
3094         results.set_resizable (false);
3095
3096         results.run ();
3097
3098 }
3099
3100 void
3101 ARDOUR_UI::cleanup ()
3102 {
3103         if (_session == 0) {
3104                 /* shouldn't happen: menu item is insensitive */
3105                 return;
3106         }
3107
3108
3109         MessageDialog checker (_("Are you sure you want to clean-up?"),
3110                                 true,
3111                                 Gtk::MESSAGE_QUESTION,
3112                                 (Gtk::ButtonsType)(Gtk::BUTTONS_NONE));
3113
3114         checker.set_title (_("Clean-up"));
3115
3116         checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
3117 ALL undo/redo information will be lost if you clean-up.\n\
3118 Clean-up will move all unused files to a \"dead\" location."));
3119
3120         checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3121         checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
3122         checker.set_default_response (RESPONSE_CANCEL);
3123
3124         checker.set_name (_("CleanupDialog"));
3125         checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3126         checker.set_position (Gtk::WIN_POS_MOUSE);
3127
3128         switch (checker.run()) {
3129         case RESPONSE_ACCEPT:
3130                 break;
3131         default:
3132                 return;
3133         }
3134
3135         ARDOUR::CleanupReport rep;
3136
3137         editor->prepare_for_cleanup ();
3138
3139         /* do not allow flush until a session is reloaded */
3140
3141         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3142         if (act) {
3143                 act->set_sensitive (false);
3144         }
3145
3146         if (_session->cleanup_sources (rep)) {
3147                 editor->finish_cleanup ();
3148                 return;
3149         }
3150
3151         editor->finish_cleanup ();
3152
3153         checker.hide();
3154         display_cleanup_results (rep,
3155                                  _("Cleaned Files"),
3156                                  _("\
3157 The following %1 files were not in use and \n\
3158 have been moved to:\n\n\
3159 %2\n\n\
3160 After a restart of Ardour,\n\n\
3161 Session -> Clean-up -> Flush Wastebasket\n\n\
3162 will release an additional\n\
3163 %3 %4bytes of disk space.\n"),
3164                                  _("\
3165 The following file was not in use and \n\
3166 has been moved to:\n                            \
3167 %2\n\n\
3168 After a restart of Ardour,\n\n\
3169 Session -> Clean-up -> Flush Wastebasket\n\n\
3170 will release an additional\n\
3171 %3 %4bytes of disk space.\n"
3172                                          ));
3173
3174 }
3175
3176 void
3177 ARDOUR_UI::flush_trash ()
3178 {
3179         if (_session == 0) {
3180                 /* shouldn't happen: menu item is insensitive */
3181                 return;
3182         }
3183
3184         ARDOUR::CleanupReport rep;
3185
3186         if (_session->cleanup_trash_sources (rep)) {
3187                 return;
3188         }
3189
3190         display_cleanup_results (rep,
3191                                  _("deleted file"),
3192                                  _("The following %1 files were deleted from\n\
3193 %2,\n\
3194 releasing %3 %4bytes of disk space"),
3195                                  _("The following file was deleted from\n\
3196 %2,\n\
3197 releasing %3 %4bytes of disk space"));
3198 }
3199
3200 void
3201 ARDOUR_UI::add_route (Gtk::Window* float_window)
3202 {
3203         int count;
3204
3205         if (!_session) {
3206                 return;
3207         }
3208
3209         if (add_route_dialog == 0) {
3210                 add_route_dialog = new AddRouteDialog (_session);
3211                 if (float_window) {
3212                         add_route_dialog->set_transient_for (*float_window);
3213                 }
3214         }
3215
3216         if (add_route_dialog->is_visible()) {
3217                 /* we're already doing this */
3218                 return;
3219         }
3220
3221         ResponseType r = (ResponseType) add_route_dialog->run ();
3222
3223         add_route_dialog->hide();
3224
3225         switch (r) {
3226                 case RESPONSE_ACCEPT:
3227                         break;
3228                 default:
3229                         return;
3230                         break;
3231         }
3232
3233         if ((count = add_route_dialog->count()) <= 0) {
3234                 return;
3235         }
3236
3237         string template_path = add_route_dialog->track_template();
3238
3239         if (!template_path.empty()) {
3240                 _session->new_route_from_template (count, template_path);
3241                 return;
3242         }
3243
3244         uint32_t input_chan = add_route_dialog->channels ();
3245         uint32_t output_chan;
3246         string name_template = add_route_dialog->name_template ();
3247         bool track = add_route_dialog->track ();
3248         RouteGroup* route_group = add_route_dialog->route_group ();
3249
3250         AutoConnectOption oac = Config->get_output_auto_connect();
3251
3252         if (oac & AutoConnectMaster) {
3253                 output_chan = (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan);
3254         } else {
3255                 output_chan = input_chan;
3256         }
3257
3258         /* XXX do something with name template */
3259
3260         if (add_route_dialog->type() == ARDOUR::DataType::MIDI) {
3261                 if (track) {
3262                         session_add_midi_track (route_group, count, name_template);
3263                 } else  {
3264                         MessageDialog msg (*editor,
3265                                         _("Sorry, MIDI Busses are not supported at this time."));
3266                         msg.run ();
3267                         //session_add_midi_bus();
3268                 }
3269         } else {
3270                 if (track) {
3271                         session_add_audio_track (input_chan, output_chan, add_route_dialog->mode(), route_group, count, name_template);
3272                 } else {
3273                         session_add_audio_bus (input_chan, output_chan, route_group, count, name_template);
3274                 }
3275         }
3276 }
3277
3278 XMLNode*
3279 ARDOUR_UI::mixer_settings () const
3280 {
3281         XMLNode* node = 0;
3282
3283         if (_session) {
3284                 node = _session->instant_xml(X_("Mixer"));
3285         } else {
3286                 node = Config->instant_xml(X_("Mixer"));
3287         }
3288
3289         if (!node) {
3290                 node = new XMLNode (X_("Mixer"));
3291         }
3292
3293         return node;
3294 }
3295
3296 XMLNode*
3297 ARDOUR_UI::editor_settings () const
3298 {
3299         XMLNode* node = 0;
3300
3301         if (_session) {
3302                 node = _session->instant_xml(X_("Editor"));
3303         } else {
3304                 node = Config->instant_xml(X_("Editor"));
3305         }
3306
3307         if (!node) {
3308                 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
3309                         node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
3310                 }
3311         }
3312
3313         if (!node) {
3314                 node = new XMLNode (X_("Editor"));
3315         }
3316
3317         return node;
3318 }
3319
3320 XMLNode*
3321 ARDOUR_UI::keyboard_settings () const
3322 {
3323         XMLNode* node = 0;
3324
3325         node = Config->extra_xml(X_("Keyboard"));
3326
3327         if (!node) {
3328                 node = new XMLNode (X_("Keyboard"));
3329         }
3330
3331         return node;
3332 }
3333
3334 void
3335 ARDOUR_UI::create_xrun_marker (framepos_t where)
3336 {
3337         editor->mouse_add_new_marker (where, false, true);
3338 }
3339
3340 void
3341 ARDOUR_UI::halt_on_xrun_message ()
3342 {
3343         MessageDialog msg (*editor,
3344                            _("Recording was stopped because your system could not keep up."));
3345         msg.run ();
3346 }
3347
3348 void
3349 ARDOUR_UI::xrun_handler (framepos_t where)
3350 {
3351         if (!_session) {
3352                 return;
3353         }
3354
3355         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
3356
3357         if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
3358                 create_xrun_marker(where);
3359         }
3360
3361         if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
3362                 halt_on_xrun_message ();
3363         }
3364 }
3365
3366 void
3367 ARDOUR_UI::disk_overrun_handler ()
3368 {
3369         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
3370
3371         if (!have_disk_speed_dialog_displayed) {
3372                 have_disk_speed_dialog_displayed = true;
3373                 MessageDialog* msg = new MessageDialog (*editor, string_compose (_("\
3374 The disk system on your computer\n\
3375 was not able to keep up with %1.\n\
3376 \n\
3377 Specifically, it failed to write data to disk\n\
3378 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
3379                 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3380                 msg->show ();
3381         }
3382 }
3383
3384 void
3385 ARDOUR_UI::disk_underrun_handler ()
3386 {
3387         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
3388
3389         if (!have_disk_speed_dialog_displayed) {
3390                 have_disk_speed_dialog_displayed = true;
3391                 MessageDialog* msg = new MessageDialog (
3392                         *editor, string_compose (_("The disk system on your computer\n\
3393 was not able to keep up with %1.\n\
3394 \n\
3395 Specifically, it failed to read data from disk\n\
3396 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
3397                 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3398                 msg->show ();
3399         }
3400 }
3401
3402 void
3403 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
3404 {
3405         have_disk_speed_dialog_displayed = false;
3406         delete msg;
3407 }
3408
3409 void
3410 ARDOUR_UI::session_dialog (std::string msg)
3411 {
3412         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
3413
3414         MessageDialog* d;
3415
3416         if (editor) {
3417                 d = new MessageDialog (*editor, msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3418         } else {
3419                 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3420         }
3421
3422         d->show_all ();
3423         d->run ();
3424         delete d;
3425 }
3426
3427 int
3428 ARDOUR_UI::pending_state_dialog ()
3429 {
3430         HBox* hbox = new HBox();
3431         Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3432         ArdourDialog dialog (_("Crash Recovery"), true);
3433         Label  message (_("\
3434 This session appears to have been in\n\
3435 middle of recording when ardour or\n\
3436 the computer was shutdown.\n\
3437 \n\
3438 Ardour can recover any captured audio for\n\
3439 you, or it can ignore it. Please decide\n\
3440 what you would like to do.\n"));
3441         image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3442         hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3443         hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3444         dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3445         dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
3446         dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
3447         dialog.set_default_response (RESPONSE_ACCEPT);
3448         dialog.set_position (WIN_POS_CENTER);
3449         message.show();
3450         image->show();
3451         hbox->show();
3452
3453         switch (dialog.run ()) {
3454         case RESPONSE_ACCEPT:
3455                 return 1;
3456         default:
3457                 return 0;
3458         }
3459 }
3460
3461 int
3462 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
3463 {
3464         HBox* hbox = new HBox();
3465         Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3466         ArdourDialog dialog (_("Sample Rate Mismatch"), true);
3467         Label  message (string_compose (_("\
3468 This session was created with a sample rate of %1 Hz\n\
3469 \n\
3470 The audioengine is currently running at %2 Hz\n"), desired, actual));
3471
3472         image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3473         hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3474         hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3475         dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3476         dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
3477         dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
3478         dialog.set_default_response (RESPONSE_ACCEPT);
3479         dialog.set_position (WIN_POS_CENTER);
3480         message.show();
3481         image->show();
3482         hbox->show();
3483
3484         switch (dialog.run ()) {
3485         case RESPONSE_ACCEPT:
3486                 return 0;
3487         default:
3488                 return 1;
3489         }
3490 }
3491
3492
3493 void
3494 ARDOUR_UI::disconnect_from_jack ()
3495 {
3496         if (engine) {
3497                 if( engine->disconnect_from_jack ()) {
3498                         MessageDialog msg (*editor, _("Could not disconnect from JACK"));
3499                         msg.run ();
3500                 }
3501
3502                 update_sample_rate (0);
3503         }
3504 }
3505
3506 void
3507 ARDOUR_UI::reconnect_to_jack ()
3508 {
3509         if (engine) {
3510                 if (engine->reconnect_to_jack ()) {
3511                         MessageDialog msg (*editor,  _("Could not reconnect to JACK"));
3512                         msg.run ();
3513                 }
3514
3515                 update_sample_rate (0);
3516         }
3517 }
3518
3519 void
3520 ARDOUR_UI::use_config ()
3521 {
3522         XMLNode* node = Config->extra_xml (X_("TransportControllables"));
3523         if (node) {
3524                 set_transport_controllable_state (*node);
3525         }
3526 }
3527
3528 void
3529 ARDOUR_UI::update_transport_clocks (framepos_t pos)
3530 {
3531         if (Config->get_primary_clock_delta_edit_cursor()) {
3532                 primary_clock->set (pos, false, editor->get_preferred_edit_position(), 1);
3533         } else {
3534                 primary_clock->set (pos, 0, true);
3535         }
3536
3537         if (Config->get_secondary_clock_delta_edit_cursor()) {
3538                 secondary_clock->set (pos, false, editor->get_preferred_edit_position(), 2);
3539         } else {
3540                 secondary_clock->set (pos);
3541         }
3542
3543         if (big_clock_window->get()) {
3544                 big_clock->set (pos);
3545         }
3546 }
3547
3548
3549 void
3550 ARDOUR_UI::step_edit_status_change (bool yn)
3551 {
3552         // XXX should really store pre-step edit status of things
3553         // we make insensitive
3554
3555         if (yn) {
3556                 rec_button.set_visual_state (3);
3557                 rec_button.set_sensitive (false);
3558         } else {
3559                 rec_button.set_visual_state (0);
3560                 rec_button.set_sensitive (true);
3561         }
3562 }
3563
3564 void
3565 ARDOUR_UI::record_state_changed ()
3566 {
3567         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
3568
3569         if (!_session || !big_clock_window->get()) {
3570                 /* why bother - the clock isn't visible */
3571                 return;
3572         }
3573
3574         Session::RecordState const r = _session->record_status ();
3575         bool const h = _session->have_rec_enabled_track ();
3576
3577         if (r == Session::Recording && h)  {
3578                 big_clock->set_widget_name ("BigClockRecording");
3579         } else {
3580                 big_clock->set_widget_name ("BigClockNonRecording");
3581         }
3582 }
3583
3584 bool
3585 ARDOUR_UI::first_idle ()
3586 {
3587         if (_session) {
3588                 _session->allow_auto_play (true);
3589         }
3590
3591         if (editor) {
3592                 editor->first_idle();
3593         }
3594
3595         Keyboard::set_can_save_keybindings (true);
3596         return false;
3597 }
3598
3599 void
3600 ARDOUR_UI::store_clock_modes ()
3601 {
3602         XMLNode* node = new XMLNode(X_("ClockModes"));
3603
3604         for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
3605                 XMLNode* child = new XMLNode (X_("Clock"));
3606                 
3607                 child->add_property (X_("name"), (*x)->name());
3608                 child->add_property (X_("mode"), enum_2_string ((*x)->mode()));
3609                 child->add_property (X_("on"), ((*x)->off() ? X_("no") : X_("yes")));
3610
3611                 node->add_child_nocopy (*child);
3612         }
3613
3614         _session->add_extra_xml (*node);
3615         _session->set_dirty ();
3616 }
3617
3618 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
3619         : Controllable (name), ui (u), type(tp)
3620 {
3621
3622 }
3623
3624 void
3625 ARDOUR_UI::TransportControllable::set_value (double val)
3626 {
3627         if (val < 0.5) {
3628                 /* do nothing: these are radio-style actions */
3629                 return;
3630         }
3631
3632         const char *action = 0;
3633
3634         switch (type) {
3635         case Roll:
3636                 action = X_("Roll");
3637                 break;
3638         case Stop:
3639                 action = X_("Stop");
3640                 break;
3641         case GotoStart:
3642                 action = X_("Goto Start");
3643                 break;
3644         case GotoEnd:
3645                 action = X_("Goto End");
3646                 break;
3647         case AutoLoop:
3648                 action = X_("Loop");
3649                 break;
3650         case PlaySelection:
3651                 action = X_("Play Selection");
3652                 break;
3653         case RecordEnable:
3654                 action = X_("Record");
3655                 break;
3656         default:
3657                 break;
3658         }
3659
3660         if (action == 0) {
3661                 return;
3662         }
3663
3664         Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
3665
3666         if (act) {
3667                 act->activate ();
3668         }
3669 }
3670
3671 double
3672 ARDOUR_UI::TransportControllable::get_value (void) const
3673 {
3674         float val = 0.0;
3675
3676         switch (type) {
3677         case Roll:
3678                 break;
3679         case Stop:
3680                 break;
3681         case GotoStart:
3682                 break;
3683         case GotoEnd:
3684                 break;
3685         case AutoLoop:
3686                 break;
3687         case PlaySelection:
3688                 break;
3689         case RecordEnable:
3690                 break;
3691         default:
3692                 break;
3693         }
3694
3695         return val;
3696 }
3697
3698 void
3699 ARDOUR_UI::TransportControllable::set_id (const string& str)
3700 {
3701         _id = str;
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 }