a6236b2038f5099d0a5a92f91a663caad7190211
[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, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
244         ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
245
246         /* handle dialog requests */
247
248         ARDOUR::Session::Dialog.connect (forever_connections, 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);
332
333         } catch (...) {
334
335                 return -1;
336         }
337
338         engine->Stopped.connect (forever_connections, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
339         engine->Running.connect (forever_connections, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
340         engine->Halted.connect (forever_connections, boost::bind (&ARDOUR_UI::engine_halted, this), gui_context());
341         engine->SampleRateChanged.connect (forever_connections, 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, 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 #if CONTROLOUTS
1328                 if (need_control_room_outs) {
1329                         pan_t pans[2];
1330
1331                         pans[0] = 0.5;
1332                         pans[1] = 0.5;
1333
1334                         route->set_stereo_control_outs (control_lr_channels);
1335                         route->control_outs()->set_stereo_pan (pans, this);
1336                 }
1337 #endif /* CONTROLOUTS */
1338         }
1339
1340         catch (...) {
1341                 MessageDialog msg (*editor,
1342                                    _("There are insufficient JACK ports available\n\
1343 to create a new track or bus.\n\
1344 You should save Ardour, exit and\n\
1345 restart JACK with more ports."));
1346                 pop_back_splash ();
1347                 msg.run ();
1348         }
1349 }
1350
1351 void
1352 ARDOUR_UI::do_transport_locate (nframes_t new_position)
1353 {
1354         nframes_t _preroll = 0;
1355
1356         if (_session) {
1357                 // XXX CONFIG_CHANGE FIX - requires AnyTime handling
1358                 // _preroll = _session->convert_to_frames_at (new_position, Config->get_preroll());
1359
1360                 if (new_position > _preroll) {
1361                         new_position -= _preroll;
1362                 } else {
1363                         new_position = 0;
1364                 }
1365
1366                 _session->request_locate (new_position);
1367         }
1368 }
1369
1370 void
1371 ARDOUR_UI::transport_goto_start ()
1372 {
1373         if (_session) {
1374                 _session->goto_start();
1375
1376                 /* force displayed area in editor to start no matter
1377                    what "follow playhead" setting is.
1378                 */
1379
1380                 if (editor) {
1381                         editor->center_screen (_session->current_start_frame ());
1382                 }
1383         }
1384 }
1385
1386 void
1387 ARDOUR_UI::transport_goto_zero ()
1388 {
1389         if (_session) {
1390                 _session->request_locate (0);
1391
1392                 /* force displayed area in editor to start no matter
1393                    what "follow playhead" setting is.
1394                 */
1395
1396                 if (editor) {
1397                         editor->reset_x_origin (0);
1398                 }
1399         }
1400 }
1401
1402 void
1403 ARDOUR_UI::transport_goto_wallclock ()
1404 {
1405         if (_session && editor) {
1406
1407                 time_t now;
1408                 struct tm tmnow;
1409                 nframes64_t frames;
1410
1411                 time (&now);
1412                 localtime_r (&now, &tmnow);
1413
1414                 frames = tmnow.tm_hour * (60 * 60 * _session->frame_rate());
1415                 frames += tmnow.tm_min * (60 * _session->frame_rate());
1416                 frames += tmnow.tm_sec * _session->frame_rate();
1417
1418                 _session->request_locate (frames);
1419
1420                 /* force displayed area in editor to start no matter
1421                    what "follow playhead" setting is.
1422                 */
1423
1424                 if (editor) {
1425                         editor->center_screen (frames);
1426                 }
1427         }
1428 }
1429
1430 void
1431 ARDOUR_UI::transport_goto_end ()
1432 {
1433         if (_session) {
1434                 nframes_t const frame = _session->current_end_frame();
1435                 _session->request_locate (frame);
1436
1437                 /* force displayed area in editor to start no matter
1438                    what "follow playhead" setting is.
1439                 */
1440
1441                 if (editor) {
1442                         editor->center_screen (frame);
1443                 }
1444         }
1445 }
1446
1447 void
1448 ARDOUR_UI::transport_stop ()
1449 {
1450         if (!_session) {
1451                 return;
1452         }
1453
1454         if (_session->is_auditioning()) {
1455                 _session->cancel_audition ();
1456                 return;
1457         }
1458
1459         _session->request_stop ();
1460 }
1461
1462 void
1463 ARDOUR_UI::transport_stop_and_forget_capture ()
1464 {
1465         if (_session) {
1466                 _session->request_stop (true);
1467         }
1468 }
1469
1470 void
1471 ARDOUR_UI::remove_last_capture()
1472 {
1473         if (editor) {
1474                 editor->remove_last_capture();
1475         }
1476 }
1477
1478 void
1479 ARDOUR_UI::transport_record (bool roll)
1480 {
1481
1482         if (_session) {
1483                 switch (_session->record_status()) {
1484                 case Session::Disabled:
1485                         if (_session->ntracks() == 0) {
1486                                 MessageDialog msg (*editor, _("Please create 1 or more track\nbefore trying to record.\nCheck the Session menu."));
1487                                 msg.run ();
1488                                 return;
1489                         }
1490                         _session->maybe_enable_record ();
1491                         if (roll) {
1492                                 transport_roll ();
1493                         }
1494                         break;
1495                 case Session::Recording:
1496                         if (roll) {
1497                                 _session->request_stop();
1498                         } else {
1499                                 _session->disable_record (false, true);
1500                         }
1501                         break;
1502
1503                 case Session::Enabled:
1504                         _session->disable_record (false, true);
1505                 }
1506         }
1507         //cerr << "ARDOUR_UI::transport_record () called roll = " << roll << " _session->record_status() = " << _session->record_status() << endl;
1508 }
1509
1510 void 
1511 ARDOUR_UI::transport_roll ()
1512 {
1513         if (!_session) {
1514                 return;
1515         }
1516
1517         if (_session->is_auditioning()) {
1518                 return;
1519         }
1520         
1521         if (_session->config.get_external_sync()) {
1522                 switch (_session->config.get_sync_source()) {
1523                 case JACK:
1524                         break;
1525                 default:
1526                         /* transport controlled by the master */
1527                         return;
1528                 }
1529         }
1530
1531         bool rolling = _session->transport_rolling();
1532
1533         if (_session->get_play_loop()) {
1534                 _session->request_play_loop (false, true);
1535         } else if (_session->get_play_range () && !join_play_range_button.get_active()) {
1536                 /* stop playing a range if we currently are */
1537                 _session->request_play_range (0, true);
1538         }
1539
1540         if (join_play_range_button.get_active()) {
1541                 _session->request_play_range (&editor->get_selection().time, true);
1542         }
1543
1544         if (!rolling) {
1545                 _session->request_transport_speed (1.0f);
1546         }
1547
1548         map_transport_state ();
1549 }
1550
1551 void
1552 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
1553 {
1554         
1555         if (!_session) {
1556                 return;
1557         }
1558
1559         if (_session->is_auditioning()) {
1560                 _session->cancel_audition ();
1561                 return;
1562         }
1563         
1564         if (_session->config.get_external_sync()) {
1565                 switch (_session->config.get_sync_source()) {
1566                 case JACK:
1567                         break;
1568                 default:
1569                         /* transport controlled by the master */
1570                         return;
1571                 }
1572         }
1573
1574         bool rolling = _session->transport_rolling();
1575         bool affect_transport = true;
1576
1577         if (rolling && roll_out_of_bounded_mode) {
1578                 /* drop out of loop/range playback but leave transport rolling */
1579                 if (_session->get_play_loop()) {
1580                         if (Config->get_seamless_loop()) {
1581                                 /* the disk buffers contain copies of the loop - we can't 
1582                                    just keep playing, so stop the transport. the user
1583                                    can restart as they wish.
1584                                 */
1585                                 affect_transport = true;
1586                         } else {
1587                                 /* disk buffers are normal, so we can keep playing */
1588                                 affect_transport = false;
1589                         }
1590                         _session->request_play_loop (false, true);
1591                 } else if (_session->get_play_range ()) {
1592                         affect_transport = false;
1593                         _session->request_play_range (0, true);
1594                 } 
1595         } 
1596
1597         if (affect_transport) {
1598                 if (rolling) {
1599                         _session->request_stop (with_abort, true);
1600                 } else {
1601                         if (join_play_range_button.get_active()) {
1602                                 _session->request_play_range (&editor->get_selection().time, true);
1603                         }
1604                         
1605                         _session->request_transport_speed (1.0f);
1606                 }
1607         }
1608
1609         map_transport_state (); 
1610 }
1611
1612 void
1613 ARDOUR_UI::toggle_session_auto_loop ()
1614 {
1615         if (_session) {
1616                 if (_session->get_play_loop()) {
1617                         if (_session->transport_rolling()) {
1618                                 Location * looploc = _session->locations()->auto_loop_location();
1619                                 if (looploc) {
1620                                         _session->request_locate (looploc->start(), true);
1621                                 }
1622                         } else {
1623                                 _session->request_play_loop (false);
1624                         }
1625                 } else {
1626                         Location * looploc = _session->locations()->auto_loop_location();
1627                         if (looploc) {
1628                                 _session->request_play_loop (true);
1629                         }
1630                 }
1631         }
1632 }
1633
1634 void
1635 ARDOUR_UI::transport_play_selection ()
1636 {
1637         if (!_session) {
1638                 return;
1639         }
1640
1641         editor->play_selection ();
1642 }
1643
1644 void
1645 ARDOUR_UI::transport_rewind (int option)
1646 {
1647         float current_transport_speed;
1648
1649         if (_session) {
1650                 current_transport_speed = _session->transport_speed();
1651
1652                 if (current_transport_speed >= 0.0f) {
1653                         switch (option) {
1654                         case 0:
1655                                 _session->request_transport_speed (-1.0f);
1656                                 break;
1657                         case 1:
1658                                 _session->request_transport_speed (-4.0f);
1659                                 break;
1660                         case -1:
1661                                 _session->request_transport_speed (-0.5f);
1662                                 break;
1663                         }
1664                 } else {
1665                         /* speed up */
1666                         _session->request_transport_speed (current_transport_speed * 1.5f);
1667                 }
1668         }
1669 }
1670
1671 void
1672 ARDOUR_UI::transport_forward (int option)
1673 {
1674         float current_transport_speed;
1675
1676         if (_session) {
1677                 current_transport_speed = _session->transport_speed();
1678
1679                 if (current_transport_speed <= 0.0f) {
1680                         switch (option) {
1681                         case 0:
1682                                 _session->request_transport_speed (1.0f);
1683                                 break;
1684                         case 1:
1685                                 _session->request_transport_speed (4.0f);
1686                                 break;
1687                         case -1:
1688                                 _session->request_transport_speed (0.5f);
1689                                 break;
1690                         }
1691                 } else {
1692                         /* speed up */
1693                         _session->request_transport_speed (current_transport_speed * 1.5f);
1694                 }
1695
1696         }
1697 }
1698
1699 void
1700 ARDOUR_UI::toggle_record_enable (uint32_t dstream)
1701 {
1702         if (_session == 0) {
1703                 return;
1704         }
1705
1706         boost::shared_ptr<Route> r;
1707
1708         if ((r = _session->route_by_remote_id (dstream)) != 0) {
1709
1710                 Track* t;
1711
1712                 if ((t = dynamic_cast<Track*>(r.get())) != 0) {
1713                         t->diskstream()->set_record_enabled (!t->diskstream()->record_enabled());
1714                 }
1715         }
1716         if (_session == 0) {
1717                 return;
1718         }
1719 }
1720
1721 void
1722 ARDOUR_UI::map_transport_state ()
1723 {
1724         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::map_transport_state)
1725
1726         if (!_session) {
1727                 auto_loop_button.set_visual_state (0);
1728                 play_selection_button.set_visual_state (0);
1729                 roll_button.set_visual_state (0);
1730                 stop_button.set_visual_state (1);
1731                 return;
1732         }
1733
1734         float sp = _session->transport_speed();
1735
1736         if (sp == 1.0f) {
1737                 shuttle_fract = SHUTTLE_FRACT_SPEED1;  /* speed = 1.0, believe it or not */
1738                 shuttle_box.queue_draw ();
1739         } else if (sp == 0.0f) {
1740                 shuttle_fract = 0;
1741                 shuttle_box.queue_draw ();
1742                 update_disk_space ();
1743         }
1744
1745         if (sp != 0.0) {
1746
1747                 /* we're rolling */
1748
1749                 if (_session->get_play_range()) {
1750
1751                         play_selection_button.set_visual_state (1);
1752                         roll_button.set_visual_state (0);
1753                         auto_loop_button.set_visual_state (0);
1754
1755                 } else if (_session->get_play_loop ()) {
1756                         
1757                         auto_loop_button.set_visual_state (1);
1758                         play_selection_button.set_visual_state (0);
1759                         roll_button.set_visual_state (0);
1760
1761                 } else {
1762                         
1763                         roll_button.set_visual_state (1);
1764                         play_selection_button.set_visual_state (0);
1765                         auto_loop_button.set_visual_state (0);
1766                 }
1767
1768                 if (join_play_range_button.get_active()) {
1769                         /* light up both roll and play-selection if they are joined */
1770                         roll_button.set_visual_state (1);
1771                         play_selection_button.set_visual_state (1);
1772                 }
1773
1774                 stop_button.set_visual_state (0);
1775
1776         } else {
1777
1778                 stop_button.set_visual_state (1);
1779                 roll_button.set_visual_state (0);
1780                 play_selection_button.set_visual_state (0);
1781                 auto_loop_button.set_visual_state (0);
1782         }
1783
1784 }
1785
1786 void
1787 ARDOUR_UI::engine_stopped ()
1788 {
1789         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
1790         ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1791         ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1792 }
1793
1794 void
1795 ARDOUR_UI::engine_running ()
1796 {
1797         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
1798         ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, true);
1799         ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, false);
1800
1801         Glib::RefPtr<Action> action;
1802         const char* action_name = 0;
1803
1804         switch (engine->frames_per_cycle()) {
1805         case 32:
1806                 action_name = X_("JACKLatency32");
1807                 break;
1808         case 64:
1809                 action_name = X_("JACKLatency64");
1810                 break;
1811         case 128:
1812                 action_name = X_("JACKLatency128");
1813                 break;
1814         case 512:
1815                 action_name = X_("JACKLatency512");
1816                 break;
1817         case 1024:
1818                 action_name = X_("JACKLatency1024");
1819                 break;
1820         case 2048:
1821                 action_name = X_("JACKLatency2048");
1822                 break;
1823         case 4096:
1824                 action_name = X_("JACKLatency4096");
1825                 break;
1826         case 8192:
1827                 action_name = X_("JACKLatency8192");
1828                 break;
1829         default:
1830                 /* XXX can we do anything useful ? */
1831                 break;
1832         }
1833
1834         if (action_name) {
1835
1836                 action = ActionManager::get_action (X_("JACK"), action_name);
1837
1838                 if (action) {
1839                         Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (action);
1840                         ract->set_active ();
1841                 }
1842         }
1843 }
1844
1845 void
1846 ARDOUR_UI::engine_halted ()
1847 {
1848         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_halted)
1849
1850         ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1851         ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1852
1853         update_sample_rate (0);
1854
1855         MessageDialog msg (*editor,
1856                            _("\
1857 JACK has either been shutdown or it\n\
1858 disconnected Ardour because Ardour\n\
1859 was not fast enough. Try to restart\n\
1860 JACK, reconnect and save the session."));
1861         pop_back_splash ();
1862         msg.run ();
1863 }
1864
1865 int32_t
1866 ARDOUR_UI::do_engine_start ()
1867 {
1868         try {
1869                 engine->start();
1870         }
1871
1872         catch (...) {
1873                 engine->stop ();
1874                 error << _("Unable to start the session running")
1875                       << endmsg;
1876                 unload_session ();
1877                 return -2;
1878         }
1879
1880         return 0;
1881 }
1882
1883 void
1884 ARDOUR_UI::setup_theme ()
1885 {
1886         theme_manager->setup_theme();
1887 }
1888
1889 void
1890 ARDOUR_UI::update_clocks ()
1891 {
1892         if (!editor || !editor->dragging_playhead()) {
1893                 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position()); /* EMIT_SIGNAL */
1894         }
1895 }
1896
1897 void
1898 ARDOUR_UI::start_clocking ()
1899 {
1900         clock_signal_connection = RapidScreenUpdate.connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
1901 }
1902
1903 void
1904 ARDOUR_UI::stop_clocking ()
1905 {
1906         clock_signal_connection.disconnect ();
1907 }
1908
1909 void
1910 ARDOUR_UI::toggle_clocking ()
1911 {
1912 #if 0
1913         if (clock_button.get_active()) {
1914                 start_clocking ();
1915         } else {
1916                 stop_clocking ();
1917         }
1918 #endif
1919 }
1920
1921 gint
1922 ARDOUR_UI::_blink (void *arg)
1923
1924 {
1925         ((ARDOUR_UI *) arg)->blink ();
1926         return TRUE;
1927 }
1928
1929 void
1930 ARDOUR_UI::blink ()
1931 {
1932         Blink (blink_on = !blink_on); /* EMIT_SIGNAL */
1933 }
1934
1935 void
1936 ARDOUR_UI::start_blinking ()
1937 {
1938         /* Start the blink signal. Everybody with a blinking widget
1939            uses Blink to drive the widget's state.
1940         */
1941
1942         if (blink_timeout_tag < 0) {
1943                 blink_on = false;
1944                 blink_timeout_tag = g_timeout_add (240, _blink, this);
1945         }
1946 }
1947
1948 void
1949 ARDOUR_UI::stop_blinking ()
1950 {
1951         if (blink_timeout_tag >= 0) {
1952                 g_source_remove (blink_timeout_tag);
1953                 blink_timeout_tag = -1;
1954         }
1955 }
1956
1957
1958 /** Ask the user for the name of a new shapshot and then take it.
1959  */
1960 void
1961 ARDOUR_UI::snapshot_session ()
1962 {
1963         ArdourPrompter prompter (true);
1964         string snapname;
1965         char timebuf[128];
1966         time_t n;
1967         struct tm local_time;
1968
1969         time (&n);
1970         localtime_r (&n, &local_time);
1971         strftime (timebuf, sizeof(timebuf), "%FT%T", &local_time);
1972
1973         prompter.set_name ("Prompter");
1974         prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1975         prompter.set_title (_("Take Snapshot"));
1976         prompter.set_prompt (_("Name of New Snapshot"));
1977         prompter.set_initial_text (timebuf);
1978
1979   again:
1980         switch (prompter.run()) {
1981         case RESPONSE_ACCEPT:
1982         {
1983                 prompter.get_result (snapname);
1984
1985                 bool do_save = (snapname.length() != 0);
1986
1987                 if (do_save) {
1988                         if (snapname.find ('/') != string::npos) {
1989                                 MessageDialog msg (_("To ensure compatibility with various systems\n"
1990                                                      "snapshot names may not contain a '/' character"));
1991                                 msg.run ();
1992                                 goto again;
1993                         }
1994                         if (snapname.find ('\\') != string::npos) {
1995                                 MessageDialog msg (_("To ensure compatibility with various systems\n"
1996                                                      "snapshot names may not contain a '\\' character"));
1997                                 msg.run ();
1998                                 goto again;
1999                         }
2000                 }
2001
2002                 vector<sys::path> p;
2003                 get_state_files_in_directory (_session->session_directory().root_path(), p);
2004                 vector<string> n = get_file_names_no_extension (p);
2005                 if (find (n.begin(), n.end(), snapname) != n.end()) {
2006
2007                         ArdourDialog confirm (_("Confirm snapshot overwrite"), true);
2008                         Label m (_("A snapshot already exists with that name.  Do you want to overwrite it?"));
2009                         confirm.get_vbox()->pack_start (m, true, true);
2010                         confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2011                         confirm.add_button (_("Overwrite"), Gtk::RESPONSE_ACCEPT);
2012                         confirm.show_all ();
2013                         switch (confirm.run()) {
2014                         case RESPONSE_CANCEL:
2015                                 do_save = false;
2016                         }
2017                 }
2018
2019                 if (do_save) {
2020                         save_state (snapname);
2021                 }
2022                 break;
2023         }
2024
2025         default:
2026                 break;
2027         }
2028 }
2029
2030 void
2031 ARDOUR_UI::save_state (const string & name)
2032 {
2033         save_state_canfail (name);
2034 }
2035
2036 int
2037 ARDOUR_UI::save_state_canfail (string name)
2038 {
2039         if (_session) {
2040                 int ret;
2041
2042                 if (name.length() == 0) {
2043                         name = _session->snap_name();
2044                 }
2045
2046                 if ((ret = _session->save_state (name)) != 0) {
2047                         return ret;
2048                 }
2049         }
2050         cerr << "SS canfail\n";
2051         save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2052         return 0;
2053 }
2054
2055 void
2056 ARDOUR_UI::primary_clock_value_changed ()
2057 {
2058         if (_session) {
2059                 _session->request_locate (primary_clock.current_time ());
2060         }
2061 }
2062
2063 void
2064 ARDOUR_UI::big_clock_value_changed ()
2065 {
2066         if (_session) {
2067                 _session->request_locate (big_clock.current_time ());
2068         }
2069 }
2070
2071 void
2072 ARDOUR_UI::secondary_clock_value_changed ()
2073 {
2074         if (_session) {
2075                 _session->request_locate (secondary_clock.current_time ());
2076         }
2077 }
2078
2079 void
2080 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2081 {
2082         if (_session == 0) {
2083                 return;
2084         }
2085
2086         Session::RecordState const r = _session->record_status ();
2087         bool const h = _session->have_rec_enabled_diskstream ();
2088
2089         if (r == Session::Enabled || (r == Session::Recording && !h)) {
2090                 if (onoff) {
2091                         rec_button.set_visual_state (2);
2092                 } else {
2093                         rec_button.set_visual_state (0);
2094                 }
2095         } else if (r == Session::Recording && h) {
2096                 rec_button.set_visual_state (1);
2097         } else {
2098                 rec_button.set_visual_state (0);
2099         }
2100 }
2101
2102 void
2103 ARDOUR_UI::save_template ()
2104 {
2105         ArdourPrompter prompter (true);
2106         string name;
2107
2108         if (!check_audioengine()) {
2109                 return;
2110         }
2111
2112         prompter.set_name (X_("Prompter"));
2113         prompter.set_title (_("Save Mix Template"));
2114         prompter.set_prompt (_("Name for mix template:"));
2115         prompter.set_initial_text(_session->name() + _("-template"));
2116         prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2117
2118         switch (prompter.run()) {
2119         case RESPONSE_ACCEPT:
2120                 prompter.get_result (name);
2121
2122                 if (name.length()) {
2123                         _session->save_template (name);
2124                 }
2125                 break;
2126
2127         default:
2128                 break;
2129         }
2130 }
2131
2132 void
2133 ARDOUR_UI::edit_metadata ()
2134 {
2135         SessionMetadataEditor dialog;
2136         dialog.set_session (_session);
2137         editor->ensure_float (dialog);
2138         dialog.run ();
2139 }
2140
2141 void
2142 ARDOUR_UI::import_metadata ()
2143 {
2144         SessionMetadataImporter dialog;
2145         dialog.set_session (_session);
2146         editor->ensure_float (dialog);
2147         dialog.run ();
2148 }
2149
2150 void
2151 ARDOUR_UI::fontconfig_dialog ()
2152 {
2153 #ifdef GTKOSX
2154         /* X11 users will always have fontconfig info around, but new GTK-OSX users
2155            may not and it can take a while to build it. Warn them.
2156         */
2157
2158         Glib::ustring fontconfig = Glib::build_filename (Glib::get_home_dir(), ".fontconfig");
2159
2160         if (!Glib::file_test (fontconfig, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_DIR)) {
2161                 MessageDialog msg (*_startup,
2162                                    _("Welcome to Ardour.\n\n"
2163                                      "The program will take a bit longer to start up\n"
2164                                      "while the system fonts are checked.\n\n"
2165                                      "This will only be done once, and you will\n"
2166                                      "not see this message again\n"),
2167                                    true,
2168                                    Gtk::MESSAGE_INFO,
2169                                    Gtk::BUTTONS_OK);
2170                 pop_back_splash ();
2171                 msg.show_all ();
2172                 msg.present ();
2173                 msg.run ();
2174         }
2175 #endif
2176 }
2177
2178 void
2179 ARDOUR_UI::parse_cmdline_path (const Glib::ustring& cmdline_path, Glib::ustring& session_name, Glib::ustring& session_path, bool& existing_session)
2180 {
2181         existing_session = false;
2182
2183         if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_DIR)) {
2184                 session_path = cmdline_path;
2185                 existing_session = true;
2186         } else if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_REGULAR)) {
2187                 session_path = Glib::path_get_dirname (string (cmdline_path));
2188                 existing_session = true;
2189         } else {
2190                 /* it doesn't exist, assume the best */
2191                 session_path = Glib::path_get_dirname (string (cmdline_path));
2192         }
2193
2194         session_name = basename_nosuffix (string (cmdline_path));
2195 }
2196
2197 int
2198 ARDOUR_UI::load_cmdline_session (const Glib::ustring& session_name, const Glib::ustring& session_path, bool& existing_session)
2199 {
2200         /* when this is called, the backend audio system must be running */
2201
2202         /* the main idea here is to deal with the fact that a cmdline argument for the session
2203            can be interpreted in different ways - it could be a directory or a file, and before
2204            we load, we need to know both the session directory and the snapshot (statefile) within it
2205            that we are supposed to use.
2206         */
2207
2208         if (session_name.length() == 0 || session_path.length() == 0) {
2209                 return false;
2210         }
2211
2212         if (Glib::file_test (session_path, Glib::FILE_TEST_IS_DIR)) {
2213
2214                 Glib::ustring predicted_session_file;
2215
2216                 predicted_session_file = session_path;
2217                 predicted_session_file += '/';
2218                 predicted_session_file += session_name;
2219                 predicted_session_file += ARDOUR::statefile_suffix;
2220
2221                 if (Glib::file_test (predicted_session_file, Glib::FILE_TEST_EXISTS)) {
2222                         existing_session = true;
2223                 }
2224
2225         } else if (Glib::file_test (session_path, Glib::FILE_TEST_EXISTS)) {
2226
2227                 if (session_path.find (ARDOUR::statefile_suffix) == session_path.length() - 7) {
2228                         /* existing .ardour file */
2229                         existing_session = true;
2230                 }
2231
2232         } else {
2233                 existing_session = false;
2234         }
2235
2236         /* lets just try to load it */
2237
2238         if (create_engine ()) {
2239                 backend_audio_error (false, _startup);
2240                 return -1;
2241         }
2242
2243         return load_session (session_path, session_name);
2244 }
2245
2246 bool
2247 ARDOUR_UI::ask_about_loading_existing_session (const Glib::ustring& session_path)
2248 {
2249         Glib::ustring str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2250
2251         MessageDialog msg (str,
2252                            false,
2253                            Gtk::MESSAGE_WARNING,
2254                            Gtk::BUTTONS_YES_NO,
2255                            true);
2256
2257
2258         msg.set_name (X_("OpenExistingDialog"));
2259         msg.set_title (_("Open Existing Session"));
2260         msg.set_wmclass (X_("existing_session"), "Ardour");
2261         msg.set_position (Gtk::WIN_POS_MOUSE);
2262         pop_back_splash ();
2263
2264         switch (msg.run()) {
2265         case RESPONSE_YES:
2266                 return true;
2267                 break;
2268         }
2269         return false;
2270 }
2271
2272 int
2273 ARDOUR_UI::build_session_from_nsd (const Glib::ustring& session_path, const Glib::ustring& session_name)
2274 {
2275
2276         uint32_t mchns;
2277         AutoConnectOption iconnect;
2278         AutoConnectOption oconnect;
2279         uint32_t nphysin;
2280         uint32_t nphysout;
2281
2282         if (Profile->get_sae()) {
2283
2284                 mchns = 2;
2285                 iconnect = AutoConnectPhysical;
2286                 oconnect = AutoConnectMaster;
2287                 nphysin = 0; // use all available
2288                 nphysout = 0; // use all available
2289
2290         } else {
2291
2292                 /* get settings from advanced section of NSD */
2293
2294                 if (_startup->create_master_bus()) {
2295                         mchns = (uint32_t) _startup->master_channel_count();
2296                 } else {
2297                         mchns = 0;
2298                 }
2299
2300                 if (_startup->connect_inputs()) {
2301                         iconnect = AutoConnectPhysical;
2302                 } else {
2303                         iconnect = AutoConnectOption (0);
2304                 }
2305
2306                 /// @todo some minor tweaks.
2307
2308                 oconnect = AutoConnectOption (0);
2309
2310                 if (_startup->connect_outputs ()) {
2311                         if (_startup->connect_outs_to_master()) {
2312                                 oconnect = AutoConnectMaster;
2313                         } else if (_startup->connect_outs_to_physical()) {
2314                                 oconnect = AutoConnectPhysical;
2315                         }
2316                 }
2317
2318                 nphysin = (uint32_t) _startup->input_limit_count();
2319                 nphysout = (uint32_t) _startup->output_limit_count();
2320         }
2321
2322         if (build_session (session_path,
2323                            session_name,
2324                            mchns,
2325                            iconnect,
2326                            oconnect,
2327                            nphysin,
2328                            nphysout,
2329                            engine->frame_rate() * 60 * 5)) {
2330
2331                 return -1;
2332         }
2333
2334         return 0;
2335 }
2336
2337 void
2338 ARDOUR_UI::idle_load (const Glib::ustring& path)
2339 {
2340         if (_session) {
2341                 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2342                         /* /path/to/foo => /path/to/foo, foo */
2343                         load_session (path, basename_nosuffix (path));
2344                 } else {
2345                         /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2346                         load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2347                 }
2348         } else {
2349
2350                 ARDOUR_COMMAND_LINE::session_name = path;
2351
2352                 /*
2353                  * new_session_dialog doens't exist in A3
2354                  * Try to remove all references to it to
2355                  * see if it will compile.  NOTE: this will
2356                  * likely cause a runtime issue is my somewhat
2357                  * uneducated guess.
2358                  */
2359
2360                 //if (new_session_dialog) {
2361
2362
2363                         /* make it break out of Dialog::run() and
2364                            start again.
2365                          */
2366
2367                         //new_session_dialog->response (1);
2368                 //}
2369         }
2370 }
2371
2372 void
2373 ARDOUR_UI::end_loading_messages ()
2374 {
2375         // hide_splash ();
2376 }
2377
2378 void
2379 ARDOUR_UI::loading_message (const std::string& /*msg*/)
2380 {
2381         // show_splash ();
2382         // splash->message (msg);
2383         flush_pending ();
2384 }
2385
2386 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
2387 int
2388 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new)
2389 {
2390         Glib::ustring session_name;
2391         Glib::ustring session_path;
2392         Glib::ustring template_name;
2393         int ret = -1;
2394         bool likely_new = false;
2395
2396         while (ret != 0) {
2397
2398                 if (!should_be_new && !ARDOUR_COMMAND_LINE::session_name.empty()) {
2399
2400                         /* if they named a specific statefile, use it, otherwise they are
2401                            just giving a session folder, and we want to use it as is
2402                            to find the session.
2403                         */
2404
2405                         if (ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix) != string::npos) {
2406                                 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
2407                         } else {
2408                                 session_path = ARDOUR_COMMAND_LINE::session_name;
2409                         }
2410
2411                         session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
2412
2413                 } else {
2414
2415                         bool const apply = run_startup (should_be_new);
2416                         if (!apply) {
2417                                 if (quit_on_cancel) {
2418                                         exit (1);
2419                                 } else {
2420                                         return ret;
2421                                 }
2422                         }
2423
2424                         /* if we run the startup dialog again, offer more than just "new session" */
2425
2426                         should_be_new = false;
2427
2428                         session_name = _startup->session_name (likely_new);
2429
2430                         /* this shouldn't happen, but we catch it just in case it does */
2431
2432                         if (session_name.empty()) {
2433                                 break;
2434                         }
2435                         if (_startup->use_session_template()) {
2436                                 template_name = _startup->session_template_name();
2437                                 _session_is_new = true;
2438                         }
2439
2440                         if (session_name[0] == '/' ||
2441                             (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == '/') ||
2442                             (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == '/')) {
2443
2444                                 /* absolute path or cwd-relative path specified for session name: infer session folder
2445                                    from what was given.
2446                                 */
2447                                 
2448                                 session_path = Glib::path_get_dirname (session_name);
2449                                 session_name = Glib::path_get_basename (session_name);
2450
2451                         } else {
2452
2453                                 session_path = _startup->session_folder();
2454                         }
2455                 }
2456
2457                 if (create_engine ()) {
2458                         break;
2459                 }
2460
2461                 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
2462
2463                         if (likely_new) {
2464
2465                                 Glib::ustring existing = Glib::build_filename (session_path, session_name);
2466
2467                                 if (!ask_about_loading_existing_session (existing)) {
2468                                         ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2469                                         continue;
2470                                 }
2471                         }
2472
2473                         _session_is_new = false;
2474
2475                 } else {
2476
2477                         if (!likely_new) {
2478                                 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
2479                                 msg.run ();
2480                                 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2481                                 continue;
2482                         }
2483
2484                         if (session_name.find ('/') != Glib::ustring::npos) {
2485                                 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2486                                                                           "session names may not contain a '/' character"));
2487                                 msg.run ();
2488                                 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2489                                 continue;
2490                         }
2491
2492                         if (session_name.find ('\\') != Glib::ustring::npos) {
2493                                 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2494                                                                           "session names may not contain a '\\' character"));
2495                                 msg.run ();
2496                                 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2497                                 continue;
2498                         }
2499
2500                         _session_is_new = true;
2501                 }
2502
2503                 if (likely_new && template_name.empty()) {
2504
2505                         ret = build_session_from_nsd (session_path, session_name);
2506
2507                 } else {
2508
2509                         ret = load_session (session_path, session_name, template_name);
2510                         if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
2511                                 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
2512                                 exit (1);
2513                         }
2514                 }
2515         }
2516
2517         return ret;
2518 }
2519
2520 void
2521 ARDOUR_UI::close_session()
2522 {
2523         if (!check_audioengine()) {
2524                 return;
2525         }
2526
2527         if (unload_session (true)) {
2528                 return;
2529         }
2530
2531         ARDOUR_COMMAND_LINE::session_name = "";
2532         get_session_parameters (true, false);
2533 }
2534
2535 int
2536 ARDOUR_UI::load_session (const Glib::ustring& path, const Glib::ustring& snap_name, Glib::ustring mix_template)
2537 {
2538         Session *new_session;
2539         int unload_status;
2540         int retval = -1;
2541
2542         session_loaded = false;
2543
2544         if (!check_audioengine()) {
2545                 return -1;
2546         }
2547
2548         unload_status = unload_session ();
2549
2550         if (unload_status < 0) {
2551                 goto out;
2552         } else if (unload_status > 0) {
2553                 retval = 0;
2554                 goto out;
2555         }
2556
2557         loading_message (string_compose (_("Please wait while %1loads your session"), PROGRAM_NAME));
2558
2559         try {
2560                 new_session = new Session (*engine, path, snap_name, mix_template);
2561         }
2562
2563         /* this one is special */
2564
2565         catch (AudioEngine::PortRegistrationFailure& err) {
2566
2567                 MessageDialog msg (err.what(),
2568                                    true,
2569                                    Gtk::MESSAGE_INFO,
2570                                    Gtk::BUTTONS_CLOSE);
2571
2572                 msg.set_title (_("Port Registration Error"));
2573                 msg.set_secondary_text (_("Click the Close button to try again."));
2574                 msg.set_position (Gtk::WIN_POS_CENTER);
2575                 pop_back_splash ();
2576                 msg.present ();
2577
2578                 int response = msg.run ();
2579
2580                 msg.hide ();
2581
2582                 switch (response) {
2583                 case RESPONSE_CANCEL:
2584                         exit (1);
2585                 default:
2586                         break;
2587                 }
2588                 goto out;
2589         }
2590
2591         catch (...) {
2592
2593                 MessageDialog msg (string_compose(_("Session \"%1 (snapshot %2)\" did not load successfully"), path, snap_name),
2594                                    true,
2595                                    Gtk::MESSAGE_INFO,
2596                                    Gtk::BUTTONS_CLOSE);
2597
2598                 msg.set_title (_("Loading Error"));
2599                 msg.set_secondary_text (_("Click the Close button to try again."));
2600                 msg.set_position (Gtk::WIN_POS_CENTER);
2601                 pop_back_splash ();
2602                 msg.present ();
2603
2604                 int response = msg.run ();
2605
2606                 msg.hide ();
2607
2608                 switch (response) {
2609                 case RESPONSE_CANCEL:
2610                         exit (1);
2611                 default:
2612                         break;
2613                 }
2614                 goto out;
2615         }
2616
2617         set_session (new_session);
2618
2619         session_loaded = true;
2620
2621         goto_editor_window ();
2622
2623         if (_session) {
2624                 _session->set_clean ();
2625         }
2626
2627         flush_pending ();
2628         retval = 0;
2629
2630   out:
2631         return retval;
2632 }
2633
2634 int
2635 ARDOUR_UI::build_session (const Glib::ustring& path, const Glib::ustring& snap_name,
2636                           uint32_t master_channels,
2637                           AutoConnectOption input_connect,
2638                           AutoConnectOption output_connect,
2639                           uint32_t nphysin,
2640                           uint32_t nphysout,
2641                           nframes_t initial_length)
2642 {
2643         Session *new_session;
2644         int x;
2645
2646         if (!check_audioengine()) {
2647                 return -1;
2648         }
2649
2650         session_loaded = false;
2651
2652         x = unload_session ();
2653
2654         if (x < 0) {
2655                 return -1;
2656         } else if (x > 0) {
2657                 return 0;
2658         }
2659
2660         _session_is_new = true;
2661
2662         try {
2663                 new_session = new Session (*engine, path, snap_name, input_connect, output_connect,
2664                                            master_channels, nphysin, nphysout, initial_length);
2665         }
2666
2667         catch (...) {
2668
2669                 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
2670                 pop_back_splash ();
2671                 msg.run ();
2672                 return -1;
2673         }
2674
2675         set_session (new_session);
2676
2677         session_loaded = true;
2678
2679         new_session->save_state(new_session->name());
2680
2681         return 0;
2682 }
2683
2684 void
2685 ARDOUR_UI::show ()
2686 {
2687         if (editor) {
2688                 editor->show_window ();
2689
2690                 if (!shown_flag) {
2691                         editor->present ();
2692                 }
2693
2694                 shown_flag = true;
2695         }
2696 }
2697
2698 void
2699 ARDOUR_UI::launch_chat ()
2700 {
2701 #ifdef __APPLE__
2702         open_uri("http://webchat.freenode.net/?channels=ardour-osx");
2703 #else
2704         open_uri("http://webchat.freenode.net/?channels=ardour");
2705 #endif
2706 }
2707
2708 void
2709 ARDOUR_UI::show_about ()
2710 {
2711         if (about == 0) {
2712                 about = new About;
2713                 about->signal_response().connect(sigc::mem_fun (*this, &ARDOUR_UI::about_signal_response) );
2714         }
2715
2716         about->set_transient_for(*editor);
2717         about->show_all ();
2718 }
2719
2720 void
2721 ARDOUR_UI::hide_about ()
2722 {
2723         if (about) {
2724                 about->get_window()->set_cursor ();
2725                 about->hide ();
2726         }
2727 }
2728
2729 void
2730 ARDOUR_UI::about_signal_response (int /*response*/)
2731 {
2732         hide_about();
2733 }
2734
2735 void
2736 ARDOUR_UI::show_splash ()
2737 {
2738         if (splash == 0) {
2739                 try {
2740                         splash = new Splash;
2741                 } catch (...) {
2742                         return;
2743                 }
2744         }
2745
2746         splash->show ();
2747         splash->present ();
2748         splash->queue_draw ();
2749         splash->get_window()->process_updates (true);
2750         flush_pending ();
2751 }
2752
2753 void
2754 ARDOUR_UI::hide_splash ()
2755 {
2756         if (splash) {
2757                 splash->hide();
2758         }
2759 }
2760
2761 void
2762 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title,
2763                                     const string& plural_msg, const string& singular_msg)
2764 {
2765         size_t removed;
2766
2767         removed = rep.paths.size();
2768
2769         if (removed == 0) {
2770                 MessageDialog msgd (*editor,
2771                                     _("No audio files were ready for cleanup"),
2772                                     true,
2773                                     Gtk::MESSAGE_INFO,
2774                                     (Gtk::ButtonsType)(Gtk::BUTTONS_OK)  );
2775                 msgd.set_secondary_text (_("If this seems suprising, \n\
2776 check for any existing snapshots.\n\
2777 These may still include regions that\n\
2778 require some unused files to continue to exist."));
2779
2780                 msgd.run ();
2781                 return;
2782         }
2783
2784         ArdourDialog results (_("ardour: cleanup"), true, false);
2785
2786         struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
2787             CleanupResultsModelColumns() {
2788                     add (visible_name);
2789                     add (fullpath);
2790             }
2791             Gtk::TreeModelColumn<Glib::ustring> visible_name;
2792             Gtk::TreeModelColumn<Glib::ustring> fullpath;
2793         };
2794
2795
2796         CleanupResultsModelColumns results_columns;
2797         Glib::RefPtr<Gtk::ListStore> results_model;
2798         Gtk::TreeView results_display;
2799
2800         results_model = ListStore::create (results_columns);
2801         results_display.set_model (results_model);
2802         results_display.append_column (list_title, results_columns.visible_name);
2803
2804         results_display.set_name ("CleanupResultsList");
2805         results_display.set_headers_visible (true);
2806         results_display.set_headers_clickable (false);
2807         results_display.set_reorderable (false);
2808
2809         Gtk::ScrolledWindow list_scroller;
2810         Gtk::Label txt;
2811         Gtk::VBox dvbox;
2812         Gtk::HBox dhbox;  // the hbox for the image and text
2813         Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
2814         Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO,  Gtk::ICON_SIZE_DIALOG));
2815
2816         dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
2817
2818         const string dead_sound_directory = _session->session_directory().dead_sound_path().to_string();
2819
2820         /* subst:
2821            %1 - number of files removed
2822            %2 - location of "dead_sounds"
2823            %3 - size of files affected
2824            %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
2825         */
2826
2827         const char* bprefix;
2828         double space_adjusted = 0;
2829
2830         if (rep.space < 100000.0f) {
2831                 bprefix = X_("kilo");
2832         } else if (rep.space < 1000000.0f * 1000) {
2833                 bprefix = X_("mega");
2834                 space_adjusted = truncf((float)rep.space / 1000.0);
2835         } else {
2836                 bprefix = X_("giga");
2837                 space_adjusted = truncf((float)rep.space / (1000000.0 * 1000));
2838         }
2839
2840         if (removed > 1) {
2841                 txt.set_text (string_compose (plural_msg, removed, _session->path() + "dead_sounds", space_adjusted, bprefix));
2842         } else {
2843                 txt.set_text (string_compose (singular_msg, removed, _session->path() + "dead_sounds", space_adjusted, bprefix));
2844         }
2845
2846         dhbox.pack_start (*dimage, true, false, 5);
2847         dhbox.pack_start (txt, true, false, 5);
2848
2849         for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
2850                 TreeModel::Row row = *(results_model->append());
2851                 row[results_columns.visible_name] = *i;
2852                 row[results_columns.fullpath] = *i;
2853         }
2854
2855         list_scroller.add (results_display);
2856         list_scroller.set_size_request (-1, 150);
2857         list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
2858
2859         dvbox.pack_start (dhbox, true, false, 5);
2860         dvbox.pack_start (list_scroller, true, false, 5);
2861         ddhbox.pack_start (dvbox, true, false, 5);
2862
2863         results.get_vbox()->pack_start (ddhbox, true, false, 5);
2864         results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
2865         results.set_default_response (RESPONSE_CLOSE);
2866         results.set_position (Gtk::WIN_POS_MOUSE);
2867
2868         results_display.show();
2869         list_scroller.show();
2870         txt.show();
2871         dvbox.show();
2872         dhbox.show();
2873         ddhbox.show();
2874         dimage->show();
2875
2876         //results.get_vbox()->show();
2877         results.set_resizable (false);
2878
2879         results.run ();
2880
2881 }
2882
2883 void
2884 ARDOUR_UI::cleanup ()
2885 {
2886         if (_session == 0) {
2887                 /* shouldn't happen: menu item is insensitive */
2888                 return;
2889         }
2890
2891
2892         MessageDialog  checker (_("Are you sure you want to cleanup?"),
2893                                 true,
2894                                 Gtk::MESSAGE_QUESTION,
2895                                 (Gtk::ButtonsType)(Gtk::BUTTONS_NONE));
2896
2897         checker.set_secondary_text(_("Cleanup is a destructive operation.\n\
2898 ALL undo/redo information will be lost if you cleanup.\n\
2899 After cleanup, unused audio files will be moved to a \
2900 \"dead sounds\" location."));
2901
2902         checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
2903         checker.add_button (_("Clean Up"), RESPONSE_ACCEPT);
2904         checker.set_default_response (RESPONSE_CANCEL);
2905
2906         checker.set_name (_("CleanupDialog"));
2907         checker.set_wmclass (X_("ardour_cleanup"), "Ardour");
2908         checker.set_position (Gtk::WIN_POS_MOUSE);
2909
2910         switch (checker.run()) {
2911         case RESPONSE_ACCEPT:
2912                 break;
2913         default:
2914                 return;
2915         }
2916
2917         ARDOUR::CleanupReport rep;
2918
2919         editor->prepare_for_cleanup ();
2920
2921         /* do not allow flush until a session is reloaded */
2922
2923         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
2924         if (act) {
2925                 act->set_sensitive (false);
2926         }
2927
2928         if (_session->cleanup_sources (rep)) {
2929                 editor->finish_cleanup ();
2930                 return;
2931         }
2932
2933         editor->finish_cleanup ();
2934
2935         checker.hide();
2936         display_cleanup_results (rep,
2937                                  _("cleaned files"),
2938                                  _("\
2939 The following %1 files were not in use and \n\
2940 have been moved to:\n\
2941 %2. \n\n\
2942 Flushing the wastebasket will \n\
2943 release an additional\n\
2944 %3 %4bytes of disk space.\n"),
2945                                  _("\
2946 The following file was not in use and \n        \
2947 has been moved to:\n                            \
2948 %2. \n\n\
2949 Flushing the wastebasket will \n\
2950 release an additional\n\
2951 %3 %4bytes of disk space.\n"
2952                                          ));
2953
2954 }
2955
2956 void
2957 ARDOUR_UI::flush_trash ()
2958 {
2959         if (_session == 0) {
2960                 /* shouldn't happen: menu item is insensitive */
2961                 return;
2962         }
2963
2964         ARDOUR::CleanupReport rep;
2965
2966         if (_session->cleanup_trash_sources (rep)) {
2967                 return;
2968         }
2969
2970         display_cleanup_results (rep,
2971                                  _("deleted file"),
2972                                  _("The following %1 files were deleted from\n\
2973 %2,\n\
2974 releasing %3 %4bytes of disk space"),
2975                                  _("The following file was deleted from\n\
2976 %2,\n\
2977 releasing %3 %4bytes of disk space"));
2978 }
2979
2980 void
2981 ARDOUR_UI::add_route (Gtk::Window* float_window)
2982 {
2983         int count;
2984
2985         if (!_session) {
2986                 return;
2987         }
2988
2989         if (add_route_dialog == 0) {
2990                 add_route_dialog = new AddRouteDialog (_session);
2991                 if (float_window) {
2992                         add_route_dialog->set_transient_for (*float_window);
2993                 }
2994         }
2995
2996         if (add_route_dialog->is_visible()) {
2997                 /* we're already doing this */
2998                 return;
2999         }
3000
3001         ResponseType r = (ResponseType) add_route_dialog->run ();
3002
3003         add_route_dialog->hide();
3004
3005         switch (r) {
3006                 case RESPONSE_ACCEPT:
3007                         break;
3008                 default:
3009                         return;
3010                         break;
3011         }
3012
3013         if ((count = add_route_dialog->count()) <= 0) {
3014                 return;
3015         }
3016
3017         string template_path = add_route_dialog->track_template();
3018
3019         if (!template_path.empty()) {
3020                 _session->new_route_from_template (count, template_path);
3021                 return;
3022         }
3023
3024         uint32_t input_chan = add_route_dialog->channels ();
3025         uint32_t output_chan;
3026         string name_template = add_route_dialog->name_template ();
3027         bool track = add_route_dialog->track ();
3028         bool aux = !track && add_route_dialog->aux();
3029         RouteGroup* route_group = add_route_dialog->route_group ();
3030
3031         AutoConnectOption oac = Config->get_output_auto_connect();
3032
3033         if (oac & AutoConnectMaster) {
3034                 output_chan = (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan);
3035         } else {
3036                 output_chan = input_chan;
3037         }
3038
3039         /* XXX do something with name template */
3040
3041         if (add_route_dialog->type() == ARDOUR::DataType::MIDI) {
3042                 if (track) {
3043                         session_add_midi_track (route_group, count);
3044                 } else  {
3045                         MessageDialog msg (*editor,
3046                                         _("Sorry, MIDI Busses are not supported at this time."));
3047                         msg.run ();
3048                         //session_add_midi_bus();
3049                 }
3050         } else {
3051                 if (track) {
3052                         session_add_audio_track (input_chan, output_chan, add_route_dialog->mode(), route_group, count);
3053                 } else {
3054                         session_add_audio_bus (aux, input_chan, output_chan, route_group, count);
3055                 }
3056         }
3057 }
3058
3059 XMLNode*
3060 ARDOUR_UI::mixer_settings () const
3061 {
3062         XMLNode* node = 0;
3063
3064         if (_session) {
3065                 node = _session->instant_xml(X_("Mixer"));
3066         } else {
3067                 node = Config->instant_xml(X_("Mixer"));
3068         }
3069
3070         if (!node) {
3071                 node = new XMLNode (X_("Mixer"));
3072         }
3073
3074         return node;
3075 }
3076
3077 XMLNode*
3078 ARDOUR_UI::editor_settings () const
3079 {
3080         XMLNode* node = 0;
3081
3082         if (_session) {
3083                 node = _session->instant_xml(X_("Editor"));
3084         } else {
3085                 node = Config->instant_xml(X_("Editor"));
3086         }
3087
3088         if (!node) {
3089                 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
3090                         node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
3091                 }
3092         }
3093
3094         if (!node) {
3095                 node = new XMLNode (X_("Editor"));
3096         }
3097
3098         return node;
3099 }
3100
3101 XMLNode*
3102 ARDOUR_UI::keyboard_settings () const
3103 {
3104         XMLNode* node = 0;
3105
3106         node = Config->extra_xml(X_("Keyboard"));
3107
3108         if (!node) {
3109                 node = new XMLNode (X_("Keyboard"));
3110         }
3111         return node;
3112 }
3113
3114 void
3115 ARDOUR_UI::create_xrun_marker(nframes_t where)
3116 {
3117         editor->mouse_add_new_marker (where, false, true);
3118 }
3119
3120 void
3121 ARDOUR_UI::halt_on_xrun_message ()
3122 {
3123         MessageDialog msg (*editor,
3124                            _("Recording was stopped because your system could not keep up."));
3125         msg.run ();
3126 }
3127
3128 void
3129 ARDOUR_UI::xrun_handler(nframes_t where)
3130 {
3131         if (!_session) {
3132                 return;
3133         }
3134
3135         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
3136
3137         if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
3138                 create_xrun_marker(where);
3139         }
3140
3141         if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
3142                 halt_on_xrun_message ();
3143         }
3144 }
3145
3146 void
3147 ARDOUR_UI::push_buffer_stats (uint32_t capture, uint32_t playback)
3148 {
3149         time_t now;
3150         time (&now);
3151
3152         while (disk_buffer_stats.size() > 60) {
3153                 disk_buffer_stats.pop_front ();
3154         }
3155
3156         disk_buffer_stats.push_back (DiskBufferStat (now, capture, playback));
3157 }
3158
3159 void
3160 ARDOUR_UI::write_buffer_stats ()
3161 {
3162         std::ofstream fout;
3163         struct tm tm;
3164         char buf[64];
3165         char path[PATH_MAX+1];  int fd;
3166
3167         strcpy (path, "ardourBufferingXXXXXX");
3168
3169         if ((fd = mkstemp (path )) < 0) {
3170                 cerr << X_("cannot find temporary name for buffer stats") << endl;
3171                 return;
3172         }
3173         
3174         fout.open (path);
3175         close (fd);
3176
3177         if (!fout) {
3178                 cerr << string_compose (X_("cannot open file %1 for buffer stats"), path) << endl;
3179                 return;
3180         }
3181
3182         for (list<DiskBufferStat>::iterator i = disk_buffer_stats.begin(); i != disk_buffer_stats.end(); ++i) {
3183                 localtime_r (&(*i).when, &tm);
3184                 strftime (buf, sizeof (buf), "%T", &tm);
3185                 fout << buf << ' ' << (*i).capture << ' ' << (*i).playback << endl;
3186         }
3187         
3188         disk_buffer_stats.clear ();
3189
3190         fout.close ();
3191
3192         cerr << "buffering statistics can be found in: " << path << endl;
3193 }
3194
3195 void
3196 ARDOUR_UI::disk_overrun_handler ()
3197 {
3198         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
3199
3200         write_buffer_stats ();
3201
3202         if (!have_disk_speed_dialog_displayed) {
3203                 have_disk_speed_dialog_displayed = true;
3204                 MessageDialog* msg = new MessageDialog (*editor, _("\
3205 The disk system on your computer\n\
3206 was not able to keep up with Ardour.\n\
3207 \n\
3208 Specifically, it failed to write data to disk\n\
3209 quickly enough to keep up with recording.\n"));
3210                 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3211                 msg->show ();
3212         }
3213 }
3214
3215 void
3216 ARDOUR_UI::disk_underrun_handler ()
3217 {
3218         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
3219
3220         write_buffer_stats ();
3221
3222         if (!have_disk_speed_dialog_displayed) {
3223                 have_disk_speed_dialog_displayed = true;
3224                 MessageDialog* msg = new MessageDialog (*editor,
3225                                    _("The disk system on your computer\n\
3226 was not able to keep up with Ardour.\n\
3227 \n\
3228 Specifically, it failed to read data from disk\n\
3229 quickly enough to keep up with playback.\n"));
3230                 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3231                 msg->show ();
3232         }
3233 }
3234
3235 void
3236 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
3237 {
3238         have_disk_speed_dialog_displayed = false;
3239         delete msg;
3240 }
3241
3242 void
3243 ARDOUR_UI::session_dialog (std::string msg)
3244 {
3245         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
3246
3247         MessageDialog* d;
3248
3249         if (editor) {
3250                 d = new MessageDialog (*editor, msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3251         } else {
3252                 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3253         }
3254
3255         d->show_all ();
3256         d->run ();
3257         delete d;
3258 }
3259
3260 int
3261 ARDOUR_UI::pending_state_dialog ()
3262 {
3263         HBox* hbox = new HBox();
3264         Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3265         ArdourDialog dialog (_("Crash Recovery"), true);
3266         Label  message (_("\
3267 This session appears to have been in\n\
3268 middle of recording when ardour or\n\
3269 the computer was shutdown.\n\
3270 \n\
3271 Ardour can recover any captured audio for\n\
3272 you, or it can ignore it. Please decide\n\
3273 what you would like to do.\n"));
3274         image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3275         hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3276         hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3277         dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3278         dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
3279         dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
3280         dialog.set_default_response (RESPONSE_ACCEPT);
3281         dialog.set_position (WIN_POS_CENTER);
3282         message.show();
3283         image->show();
3284         hbox->show();
3285
3286         switch (dialog.run ()) {
3287         case RESPONSE_ACCEPT:
3288                 return 1;
3289         default:
3290                 return 0;
3291         }
3292 }
3293
3294 int
3295 ARDOUR_UI::sr_mismatch_dialog (nframes_t desired, nframes_t actual)
3296 {
3297         HBox* hbox = new HBox();
3298         Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3299         ArdourDialog dialog (_("Sample Rate Mismatch"), true);
3300         Label  message (string_compose (_("\
3301 This session was created with a sample rate of %1 Hz\n\
3302 \n\
3303 The audioengine is currently running at %2 Hz\n"), desired, actual));
3304
3305         image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3306         hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3307         hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3308         dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3309         dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
3310         dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
3311         dialog.set_default_response (RESPONSE_ACCEPT);
3312         dialog.set_position (WIN_POS_CENTER);
3313         message.show();
3314         image->show();
3315         hbox->show();
3316
3317         switch (dialog.run ()) {
3318         case RESPONSE_ACCEPT:
3319                 return 0;
3320         default:
3321                 return 1;
3322         }
3323 }
3324
3325
3326 void
3327 ARDOUR_UI::disconnect_from_jack ()
3328 {
3329         if (engine) {
3330                 if( engine->disconnect_from_jack ()) {
3331                         MessageDialog msg (*editor, _("Could not disconnect from JACK"));
3332                         msg.run ();
3333                 }
3334
3335                 update_sample_rate (0);
3336         }
3337 }
3338
3339 void
3340 ARDOUR_UI::reconnect_to_jack ()
3341 {
3342         if (engine) {
3343                 if (engine->reconnect_to_jack ()) {
3344                         MessageDialog msg (*editor,  _("Could not reconnect to JACK"));
3345                         msg.run ();
3346                 }
3347
3348                 update_sample_rate (0);
3349         }
3350 }
3351
3352 void
3353 ARDOUR_UI::use_config ()
3354 {
3355
3356         XMLNode* node = Config->extra_xml (X_("TransportControllables"));
3357         if (node) {
3358                 set_transport_controllable_state (*node);
3359         }
3360
3361         node = Config->extra_xml (X_("UI"));
3362
3363         if (node) {
3364                 const XMLProperty* prop = node->property (X_("show-big-clock"));
3365                 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleBigClock"));
3366                 if (act) {
3367                         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
3368                         tact->set_active (string_is_affirmative (prop->value()));
3369                 }
3370         }
3371 }
3372
3373 void
3374 ARDOUR_UI::update_transport_clocks (nframes_t pos)
3375 {
3376         if (Config->get_primary_clock_delta_edit_cursor()) {
3377                 primary_clock.set (pos, false, editor->get_preferred_edit_position(), 1);
3378         } else {
3379                 primary_clock.set (pos, 0, true);
3380         }
3381
3382         if (Config->get_secondary_clock_delta_edit_cursor()) {
3383                 secondary_clock.set (pos, false, editor->get_preferred_edit_position(), 2);
3384         } else {
3385                 secondary_clock.set (pos);
3386         }
3387
3388         if (big_clock_window) {
3389                 big_clock.set (pos);
3390         }
3391 }
3392
3393 void
3394 ARDOUR_UI::record_state_changed ()
3395 {
3396         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
3397
3398         if (!_session || !big_clock_window) {
3399                 /* why bother - the clock isn't visible */
3400                 return;
3401         }
3402
3403         Session::RecordState const r = _session->record_status ();
3404         bool const h = _session->have_rec_enabled_diskstream ();
3405
3406         if (r == Session::Recording && h)  {
3407                 big_clock.set_widget_name ("BigClockRecording");
3408         } else {
3409                 big_clock.set_widget_name ("BigClockNonRecording");
3410         }
3411 }
3412
3413 bool
3414 ARDOUR_UI::first_idle ()
3415 {
3416         if (_session) {
3417                 _session->allow_auto_play (true);
3418         }
3419
3420         if (editor) {
3421                 editor->first_idle();
3422         }
3423
3424         Keyboard::set_can_save_keybindings (true);
3425         return false;
3426 }
3427
3428 void
3429 ARDOUR_UI::store_clock_modes ()
3430 {
3431         XMLNode* node = new XMLNode(X_("ClockModes"));
3432
3433         for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
3434                 node->add_property ((*x)->name().c_str(), enum_2_string ((*x)->mode()));
3435         }
3436
3437         _session->add_extra_xml (*node);
3438         _session->set_dirty ();
3439 }
3440
3441
3442
3443 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
3444         : Controllable (name), ui (u), type(tp)
3445 {
3446
3447 }
3448
3449 void
3450 ARDOUR_UI::TransportControllable::set_value (float val)
3451 {
3452         if (type == ShuttleControl) {
3453                 double fract;
3454
3455                 if (val == 0.5f) {
3456                         fract = 0.0;
3457                 } else {
3458                         if (val < 0.5f) {
3459                                 fract = -((0.5f - val)/0.5f);
3460                         } else {
3461                                 fract = ((val - 0.5f)/0.5f);
3462                         }
3463                 }
3464
3465                 ui.set_shuttle_fract (fract);
3466                 return;
3467         }
3468
3469         if (val < 0.5f) {
3470                 /* do nothing: these are radio-style actions */
3471                 return;
3472         }
3473
3474         const char *action = 0;
3475
3476         switch (type) {
3477         case Roll:
3478                 action = X_("Roll");
3479                 break;
3480         case Stop:
3481                 action = X_("Stop");
3482                 break;
3483         case GotoStart:
3484                 action = X_("Goto Start");
3485                 break;
3486         case GotoEnd:
3487                 action = X_("Goto End");
3488                 break;
3489         case AutoLoop:
3490                 action = X_("Loop");
3491                 break;
3492         case PlaySelection:
3493                 action = X_("Play Selection");
3494                 break;
3495         case RecordEnable:
3496                 action = X_("Record");
3497                 break;
3498         default:
3499                 break;
3500         }
3501
3502         if (action == 0) {
3503                 return;
3504         }
3505
3506         Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
3507
3508         if (act) {
3509                 act->activate ();
3510         }
3511 }
3512
3513 float
3514 ARDOUR_UI::TransportControllable::get_value (void) const
3515 {
3516         float val = 0.0f;
3517
3518         switch (type) {
3519         case Roll:
3520                 break;
3521         case Stop:
3522                 break;
3523         case GotoStart:
3524                 break;
3525         case GotoEnd:
3526                 break;
3527         case AutoLoop:
3528                 break;
3529         case PlaySelection:
3530                 break;
3531         case RecordEnable:
3532                 break;
3533         case ShuttleControl:
3534                 break;
3535         default:
3536                 break;
3537         }
3538
3539         return val;
3540 }
3541
3542 void
3543 ARDOUR_UI::TransportControllable::set_id (const string& str)
3544 {
3545         _id = str;
3546 }
3547
3548 void
3549 ARDOUR_UI::setup_profile ()
3550 {
3551         if (gdk_screen_width() < 1200) {
3552                 Profile->set_small_screen ();
3553         }
3554
3555
3556         if (getenv ("ARDOUR_SAE")) {
3557                 Profile->set_sae ();
3558                 Profile->set_single_package ();
3559         }
3560 }
3561