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