not-yet-complete JACK session management patch (TODO: get program name, vary snapshot...
[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/stop_signal.h"
53 #include "gtkmm2ext/popup.h"
54 #include "gtkmm2ext/window_title.h"
55
56 #include "midi++/manager.h"
57
58 #include "ardour/ardour.h"
59 #include "ardour/profile.h"
60 #include "ardour/session_directory.h"
61 #include "ardour/session_route.h"
62 #include "ardour/session_state_utils.h"
63 #include "ardour/session_utils.h"
64 #include "ardour/port.h"
65 #include "ardour/audioengine.h"
66 #include "ardour/playlist.h"
67 #include "ardour/utils.h"
68 #include "ardour/audio_diskstream.h"
69 #include "ardour/audiofilesource.h"
70 #include "ardour/recent_sessions.h"
71 #include "ardour/port.h"
72 #include "ardour/audio_track.h"
73 #include "ardour/midi_track.h"
74 #include "ardour/filesystem_paths.h"
75 #include "ardour/filename_extensions.h"
76
77 typedef uint64_t microseconds_t;
78
79 #include "actions.h"
80 #include "ardour_ui.h"
81 #include "public_editor.h"
82 #include "audio_clock.h"
83 #include "keyboard.h"
84 #include "mixer_ui.h"
85 #include "prompter.h"
86 #include "opts.h"
87 #include "add_route_dialog.h"
88 #include "about.h"
89 #include "splash.h"
90 #include "utils.h"
91 #include "gui_thread.h"
92 #include "theme_manager.h"
93 #include "bundle_manager.h"
94 #include "session_metadata_dialog.h"
95 #include "gain_meter.h"
96 #include "route_time_axis.h"
97 #include "startup.h"
98 #include "engine_dialog.h"
99 #include "processor_box.h"
100
101 #include "i18n.h"
102
103 using namespace ARDOUR;
104 using namespace PBD;
105 using namespace Gtkmm2ext;
106 using namespace Gtk;
107
108 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
109 UIConfiguration *ARDOUR_UI::ui_config = 0;
110
111 sigc::signal<void,bool> ARDOUR_UI::Blink;
112 sigc::signal<void>      ARDOUR_UI::RapidScreenUpdate;
113 sigc::signal<void>      ARDOUR_UI::SuperRapidScreenUpdate;
114 sigc::signal<void,nframes_t, bool, nframes_t> ARDOUR_UI::Clock;
115
116 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[])
117
118         : Gtkmm2ext::UI (PROGRAM_NAME, argcp, argvp),
119
120           primary_clock (X_("primary"), false, X_("TransportClockDisplay"), true, true, false, true),
121           secondary_clock (X_("secondary"), false, X_("SecondaryClockDisplay"), true, true, false, true),
122           preroll_clock (X_("preroll"), false, X_("PreRollClock"), true, false, true),
123           postroll_clock (X_("postroll"), false, X_("PostRollClock"), true, false, true),
124
125           /* preroll stuff */
126
127           preroll_button (_("pre\nroll")),
128           postroll_button (_("post\nroll")),
129
130           /* big clock */
131
132           big_clock (X_("bigclock"), false, "BigClockNonRecording", true, true, false, false),
133
134           /* transport */
135
136           roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll)),
137           stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop)),
138           goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart)),
139           goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd)),
140           auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop)),
141           play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection)),
142           rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable)),
143           shuttle_controllable (new TransportControllable ("shuttle", *this, TransportControllable::ShuttleControl)),
144           shuttle_controller_binding_proxy (shuttle_controllable),
145
146           roll_button (roll_controllable),
147           stop_button (stop_controllable),
148           goto_start_button (goto_start_controllable),
149           goto_end_button (goto_end_controllable),
150           auto_loop_button (auto_loop_controllable),
151           play_selection_button (play_selection_controllable),
152           rec_button (rec_controllable),
153
154           shuttle_units_button (_("% ")),
155
156           punch_in_button (_("Punch In")),
157           punch_out_button (_("Punch Out")),
158           auto_return_button (_("Auto Return")),
159           auto_play_button (_("Auto Play")),
160           auto_input_button (_("Auto Input")),
161           click_button (_("Click")),
162           time_master_button (_("time\nmaster")),
163
164           auditioning_alert_button (_("AUDITION")),
165           solo_alert_button (_("SOLO")),
166           shown_flag (false),
167           error_log_button (_("Errors"))
168
169 {
170         using namespace Gtk::Menu_Helpers;
171
172         Gtkmm2ext::init();
173
174
175 #ifdef TOP_MENUBAR
176         // _auto_display_errors = false;
177         /*
178          * This was commented out as it wasn't defined
179          * in A3 IIRC.  If this is not needed it should
180          * be completely removed.
181          */
182 #endif
183
184         about = 0;
185         splash = 0;
186         _startup = 0;
187
188         if (theArdourUI == 0) {
189                 theArdourUI = this;
190         }
191
192         ui_config = new UIConfiguration();
193         theme_manager = new ThemeManager();
194
195         editor = 0;
196         mixer = 0;
197         editor = 0;
198         engine = 0;
199         _session_is_new = false;
200         big_clock_window = 0;
201         big_clock_height = 0;
202         big_clock_resize_in_progress = false;
203         session_selector_window = 0;
204         last_key_press_time = 0;
205         _will_create_new_session_automatically = false;
206         add_route_dialog = 0;
207         route_params = 0;
208         rc_option_editor = 0;
209         session_option_editor = 0;
210         location_ui = 0;
211         open_session_selector = 0;
212         have_configure_timeout = false;
213         have_disk_speed_dialog_displayed = false;
214         session_loaded = false;
215         last_speed_displayed = -1.0f;
216         ignore_dual_punch = false;
217         _mixer_on_top = false;
218         original_big_clock_width = -1;
219         original_big_clock_height = -1;
220         original_big_clock_font_size = 0;
221
222         roll_button.unset_flags (Gtk::CAN_FOCUS);
223         stop_button.unset_flags (Gtk::CAN_FOCUS);
224         goto_start_button.unset_flags (Gtk::CAN_FOCUS);
225         goto_end_button.unset_flags (Gtk::CAN_FOCUS);
226         auto_loop_button.unset_flags (Gtk::CAN_FOCUS);
227         play_selection_button.unset_flags (Gtk::CAN_FOCUS);
228         rec_button.unset_flags (Gtk::CAN_FOCUS);
229
230         last_configure_time= 0;
231
232         shuttle_grabbed = false;
233         shuttle_fract = 0.0;
234         shuttle_max_speed = 8.0f;
235
236         shuttle_style_menu = 0;
237         shuttle_unit_menu = 0;
238
239         // We do not have jack linked in yet so;
240
241         last_shuttle_request = last_peak_grab = 0; //  get_microseconds();
242
243         ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
244         ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
245
246         /* handle dialog requests */
247
248         ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
249
250         /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
251
252         ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
253
254         /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
255
256         ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
257
258         /* lets get this party started */
259
260         try {
261                 if (ARDOUR::init (ARDOUR_COMMAND_LINE::use_vst, ARDOUR_COMMAND_LINE::try_hw_optimization)) {
262                         throw failed_constructor ();
263                 }
264
265                 setup_gtk_ardour_enums ();
266                 setup_profile ();
267
268                 GainMeter::setup_slider_pix ();
269                 RouteTimeAxisView::setup_slider_pix ();
270                 SendProcessorEntry::setup_slider_pix ();
271                 SessionEvent::create_per_thread_pool ("GUI", 512);
272
273         } catch (failed_constructor& err) {
274                 error << _("could not initialize Ardour.") << endmsg;
275                 // pass it on up
276                 throw;
277         }
278
279         /* we like keyboards */
280
281         keyboard = new ArdourKeyboard(*this);
282
283         XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
284         if (node) {
285                 keyboard->set_state (*node, Stateful::loading_state_version);
286         }
287
288         reset_dpi();
289
290         starting.connect (sigc::mem_fun(*this, &ARDOUR_UI::startup));
291         stopping.connect (sigc::mem_fun(*this, &ARDOUR_UI::shutdown));
292
293         platform_setup ();
294 }
295
296 /** @return true if a session was chosen and `apply' clicked, otherwise false if `cancel' was clicked */
297 bool
298 ARDOUR_UI::run_startup (bool should_be_new)
299 {
300         if (_startup == 0) {
301                 _startup = new ArdourStartup ();
302         }
303
304         _startup->set_new_only (should_be_new);
305         _startup->present ();
306
307         main().run();
308
309         _startup->hide ();
310
311         switch (_startup->response()) {
312         case RESPONSE_OK:
313                 return true;
314         default:
315                 return false;
316         }
317 }
318
319 int
320 ARDOUR_UI::create_engine ()
321 {
322         // this gets called every time by new_session()
323
324         if (engine) {
325                 return 0;
326         }
327
328         loading_message (_("Starting audio engine"));
329
330         try {
331                 engine = new ARDOUR::AudioEngine (ARDOUR_COMMAND_LINE::jack_client_name, ARDOUR_COMMAND_LINE::jack_session_uuid);
332
333         } catch (...) {
334
335                 return -1;
336         }
337
338         engine->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
339         engine->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
340         engine->Halted.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_halted, this), gui_context());
341         engine->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
342
343         post_engine ();
344
345         return 0;
346 }
347
348 void
349 ARDOUR_UI::post_engine ()
350 {
351         /* Things to be done once we create the AudioEngine
352          */
353
354         MIDI::Manager::instance()->set_api_data (engine->jack());
355         setup_midi ();
356         
357         ARDOUR::init_post_engine ();
358
359         ActionManager::init ();
360         _tooltips.enable();
361
362         if (setup_windows ()) {
363                 throw failed_constructor ();
364         }
365         
366         check_memory_locking();
367
368         /* this is the first point at which all the keybindings are available */
369
370         if (ARDOUR_COMMAND_LINE::show_key_actions) {
371                 vector<string> names;
372                 vector<string> paths;
373                 vector<string> keys;
374                 vector<AccelKey> bindings;
375
376                 ActionManager::get_all_actions (names, paths, keys, bindings);
377
378                 vector<string>::iterator n;
379                 vector<string>::iterator k;
380                 for (n = names.begin(), k = keys.begin(); n != names.end(); ++n, ++k) {
381                         cerr << "Action: " << (*n) << " bound to " << (*k) << endl;
382                 }
383
384                 exit (0);
385         }
386
387         blink_timeout_tag = -1;
388
389         /* this being a GUI and all, we want peakfiles */
390
391         AudioFileSource::set_build_peakfiles (true);
392         AudioFileSource::set_build_missing_peakfiles (true);
393
394         /* set default clock modes */
395
396         if (Profile->get_sae()) {
397                 primary_clock.set_mode (AudioClock::BBT);
398                 secondary_clock.set_mode (AudioClock::MinSec);
399         }  else {
400                 primary_clock.set_mode (AudioClock::Timecode);
401                 secondary_clock.set_mode (AudioClock::BBT);
402         }
403
404         /* start the time-of-day-clock */
405
406 #ifndef GTKOSX
407         /* OS X provides a nearly-always visible wallclock, so don't be stupid */
408         update_wall_clock ();
409         Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 60000);
410 #endif
411
412         update_disk_space ();
413         update_cpu_load ();
414         update_sample_rate (engine->frame_rate());
415
416         Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
417         boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
418         Config->map_parameters (pc);
419
420         /* now start and maybe save state */
421
422         if (do_engine_start () == 0) {
423                 if (_session && _session_is_new) {
424                         /* we need to retain initial visual
425                            settings for a new session
426                         */
427                         _session->save_state ("");
428                 }
429         }
430 }
431
432 ARDOUR_UI::~ARDOUR_UI ()
433 {
434         delete keyboard;
435         delete editor;
436         delete mixer;
437         delete add_route_dialog;
438 }
439
440 void
441 ARDOUR_UI::pop_back_splash ()
442 {
443         if (Splash::instance()) {
444                 // Splash::instance()->pop_back();
445                 Splash::instance()->hide ();
446         }
447 }
448
449 gint
450 ARDOUR_UI::configure_timeout ()
451 {
452         if (last_configure_time == 0) {
453                 /* no configure events yet */
454                 return true;
455         }
456
457         /* force a gap of 0.5 seconds since the last configure event
458          */
459
460         if (get_microseconds() - last_configure_time < 500000) {
461                 return true;
462         } else {
463                 have_configure_timeout = false;
464                 cerr << "config event-driven save\n";
465                 save_ardour_state ();
466                 return false;
467         }
468 }
469
470 gboolean
471 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
472 {
473         if (have_configure_timeout) {
474                 last_configure_time = get_microseconds();
475         } else {
476                 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
477                 have_configure_timeout = true;
478         }
479
480         return FALSE;
481 }
482
483 void
484 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
485 {
486         const XMLProperty* prop;
487
488         if ((prop = node.property ("roll")) != 0) {
489                 roll_controllable->set_id (prop->value());
490         }
491         if ((prop = node.property ("stop")) != 0) {
492                 stop_controllable->set_id (prop->value());
493         }
494         if ((prop = node.property ("goto-start")) != 0) {
495                 goto_start_controllable->set_id (prop->value());
496         }
497         if ((prop = node.property ("goto-end")) != 0) {
498                 goto_end_controllable->set_id (prop->value());
499         }
500         if ((prop = node.property ("auto-loop")) != 0) {
501                 auto_loop_controllable->set_id (prop->value());
502         }
503         if ((prop = node.property ("play-selection")) != 0) {
504                 play_selection_controllable->set_id (prop->value());
505         }
506         if ((prop = node.property ("rec")) != 0) {
507                 rec_controllable->set_id (prop->value());
508         }
509         if ((prop = node.property ("shuttle")) != 0) {
510                 shuttle_controllable->set_id (prop->value());
511         }
512 }
513
514 XMLNode&
515 ARDOUR_UI::get_transport_controllable_state ()
516 {
517         XMLNode* node = new XMLNode(X_("TransportControllables"));
518         char buf[64];
519
520         roll_controllable->id().print (buf, sizeof (buf));
521         node->add_property (X_("roll"), buf);
522         stop_controllable->id().print (buf, sizeof (buf));
523         node->add_property (X_("stop"), buf);
524         goto_start_controllable->id().print (buf, sizeof (buf));
525         node->add_property (X_("goto_start"), buf);
526         goto_end_controllable->id().print (buf, sizeof (buf));
527         node->add_property (X_("goto_end"), buf);
528         auto_loop_controllable->id().print (buf, sizeof (buf));
529         node->add_property (X_("auto_loop"), buf);
530         play_selection_controllable->id().print (buf, sizeof (buf));
531         node->add_property (X_("play_selection"), buf);
532         rec_controllable->id().print (buf, sizeof (buf));
533         node->add_property (X_("rec"), buf);
534         shuttle_controllable->id().print (buf, sizeof (buf));
535         node->add_property (X_("shuttle"), buf);
536
537         return *node;
538 }
539
540
541 gint
542 ARDOUR_UI::autosave_session ()
543 {
544         if (g_main_depth() > 1) {
545                 /* inside a recursive main loop,
546                    give up because we may not be able to
547                    take a lock.
548                 */
549                 return 1;
550         }
551
552         if (!Config->get_periodic_safety_backups()) {
553                 return 1;
554         }
555
556         if (_session) {
557                 _session->maybe_write_autosave();
558         }
559
560         return 1;
561 }
562
563 void
564 ARDOUR_UI::update_autosave ()
565 {
566         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_autosave)
567
568         if (_session && _session->dirty()) {
569                 if (_autosave_connection.connected()) {
570                         _autosave_connection.disconnect();
571                 }
572
573                 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
574                                 Config->get_periodic_safety_backup_interval() * 1000);
575
576         } else {
577                 if (_autosave_connection.connected()) {
578                         _autosave_connection.disconnect();
579                 }
580         }
581 }
582
583 void
584 ARDOUR_UI::backend_audio_error (bool we_set_params, Gtk::Window* toplevel)
585 {
586         string title;
587         if (we_set_params) {
588                 title = string_compose (_("%1 could not start JACK"), PROGRAM_NAME);
589         } else {
590                 title = string_compose (_("%1 could not connect to JACK."), PROGRAM_NAME);
591         }
592
593         MessageDialog win (title,
594                            false,
595                            Gtk::MESSAGE_INFO,
596                            Gtk::BUTTONS_NONE);
597
598         if (we_set_params) {
599                 win.set_secondary_text(_("There are several possible reasons:\n\
600 \n\
601 1) You requested audio parameters that are not supported..\n\
602 2) JACK is running as another user.\n\
603 \n\
604 Please consider the possibilities, and perhaps try different parameters."));
605         } else {
606                 win.set_secondary_text(_("There are several possible reasons:\n\
607 \n\
608 1) JACK is not running.\n\
609 2) JACK is running as another user, perhaps root.\n\
610 3) There is already another client called \"ardour\".\n\
611 \n\
612 Please consider the possibilities, and perhaps (re)start JACK."));
613         }
614
615         if (toplevel) {
616                 win.set_transient_for (*toplevel);
617         }
618
619         if (we_set_params) {
620                 win.add_button (Stock::OK, RESPONSE_CLOSE);
621         } else {
622                 win.add_button (Stock::QUIT, RESPONSE_CLOSE);
623         }
624
625         win.set_default_response (RESPONSE_CLOSE);
626
627         win.show_all ();
628         win.set_position (Gtk::WIN_POS_CENTER);
629         pop_back_splash ();
630
631         /* we just don't care about the result, but we want to block */
632
633         win.run ();
634 }
635
636 void
637 ARDOUR_UI::startup ()
638 {
639         XMLNode* audio_setup = Config->extra_xml ("AudioSetup");
640
641         if (audio_setup && _startup && _startup->engine_control()) {
642                 _startup->engine_control()->set_state (*audio_setup);
643         }
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
730                 if (_session->transport_rolling()) {
731                         _session->request_stop ();
732                         usleep (250000);
733                 }
734
735                 if (_session->dirty()) {
736                         switch (ask_about_saving_session(_("quit"))) {
737                         case -1:
738                                 return;
739                                 break;
740                         case 1:
741                                 /* use the default name */
742                                 if (save_state_canfail ("")) {
743                                         /* failed - don't quit */
744                                         MessageDialog msg (*editor,
745                                                            _("\
746 Ardour was unable to save your session.\n\n\
747 If you still wish to quit, please use the\n\n\
748 \"Just quit\" option."));
749                                         pop_back_splash();
750                                         msg.run ();
751                                         return;
752                                 }
753                                 break;
754                         case 0:
755                                 break;
756                         }
757                 }
758
759                 second_connection.disconnect ();
760                 point_one_second_connection.disconnect ();
761                 point_oh_five_second_connection.disconnect ();
762                 point_zero_one_second_connection.disconnect();
763                 
764                 // _session->set_deletion_in_progress ();
765                 _session->remove_pending_capture_state ();
766                 delete _session;
767                 _session = 0;
768         }
769
770         ArdourDialog::close_all_dialogs ();
771         engine->stop (true);
772         cerr << "Save before quit\n";
773         save_ardour_state ();
774         quit ();
775 }
776
777 int
778 ARDOUR_UI::ask_about_saving_session (const string & what)
779 {
780         ArdourDialog window (_("ardour: save session?"));
781         Gtk::HBox dhbox;  // the hbox for the image and text
782         Gtk::Label  prompt_label;
783         Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING,  Gtk::ICON_SIZE_DIALOG));
784
785         string msg;
786
787         msg = string_compose(_("Don't %1"), what);
788         window.add_button (msg, RESPONSE_REJECT);
789         msg = string_compose(_("Just %1"), what);
790         window.add_button (msg, RESPONSE_APPLY);
791         msg = string_compose(_("Save and %1"), what);
792         window.add_button (msg, RESPONSE_ACCEPT);
793
794         window.set_default_response (RESPONSE_ACCEPT);
795
796         Gtk::Button noquit_button (msg);
797         noquit_button.set_name ("EditorGTKButton");
798
799         string prompt;
800         string type;
801
802         if (_session->snap_name() == _session->name()) {
803                 type = _("session");
804         } else {
805                 type = _("snapshot");
806         }
807         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?"),
808                          type, _session->snap_name());
809
810         prompt_label.set_text (prompt);
811         prompt_label.set_name (X_("PrompterLabel"));
812         prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
813
814         dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
815         dhbox.set_homogeneous (false);
816         dhbox.pack_start (*dimage, false, false, 5);
817         dhbox.pack_start (prompt_label, true, false, 5);
818         window.get_vbox()->pack_start (dhbox);
819
820         window.set_name (_("Prompter"));
821         window.set_position (Gtk::WIN_POS_MOUSE);
822         window.set_modal (true);
823         window.set_resizable (false);
824
825         dhbox.show();
826         prompt_label.show();
827         dimage->show();
828         window.show();
829         window.set_keep_above (true);
830         window.present ();
831
832         ResponseType r = (ResponseType) window.run();
833
834         window.hide ();
835
836         switch (r) {
837         case RESPONSE_ACCEPT: // save and get out of here
838                 return 1;
839         case RESPONSE_APPLY:  // get out of here
840                 return 0;
841         default:
842                 break;
843         }
844
845         return -1;
846 }
847
848 gint
849 ARDOUR_UI::every_second ()
850 {
851         update_cpu_load ();
852         update_buffer_load ();
853         update_disk_space ();
854         return TRUE;
855 }
856
857 gint
858 ARDOUR_UI::every_point_one_seconds ()
859 {
860         update_speed_display ();
861         RapidScreenUpdate(); /* EMIT_SIGNAL */
862         return TRUE;
863 }
864
865 gint
866 ARDOUR_UI::every_point_zero_one_seconds ()
867 {
868         // august 2007: actual update frequency: 40Hz, not 100Hz
869
870         SuperRapidScreenUpdate(); /* EMIT_SIGNAL */
871         return TRUE;
872 }
873
874 void
875 ARDOUR_UI::update_sample_rate (nframes_t)
876 {
877         char buf[32];
878
879         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
880
881         if (!engine->connected()) {
882
883                 snprintf (buf, sizeof (buf), _("disconnected"));
884
885         } else {
886
887                 nframes_t rate = engine->frame_rate();
888
889                 if (fmod (rate, 1000.0) != 0.0) {
890                         snprintf (buf, sizeof (buf), _("%.1f kHz / %4.1f ms"),
891                                   (float) rate/1000.0f,
892                                   (engine->frames_per_cycle() / (float) rate) * 1000.0f);
893                 } else {
894                         snprintf (buf, sizeof (buf), _("%u kHz / %4.1f ms"),
895                                   rate/1000,
896                                   (engine->frames_per_cycle() / (float) rate) * 1000.0f);
897                 }
898         }
899
900         sample_rate_label.set_text (buf);
901 }
902
903 void
904 ARDOUR_UI::update_cpu_load ()
905 {
906         char buf[32];
907         snprintf (buf, sizeof (buf), _("DSP: %5.1f%%"), engine->get_cpu_load());
908         cpu_load_label.set_text (buf);
909 }
910
911 void
912 ARDOUR_UI::update_buffer_load ()
913 {
914         char buf[64];
915         uint32_t c, p;
916
917         if (_session) {
918                 c = _session->capture_load ();
919                 p = _session->playback_load ();
920
921                 push_buffer_stats (c, p);
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->diskstream()->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 ();
1448 }
1449
1450 void
1451 ARDOUR_UI::transport_stop_and_forget_capture ()
1452 {
1453         if (_session) {
1454                 _session->request_stop (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                 _session->request_play_loop (false, true);
1523         } else if (_session->get_play_range () && !join_play_range_button.get_active()) {
1524                 /* stop playing a range if we currently are */
1525                 _session->request_play_range (0, true);
1526         }
1527
1528         if (join_play_range_button.get_active()) {
1529                 _session->request_play_range (&editor->get_selection().time, true);
1530         }
1531
1532         if (!rolling) {
1533                 _session->request_transport_speed (1.0f);
1534         }
1535 }
1536
1537 void
1538 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
1539 {
1540         
1541         if (!_session) {
1542                 return;
1543         }
1544
1545         if (_session->is_auditioning()) {
1546                 _session->cancel_audition ();
1547                 return;
1548         }
1549         
1550         if (_session->config.get_external_sync()) {
1551                 switch (_session->config.get_sync_source()) {
1552                 case JACK:
1553                         break;
1554                 default:
1555                         /* transport controlled by the master */
1556                         return;
1557                 }
1558         }
1559
1560         bool rolling = _session->transport_rolling();
1561         bool affect_transport = true;
1562
1563         if (rolling && roll_out_of_bounded_mode) {
1564                 /* drop out of loop/range playback but leave transport rolling */
1565                 if (_session->get_play_loop()) {
1566                         if (Config->get_seamless_loop()) {
1567                                 /* the disk buffers contain copies of the loop - we can't 
1568                                    just keep playing, so stop the transport. the user
1569                                    can restart as they wish.
1570                                 */
1571                                 affect_transport = true;
1572                         } else {
1573                                 /* disk buffers are normal, so we can keep playing */
1574                                 affect_transport = false;
1575                         }
1576                         _session->request_play_loop (false, true);
1577                 } else if (_session->get_play_range ()) {
1578                         affect_transport = false;
1579                         _session->request_play_range (0, true);
1580                 } 
1581         } 
1582
1583         if (affect_transport) {
1584                 if (rolling) {
1585                         _session->request_stop (with_abort, true);
1586                 } else {
1587                         if (join_play_range_button.get_active()) {
1588                                 _session->request_play_range (&editor->get_selection().time, true);
1589                         }
1590                         
1591                         _session->request_transport_speed (1.0f);
1592                 }
1593         }
1594 }
1595
1596 void
1597 ARDOUR_UI::toggle_session_auto_loop ()
1598 {
1599         if (_session) {
1600                 if (_session->get_play_loop()) {
1601                         if (_session->transport_rolling()) {
1602                                 Location * looploc = _session->locations()->auto_loop_location();
1603                                 if (looploc) {
1604                                         _session->request_locate (looploc->start(), true);
1605                                 }
1606                         } else {
1607                                 _session->request_play_loop (false);
1608                         }
1609                 } else {
1610                         Location * looploc = _session->locations()->auto_loop_location();
1611                         if (looploc) {
1612                                 _session->request_play_loop (true);
1613                         }
1614                 }
1615         }
1616 }
1617
1618 void
1619 ARDOUR_UI::transport_play_selection ()
1620 {
1621         if (!_session) {
1622                 return;
1623         }
1624
1625         editor->play_selection ();
1626 }
1627
1628 void
1629 ARDOUR_UI::transport_rewind (int option)
1630 {
1631         float current_transport_speed;
1632
1633         if (_session) {
1634                 current_transport_speed = _session->transport_speed();
1635
1636                 if (current_transport_speed >= 0.0f) {
1637                         switch (option) {
1638                         case 0:
1639                                 _session->request_transport_speed (-1.0f);
1640                                 break;
1641                         case 1:
1642                                 _session->request_transport_speed (-4.0f);
1643                                 break;
1644                         case -1:
1645                                 _session->request_transport_speed (-0.5f);
1646                                 break;
1647                         }
1648                 } else {
1649                         /* speed up */
1650                         _session->request_transport_speed (current_transport_speed * 1.5f);
1651                 }
1652         }
1653 }
1654
1655 void
1656 ARDOUR_UI::transport_forward (int option)
1657 {
1658         float current_transport_speed;
1659
1660         if (_session) {
1661                 current_transport_speed = _session->transport_speed();
1662
1663                 if (current_transport_speed <= 0.0f) {
1664                         switch (option) {
1665                         case 0:
1666                                 _session->request_transport_speed (1.0f);
1667                                 break;
1668                         case 1:
1669                                 _session->request_transport_speed (4.0f);
1670                                 break;
1671                         case -1:
1672                                 _session->request_transport_speed (0.5f);
1673                                 break;
1674                         }
1675                 } else {
1676                         /* speed up */
1677                         _session->request_transport_speed (current_transport_speed * 1.5f);
1678                 }
1679
1680         }
1681 }
1682
1683 void
1684 ARDOUR_UI::toggle_record_enable (uint32_t dstream)
1685 {
1686         if (_session == 0) {
1687                 return;
1688         }
1689
1690         boost::shared_ptr<Route> r;
1691
1692         if ((r = _session->route_by_remote_id (dstream)) != 0) {
1693
1694                 Track* t;
1695
1696                 if ((t = dynamic_cast<Track*>(r.get())) != 0) {
1697                         t->diskstream()->set_record_enabled (!t->diskstream()->record_enabled());
1698                 }
1699         }
1700         if (_session == 0) {
1701                 return;
1702         }
1703 }
1704
1705 void
1706 ARDOUR_UI::map_transport_state ()
1707 {
1708         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::map_transport_state)
1709
1710         if (!_session) {
1711                 auto_loop_button.set_visual_state (0);
1712                 play_selection_button.set_visual_state (0);
1713                 roll_button.set_visual_state (0);
1714                 stop_button.set_visual_state (1);
1715                 return;
1716         }
1717
1718         float sp = _session->transport_speed();
1719
1720         if (sp == 1.0f) {
1721                 shuttle_fract = SHUTTLE_FRACT_SPEED1;  /* speed = 1.0, believe it or not */
1722                 shuttle_box.queue_draw ();
1723         } else if (sp == 0.0f) {
1724                 shuttle_fract = 0;
1725                 shuttle_box.queue_draw ();
1726                 update_disk_space ();
1727         }
1728
1729         if (sp != 0.0) {
1730
1731                 /* we're rolling */
1732
1733                 if (_session->get_play_range()) {
1734
1735                         play_selection_button.set_visual_state (1);
1736                         roll_button.set_visual_state (0);
1737                         auto_loop_button.set_visual_state (0);
1738
1739                 } else if (_session->get_play_loop ()) {
1740                         
1741                         auto_loop_button.set_visual_state (1);
1742                         play_selection_button.set_visual_state (0);
1743                         roll_button.set_visual_state (0);
1744
1745                 } else {
1746                         
1747                         roll_button.set_visual_state (1);
1748                         play_selection_button.set_visual_state (0);
1749                         auto_loop_button.set_visual_state (0);
1750                 }
1751
1752                 if (join_play_range_button.get_active()) {
1753                         /* light up both roll and play-selection if they are joined */
1754                         roll_button.set_visual_state (1);
1755                         play_selection_button.set_visual_state (1);
1756                 }
1757
1758                 stop_button.set_visual_state (0);
1759
1760         } else {
1761
1762                 stop_button.set_visual_state (1);
1763                 roll_button.set_visual_state (0);
1764                 play_selection_button.set_visual_state (0);
1765                 auto_loop_button.set_visual_state (0);
1766         }
1767 }
1768
1769 void
1770 ARDOUR_UI::engine_stopped ()
1771 {
1772         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
1773         ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1774         ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1775 }
1776
1777 void
1778 ARDOUR_UI::engine_running ()
1779 {
1780         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
1781         ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, true);
1782         ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, false);
1783
1784         Glib::RefPtr<Action> action;
1785         const char* action_name = 0;
1786
1787         switch (engine->frames_per_cycle()) {
1788         case 32:
1789                 action_name = X_("JACKLatency32");
1790                 break;
1791         case 64:
1792                 action_name = X_("JACKLatency64");
1793                 break;
1794         case 128:
1795                 action_name = X_("JACKLatency128");
1796                 break;
1797         case 512:
1798                 action_name = X_("JACKLatency512");
1799                 break;
1800         case 1024:
1801                 action_name = X_("JACKLatency1024");
1802                 break;
1803         case 2048:
1804                 action_name = X_("JACKLatency2048");
1805                 break;
1806         case 4096:
1807                 action_name = X_("JACKLatency4096");
1808                 break;
1809         case 8192:
1810                 action_name = X_("JACKLatency8192");
1811                 break;
1812         default:
1813                 /* XXX can we do anything useful ? */
1814                 break;
1815         }
1816
1817         if (action_name) {
1818
1819                 action = ActionManager::get_action (X_("JACK"), action_name);
1820
1821                 if (action) {
1822                         Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (action);
1823                         ract->set_active ();
1824                 }
1825         }
1826 }
1827
1828 void
1829 ARDOUR_UI::engine_halted ()
1830 {
1831         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_halted)
1832
1833         ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1834         ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1835
1836         update_sample_rate (0);
1837
1838         MessageDialog msg (*editor,
1839                            _("\
1840 JACK has either been shutdown or it\n\
1841 disconnected Ardour because Ardour\n\
1842 was not fast enough. Try to restart\n\
1843 JACK, reconnect and save the session."));
1844         pop_back_splash ();
1845         msg.run ();
1846 }
1847
1848 int32_t
1849 ARDOUR_UI::do_engine_start ()
1850 {
1851         try {
1852                 engine->start();
1853         }
1854
1855         catch (...) {
1856                 engine->stop ();
1857                 error << _("Unable to start the session running")
1858                       << endmsg;
1859                 unload_session ();
1860                 return -2;
1861         }
1862
1863         return 0;
1864 }
1865
1866 void
1867 ARDOUR_UI::setup_theme ()
1868 {
1869         theme_manager->setup_theme();
1870 }
1871
1872 void
1873 ARDOUR_UI::update_clocks ()
1874 {
1875         if (!editor || !editor->dragging_playhead()) {
1876                 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position()); /* EMIT_SIGNAL */
1877         }
1878 }
1879
1880 void
1881 ARDOUR_UI::start_clocking ()
1882 {
1883         clock_signal_connection = RapidScreenUpdate.connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
1884 }
1885
1886 void
1887 ARDOUR_UI::stop_clocking ()
1888 {
1889         clock_signal_connection.disconnect ();
1890 }
1891
1892 void
1893 ARDOUR_UI::toggle_clocking ()
1894 {
1895 #if 0
1896         if (clock_button.get_active()) {
1897                 start_clocking ();
1898         } else {
1899                 stop_clocking ();
1900         }
1901 #endif
1902 }
1903
1904 gint
1905 ARDOUR_UI::_blink (void *arg)
1906
1907 {
1908         ((ARDOUR_UI *) arg)->blink ();
1909         return TRUE;
1910 }
1911
1912 void
1913 ARDOUR_UI::blink ()
1914 {
1915         Blink (blink_on = !blink_on); /* EMIT_SIGNAL */
1916 }
1917
1918 void
1919 ARDOUR_UI::start_blinking ()
1920 {
1921         /* Start the blink signal. Everybody with a blinking widget
1922            uses Blink to drive the widget's state.
1923         */
1924
1925         if (blink_timeout_tag < 0) {
1926                 blink_on = false;
1927                 blink_timeout_tag = g_timeout_add (240, _blink, this);
1928         }
1929 }
1930
1931 void
1932 ARDOUR_UI::stop_blinking ()
1933 {
1934         if (blink_timeout_tag >= 0) {
1935                 g_source_remove (blink_timeout_tag);
1936                 blink_timeout_tag = -1;
1937         }
1938 }
1939
1940
1941 /** Ask the user for the name of a new shapshot and then take it.
1942  */
1943 void
1944 ARDOUR_UI::snapshot_session ()
1945 {
1946         ArdourPrompter prompter (true);
1947         string snapname;
1948         char timebuf[128];
1949         time_t n;
1950         struct tm local_time;
1951
1952         time (&n);
1953         localtime_r (&n, &local_time);
1954         strftime (timebuf, sizeof(timebuf), "%FT%T", &local_time);
1955
1956         prompter.set_name ("Prompter");
1957         prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1958         prompter.set_title (_("Take Snapshot"));
1959         prompter.set_prompt (_("Name of New Snapshot"));
1960         prompter.set_initial_text (timebuf);
1961
1962   again:
1963         switch (prompter.run()) {
1964         case RESPONSE_ACCEPT:
1965         {
1966                 prompter.get_result (snapname);
1967
1968                 bool do_save = (snapname.length() != 0);
1969
1970                 if (do_save) {
1971                         if (snapname.find ('/') != string::npos) {
1972                                 MessageDialog msg (_("To ensure compatibility with various systems\n"
1973                                                      "snapshot names may not contain a '/' character"));
1974                                 msg.run ();
1975                                 goto again;
1976                         }
1977                         if (snapname.find ('\\') != string::npos) {
1978                                 MessageDialog msg (_("To ensure compatibility with various systems\n"
1979                                                      "snapshot names may not contain a '\\' character"));
1980                                 msg.run ();
1981                                 goto again;
1982                         }
1983                 }
1984
1985                 vector<sys::path> p;
1986                 get_state_files_in_directory (_session->session_directory().root_path(), p);
1987                 vector<string> n = get_file_names_no_extension (p);
1988                 if (find (n.begin(), n.end(), snapname) != n.end()) {
1989
1990                         ArdourDialog confirm (_("Confirm snapshot overwrite"), true);
1991                         Label m (_("A snapshot already exists with that name.  Do you want to overwrite it?"));
1992                         confirm.get_vbox()->pack_start (m, true, true);
1993                         confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1994                         confirm.add_button (_("Overwrite"), Gtk::RESPONSE_ACCEPT);
1995                         confirm.show_all ();
1996                         switch (confirm.run()) {
1997                         case RESPONSE_CANCEL:
1998                                 do_save = false;
1999                         }
2000                 }
2001
2002                 if (do_save) {
2003                         save_state (snapname);
2004                 }
2005                 break;
2006         }
2007
2008         default:
2009                 break;
2010         }
2011 }
2012
2013 void
2014 ARDOUR_UI::save_state (const string & name)
2015 {
2016         save_state_canfail (name);
2017 }
2018
2019 int
2020 ARDOUR_UI::save_state_canfail (string name)
2021 {
2022         if (_session) {
2023                 int ret;
2024
2025                 if (name.length() == 0) {
2026                         name = _session->snap_name();
2027                 }
2028
2029                 if ((ret = _session->save_state (name)) != 0) {
2030                         return ret;
2031                 }
2032         }
2033         cerr << "SS canfail\n";
2034         save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2035         return 0;
2036 }
2037
2038 void
2039 ARDOUR_UI::primary_clock_value_changed ()
2040 {
2041         if (_session) {
2042                 _session->request_locate (primary_clock.current_time ());
2043         }
2044 }
2045
2046 void
2047 ARDOUR_UI::big_clock_value_changed ()
2048 {
2049         if (_session) {
2050                 _session->request_locate (big_clock.current_time ());
2051         }
2052 }
2053
2054 void
2055 ARDOUR_UI::secondary_clock_value_changed ()
2056 {
2057         if (_session) {
2058                 _session->request_locate (secondary_clock.current_time ());
2059         }
2060 }
2061
2062 void
2063 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2064 {
2065         if (_session == 0) {
2066                 return;
2067         }
2068
2069         Session::RecordState const r = _session->record_status ();
2070         bool const h = _session->have_rec_enabled_diskstream ();
2071
2072         if (r == Session::Enabled || (r == Session::Recording && !h)) {
2073                 if (onoff) {
2074                         rec_button.set_visual_state (2);
2075                 } else {
2076                         rec_button.set_visual_state (0);
2077                 }
2078         } else if (r == Session::Recording && h) {
2079                 rec_button.set_visual_state (1);
2080         } else {
2081                 rec_button.set_visual_state (0);
2082         }
2083 }
2084
2085 void
2086 ARDOUR_UI::save_template ()
2087 {
2088         ArdourPrompter prompter (true);
2089         string name;
2090
2091         if (!check_audioengine()) {
2092                 return;
2093         }
2094
2095         prompter.set_name (X_("Prompter"));
2096         prompter.set_title (_("Save Mix Template"));
2097         prompter.set_prompt (_("Name for mix template:"));
2098         prompter.set_initial_text(_session->name() + _("-template"));
2099         prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2100
2101         switch (prompter.run()) {
2102         case RESPONSE_ACCEPT:
2103                 prompter.get_result (name);
2104
2105                 if (name.length()) {
2106                         _session->save_template (name);
2107                 }
2108                 break;
2109
2110         default:
2111                 break;
2112         }
2113 }
2114
2115 void
2116 ARDOUR_UI::edit_metadata ()
2117 {
2118         SessionMetadataEditor dialog;
2119         dialog.set_session (_session);
2120         editor->ensure_float (dialog);
2121         dialog.run ();
2122 }
2123
2124 void
2125 ARDOUR_UI::import_metadata ()
2126 {
2127         SessionMetadataImporter dialog;
2128         dialog.set_session (_session);
2129         editor->ensure_float (dialog);
2130         dialog.run ();
2131 }
2132
2133 void
2134 ARDOUR_UI::fontconfig_dialog ()
2135 {
2136 #ifdef GTKOSX
2137         /* X11 users will always have fontconfig info around, but new GTK-OSX users
2138            may not and it can take a while to build it. Warn them.
2139         */
2140
2141         Glib::ustring fontconfig = Glib::build_filename (Glib::get_home_dir(), ".fontconfig");
2142
2143         if (!Glib::file_test (fontconfig, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_DIR)) {
2144                 MessageDialog msg (*_startup,
2145                                    _("Welcome to Ardour.\n\n"
2146                                      "The program will take a bit longer to start up\n"
2147                                      "while the system fonts are checked.\n\n"
2148                                      "This will only be done once, and you will\n"
2149                                      "not see this message again\n"),
2150                                    true,
2151                                    Gtk::MESSAGE_INFO,
2152                                    Gtk::BUTTONS_OK);
2153                 pop_back_splash ();
2154                 msg.show_all ();
2155                 msg.present ();
2156                 msg.run ();
2157         }
2158 #endif
2159 }
2160
2161 void
2162 ARDOUR_UI::parse_cmdline_path (const Glib::ustring& cmdline_path, Glib::ustring& session_name, Glib::ustring& session_path, bool& existing_session)
2163 {
2164         existing_session = false;
2165
2166         if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_DIR)) {
2167                 session_path = cmdline_path;
2168                 existing_session = true;
2169         } else if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_REGULAR)) {
2170                 session_path = Glib::path_get_dirname (string (cmdline_path));
2171                 existing_session = true;
2172         } else {
2173                 /* it doesn't exist, assume the best */
2174                 session_path = Glib::path_get_dirname (string (cmdline_path));
2175         }
2176
2177         session_name = basename_nosuffix (string (cmdline_path));
2178 }
2179
2180 int
2181 ARDOUR_UI::load_cmdline_session (const Glib::ustring& session_name, const Glib::ustring& session_path, bool& existing_session)
2182 {
2183         /* when this is called, the backend audio system must be running */
2184
2185         /* the main idea here is to deal with the fact that a cmdline argument for the session
2186            can be interpreted in different ways - it could be a directory or a file, and before
2187            we load, we need to know both the session directory and the snapshot (statefile) within it
2188            that we are supposed to use.
2189         */
2190
2191         if (session_name.length() == 0 || session_path.length() == 0) {
2192                 return false;
2193         }
2194
2195         if (Glib::file_test (session_path, Glib::FILE_TEST_IS_DIR)) {
2196
2197                 Glib::ustring predicted_session_file;
2198
2199                 predicted_session_file = session_path;
2200                 predicted_session_file += '/';
2201                 predicted_session_file += session_name;
2202                 predicted_session_file += ARDOUR::statefile_suffix;
2203
2204                 if (Glib::file_test (predicted_session_file, Glib::FILE_TEST_EXISTS)) {
2205                         existing_session = true;
2206                 }
2207
2208         } else if (Glib::file_test (session_path, Glib::FILE_TEST_EXISTS)) {
2209
2210                 if (session_path.find (ARDOUR::statefile_suffix) == session_path.length() - 7) {
2211                         /* existing .ardour file */
2212                         existing_session = true;
2213                 }
2214
2215         } else {
2216                 existing_session = false;
2217         }
2218
2219         /* lets just try to load it */
2220
2221         if (create_engine ()) {
2222                 backend_audio_error (false, _startup);
2223                 return -1;
2224         }
2225
2226         return load_session (session_path, session_name);
2227 }
2228
2229 bool
2230 ARDOUR_UI::ask_about_loading_existing_session (const Glib::ustring& session_path)
2231 {
2232         Glib::ustring str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2233
2234         MessageDialog msg (str,
2235                            false,
2236                            Gtk::MESSAGE_WARNING,
2237                            Gtk::BUTTONS_YES_NO,
2238                            true);
2239
2240
2241         msg.set_name (X_("OpenExistingDialog"));
2242         msg.set_title (_("Open Existing Session"));
2243         msg.set_wmclass (X_("existing_session"), "Ardour");
2244         msg.set_position (Gtk::WIN_POS_MOUSE);
2245         pop_back_splash ();
2246
2247         switch (msg.run()) {
2248         case RESPONSE_YES:
2249                 return true;
2250                 break;
2251         }
2252         return false;
2253 }
2254
2255 int
2256 ARDOUR_UI::build_session_from_nsd (const Glib::ustring& session_path, const Glib::ustring& session_name)
2257 {
2258         BusProfile bus_profile;
2259
2260         if (Profile->get_sae()) {
2261
2262                 bus_profile.master_out_channels = 2;
2263                 bus_profile.input_ac = AutoConnectPhysical;
2264                 bus_profile.output_ac = AutoConnectMaster;
2265                 bus_profile.requested_physical_in = 0; // use all available
2266                 bus_profile.requested_physical_out = 0; // use all available
2267
2268         } else {
2269
2270                 /* get settings from advanced section of NSD */
2271
2272                 if (_startup->create_master_bus()) {
2273                         bus_profile.master_out_channels = (uint32_t) _startup->master_channel_count();
2274                 } else {
2275                         bus_profile.master_out_channels = 0;
2276                 }
2277
2278                 if (_startup->connect_inputs()) {
2279                         bus_profile.input_ac = AutoConnectPhysical;
2280                 } else {
2281                         bus_profile.input_ac = AutoConnectOption (0);
2282                 }
2283
2284                 /// @todo some minor tweaks.
2285                 
2286                 bus_profile.output_ac = AutoConnectOption (0);
2287
2288                 if (_startup->connect_outputs ()) {
2289                         if (_startup->connect_outs_to_master()) {
2290                                 bus_profile.output_ac = AutoConnectMaster;
2291                         } else if (_startup->connect_outs_to_physical()) {
2292                                 bus_profile.output_ac = AutoConnectPhysical;
2293                         }
2294                 }
2295
2296                 bus_profile.requested_physical_in = (uint32_t) _startup->input_limit_count();
2297                 bus_profile.requested_physical_out = (uint32_t) _startup->output_limit_count();
2298         }
2299
2300         if (build_session (session_path, session_name, bus_profile)) {
2301                 return -1;
2302         }
2303
2304         return 0;
2305 }
2306
2307 void
2308 ARDOUR_UI::idle_load (const Glib::ustring& path)
2309 {
2310         if (_session) {
2311                 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2312                         /* /path/to/foo => /path/to/foo, foo */
2313                         load_session (path, basename_nosuffix (path));
2314                 } else {
2315                         /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2316                         load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2317                 }
2318         } else {
2319
2320                 ARDOUR_COMMAND_LINE::session_name = path;
2321
2322                 /*
2323                  * new_session_dialog doens't exist in A3
2324                  * Try to remove all references to it to
2325                  * see if it will compile.  NOTE: this will
2326                  * likely cause a runtime issue is my somewhat
2327                  * uneducated guess.
2328                  */
2329
2330                 //if (new_session_dialog) {
2331
2332
2333                         /* make it break out of Dialog::run() and
2334                            start again.
2335                          */
2336
2337                         //new_session_dialog->response (1);
2338                 //}
2339         }
2340 }
2341
2342 void
2343 ARDOUR_UI::end_loading_messages ()
2344 {
2345         // hide_splash ();
2346 }
2347
2348 void
2349 ARDOUR_UI::loading_message (const std::string& /*msg*/)
2350 {
2351         // show_splash ();
2352         // splash->message (msg);
2353         flush_pending ();
2354 }
2355
2356 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
2357 int
2358 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new)
2359 {
2360         Glib::ustring session_name;
2361         Glib::ustring session_path;
2362         Glib::ustring template_name;
2363         int ret = -1;
2364         bool likely_new = false;
2365
2366         while (ret != 0) {
2367
2368                 if (!should_be_new && !ARDOUR_COMMAND_LINE::session_name.empty()) {
2369
2370                         /* if they named a specific statefile, use it, otherwise they are
2371                            just giving a session folder, and we want to use it as is
2372                            to find the session.
2373                         */
2374
2375                         if (ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix) != string::npos) {
2376                                 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
2377                         } else {
2378                                 session_path = ARDOUR_COMMAND_LINE::session_name;
2379                         }
2380
2381                         session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
2382
2383                 } else {
2384
2385                         bool const apply = run_startup (should_be_new);
2386                         if (!apply) {
2387                                 if (quit_on_cancel) {
2388                                         exit (1);
2389                                 } else {
2390                                         return ret;
2391                                 }
2392                         }
2393
2394                         /* if we run the startup dialog again, offer more than just "new session" */
2395
2396                         should_be_new = false;
2397
2398                         session_name = _startup->session_name (likely_new);
2399
2400                         /* this shouldn't happen, but we catch it just in case it does */
2401
2402                         if (session_name.empty()) {
2403                                 break;
2404                         }
2405                         if (_startup->use_session_template()) {
2406                                 template_name = _startup->session_template_name();
2407                                 _session_is_new = true;
2408                         }
2409
2410                         if (session_name[0] == '/' ||
2411                             (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == '/') ||
2412                             (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == '/')) {
2413
2414                                 /* absolute path or cwd-relative path specified for session name: infer session folder
2415                                    from what was given.
2416                                 */
2417                                 
2418                                 session_path = Glib::path_get_dirname (session_name);
2419                                 session_name = Glib::path_get_basename (session_name);
2420
2421                         } else {
2422
2423                                 session_path = _startup->session_folder();
2424                         }
2425                 }
2426
2427                 if (create_engine ()) {
2428                         break;
2429                 }
2430
2431                 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
2432
2433                         if (likely_new) {
2434
2435                                 Glib::ustring existing = Glib::build_filename (session_path, session_name);
2436
2437                                 if (!ask_about_loading_existing_session (existing)) {
2438                                         ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2439                                         continue;
2440                                 }
2441                         }
2442
2443                         _session_is_new = false;
2444
2445                 } else {
2446
2447                         if (!likely_new) {
2448                                 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
2449                                 msg.run ();
2450                                 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2451                                 continue;
2452                         }
2453
2454                         if (session_name.find ('/') != Glib::ustring::npos) {
2455                                 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2456                                                                           "session names may not contain a '/' character"));
2457                                 msg.run ();
2458                                 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2459                                 continue;
2460                         }
2461
2462                         if (session_name.find ('\\') != Glib::ustring::npos) {
2463                                 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2464                                                                           "session names may not contain a '\\' character"));
2465                                 msg.run ();
2466                                 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2467                                 continue;
2468                         }
2469
2470                         _session_is_new = true;
2471                 }
2472
2473                 if (likely_new && template_name.empty()) {
2474
2475                         ret = build_session_from_nsd (session_path, session_name);
2476
2477                 } else {
2478
2479                         ret = load_session (session_path, session_name, template_name);
2480                         if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
2481                                 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
2482                                 exit (1);
2483                         }
2484                 }
2485         }
2486
2487         return ret;
2488 }
2489
2490 void
2491 ARDOUR_UI::close_session()
2492 {
2493         if (!check_audioengine()) {
2494                 return;
2495         }
2496
2497         if (unload_session (true)) {
2498                 return;
2499         }
2500
2501         ARDOUR_COMMAND_LINE::session_name = "";
2502         get_session_parameters (true, false);
2503 }
2504
2505 int
2506 ARDOUR_UI::load_session (const Glib::ustring& path, const Glib::ustring& snap_name, Glib::ustring mix_template)
2507 {
2508         Session *new_session;
2509         int unload_status;
2510         int retval = -1;
2511
2512         session_loaded = false;
2513
2514         if (!check_audioengine()) {
2515                 return -1;
2516         }
2517
2518         unload_status = unload_session ();
2519
2520         if (unload_status < 0) {
2521                 goto out;
2522         } else if (unload_status > 0) {
2523                 retval = 0;
2524                 goto out;
2525         }
2526
2527         loading_message (string_compose (_("Please wait while %1loads your session"), PROGRAM_NAME));
2528
2529         try {
2530                 new_session = new Session (*engine, path, snap_name, 0, mix_template);
2531         }
2532
2533         /* this one is special */
2534
2535         catch (AudioEngine::PortRegistrationFailure& err) {
2536
2537                 MessageDialog msg (err.what(),
2538                                    true,
2539                                    Gtk::MESSAGE_INFO,
2540                                    Gtk::BUTTONS_CLOSE);
2541
2542                 msg.set_title (_("Port Registration Error"));
2543                 msg.set_secondary_text (_("Click the Close button to try again."));
2544                 msg.set_position (Gtk::WIN_POS_CENTER);
2545                 pop_back_splash ();
2546                 msg.present ();
2547
2548                 int response = msg.run ();
2549
2550                 msg.hide ();
2551
2552                 switch (response) {
2553                 case RESPONSE_CANCEL:
2554                         exit (1);
2555                 default:
2556                         break;
2557                 }
2558                 goto out;
2559         }
2560
2561         catch (...) {
2562
2563                 MessageDialog msg (string_compose(_("Session \"%1 (snapshot %2)\" did not load successfully"), path, snap_name),
2564                                    true,
2565                                    Gtk::MESSAGE_INFO,
2566                                    Gtk::BUTTONS_CLOSE);
2567
2568                 msg.set_title (_("Loading Error"));
2569                 msg.set_secondary_text (_("Click the Close button to try again."));
2570                 msg.set_position (Gtk::WIN_POS_CENTER);
2571                 pop_back_splash ();
2572                 msg.present ();
2573
2574                 int response = msg.run ();
2575
2576                 msg.hide ();
2577
2578                 switch (response) {
2579                 case RESPONSE_CANCEL:
2580                         exit (1);
2581                 default:
2582                         break;
2583                 }
2584                 goto out;
2585         }
2586
2587         set_session (new_session);
2588
2589         session_loaded = true;
2590
2591         goto_editor_window ();
2592
2593         if (_session) {
2594                 _session->set_clean ();
2595         }
2596
2597         flush_pending ();
2598         retval = 0;
2599
2600   out:
2601         return retval;
2602 }
2603
2604 int
2605 ARDOUR_UI::build_session (const Glib::ustring& path, const Glib::ustring& snap_name, BusProfile& bus_profile)
2606 {
2607         Session *new_session;
2608         int x;
2609
2610         if (!check_audioengine()) {
2611                 return -1;
2612         }
2613
2614         session_loaded = false;
2615
2616         x = unload_session ();
2617
2618         if (x < 0) {
2619                 return -1;
2620         } else if (x > 0) {
2621                 return 0;
2622         }
2623
2624         _session_is_new = true;
2625
2626         try {
2627                 new_session = new Session (*engine, path, snap_name, &bus_profile);
2628         }
2629
2630         catch (...) {
2631
2632                 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
2633                 pop_back_splash ();
2634                 msg.run ();
2635                 return -1;
2636         }
2637
2638         set_session (new_session);
2639
2640         session_loaded = true;
2641
2642         new_session->save_state(new_session->name());
2643
2644         return 0;
2645 }
2646
2647 void
2648 ARDOUR_UI::show ()
2649 {
2650         if (editor) {
2651                 editor->show_window ();
2652
2653                 if (!shown_flag) {
2654                         editor->present ();
2655                 }
2656
2657                 shown_flag = true;
2658         }
2659 }
2660
2661 void
2662 ARDOUR_UI::launch_chat ()
2663 {
2664 #ifdef __APPLE__
2665         open_uri("http://webchat.freenode.net/?channels=ardour-osx");
2666 #else
2667         open_uri("http://webchat.freenode.net/?channels=ardour");
2668 #endif
2669 }
2670
2671 void
2672 ARDOUR_UI::show_about ()
2673 {
2674         if (about == 0) {
2675                 about = new About;
2676                 about->signal_response().connect(sigc::mem_fun (*this, &ARDOUR_UI::about_signal_response) );
2677         }
2678
2679         about->set_transient_for(*editor);
2680         about->show_all ();
2681 }
2682
2683 void
2684 ARDOUR_UI::hide_about ()
2685 {
2686         if (about) {
2687                 about->get_window()->set_cursor ();
2688                 about->hide ();
2689         }
2690 }
2691
2692 void
2693 ARDOUR_UI::about_signal_response (int /*response*/)
2694 {
2695         hide_about();
2696 }
2697
2698 void
2699 ARDOUR_UI::show_splash ()
2700 {
2701         if (splash == 0) {
2702                 try {
2703                         splash = new Splash;
2704                 } catch (...) {
2705                         return;
2706                 }
2707         }
2708
2709         splash->show ();
2710         splash->present ();
2711         splash->queue_draw ();
2712         splash->get_window()->process_updates (true);
2713         flush_pending ();
2714 }
2715
2716 void
2717 ARDOUR_UI::hide_splash ()
2718 {
2719         if (splash) {
2720                 splash->hide();
2721         }
2722 }
2723
2724 void
2725 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title,
2726                                     const string& plural_msg, const string& singular_msg)
2727 {
2728         size_t removed;
2729
2730         removed = rep.paths.size();
2731
2732         if (removed == 0) {
2733                 MessageDialog msgd (*editor,
2734                                     _("No audio files were ready for cleanup"),
2735                                     true,
2736                                     Gtk::MESSAGE_INFO,
2737                                     (Gtk::ButtonsType)(Gtk::BUTTONS_OK)  );
2738                 msgd.set_secondary_text (_("If this seems suprising, \n\
2739 check for any existing snapshots.\n\
2740 These may still include regions that\n\
2741 require some unused files to continue to exist."));
2742
2743                 msgd.run ();
2744                 return;
2745         }
2746
2747         ArdourDialog results (_("ardour: cleanup"), true, false);
2748
2749         struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
2750             CleanupResultsModelColumns() {
2751                     add (visible_name);
2752                     add (fullpath);
2753             }
2754             Gtk::TreeModelColumn<Glib::ustring> visible_name;
2755             Gtk::TreeModelColumn<Glib::ustring> fullpath;
2756         };
2757
2758
2759         CleanupResultsModelColumns results_columns;
2760         Glib::RefPtr<Gtk::ListStore> results_model;
2761         Gtk::TreeView results_display;
2762
2763         results_model = ListStore::create (results_columns);
2764         results_display.set_model (results_model);
2765         results_display.append_column (list_title, results_columns.visible_name);
2766
2767         results_display.set_name ("CleanupResultsList");
2768         results_display.set_headers_visible (true);
2769         results_display.set_headers_clickable (false);
2770         results_display.set_reorderable (false);
2771
2772         Gtk::ScrolledWindow list_scroller;
2773         Gtk::Label txt;
2774         Gtk::VBox dvbox;
2775         Gtk::HBox dhbox;  // the hbox for the image and text
2776         Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
2777         Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO,  Gtk::ICON_SIZE_DIALOG));
2778
2779         dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
2780
2781         const string dead_sound_directory = _session->session_directory().dead_sound_path().to_string();
2782
2783         /* subst:
2784            %1 - number of files removed
2785            %2 - location of "dead_sounds"
2786            %3 - size of files affected
2787            %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
2788         */
2789
2790         const char* bprefix;
2791         double space_adjusted = 0;
2792
2793         if (rep.space < 100000.0f) {
2794                 bprefix = X_("kilo");
2795         } else if (rep.space < 1000000.0f * 1000) {
2796                 bprefix = X_("mega");
2797                 space_adjusted = truncf((float)rep.space / 1000.0);
2798         } else {
2799                 bprefix = X_("giga");
2800                 space_adjusted = truncf((float)rep.space / (1000000.0 * 1000));
2801         }
2802
2803         if (removed > 1) {
2804                 txt.set_text (string_compose (plural_msg, removed, _session->path() + "dead_sounds", space_adjusted, bprefix));
2805         } else {
2806                 txt.set_text (string_compose (singular_msg, removed, _session->path() + "dead_sounds", space_adjusted, bprefix));
2807         }
2808
2809         dhbox.pack_start (*dimage, true, false, 5);
2810         dhbox.pack_start (txt, true, false, 5);
2811
2812         for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
2813                 TreeModel::Row row = *(results_model->append());
2814                 row[results_columns.visible_name] = *i;
2815                 row[results_columns.fullpath] = *i;
2816         }
2817
2818         list_scroller.add (results_display);
2819         list_scroller.set_size_request (-1, 150);
2820         list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
2821
2822         dvbox.pack_start (dhbox, true, false, 5);
2823         dvbox.pack_start (list_scroller, true, false, 5);
2824         ddhbox.pack_start (dvbox, true, false, 5);
2825
2826         results.get_vbox()->pack_start (ddhbox, true, false, 5);
2827         results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
2828         results.set_default_response (RESPONSE_CLOSE);
2829         results.set_position (Gtk::WIN_POS_MOUSE);
2830
2831         results_display.show();
2832         list_scroller.show();
2833         txt.show();
2834         dvbox.show();
2835         dhbox.show();
2836         ddhbox.show();
2837         dimage->show();
2838
2839         //results.get_vbox()->show();
2840         results.set_resizable (false);
2841
2842         results.run ();
2843
2844 }
2845
2846 void
2847 ARDOUR_UI::cleanup ()
2848 {
2849         if (_session == 0) {
2850                 /* shouldn't happen: menu item is insensitive */
2851                 return;
2852         }
2853
2854
2855         MessageDialog  checker (_("Are you sure you want to cleanup?"),
2856                                 true,
2857                                 Gtk::MESSAGE_QUESTION,
2858                                 (Gtk::ButtonsType)(Gtk::BUTTONS_NONE));
2859
2860         checker.set_secondary_text(_("Cleanup is a destructive operation.\n\
2861 ALL undo/redo information will be lost if you cleanup.\n\
2862 After cleanup, unused audio files will be moved to a \
2863 \"dead sounds\" location."));
2864
2865         checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
2866         checker.add_button (_("Clean Up"), RESPONSE_ACCEPT);
2867         checker.set_default_response (RESPONSE_CANCEL);
2868
2869         checker.set_name (_("CleanupDialog"));
2870         checker.set_wmclass (X_("ardour_cleanup"), "Ardour");
2871         checker.set_position (Gtk::WIN_POS_MOUSE);
2872
2873         switch (checker.run()) {
2874         case RESPONSE_ACCEPT:
2875                 break;
2876         default:
2877                 return;
2878         }
2879
2880         ARDOUR::CleanupReport rep;
2881
2882         editor->prepare_for_cleanup ();
2883
2884         /* do not allow flush until a session is reloaded */
2885
2886         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
2887         if (act) {
2888                 act->set_sensitive (false);
2889         }
2890
2891         if (_session->cleanup_sources (rep)) {
2892                 editor->finish_cleanup ();
2893                 return;
2894         }
2895
2896         editor->finish_cleanup ();
2897
2898         checker.hide();
2899         display_cleanup_results (rep,
2900                                  _("cleaned files"),
2901                                  _("\
2902 The following %1 files were not in use and \n\
2903 have been moved to:\n\
2904 %2. \n\n\
2905 Flushing the wastebasket will \n\
2906 release an additional\n\
2907 %3 %4bytes of disk space.\n"),
2908                                  _("\
2909 The following file was not in use and \n        \
2910 has been moved to:\n                            \
2911 %2. \n\n\
2912 Flushing the wastebasket will \n\
2913 release an additional\n\
2914 %3 %4bytes of disk space.\n"
2915                                          ));
2916
2917 }
2918
2919 void
2920 ARDOUR_UI::flush_trash ()
2921 {
2922         if (_session == 0) {
2923                 /* shouldn't happen: menu item is insensitive */
2924                 return;
2925         }
2926
2927         ARDOUR::CleanupReport rep;
2928
2929         if (_session->cleanup_trash_sources (rep)) {
2930                 return;
2931         }
2932
2933         display_cleanup_results (rep,
2934                                  _("deleted file"),
2935                                  _("The following %1 files were deleted from\n\
2936 %2,\n\
2937 releasing %3 %4bytes of disk space"),
2938                                  _("The following file was deleted from\n\
2939 %2,\n\
2940 releasing %3 %4bytes of disk space"));
2941 }
2942
2943 void
2944 ARDOUR_UI::add_route (Gtk::Window* float_window)
2945 {
2946         int count;
2947
2948         if (!_session) {
2949                 return;
2950         }
2951
2952         if (add_route_dialog == 0) {
2953                 add_route_dialog = new AddRouteDialog (_session);
2954                 if (float_window) {
2955                         add_route_dialog->set_transient_for (*float_window);
2956                 }
2957         }
2958
2959         if (add_route_dialog->is_visible()) {
2960                 /* we're already doing this */
2961                 return;
2962         }
2963
2964         ResponseType r = (ResponseType) add_route_dialog->run ();
2965
2966         add_route_dialog->hide();
2967
2968         switch (r) {
2969                 case RESPONSE_ACCEPT:
2970                         break;
2971                 default:
2972                         return;
2973                         break;
2974         }
2975
2976         if ((count = add_route_dialog->count()) <= 0) {
2977                 return;
2978         }
2979
2980         string template_path = add_route_dialog->track_template();
2981
2982         if (!template_path.empty()) {
2983                 _session->new_route_from_template (count, template_path);
2984                 return;
2985         }
2986
2987         uint32_t input_chan = add_route_dialog->channels ();
2988         uint32_t output_chan;
2989         string name_template = add_route_dialog->name_template ();
2990         bool track = add_route_dialog->track ();
2991         bool aux = !track && add_route_dialog->aux();
2992         RouteGroup* route_group = add_route_dialog->route_group ();
2993
2994         AutoConnectOption oac = Config->get_output_auto_connect();
2995
2996         if (oac & AutoConnectMaster) {
2997                 output_chan = (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan);
2998         } else {
2999                 output_chan = input_chan;
3000         }
3001
3002         /* XXX do something with name template */
3003
3004         if (add_route_dialog->type() == ARDOUR::DataType::MIDI) {
3005                 if (track) {
3006                         session_add_midi_track (route_group, count);
3007                 } else  {
3008                         MessageDialog msg (*editor,
3009                                         _("Sorry, MIDI Busses are not supported at this time."));
3010                         msg.run ();
3011                         //session_add_midi_bus();
3012                 }
3013         } else {
3014                 if (track) {
3015                         session_add_audio_track (input_chan, output_chan, add_route_dialog->mode(), route_group, count);
3016                 } else {
3017                         session_add_audio_bus (aux, input_chan, output_chan, route_group, count);
3018                 }
3019         }
3020 }
3021
3022 XMLNode*
3023 ARDOUR_UI::mixer_settings () const
3024 {
3025         XMLNode* node = 0;
3026
3027         if (_session) {
3028                 node = _session->instant_xml(X_("Mixer"));
3029         } else {
3030                 node = Config->instant_xml(X_("Mixer"));
3031         }
3032
3033         if (!node) {
3034                 node = new XMLNode (X_("Mixer"));
3035         }
3036
3037         return node;
3038 }
3039
3040 XMLNode*
3041 ARDOUR_UI::editor_settings () const
3042 {
3043         XMLNode* node = 0;
3044
3045         if (_session) {
3046                 node = _session->instant_xml(X_("Editor"));
3047         } else {
3048                 node = Config->instant_xml(X_("Editor"));
3049         }
3050
3051         if (!node) {
3052                 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
3053                         node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
3054                 }
3055         }
3056
3057         if (!node) {
3058                 node = new XMLNode (X_("Editor"));
3059         }
3060
3061         return node;
3062 }
3063
3064 XMLNode*
3065 ARDOUR_UI::keyboard_settings () const
3066 {
3067         XMLNode* node = 0;
3068
3069         node = Config->extra_xml(X_("Keyboard"));
3070
3071         if (!node) {
3072                 node = new XMLNode (X_("Keyboard"));
3073         }
3074         return node;
3075 }
3076
3077 void
3078 ARDOUR_UI::create_xrun_marker(nframes_t where)
3079 {
3080         editor->mouse_add_new_marker (where, false, true);
3081 }
3082
3083 void
3084 ARDOUR_UI::halt_on_xrun_message ()
3085 {
3086         MessageDialog msg (*editor,
3087                            _("Recording was stopped because your system could not keep up."));
3088         msg.run ();
3089 }
3090
3091 void
3092 ARDOUR_UI::xrun_handler(nframes_t where)
3093 {
3094         if (!_session) {
3095                 return;
3096         }
3097
3098         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
3099
3100         if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
3101                 create_xrun_marker(where);
3102         }
3103
3104         if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
3105                 halt_on_xrun_message ();
3106         }
3107 }
3108
3109 void
3110 ARDOUR_UI::push_buffer_stats (uint32_t capture, uint32_t playback)
3111 {
3112         time_t now;
3113         time (&now);
3114
3115         while (disk_buffer_stats.size() > 60) {
3116                 disk_buffer_stats.pop_front ();
3117         }
3118
3119         disk_buffer_stats.push_back (DiskBufferStat (now, capture, playback));
3120 }
3121
3122 void
3123 ARDOUR_UI::write_buffer_stats ()
3124 {
3125         std::ofstream fout;
3126         struct tm tm;
3127         char buf[64];
3128         char path[PATH_MAX+1];  int fd;
3129
3130         strcpy (path, "ardourBufferingXXXXXX");
3131
3132         if ((fd = mkstemp (path )) < 0) {
3133                 cerr << X_("cannot find temporary name for buffer stats") << endl;
3134                 return;
3135         }
3136         
3137         fout.open (path);
3138         close (fd);
3139
3140         if (!fout) {
3141                 cerr << string_compose (X_("cannot open file %1 for buffer stats"), path) << endl;
3142                 return;
3143         }
3144
3145         for (list<DiskBufferStat>::iterator i = disk_buffer_stats.begin(); i != disk_buffer_stats.end(); ++i) {
3146                 localtime_r (&(*i).when, &tm);
3147                 strftime (buf, sizeof (buf), "%T", &tm);
3148                 fout << buf << ' ' << (*i).capture << ' ' << (*i).playback << endl;
3149         }
3150         
3151         disk_buffer_stats.clear ();
3152
3153         fout.close ();
3154
3155         cerr << "buffering statistics can be found in: " << path << endl;
3156 }
3157
3158 void
3159 ARDOUR_UI::disk_overrun_handler ()
3160 {
3161         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
3162
3163         write_buffer_stats ();
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 write data to disk\n\
3172 quickly enough to keep up with recording.\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_underrun_handler ()
3180 {
3181         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
3182
3183         write_buffer_stats ();
3184
3185         if (!have_disk_speed_dialog_displayed) {
3186                 have_disk_speed_dialog_displayed = true;
3187                 MessageDialog* msg = new MessageDialog (*editor,
3188                                    _("The disk system on your computer\n\
3189 was not able to keep up with Ardour.\n\
3190 \n\
3191 Specifically, it failed to read data from disk\n\
3192 quickly enough to keep up with playback.\n"));
3193                 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3194                 msg->show ();
3195         }
3196 }
3197
3198 void
3199 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
3200 {
3201         have_disk_speed_dialog_displayed = false;
3202         delete msg;
3203 }
3204
3205 void
3206 ARDOUR_UI::session_dialog (std::string msg)
3207 {
3208         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
3209
3210         MessageDialog* d;
3211
3212         if (editor) {
3213                 d = new MessageDialog (*editor, msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3214         } else {
3215                 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3216         }
3217
3218         d->show_all ();
3219         d->run ();
3220         delete d;
3221 }
3222
3223 int
3224 ARDOUR_UI::pending_state_dialog ()
3225 {
3226         HBox* hbox = new HBox();
3227         Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3228         ArdourDialog dialog (_("Crash Recovery"), true);
3229         Label  message (_("\
3230 This session appears to have been in\n\
3231 middle of recording when ardour or\n\
3232 the computer was shutdown.\n\
3233 \n\
3234 Ardour can recover any captured audio for\n\
3235 you, or it can ignore it. Please decide\n\
3236 what you would like to do.\n"));
3237         image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3238         hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3239         hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3240         dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3241         dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
3242         dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
3243         dialog.set_default_response (RESPONSE_ACCEPT);
3244         dialog.set_position (WIN_POS_CENTER);
3245         message.show();
3246         image->show();
3247         hbox->show();
3248
3249         switch (dialog.run ()) {
3250         case RESPONSE_ACCEPT:
3251                 return 1;
3252         default:
3253                 return 0;
3254         }
3255 }
3256
3257 int
3258 ARDOUR_UI::sr_mismatch_dialog (nframes_t desired, nframes_t actual)
3259 {
3260         HBox* hbox = new HBox();
3261         Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3262         ArdourDialog dialog (_("Sample Rate Mismatch"), true);
3263         Label  message (string_compose (_("\
3264 This session was created with a sample rate of %1 Hz\n\
3265 \n\
3266 The audioengine is currently running at %2 Hz\n"), desired, actual));
3267
3268         image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3269         hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3270         hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3271         dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3272         dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
3273         dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
3274         dialog.set_default_response (RESPONSE_ACCEPT);
3275         dialog.set_position (WIN_POS_CENTER);
3276         message.show();
3277         image->show();
3278         hbox->show();
3279
3280         switch (dialog.run ()) {
3281         case RESPONSE_ACCEPT:
3282                 return 0;
3283         default:
3284                 return 1;
3285         }
3286 }
3287
3288
3289 void
3290 ARDOUR_UI::disconnect_from_jack ()
3291 {
3292         if (engine) {
3293                 if( engine->disconnect_from_jack ()) {
3294                         MessageDialog msg (*editor, _("Could not disconnect from JACK"));
3295                         msg.run ();
3296                 }
3297
3298                 update_sample_rate (0);
3299         }
3300 }
3301
3302 void
3303 ARDOUR_UI::reconnect_to_jack ()
3304 {
3305         if (engine) {
3306                 if (engine->reconnect_to_jack ()) {
3307                         MessageDialog msg (*editor,  _("Could not reconnect to JACK"));
3308                         msg.run ();
3309                 }
3310
3311                 update_sample_rate (0);
3312         }
3313 }
3314
3315 void
3316 ARDOUR_UI::use_config ()
3317 {
3318
3319         XMLNode* node = Config->extra_xml (X_("TransportControllables"));
3320         if (node) {
3321                 set_transport_controllable_state (*node);
3322         }
3323
3324         node = Config->extra_xml (X_("UI"));
3325
3326         if (node) {
3327                 const XMLProperty* prop = node->property (X_("show-big-clock"));
3328                 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleBigClock"));
3329                 if (act) {
3330                         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
3331                         tact->set_active (string_is_affirmative (prop->value()));
3332                 }
3333         }
3334 }
3335
3336 void
3337 ARDOUR_UI::update_transport_clocks (nframes_t pos)
3338 {
3339         if (Config->get_primary_clock_delta_edit_cursor()) {
3340                 primary_clock.set (pos, false, editor->get_preferred_edit_position(), 1);
3341         } else {
3342                 primary_clock.set (pos, 0, true);
3343         }
3344
3345         if (Config->get_secondary_clock_delta_edit_cursor()) {
3346                 secondary_clock.set (pos, false, editor->get_preferred_edit_position(), 2);
3347         } else {
3348                 secondary_clock.set (pos);
3349         }
3350
3351         if (big_clock_window) {
3352                 big_clock.set (pos);
3353         }
3354 }
3355
3356 void
3357 ARDOUR_UI::record_state_changed ()
3358 {
3359         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
3360
3361         if (!_session || !big_clock_window) {
3362                 /* why bother - the clock isn't visible */
3363                 return;
3364         }
3365
3366         Session::RecordState const r = _session->record_status ();
3367         bool const h = _session->have_rec_enabled_diskstream ();
3368
3369         if (r == Session::Recording && h)  {
3370                 big_clock.set_widget_name ("BigClockRecording");
3371         } else {
3372                 big_clock.set_widget_name ("BigClockNonRecording");
3373         }
3374 }
3375
3376 bool
3377 ARDOUR_UI::first_idle ()
3378 {
3379         if (_session) {
3380                 _session->allow_auto_play (true);
3381         }
3382
3383         if (editor) {
3384                 editor->first_idle();
3385         }
3386
3387         Keyboard::set_can_save_keybindings (true);
3388         return false;
3389 }
3390
3391 void
3392 ARDOUR_UI::store_clock_modes ()
3393 {
3394         XMLNode* node = new XMLNode(X_("ClockModes"));
3395
3396         for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
3397                 node->add_property ((*x)->name().c_str(), enum_2_string ((*x)->mode()));
3398         }
3399
3400         _session->add_extra_xml (*node);
3401         _session->set_dirty ();
3402 }
3403
3404
3405
3406 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
3407         : Controllable (name), ui (u), type(tp)
3408 {
3409
3410 }
3411
3412 void
3413 ARDOUR_UI::TransportControllable::set_value (float val)
3414 {
3415         if (type == ShuttleControl) {
3416                 double fract;
3417
3418                 if (val == 0.5f) {
3419                         fract = 0.0;
3420                 } else {
3421                         if (val < 0.5f) {
3422                                 fract = -((0.5f - val)/0.5f);
3423                         } else {
3424                                 fract = ((val - 0.5f)/0.5f);
3425                         }
3426                 }
3427
3428                 ui.set_shuttle_fract (fract);
3429                 return;
3430         }
3431
3432         if (val < 0.5f) {
3433                 /* do nothing: these are radio-style actions */
3434                 return;
3435         }
3436
3437         const char *action = 0;
3438
3439         switch (type) {
3440         case Roll:
3441                 action = X_("Roll");
3442                 break;
3443         case Stop:
3444                 action = X_("Stop");
3445                 break;
3446         case GotoStart:
3447                 action = X_("Goto Start");
3448                 break;
3449         case GotoEnd:
3450                 action = X_("Goto End");
3451                 break;
3452         case AutoLoop:
3453                 action = X_("Loop");
3454                 break;
3455         case PlaySelection:
3456                 action = X_("Play Selection");
3457                 break;
3458         case RecordEnable:
3459                 action = X_("Record");
3460                 break;
3461         default:
3462                 break;
3463         }
3464
3465         if (action == 0) {
3466                 return;
3467         }
3468
3469         Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
3470
3471         if (act) {
3472                 act->activate ();
3473         }
3474 }
3475
3476 float
3477 ARDOUR_UI::TransportControllable::get_value (void) const
3478 {
3479         float val = 0.0f;
3480
3481         switch (type) {
3482         case Roll:
3483                 break;
3484         case Stop:
3485                 break;
3486         case GotoStart:
3487                 break;
3488         case GotoEnd:
3489                 break;
3490         case AutoLoop:
3491                 break;
3492         case PlaySelection:
3493                 break;
3494         case RecordEnable:
3495                 break;
3496         case ShuttleControl:
3497                 break;
3498         default:
3499                 break;
3500         }
3501
3502         return val;
3503 }
3504
3505 void
3506 ARDOUR_UI::TransportControllable::set_id (const string& str)
3507 {
3508         _id = str;
3509 }
3510
3511 void
3512 ARDOUR_UI::setup_profile ()
3513 {
3514         if (gdk_screen_width() < 1200) {
3515                 Profile->set_small_screen ();
3516         }
3517
3518
3519         if (getenv ("ARDOUR_SAE")) {
3520                 Profile->set_sae ();
3521                 Profile->set_single_package ();
3522         }
3523 }
3524