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