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