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