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