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