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