add JAG to author list
[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 && 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                 int tries = 0;
733
734                 while (session->transport_rolling() && (++tries < 8)) {
735                         session->request_stop (true, false);
736                         usleep (10000);
737                 }
738
739                 if (session->dirty()) {
740                         switch (ask_about_saving_session(_("quit"))) {
741                         case -1:
742                                 return;
743                                 break;
744                         case 1:
745                                 /* use the default name */
746                                 if (save_state_canfail ("")) {
747                                         /* failed - don't quit */
748                                         MessageDialog msg (*editor, 
749                                                            _("\
750 Ardour was unable to save your session.\n\n\
751 If you still wish to quit, please use the\n\n\
752 \"Just quit\" option."));
753                                         pop_back_splash();
754                                         msg.run ();
755                                         return;
756                                 }
757                                 break;
758                         case 0:
759                                 break;
760                         }
761                 }
762                 
763                 session->set_deletion_in_progress ();
764         }
765
766         ArdourDialog::close_all_dialogs ();
767         engine->stop (true);
768         save_ardour_state ();
769         quit ();
770 }
771
772 int
773 ARDOUR_UI::ask_about_saving_session (const string & what)
774 {
775         ArdourDialog window (_("ardour: save session?"));
776         Gtk::HBox dhbox;  // the hbox for the image and text
777         Gtk::Label  prompt_label;
778         Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING,  Gtk::ICON_SIZE_DIALOG));
779
780         string msg;
781
782         msg = string_compose(_("Don't %1"), what);
783         window.add_button (msg, RESPONSE_REJECT);
784         msg = string_compose(_("Just %1"), what);
785         window.add_button (msg, RESPONSE_APPLY);
786         msg = string_compose(_("Save and %1"), what);
787         window.add_button (msg, RESPONSE_ACCEPT);
788
789         window.set_default_response (RESPONSE_ACCEPT);
790
791         Gtk::Button noquit_button (msg);
792         noquit_button.set_name ("EditorGTKButton");
793
794         string prompt;
795         string type;
796
797         if (session->snap_name() == session->name()) {
798                 type = _("session");
799         } else {
800                 type = _("snapshot");
801         }
802         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?"), 
803                          type, session->snap_name());
804         
805         prompt_label.set_text (prompt);
806         prompt_label.set_name (X_("PrompterLabel"));
807         prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
808
809         dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP)
810 ;
811         dhbox.set_homogeneous (false);
812         dhbox.pack_start (*dimage, false, false, 5);
813         dhbox.pack_start (prompt_label, true, false, 5);
814         window.get_vbox()->pack_start (dhbox);
815
816         window.set_name (_("Prompter"));
817         window.set_position (Gtk::WIN_POS_MOUSE);
818         window.set_modal (true);
819         window.set_resizable (false);
820         window.show_all ();
821
822         window.set_keep_above (true);
823         window.present ();
824
825         ResponseType r = (ResponseType) window.run();
826
827         window.hide ();
828
829         switch (r) {
830         case RESPONSE_ACCEPT: // save and get out of here
831                 return 1;
832         case RESPONSE_APPLY:  // get out of here
833                 return 0;
834         default:
835                 break;
836         }
837
838         return -1;
839 }
840         
841 int
842 ARDOUR_UI::every_second ()
843 {
844         update_cpu_load ();
845         update_buffer_load ();
846         update_disk_space ();
847         return TRUE;
848 }
849
850 gint
851 ARDOUR_UI::every_point_one_seconds ()
852 {
853         update_speed_display ();
854         RapidScreenUpdate(); /* EMIT_SIGNAL */
855         return TRUE;
856 }
857
858 gint
859 ARDOUR_UI::every_point_zero_one_seconds ()
860 {
861         // august 2007: actual update frequency: 40Hz, not 100Hz
862
863         SuperRapidScreenUpdate(); /* EMIT_SIGNAL */
864         return TRUE;
865 }
866
867 void
868 ARDOUR_UI::update_sample_rate (nframes_t ignored)
869 {
870         char buf[32];
871
872         ENSURE_GUI_THREAD (bind (mem_fun(*this, &ARDOUR_UI::update_sample_rate), ignored));
873
874         if (!engine->connected()) {
875
876                 snprintf (buf, sizeof (buf), _("disconnected"));
877
878         } else {
879
880                 nframes_t rate = engine->frame_rate();
881                 
882                 if (fmod (rate, 1000.0) != 0.0) {
883                         snprintf (buf, sizeof (buf), _("%.1f kHz / %4.1f ms"), 
884                                   (float) rate/1000.0f,
885                                   (engine->frames_per_cycle() / (float) rate) * 1000.0f);
886                 } else {
887                         snprintf (buf, sizeof (buf), _("%u kHz / %4.1f ms"), 
888                                   rate/1000,
889                                   (engine->frames_per_cycle() / (float) rate) * 1000.0f);
890                 }
891         }
892
893         sample_rate_label.set_text (buf);
894 }
895
896 void
897 ARDOUR_UI::update_cpu_load ()
898 {
899         char buf[32];
900         snprintf (buf, sizeof (buf), _("DSP: %5.1f%%"), engine->get_cpu_load());
901         cpu_load_label.set_text (buf);
902 }
903
904 void
905 ARDOUR_UI::update_buffer_load ()
906 {
907         char buf[64];
908         uint32_t c, p;
909
910         if (session) {
911                 c = session->capture_load ();
912                 p = session->playback_load ();
913                 
914                 push_buffer_stats (c, p);
915
916                 snprintf (buf, sizeof (buf), _("Buffers p:%" PRIu32 "%% c:%" PRIu32 "%%"), 
917                           session->playback_load(), session->capture_load());
918                 buffer_load_label.set_text (buf);
919         } else {
920                 buffer_load_label.set_text ("");
921         }
922 }
923
924 void
925 ARDOUR_UI::count_recenabled_streams (Route& route)
926 {
927         Track* track = dynamic_cast<Track*>(&route);
928         if (track && track->diskstream()->record_enabled()) {
929                 rec_enabled_streams += track->n_inputs();
930         }
931 }
932
933 void
934 ARDOUR_UI::update_disk_space()
935 {
936         if (session == 0) {
937                 return;
938         }
939
940         nframes_t frames = session->available_capture_duration();
941         char buf[64];
942
943         if (frames == max_frames) {
944                 strcpy (buf, _("Disk: 24hrs+"));
945         } else {
946                 int hrs;
947                 int mins;
948                 int secs;
949                 nframes_t fr = session->frame_rate();
950                 
951                 rec_enabled_streams = 0;
952                 session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams);
953                 
954                 if (rec_enabled_streams) {
955                         frames /= rec_enabled_streams;
956                 }
957                 
958                 hrs  = frames / (fr * 3600);
959                 frames -= hrs * fr * 3600;
960                 mins = frames / (fr * 60);
961                 frames -= mins * fr * 60;
962                 secs = frames / fr;
963                 
964                 snprintf (buf, sizeof(buf), _("Disk: %02dh:%02dm:%02ds"), hrs, mins, secs);
965         }
966
967         disk_space_label.set_text (buf);
968 }                 
969
970 gint
971 ARDOUR_UI::update_wall_clock ()
972 {
973         time_t now;
974         struct tm *tm_now;
975         char buf[16];
976
977         time (&now);
978         tm_now = localtime (&now);
979
980         sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
981         wall_clock_label.set_text (buf);
982
983         return TRUE;
984 }
985
986 gint
987 ARDOUR_UI::session_menu (GdkEventButton *ev)
988 {
989         session_popup_menu->popup (0, 0);
990         return TRUE;
991 }
992
993 void
994 ARDOUR_UI::redisplay_recent_sessions ()
995 {
996         vector<string *> *sessions;
997         vector<string *>::iterator i;
998         RecentSessionsSorter cmp;
999         
1000         recent_session_display.set_model (Glib::RefPtr<TreeModel>(0));
1001         recent_session_model->clear ();
1002
1003         RecentSessions rs;
1004         ARDOUR::read_recent_sessions (rs);
1005
1006         if (rs.empty()) {
1007                 recent_session_display.set_model (recent_session_model);
1008                 return;
1009         }
1010
1011         /* sort them alphabetically */
1012         sort (rs.begin(), rs.end(), cmp);
1013         sessions = new vector<string*>;
1014
1015         for (RecentSessions::iterator i = rs.begin(); i != rs.end(); ++i) {
1016                 sessions->push_back (new string ((*i).second));
1017         }
1018
1019         for (i = sessions->begin(); i != sessions->end(); ++i) {
1020
1021                 vector<string*>* states;
1022                 vector<const gchar*> item;
1023                 string fullpath = *(*i);
1024                 
1025                 /* remove any trailing / */
1026
1027                 if (fullpath[fullpath.length()-1] == '/') {
1028                         fullpath = fullpath.substr (0, fullpath.length()-1);
1029                 }
1030
1031                 /* check whether session still exists */
1032                 if (!Glib::file_test(fullpath.c_str(), Glib::FILE_TEST_EXISTS)) {
1033                         /* session doesn't exist */
1034                         cerr << "skipping non-existent session " << fullpath << endl;
1035                         continue;
1036                 }               
1037                 
1038                 /* now get available states for this session */
1039
1040                 if ((states = Session::possible_states (fullpath)) == 0) {
1041                         /* no state file? */
1042                         continue;
1043                 }
1044
1045                 TreeModel::Row row = *(recent_session_model->append());
1046
1047                 row[recent_session_columns.visible_name] = Glib::path_get_basename (fullpath);
1048                 row[recent_session_columns.fullpath] = fullpath;
1049
1050                 if (states->size() > 1) {
1051
1052                         /* add the children */
1053                         
1054                         for (vector<string*>::iterator i2 = states->begin(); i2 != states->end(); ++i2) {
1055                                 
1056                                 TreeModel::Row child_row = *(recent_session_model->append (row.children()));
1057
1058                                 child_row[recent_session_columns.visible_name] = **i2;
1059                                 child_row[recent_session_columns.fullpath] = fullpath;
1060
1061                                 delete *i2;
1062                         }
1063                 }
1064
1065                 delete states;
1066         }
1067
1068         recent_session_display.set_model (recent_session_model);
1069         delete sessions;
1070 }
1071
1072 void
1073 ARDOUR_UI::build_session_selector ()
1074 {
1075         session_selector_window = new ArdourDialog ("session selector");
1076         
1077         Gtk::ScrolledWindow *scroller = manage (new Gtk::ScrolledWindow);
1078         
1079         session_selector_window->add_button (Stock::CANCEL, RESPONSE_CANCEL);
1080         session_selector_window->add_button (Stock::OPEN, RESPONSE_ACCEPT);
1081         session_selector_window->set_default_response (RESPONSE_ACCEPT);
1082         recent_session_model = TreeStore::create (recent_session_columns);
1083         recent_session_display.set_model (recent_session_model);
1084         recent_session_display.append_column (_("Recent Sessions"), recent_session_columns.visible_name);
1085         recent_session_display.set_headers_visible (false);
1086         recent_session_display.get_selection()->set_mode (SELECTION_BROWSE);
1087         recent_session_display.signal_row_activated().connect (mem_fun (*this, &ARDOUR_UI::recent_session_row_activated));
1088
1089         scroller->add (recent_session_display);
1090         scroller->set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
1091
1092         session_selector_window->set_name ("SessionSelectorWindow");
1093         session_selector_window->set_size_request (200, 400);
1094         session_selector_window->get_vbox()->pack_start (*scroller);
1095         session_selector_window->show_all_children();
1096 }
1097
1098 void
1099 ARDOUR_UI::recent_session_row_activated (const TreePath& path, TreeViewColumn* col)
1100 {
1101         session_selector_window->response (RESPONSE_ACCEPT);
1102 }
1103
1104 void
1105 ARDOUR_UI::open_recent_session ()
1106 {
1107         bool can_return = (session != 0);
1108
1109         if (session_selector_window == 0) {
1110                 build_session_selector ();
1111         }
1112         
1113         redisplay_recent_sessions ();
1114
1115         while (true) {
1116                 
1117                 session_selector_window->set_position (WIN_POS_MOUSE);
1118
1119                 ResponseType r = (ResponseType) session_selector_window->run ();
1120                 
1121                 switch (r) {
1122                 case RESPONSE_ACCEPT:
1123                         break;
1124                 default:
1125                         if (can_return) {
1126                                 session_selector_window->hide();
1127                                 return;
1128                         } else {
1129                                 exit (1);
1130                         }
1131                 }
1132
1133                 if (recent_session_display.get_selection()->count_selected_rows() == 0) {
1134                         continue;
1135                 }
1136                 
1137                 session_selector_window->hide();
1138
1139                 Gtk::TreeModel::iterator i = recent_session_display.get_selection()->get_selected();
1140                 
1141                 if (i == recent_session_model->children().end()) {
1142                         return;
1143                 }
1144                 
1145                 Glib::ustring path = (*i)[recent_session_columns.fullpath];
1146                 Glib::ustring state = (*i)[recent_session_columns.visible_name];
1147                 
1148                 _session_is_new = false;
1149                 
1150                 if (load_session (path, state) == 0) {
1151                         break;
1152                 }
1153
1154                 can_return = false;
1155         }
1156 }
1157
1158 bool
1159 ARDOUR_UI::check_audioengine ()
1160 {
1161         if (engine) {
1162                 if (!engine->connected()) {
1163                         MessageDialog msg (_("Ardour is not connected to JACK\n"
1164                                              "You cannot open or close sessions in this condition"));
1165                         pop_back_splash ();
1166                         msg.set_position (WIN_POS_CENTER);
1167                         msg.run ();
1168                         return false;
1169                 }
1170                 return true;
1171         } else {
1172                 return false;
1173         }
1174 }
1175
1176 void
1177 ARDOUR_UI::open_session ()
1178 {
1179         if (!check_audioengine()) {
1180                 return;
1181         }
1182
1183         /* popup selector window */
1184
1185         if (open_session_selector == 0) {
1186
1187                 /* ardour sessions are folders */
1188
1189                 open_session_selector = new Gtk::FileChooserDialog (_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1190                 open_session_selector->add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1191                 open_session_selector->add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1192                 open_session_selector->set_default_response(Gtk::RESPONSE_ACCEPT);
1193
1194                 FileFilter session_filter;
1195                 session_filter.add_pattern ("*.ardour");
1196                 session_filter.set_name (_("Ardour sessions"));
1197                 open_session_selector->add_filter (session_filter);
1198                 open_session_selector->set_filter (session_filter);
1199         }
1200
1201         int response = open_session_selector->run();
1202         open_session_selector->hide ();
1203
1204         switch (response) {
1205         case RESPONSE_ACCEPT:
1206                 break;
1207         default:
1208                 open_session_selector->hide();
1209                 return;
1210         }
1211
1212         open_session_selector->hide();
1213         string session_path = open_session_selector->get_filename();
1214         string path, name;
1215         bool isnew;
1216
1217         if (session_path.length() > 0) {
1218                 if (Session::find_session (session_path, path, name, isnew) == 0) {
1219                         _session_is_new = isnew;
1220                         load_session (path, name);
1221                 }
1222         }
1223 }
1224
1225
1226 void
1227 ARDOUR_UI::session_add_midi_track ()
1228 {
1229         cerr << _("Patience is a virtue.\n");
1230 }
1231
1232 void
1233 ARDOUR_UI::session_add_audio_route (bool track, int32_t input_channels, int32_t output_channels, ARDOUR::TrackMode mode, uint32_t how_many)
1234 {
1235         list<boost::shared_ptr<AudioTrack> > tracks;
1236         Session::RouteList routes;
1237
1238         if (session == 0) {
1239                 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1240                 return;
1241         }
1242
1243         try { 
1244                 if (track) {
1245                         tracks = session->new_audio_track (input_channels, output_channels, mode, how_many);
1246
1247                         if (tracks.size() != how_many) {
1248                                 if (how_many == 1) {
1249                                         error << _("could not create a new audio track") << endmsg;
1250                                 } else {
1251                                         error << string_compose (_("could only create %1 of %2 new audio %3"), 
1252                                                                  tracks.size(), how_many, (track ? _("tracks") : _("busses"))) << endmsg;
1253                                 }
1254                         }
1255
1256                 } else {
1257
1258                         routes = session->new_audio_route (input_channels, output_channels, how_many);
1259
1260                         if (routes.size() != how_many) {
1261                                 if (how_many == 1) {
1262                                         error << _("could not create a new audio track") << endmsg;
1263                                 } else {
1264                                         error << string_compose (_("could not create %1 new audio tracks"), how_many) << endmsg;
1265                                 }
1266                         }
1267                 }
1268                 
1269 #if CONTROLOUTS
1270                 if (need_control_room_outs) {
1271                         pan_t pans[2];
1272                         
1273                         pans[0] = 0.5;
1274                         pans[1] = 0.5;
1275                         
1276                         route->set_stereo_control_outs (control_lr_channels);
1277                         route->control_outs()->set_stereo_pan (pans, this);
1278                 }
1279 #endif /* CONTROLOUTS */
1280         }
1281
1282         catch (...) {
1283                 MessageDialog msg (*editor, 
1284                                    _("There are insufficient JACK ports available\n\
1285 to create a new track or bus.\n\
1286 You should save Ardour, exit and\n\
1287 restart JACK with more ports."));
1288                 pop_back_splash ();
1289                 msg.run ();
1290         }
1291 }
1292
1293 void
1294 ARDOUR_UI::do_transport_locate (nframes_t new_position)
1295 {
1296         nframes_t _preroll = 0;
1297
1298         if (session) {
1299                 // XXX CONFIG_CHANGE FIX - requires AnyTime handling
1300                 // _preroll = session->convert_to_frames_at (new_position, Config->get_preroll());
1301
1302                 if (new_position > _preroll) {
1303                         new_position -= _preroll;
1304                 } else {
1305                         new_position = 0;
1306                 }
1307
1308                 session->request_locate (new_position);
1309         }
1310 }
1311
1312 void
1313 ARDOUR_UI::transport_goto_start ()  
1314 {
1315         if (session) {
1316                 session->goto_start();
1317
1318                 
1319                 /* force displayed area in editor to start no matter
1320                    what "follow playhead" setting is.
1321                 */
1322                 
1323                 if (editor) {
1324                         editor->reset_x_origin (session->current_start_frame());
1325                 }
1326         }
1327 }
1328
1329 void
1330 ARDOUR_UI::transport_goto_zero ()
1331 {
1332         if (session) {
1333                 session->request_locate (0);
1334
1335                 
1336                 /* force displayed area in editor to start no matter
1337                    what "follow playhead" setting is.
1338                 */
1339                 
1340                 if (editor) {
1341                         editor->reset_x_origin (0);
1342                 }
1343         }
1344 }
1345
1346 void
1347 ARDOUR_UI::transport_goto_wallclock ()
1348 {
1349         if (session && editor) {
1350
1351                 time_t now;
1352                 struct tm tmnow;
1353                 nframes64_t frames;
1354                 
1355                 time (&now);
1356                 localtime_r (&now, &tmnow);
1357         
1358                 frames = tmnow.tm_hour * (60 * 60 * session->frame_rate());
1359                 frames += tmnow.tm_min * (60 * session->frame_rate());
1360                 frames += tmnow.tm_sec * session->frame_rate();
1361
1362                 session->request_locate (frames);
1363
1364                 /* force displayed area in editor to start no matter
1365                    what "follow playhead" setting is.
1366                 */
1367                 
1368                 if (editor) {
1369                         editor->reset_x_origin (frames - (editor->current_page_frames()/2));
1370                 }
1371         }
1372 }
1373
1374 void
1375 ARDOUR_UI::transport_goto_end ()
1376 {
1377         if (session) {
1378                 nframes_t frame = session->current_end_frame();
1379                 session->request_locate (frame);
1380
1381                 /* force displayed area in editor to start no matter
1382                    what "follow playhead" setting is.
1383                 */
1384                 
1385                 if (editor) {
1386                         editor->reset_x_origin (frame);
1387                 }
1388         }
1389 }
1390
1391 void
1392 ARDOUR_UI::transport_stop ()
1393 {
1394         if (!session) {
1395                 return;
1396         }
1397
1398         if (session->is_auditioning()) {
1399                 session->cancel_audition ();
1400                 return;
1401         }
1402         
1403         session->request_stop (false, true);
1404 }
1405
1406 void
1407 ARDOUR_UI::transport_stop_and_forget_capture ()
1408 {
1409         if (session) {
1410                 session->request_stop (true, true);
1411         }
1412 }
1413
1414 void
1415 ARDOUR_UI::remove_last_capture()
1416 {
1417         if (editor) {
1418                 editor->remove_last_capture();
1419         }
1420 }
1421
1422 void
1423 ARDOUR_UI::transport_record (bool roll)
1424 {
1425         
1426         if (session) {
1427                 switch (session->record_status()) {
1428                 case Session::Disabled:
1429                         if (session->ntracks() == 0) {
1430                                 MessageDialog msg (*editor, _("Please create 1 or more track\nbefore trying to record.\nCheck the Session menu."));
1431                                 msg.run ();
1432                                 return;
1433                         }
1434                         session->maybe_enable_record ();
1435                         if (roll) {
1436                                 transport_roll ();
1437                         }
1438                         break;
1439                 case Session::Recording:
1440                         if (roll) {
1441                                 session->request_stop();
1442                         } else {
1443                                 session->disable_record (false, true);
1444                         }
1445                         break;
1446
1447                 case Session::Enabled:
1448                         session->disable_record (false, true);
1449                 }
1450         }
1451         //cerr << "ARDOUR_UI::transport_record () called roll = " << roll << " session->record_status() = " << session->record_status() << endl;
1452 }
1453
1454 void 
1455 ARDOUR_UI::transport_roll ()
1456 {
1457         if (!session) {
1458                 return;
1459         }
1460
1461         if (session->is_auditioning()) {
1462                 return;
1463         }
1464         
1465         switch (Config->get_slave_source()) {
1466         case None:
1467         case JACK:
1468                 break;
1469         default:
1470                 /* transport controlled by the master */
1471                 return;
1472         }
1473
1474         bool rolling = session->transport_rolling();
1475
1476         if (session->get_play_loop()) {
1477                 /* XXX it is not possible to just leave seamless loop and keep
1478                    playing at present (nov 4th 2009)
1479                 */
1480                 if (!Config->get_seamless_loop()) {
1481                         /* off, and stop */
1482                         session->request_play_loop (false, true);
1483                 } else {
1484                         return;
1485                 }
1486         } else if (session->get_play_range ()) {
1487                 session->request_play_range (0, true);
1488         } 
1489
1490         if (!rolling) {
1491                 session->request_transport_speed (1.0f);
1492         }
1493
1494         map_transport_state ();
1495 }
1496
1497 void
1498 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
1499 {
1500         
1501         if (!session) {
1502                 return;
1503         }
1504
1505         if (session->is_auditioning()) {
1506                 session->cancel_audition ();
1507                 return;
1508         }
1509         
1510         switch (Config->get_slave_source()) {
1511         case None:
1512         case JACK:
1513                 break;
1514         default:
1515                 /* transport controlled by the master */
1516                 return;
1517         }
1518
1519         bool rolling = session->transport_rolling();
1520         bool affect_transport = true;
1521
1522         if (rolling && roll_out_of_bounded_mode) {
1523                 /* drop out of loop/range playback but leave transport rolling */
1524                 if (session->get_play_loop()) {
1525                         if (Config->get_seamless_loop()) {
1526                                 /* the disk buffers contain copies of the loop - we can't 
1527                                    just keep playing, so stop the transport. the user
1528                                    can restart as they wish.
1529                                 */
1530                                 affect_transport = true;
1531                         } else {
1532                                 /* disk buffers are normal, so we can keep playing */
1533                                 affect_transport = false;
1534                         }
1535                         session->request_play_loop (false, true);
1536                 } else if (session->get_play_range ()) {
1537                         affect_transport = false;
1538                         session->request_play_range (0, true);
1539                 } 
1540         } 
1541
1542         if (affect_transport) {
1543                 if (rolling) {
1544                         session->request_stop (with_abort, true);
1545                 } else {
1546                         session->request_transport_speed (1.0f);
1547                 }
1548         }
1549
1550         map_transport_state ();
1551 }
1552
1553 void
1554 ARDOUR_UI::toggle_session_auto_loop ()
1555 {
1556         if (session) {
1557                 if (session->get_play_loop()) {
1558                         if (session->transport_rolling()) {
1559                                 Location * looploc = session->locations()->auto_loop_location();
1560                                 if (looploc) {
1561                                         session->request_locate (looploc->start(), true);
1562                                 }
1563                         } else {
1564                                 session->request_play_loop (false);
1565                         }
1566                 } else {
1567                         Location * looploc = session->locations()->auto_loop_location();
1568                         if (looploc) {
1569                                 session->request_play_loop (true);
1570                         }
1571                 }
1572         }
1573 }
1574
1575 void
1576 ARDOUR_UI::transport_play_selection ()
1577 {
1578         if (!session) {
1579                 return;
1580         }
1581
1582         editor->play_selection ();
1583 }
1584
1585 void
1586 ARDOUR_UI::transport_rewind (int option)
1587 {
1588         float current_transport_speed;
1589  
1590         if (session) {
1591                 current_transport_speed = session->transport_speed();
1592                 
1593                 if (current_transport_speed >= 0.0f) {
1594                         switch (option) {
1595                         case 0:
1596                                 session->request_transport_speed (-1.0f);
1597                                 break;
1598                         case 1:
1599                                 session->request_transport_speed (-4.0f);
1600                                 break;
1601                         case -1:
1602                                 session->request_transport_speed (-0.5f);
1603                                 break;
1604                         }
1605                 } else {
1606                         /* speed up */
1607                         session->request_transport_speed (current_transport_speed * 1.5f);
1608                 }
1609         }
1610 }
1611
1612 void
1613 ARDOUR_UI::transport_forward (int option)
1614 {
1615         float current_transport_speed;
1616         
1617         if (session) {
1618                 current_transport_speed = session->transport_speed();
1619                 
1620                 if (current_transport_speed <= 0.0f) {
1621                         switch (option) {
1622                         case 0:
1623                                 session->request_transport_speed (1.0f);
1624                                 break;
1625                         case 1:
1626                                 session->request_transport_speed (4.0f);
1627                                 break;
1628                         case -1:
1629                                 session->request_transport_speed (0.5f);
1630                                 break;
1631                         }
1632                 } else {
1633                         /* speed up */
1634                         session->request_transport_speed (current_transport_speed * 1.5f);
1635                 }
1636         }
1637 }
1638
1639 void
1640 ARDOUR_UI::toggle_record_enable (uint32_t dstream)
1641 {
1642         if (session == 0) {
1643                 return;
1644         }
1645
1646         boost::shared_ptr<Route> r;
1647         
1648         if ((r = session->route_by_remote_id (dstream)) != 0) {
1649
1650                 Track* t;
1651
1652                 if ((t = dynamic_cast<Track*>(r.get())) != 0) {
1653                         t->diskstream()->set_record_enabled (!t->diskstream()->record_enabled());
1654                 }
1655         }
1656         if (session == 0) {
1657                 return;
1658         }
1659 }
1660
1661 void
1662 ARDOUR_UI::queue_transport_change ()
1663 {
1664         Gtkmm2ext::UI::instance()->call_slot (mem_fun(*this, &ARDOUR_UI::map_transport_state));
1665 }
1666
1667 void
1668 ARDOUR_UI::map_transport_state ()
1669 {
1670         if (!session) {
1671                 auto_loop_button.set_visual_state (0);
1672                 play_selection_button.set_visual_state (0);
1673                 roll_button.set_visual_state (0);
1674                 stop_button.set_visual_state (1);
1675                 return;
1676         }
1677
1678         float sp = session->transport_speed();
1679
1680         if (sp == 1.0f) {
1681                 shuttle_fract = SHUTTLE_FRACT_SPEED1;  /* speed = 1.0, believe it or not */
1682                 shuttle_box.queue_draw ();
1683         } else if (sp == 0.0f) {
1684                 shuttle_fract = 0;
1685                 shuttle_box.queue_draw ();
1686                 update_disk_space ();
1687         }
1688
1689         if (sp != 0.0) {
1690
1691                 if (session->get_play_range()) {
1692
1693                         play_selection_button.set_visual_state (1);
1694                         roll_button.set_visual_state (0);
1695                         auto_loop_button.set_visual_state (0);
1696                         
1697                 } else if (session->get_play_loop ()) {
1698                         
1699                         auto_loop_button.set_visual_state (1);
1700                         play_selection_button.set_visual_state (0);
1701                         roll_button.set_visual_state (0);
1702
1703                 } else {
1704                         
1705                         roll_button.set_visual_state (1);
1706                         play_selection_button.set_visual_state (0);
1707                         auto_loop_button.set_visual_state (0);
1708                 }
1709
1710                 stop_button.set_visual_state (0);
1711
1712         } else {
1713
1714                 stop_button.set_visual_state (1);
1715                 roll_button.set_visual_state (0);
1716                 play_selection_button.set_visual_state (0);
1717                 auto_loop_button.set_visual_state (0);
1718         }
1719
1720 }
1721
1722 void
1723 ARDOUR_UI::GlobalClickBox::printer (char buf[32], Adjustment &adj, void *arg)
1724 {
1725         snprintf (buf, sizeof(buf), "%s", ((GlobalClickBox *) arg)->strings[
1726                 (int) adj.get_value()].c_str());
1727 }
1728
1729 void
1730 ARDOUR_UI::engine_stopped ()
1731 {
1732         ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::engine_stopped));
1733         ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1734         ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1735 }
1736
1737 void
1738 ARDOUR_UI::engine_running ()
1739 {
1740         ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::engine_running));
1741         ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, true);
1742         ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, false);
1743
1744         Glib::RefPtr<Action> action;
1745         const char* action_name = 0;
1746
1747         switch (engine->frames_per_cycle()) {
1748         case 32:
1749                 action_name = X_("JACKLatency32");
1750                 break;
1751         case 64:
1752                 action_name = X_("JACKLatency64");
1753                 break;
1754         case 128:
1755                 action_name = X_("JACKLatency128");
1756                 break;
1757         case 512:
1758                 action_name = X_("JACKLatency512");
1759                 break;
1760         case 1024:
1761                 action_name = X_("JACKLatency1024");
1762                 break;
1763         case 2048:
1764                 action_name = X_("JACKLatency2048");
1765                 break;
1766         case 4096:
1767                 action_name = X_("JACKLatency4096");
1768                 break;
1769         case 8192:
1770                 action_name = X_("JACKLatency8192");
1771                 break;
1772         default:
1773                 /* XXX can we do anything useful ? */
1774                 break;
1775         }
1776
1777         if (action_name) {
1778
1779                 action = ActionManager::get_action (X_("JACK"), action_name);
1780                 
1781                 if (action) {
1782                         Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (action);
1783                         ract->set_active ();
1784                 }
1785         }
1786 }
1787
1788 void
1789 ARDOUR_UI::engine_halted ()
1790 {
1791         ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::engine_halted));
1792
1793         ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1794         ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1795
1796         update_sample_rate (0);
1797
1798         MessageDialog msg (*editor, 
1799                            _("\
1800 JACK has either been shutdown or it\n\
1801 disconnected Ardour because Ardour\n\
1802 was not fast enough. Try to restart\n\
1803 JACK, reconnect and save the session."));
1804         pop_back_splash ();
1805         msg.run ();
1806 }
1807
1808 int32_t
1809 ARDOUR_UI::do_engine_start ()
1810 {
1811         try { 
1812                 engine->start();
1813         }
1814
1815         catch (...) {
1816                 engine->stop ();
1817                 error << _("Unable to start the session running")
1818                       << endmsg;
1819                 unload_session ();
1820                 return -2;
1821         }
1822         
1823         return 0;
1824 }
1825
1826 void
1827 ARDOUR_UI::setup_theme ()
1828 {
1829         theme_manager->setup_theme();
1830 }
1831
1832 void
1833 ARDOUR_UI::update_clocks ()
1834 {
1835         if (!editor || !editor->dragging_playhead()) {
1836                 Clock (session->audible_frame(), false, editor->get_preferred_edit_position()); /* EMIT_SIGNAL */
1837         }
1838 }
1839
1840 void
1841 ARDOUR_UI::start_clocking ()
1842 {
1843         clock_signal_connection = RapidScreenUpdate.connect (mem_fun(*this, &ARDOUR_UI::update_clocks));
1844 }
1845
1846 void
1847 ARDOUR_UI::stop_clocking ()
1848 {
1849         clock_signal_connection.disconnect ();
1850 }
1851         
1852 void
1853 ARDOUR_UI::toggle_clocking ()
1854 {
1855 #if 0
1856         if (clock_button.get_active()) {
1857                 start_clocking ();
1858         } else {
1859                 stop_clocking ();
1860         }
1861 #endif
1862 }
1863
1864 gint
1865 ARDOUR_UI::_blink (void *arg)
1866
1867 {
1868         ((ARDOUR_UI *) arg)->blink ();
1869         return TRUE;
1870 }
1871
1872 void
1873 ARDOUR_UI::blink ()
1874 {
1875         Blink (blink_on = !blink_on); /* EMIT_SIGNAL */
1876 }
1877
1878 void
1879 ARDOUR_UI::start_blinking ()
1880 {
1881         /* Start the blink signal. Everybody with a blinking widget
1882            uses Blink to drive the widget's state.
1883         */
1884
1885         if (blink_timeout_tag < 0) {
1886                 blink_on = false;       
1887                 blink_timeout_tag = g_timeout_add (240, _blink, this);
1888         }
1889 }
1890
1891 void
1892 ARDOUR_UI::stop_blinking ()
1893 {
1894         if (blink_timeout_tag >= 0) {
1895                 g_source_remove (blink_timeout_tag);
1896                 blink_timeout_tag = -1;
1897         }
1898 }
1899
1900 void
1901 ARDOUR_UI::name_io_setup (AudioEngine& engine, 
1902                           string& buf,
1903                           IO& io,
1904                           bool in)
1905 {
1906         if (in) {
1907                 if (io.n_inputs() == 0) {
1908                         buf = _("none");
1909                         return;
1910                 }
1911                 
1912                 /* XXX we're not handling multiple ports yet. */
1913
1914                 const char **connections = io.input(0)->get_connections();
1915                 
1916                 if (connections == 0 || connections[0] == '\0') {
1917                         buf = _("off");
1918                 } else {
1919                         buf = connections[0];
1920                 }
1921
1922                 free (connections);
1923
1924         } else {
1925
1926                 if (io.n_outputs() == 0) {
1927                         buf = _("none");
1928                         return;
1929                 }
1930                 
1931                 /* XXX we're not handling multiple ports yet. */
1932
1933                 const char **connections = io.output(0)->get_connections();
1934                 
1935                 if (connections == 0 || connections[0] == '\0') {
1936                         buf = _("off");
1937                 } else {
1938                         buf = connections[0];
1939                 }
1940
1941                 free (connections);
1942         }
1943 }
1944
1945 /** Ask the user for the name of a new shapshot and then take it.
1946  */
1947 void
1948 ARDOUR_UI::snapshot_session ()
1949 {
1950         ArdourPrompter prompter (true);
1951         string snapname;
1952         char timebuf[128];
1953         time_t n;
1954         struct tm local_time;
1955
1956         time (&n);
1957         localtime_r (&n, &local_time);
1958         strftime (timebuf, sizeof(timebuf), "%FT%T", &local_time);
1959
1960         prompter.set_name ("Prompter");
1961         prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1962         prompter.set_title (_("Take Snapshot"));
1963         prompter.set_prompt (_("Name of New Snapshot"));
1964         prompter.set_initial_text (timebuf);
1965
1966   again:
1967         switch (prompter.run()) {
1968         case RESPONSE_ACCEPT:
1969                 prompter.get_result (snapname);
1970                 if (snapname.length()){
1971                         if (snapname.find ('/') != string::npos) {
1972                                 MessageDialog msg (_("To ensure compatibility with various systems\n"
1973                                                      "snapshot names may not contain a '/' character"));
1974                                 msg.run ();
1975                                 goto again;
1976                         }
1977                         if (snapname.find ('\\') != string::npos) {
1978                                 MessageDialog msg (_("To ensure compatibility with various systems\n"
1979                                                      "snapshot names may not contain a '\\' character"));
1980                                 msg.run ();
1981                                 goto again;
1982                         }
1983                         save_state (snapname);
1984                 }
1985                 break;
1986
1987         default:
1988                 break;
1989         }
1990 }
1991
1992 void
1993 ARDOUR_UI::save_state (const string & name)
1994 {
1995         (void) save_state_canfail (name);
1996 }
1997                 
1998 int
1999 ARDOUR_UI::save_state_canfail (string name)
2000 {
2001         if (session) {
2002                 int ret;
2003
2004                 if (name.length() == 0) {
2005                         name = session->snap_name();
2006                 }
2007
2008                 if ((ret = session->save_state (name)) != 0) {
2009                         return ret;
2010                 }
2011         }
2012         save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2013         return 0;
2014 }
2015
2016 void
2017 ARDOUR_UI::primary_clock_value_changed ()
2018 {
2019         if (session) {
2020                 session->request_locate (primary_clock.current_time ());
2021         }
2022 }
2023
2024 void
2025 ARDOUR_UI::big_clock_value_changed ()
2026 {
2027         if (session) {
2028                 session->request_locate (big_clock.current_time ());
2029         }
2030 }
2031
2032 void
2033 ARDOUR_UI::secondary_clock_value_changed ()
2034 {
2035         if (session) {
2036                 session->request_locate (secondary_clock.current_time ());
2037         }
2038 }
2039
2040 void
2041 ARDOUR_UI::transport_rec_enable_blink (bool onoff) 
2042 {
2043         if (session == 0) {
2044                 return;
2045         }
2046         
2047         switch (session->record_status()) {
2048         case Session::Enabled:
2049                 if (onoff) {
2050                         rec_button.set_visual_state (2);
2051                 } else {
2052                         rec_button.set_visual_state (0);
2053                 }
2054                 break;
2055
2056         case Session::Recording:
2057                 rec_button.set_visual_state (1);
2058                 break;
2059
2060         default:
2061                 rec_button.set_visual_state (0);
2062                 break;
2063         }
2064 }
2065
2066 void
2067 ARDOUR_UI::save_template ()
2068 {
2069         ArdourPrompter prompter (true);
2070         string name;
2071
2072         if (!check_audioengine()) {
2073                 return;
2074         }
2075
2076         prompter.set_name (X_("Prompter"));
2077         prompter.set_title (_("Save Mix Template"));
2078         prompter.set_prompt (_("Name for mix template:"));
2079         prompter.set_initial_text(session->name() + _("-template"));
2080         prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2081
2082         switch (prompter.run()) {
2083         case RESPONSE_ACCEPT:
2084                 prompter.get_result (name);
2085                 
2086                 if (name.length()) {
2087                         session->save_template (name);
2088                 }
2089                 break;
2090
2091         default:
2092                 break;
2093         }
2094 }
2095
2096 void
2097 ARDOUR_UI::fontconfig_dialog ()
2098 {
2099 #if 0
2100   /* this issue seems to have gone away with changes to font handling in GTK/Quartz
2101    */
2102 #ifdef GTKOSX
2103         /* X11 users will always have fontconfig info around, but new GTK-OSX users 
2104            may not and it can take a while to build it. Warn them.
2105         */
2106         
2107         Glib::ustring fontconfig = Glib::build_filename (Glib::get_home_dir(), ".fontconfig");
2108         
2109         if (!Glib::file_test (fontconfig, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_DIR)) {
2110                 MessageDialog msg (*new_session_dialog,
2111                                    _("Welcome to Ardour.\n\n"
2112                                      "The program will take a bit longer to start up\n"
2113                                      "while the system fonts are checked.\n\n"
2114                                      "This will only be done once, and you will\n"
2115                                      "not see this message again\n"),
2116                                    true,
2117                                    Gtk::MESSAGE_INFO,
2118                                    Gtk::BUTTONS_OK);
2119                 pop_back_splash ();
2120                 msg.show_all ();
2121                 msg.present ();
2122                 msg.run ();
2123         }
2124 #endif
2125 #endif
2126 }
2127
2128 void
2129 ARDOUR_UI::parse_cmdline_path (const Glib::ustring& cmdline_path, Glib::ustring& session_name, Glib::ustring& session_path, bool& existing_session)
2130 {
2131         existing_session = false;
2132
2133         if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_DIR)) {
2134                 session_path = cmdline_path;
2135                 existing_session = true;
2136         } else if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_REGULAR)) {
2137                 session_path = Glib::path_get_dirname (string (cmdline_path));
2138                 existing_session = true;
2139         } else {
2140                 /* it doesn't exist, assume the best */
2141                 session_path = Glib::path_get_dirname (string (cmdline_path));
2142         }
2143         
2144         session_name = basename_nosuffix (string (cmdline_path));
2145 }
2146
2147 int
2148 ARDOUR_UI::load_cmdline_session (const Glib::ustring& session_name, const Glib::ustring& session_path, bool& existing_session)
2149 {
2150         /* when this is called, the backend audio system must be running */
2151
2152         /* the main idea here is to deal with the fact that a cmdline argument for the session
2153            can be interpreted in different ways - it could be a directory or a file, and before
2154            we load, we need to know both the session directory and the snapshot (statefile) within it
2155            that we are supposed to use.
2156         */
2157
2158         if (session_name.length() == 0 || session_path.length() == 0) {
2159                 return false;
2160         }
2161         
2162         if (Glib::file_test (session_path, Glib::FILE_TEST_IS_DIR)) {
2163
2164                 Glib::ustring predicted_session_file;
2165                 
2166                 predicted_session_file = session_path;
2167                 predicted_session_file += '/';
2168                 predicted_session_file += session_name;
2169                 predicted_session_file += Session::statefile_suffix();
2170                 
2171                 if (Glib::file_test (predicted_session_file, Glib::FILE_TEST_EXISTS)) {
2172                         existing_session = true;
2173                 }
2174                 
2175         } else if (Glib::file_test (session_path, Glib::FILE_TEST_EXISTS)) {
2176                 
2177                 if (session_path.find (Session::statefile_suffix()) == session_path.length() - 7) {
2178                         /* existing .ardour file */
2179                         existing_session = true;
2180                 }
2181
2182         } else {
2183                 existing_session = false;
2184         }
2185         
2186         /* lets just try to load it */
2187         
2188         if (create_engine ()) {
2189                 backend_audio_error (false, new_session_dialog);
2190                 return -1;
2191         }
2192         
2193         return load_session (session_path, session_name);
2194 }
2195
2196 bool
2197 ARDOUR_UI::ask_about_loading_existing_session (const Glib::ustring& session_path)
2198 {
2199         Glib::ustring str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2200         
2201         MessageDialog msg (str,
2202                            false,
2203                            Gtk::MESSAGE_WARNING,
2204                            Gtk::BUTTONS_YES_NO,
2205                            true);
2206         
2207         
2208         msg.set_name (X_("CleanupDialog"));
2209         msg.set_title (_("Cleanup Unused Sources"));
2210         msg.set_wmclass (X_("existing_session"), "Ardour");
2211         msg.set_position (Gtk::WIN_POS_MOUSE);
2212         pop_back_splash ();
2213
2214         switch (msg.run()) {
2215         case RESPONSE_YES:
2216                 return true;
2217                 break;
2218         }
2219         return false;
2220 }
2221
2222 int
2223 ARDOUR_UI::build_session_from_nsd (const Glib::ustring& session_path, const Glib::ustring& session_name)
2224 {
2225         
2226         uint32_t cchns;
2227         uint32_t mchns;
2228         AutoConnectOption iconnect;
2229         AutoConnectOption oconnect;
2230         uint32_t nphysin;
2231         uint32_t nphysout;
2232         
2233         if (Profile->get_sae()) {
2234                 
2235                 cchns = 0;
2236                 mchns = 2;
2237                 iconnect = AutoConnectPhysical;
2238                 oconnect = AutoConnectMaster;
2239                 nphysin = 0; // use all available
2240                 nphysout = 0; // use all available
2241                 
2242         } else {
2243                 
2244                 /* get settings from advanced section of NSD */
2245                 
2246                 if (new_session_dialog->create_control_bus()) {
2247                         cchns = (uint32_t) new_session_dialog->control_channel_count();
2248                 } else {
2249                         cchns = 0;
2250                 }
2251                 
2252                 if (new_session_dialog->create_master_bus()) {
2253                         mchns = (uint32_t) new_session_dialog->master_channel_count();
2254                 } else {
2255                         mchns = 0;
2256                 }
2257                 
2258                 if (new_session_dialog->connect_inputs()) {
2259                         iconnect = AutoConnectPhysical;
2260                 } else {
2261                         iconnect = AutoConnectOption (0);
2262                 }
2263                 
2264                 /// @todo some minor tweaks.
2265
2266                 oconnect = AutoConnectOption (0);
2267                 
2268                 if (new_session_dialog->connect_outputs()) {
2269                         if (new_session_dialog->connect_outs_to_master()) {
2270                                 oconnect = AutoConnectMaster;
2271                         } else if (new_session_dialog->connect_outs_to_physical()) {
2272                                 oconnect = AutoConnectPhysical;
2273                         }
2274                 }
2275                 
2276                 nphysin = (uint32_t) new_session_dialog->input_limit_count();
2277                 nphysout = (uint32_t) new_session_dialog->output_limit_count();
2278         }
2279         
2280         if (build_session (session_path,
2281                            session_name,
2282                            cchns,
2283                            mchns,
2284                            iconnect,
2285                            oconnect,
2286                            nphysin,
2287                            nphysout, 
2288                            engine->frame_rate() * 60 * 5)) {
2289                 
2290                 return -1;
2291         }
2292
2293         return 0;
2294 }
2295
2296 void
2297 ARDOUR_UI::end_loading_messages ()
2298 {
2299         // hide_splash ();
2300 }
2301
2302 void
2303 ARDOUR_UI::loading_message (const std::string& msg)
2304 {
2305         show_splash ();
2306         splash->message (msg);
2307         flush_pending ();
2308 }
2309
2310 void
2311 ARDOUR_UI::idle_load (const Glib::ustring& path)
2312 {
2313         if (session) {
2314                 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2315                         /* /path/to/foo => /path/to/foo, foo */
2316                         load_session (path, basename_nosuffix (path));
2317                 } else {
2318                         /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2319                         load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2320                 }
2321         } else {
2322
2323                 ARDOUR_COMMAND_LINE::session_name = path;
2324
2325                 if (new_session_dialog) {
2326
2327
2328                         /* make it break out of Dialog::run() and
2329                            start again.
2330                          */
2331
2332                         new_session_dialog->response (1);
2333                 }
2334         }
2335 }
2336
2337 bool
2338 ARDOUR_UI::get_session_parameters (bool backend_audio_is_running, bool should_be_new)
2339 {
2340         bool existing_session = false;
2341         Glib::ustring session_name;
2342         Glib::ustring session_path;
2343         Glib::ustring template_name;
2344         int response;
2345         
2346   begin:
2347         response = Gtk::RESPONSE_NONE;
2348
2349         if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
2350
2351                 parse_cmdline_path (ARDOUR_COMMAND_LINE::session_name, session_name, session_path, existing_session);
2352
2353                 /* don't ever reuse this */
2354
2355                 ARDOUR_COMMAND_LINE::session_name = string();
2356
2357                 if (existing_session && backend_audio_is_running) {
2358
2359                         /* just load the thing already */
2360
2361                         if (load_cmdline_session (session_name, session_path, existing_session) == 0) {
2362                                 return true;
2363                         }
2364                 }
2365
2366                 /* make the NSD use whatever information we have */
2367
2368                 new_session_dialog->set_session_name (session_name);
2369                 new_session_dialog->set_session_folder (session_path);
2370         }
2371
2372         /* loading failed, or we need the NSD for something */
2373
2374         new_session_dialog->set_modal (false);
2375         new_session_dialog->set_position (WIN_POS_CENTER);
2376         new_session_dialog->set_current_page (0);
2377         new_session_dialog->set_existing_session (existing_session);
2378         new_session_dialog->reset_recent();
2379
2380         do {
2381                 new_session_dialog->set_have_engine (backend_audio_is_running);
2382                 new_session_dialog->present ();
2383                 response = new_session_dialog->run ();
2384                 
2385                 _session_is_new = false;
2386                 
2387                 /* handle possible negative responses */
2388
2389                 switch (response) {
2390                 case 1:
2391                         /* sent by idle_load, meaning restart the whole process again */
2392                         new_session_dialog->hide();
2393                         new_session_dialog->reset();
2394                         goto begin;
2395                         break;
2396
2397                 case Gtk::RESPONSE_CANCEL:
2398                 case Gtk::RESPONSE_DELETE_EVENT:
2399                         if (!session) {
2400                                 if (engine && engine->running()) {
2401                                         engine->stop (true);
2402                                 }
2403                                 quit();
2404                         }
2405                         new_session_dialog->hide ();
2406                         return false;
2407                         
2408                 case Gtk::RESPONSE_NONE:
2409                         /* "Clear" was pressed */
2410                         goto try_again;
2411                 }
2412
2413                 fontconfig_dialog();
2414
2415                 if (!backend_audio_is_running) {
2416                         int ret = new_session_dialog->engine_control.setup_engine ();
2417                         if (ret < 0) {
2418                                 return false;
2419                         } else if (ret > 0) {
2420                                 response = Gtk::RESPONSE_REJECT;
2421                                 goto try_again;
2422                         }
2423                         
2424                         /* hide the NSD while we start up the engine */
2425
2426                         new_session_dialog->hide ();
2427                         flush_pending ();
2428                 }
2429
2430                 if (create_engine ()) {
2431
2432                         backend_audio_error (!backend_audio_is_running, new_session_dialog);
2433                         flush_pending ();
2434
2435                         new_session_dialog->set_existing_session (false);
2436                         new_session_dialog->set_current_page (0); // new engine page
2437                         new_session_dialog->engine_control.unset_interface_chosen ();
2438
2439                         response = Gtk::RESPONSE_NONE;
2440                         goto try_again;
2441                 }
2442
2443                 backend_audio_is_running = true;                
2444                         
2445                 if (response == Gtk::RESPONSE_OK) {
2446
2447                         session_name = new_session_dialog->session_name();
2448
2449                         if (session_name.empty()) {
2450                                 response = Gtk::RESPONSE_NONE;
2451                                 goto try_again;
2452                         } 
2453
2454                         /* if the user mistakenly typed path information into the session filename entry,
2455                            convert what they typed into a path & a name
2456                         */
2457                         
2458                         if (session_name[0] == '/' || 
2459                             (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == '/') ||
2460                             (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == '/')) {
2461
2462                                 session_path = Glib::path_get_dirname (session_name);
2463                                 session_name = Glib::path_get_basename (session_name);
2464                                 
2465                         } else {
2466
2467                                 session_path = new_session_dialog->session_folder();
2468
2469                         }
2470
2471                         template_name = Glib::ustring();                        
2472                         switch (new_session_dialog->which_page()) {
2473
2474                         case NewSessionDialog::OpenPage: 
2475                                 goto loadit;
2476                                 break;
2477
2478                         case NewSessionDialog::EnginePage:
2479                                 if (new_session_dialog->engine_control.interface_chosen() && !session_path.empty()) {
2480                                         goto loadit;
2481                                 } else {
2482                                         goto try_again;
2483                                 }
2484                                 break;
2485
2486                         case NewSessionDialog::NewPage: /* nominally the "new" session creator, but could be in use for an old session */
2487                                 
2488                                 should_be_new = true;
2489
2490                                 if (session_name.find ('/') != Glib::ustring::npos) {
2491                                         MessageDialog msg (*new_session_dialog, _("To ensure compatibility with various systems\n"
2492                                                          "session names may not contain a '/' character"));
2493                                         msg.run ();
2494                                         response = RESPONSE_NONE;
2495                                         goto try_again;
2496                                 }
2497
2498                                 if (session_name.find ('\\') != Glib::ustring::npos) {
2499                                         MessageDialog msg (*new_session_dialog, _("To ensure compatibility with various systems\n"
2500                                                          "session names may not contain a '\\' character"));
2501                                         msg.run ();
2502                                         response = RESPONSE_NONE;
2503                                         goto try_again;
2504                                 }
2505
2506                                 //XXX This is needed because session constructor wants a 
2507                                 //non-existant path. hopefully this will be fixed at some point.
2508
2509                                 session_path = Glib::build_filename (session_path, session_name);
2510
2511                                 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
2512
2513                                         new_session_dialog->hide ();
2514
2515                                         if (ask_about_loading_existing_session (session_path)) {
2516                                                 goto loadit;
2517                                         } else {
2518                                                 response = RESPONSE_NONE;
2519                                                 goto try_again;
2520                                         } 
2521                                 }
2522
2523                                 _session_is_new = true;
2524                                                 
2525                                 if (new_session_dialog->use_session_template()) {
2526
2527                                         template_name = new_session_dialog->session_template_name();
2528                                         goto loadit;
2529                           
2530                                 } else {
2531                                         if (build_session_from_nsd (session_path, session_name)) {
2532                                                 response = RESPONSE_NONE;
2533                                                 goto try_again;
2534                                         }
2535                                         goto done;
2536                                 }
2537                                 break;
2538                                 
2539                         default:
2540                                 break;
2541                         }
2542                         
2543                   loadit:
2544                         new_session_dialog->hide ();
2545
2546                         if (load_session (session_path, session_name, template_name)) {
2547                                 /* force a retry */
2548                                 response = Gtk::RESPONSE_NONE;
2549                         }
2550
2551                   try_again:
2552                         if (response == Gtk::RESPONSE_NONE) {
2553                                 new_session_dialog->set_existing_session (false);
2554                                 new_session_dialog->reset ();
2555                         }
2556                 }
2557
2558         } while (response == Gtk::RESPONSE_NONE || response == Gtk::RESPONSE_REJECT);
2559
2560   done:
2561         show();
2562         new_session_dialog->hide();
2563         new_session_dialog->reset();
2564         goto_editor_window ();
2565         return true;
2566 }       
2567
2568 void
2569 ARDOUR_UI::close_session ()
2570 {
2571         if (!check_audioengine()) {
2572                 return;
2573         }
2574
2575         if (unload_session (true)) {
2576                 return;
2577         }
2578         
2579         get_session_parameters (true, false);
2580 }
2581
2582 int
2583 ARDOUR_UI::load_session (const Glib::ustring& path, const Glib::ustring& snap_name, Glib::ustring mix_template)
2584 {
2585         Session *new_session;
2586         int unload_status;
2587         int retval = -1;
2588
2589         session_loaded = false;
2590
2591         if (!check_audioengine()) {
2592                 return -1;
2593         }
2594
2595         unload_status = unload_session ();
2596
2597         if (unload_status < 0) {
2598                 goto out;
2599         } else if (unload_status > 0) {
2600                 retval = 0;
2601                 goto out;
2602         }
2603
2604         loading_message (_("Please wait while Ardour loads your session"));
2605
2606         try {
2607                 new_session = new Session (*engine, path, snap_name, mix_template);
2608         }
2609
2610         /* this one is special */
2611
2612         catch (AudioEngine::PortRegistrationFailure& err) {
2613
2614                 MessageDialog msg (err.what(),
2615                                    true,
2616                                    Gtk::MESSAGE_INFO,
2617                                    Gtk::BUTTONS_CLOSE);
2618                 
2619                 msg.set_title (_("Port Registration Error"));
2620                 msg.set_secondary_text (_("Click the Close button to try again."));
2621                 msg.set_position (Gtk::WIN_POS_CENTER);
2622                 pop_back_splash ();
2623                 msg.present ();
2624
2625                 int response = msg.run ();
2626
2627                 msg.hide ();
2628
2629                 switch (response) {
2630                 case RESPONSE_CANCEL:
2631                         exit (1);
2632                 default:
2633                         break;
2634                 }
2635                 goto out;
2636         }
2637
2638         /* this exception is also special */
2639
2640         catch (Session::SRMismatchRejected& err) {
2641                 goto out; /* just go back and reload something else, etc. */
2642         }
2643
2644         catch (...) {
2645
2646                 MessageDialog msg (string_compose(_("Session \"%1 (snapshot %2)\" did not load successfully"), path, snap_name),
2647                                    true,
2648                                    Gtk::MESSAGE_INFO,
2649                                    Gtk::BUTTONS_CLOSE);
2650                 
2651                 msg.set_title (_("Loading Error"));
2652                 msg.set_secondary_text (_("Click the Close button to try again."));
2653                 msg.set_position (Gtk::WIN_POS_CENTER);
2654                 pop_back_splash ();
2655                 msg.present ();
2656
2657                 int response = msg.run ();
2658
2659                 msg.hide ();
2660
2661                 switch (response) {
2662                 case RESPONSE_CANCEL:
2663                         exit (1);
2664                 default:
2665                         break;
2666                 }
2667                 goto out;
2668         }
2669
2670         connect_to_session (new_session);
2671
2672         Config->set_current_owner (ConfigVariableBase::Interface);
2673
2674         session_loaded = true;
2675         
2676         goto_editor_window ();
2677
2678         if (session) {
2679                 session->set_clean ();
2680         }
2681
2682         flush_pending ();
2683         retval = 0;
2684
2685   out:
2686         return retval;
2687 }
2688
2689 int
2690 ARDOUR_UI::build_session (const Glib::ustring& path, const Glib::ustring& snap_name, 
2691                           uint32_t control_channels,
2692                           uint32_t master_channels, 
2693                           AutoConnectOption input_connect,
2694                           AutoConnectOption output_connect,
2695                           uint32_t nphysin,
2696                           uint32_t nphysout,
2697                           nframes_t initial_length)
2698 {
2699         Session *new_session;
2700         int x;
2701
2702         if (!check_audioengine()) {
2703                 return -1;
2704         }
2705
2706         session_loaded = false;
2707
2708         x = unload_session ();
2709
2710         if (x < 0) {
2711                 return -1;
2712         } else if (x > 0) {
2713                 return 0;
2714         }
2715         
2716         _session_is_new = true;
2717
2718         try {
2719                 new_session = new Session (*engine, path, snap_name, input_connect, output_connect,
2720                                            control_channels, master_channels, nphysin, nphysout, initial_length);
2721         }
2722
2723         catch (...) {
2724
2725                 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
2726                 pop_back_splash ();
2727                 msg.run ();
2728                 return -1;
2729         }
2730
2731         connect_to_session (new_session);
2732
2733         session_loaded = true;
2734
2735         new_session->save_state(new_session->name());
2736
2737         return 0;
2738 }
2739
2740 void
2741 ARDOUR_UI::show ()
2742 {
2743         if (editor) {
2744                 editor->show_window ();
2745                 
2746                 if (!shown_flag) {
2747                         editor->present ();
2748                 }
2749
2750                 shown_flag = true;
2751         }
2752 }
2753
2754 void
2755 ARDOUR_UI::show_about ()
2756 {
2757         if (about == 0) {
2758                 about = new About;
2759                 about->signal_response().connect(mem_fun (*this, &ARDOUR_UI::about_signal_response) );
2760         }
2761
2762         about->set_transient_for(*editor);
2763
2764         about->show_all ();
2765 }
2766
2767 void
2768 ARDOUR_UI::launch_chat ()
2769 {
2770 #ifdef __APPLE__
2771         NagScreen::open_uri("http://webchat.freenode.net/?channels=ardour-osx");
2772 #else
2773         NagScreen::open_uri("http://webchat.freenode.net/?channels=ardour");
2774 #endif
2775 }
2776
2777 void
2778 ARDOUR_UI::hide_about ()
2779 {
2780         if (about) {
2781                 about->get_window()->set_cursor ();
2782                 about->hide ();
2783         }
2784 }
2785
2786 void
2787 ARDOUR_UI::about_signal_response(int response)
2788 {
2789         hide_about();
2790 }
2791
2792 void
2793 ARDOUR_UI::show_splash ()
2794 {
2795         if (splash == 0) {
2796                 try {
2797                         splash = new Splash;
2798                 } catch (...) {
2799                         return;
2800                 }
2801         }
2802
2803         splash->show ();
2804         splash->present ();
2805         splash->queue_draw ();
2806         splash->get_window()->process_updates (true);
2807         flush_pending ();
2808 }
2809
2810 void
2811 ARDOUR_UI::hide_splash ()
2812 {
2813         if (splash) {
2814                 splash->hide();
2815         }
2816 }
2817
2818 void
2819 ARDOUR_UI::display_cleanup_results (Session::cleanup_report& rep, const gchar* list_title, 
2820                                     const string& plural_msg, const string& singular_msg)
2821 {
2822         size_t removed;
2823
2824         removed = rep.paths.size();
2825
2826         if (removed == 0) {
2827                 MessageDialog msgd (*editor,
2828                                     _("No audio files were ready for cleanup"), 
2829                                     true,
2830                                     Gtk::MESSAGE_INFO,
2831                                     (Gtk::ButtonsType)(Gtk::BUTTONS_OK)  );
2832                 msgd.set_secondary_text (_("If this seems suprising, \n\
2833 check for any existing snapshots.\n\
2834 These may still include regions that\n\
2835 require some unused files to continue to exist."));
2836         
2837                 msgd.run ();
2838                 return;
2839         } 
2840
2841         ArdourDialog results (_("ardour: cleanup"), true, false);
2842         
2843         struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
2844             CleanupResultsModelColumns() { 
2845                     add (visible_name);
2846                     add (fullpath);
2847             }
2848             Gtk::TreeModelColumn<Glib::ustring> visible_name;
2849             Gtk::TreeModelColumn<Glib::ustring> fullpath;
2850         };
2851
2852         
2853         CleanupResultsModelColumns results_columns;
2854         Glib::RefPtr<Gtk::ListStore> results_model;
2855         Gtk::TreeView results_display;
2856         
2857         results_model = ListStore::create (results_columns);
2858         results_display.set_model (results_model);
2859         results_display.append_column (list_title, results_columns.visible_name);
2860
2861         results_display.set_name ("CleanupResultsList");
2862         results_display.set_headers_visible (true);
2863         results_display.set_headers_clickable (false);
2864         results_display.set_reorderable (false);
2865
2866         Gtk::ScrolledWindow list_scroller;
2867         Gtk::Label txt;
2868         Gtk::VBox dvbox;
2869         Gtk::HBox dhbox;  // the hbox for the image and text
2870         Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
2871         Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO,  Gtk::ICON_SIZE_DIALOG));
2872
2873         dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
2874
2875
2876         /* subst:
2877            %1 - number of files removed
2878            %2 - location of "dead_sounds"
2879            %3 - size of files affected
2880            %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
2881         */
2882
2883         const char* bprefix;
2884         float space_adjusted;
2885
2886         if (rep.space < 1000000.0f) {
2887                 bprefix = X_("kilo");
2888                 space_adjusted = truncf((float)rep.space / 1000.0f);
2889         } else if (rep.space < (1000000.0f * 1000)) {
2890                 bprefix = X_("mega");
2891                 space_adjusted = truncf((float)rep.space / (1000000.0f));
2892         } else {
2893                 bprefix = X_("giga");
2894                 space_adjusted = truncf((float)rep.space / (1000000.0f * 1000));
2895         }
2896
2897         if (removed > 1) {
2898                 txt.set_text (string_compose (plural_msg, removed, session->path() + "dead_sounds", space_adjusted, bprefix));
2899         } else {
2900                 txt.set_text (string_compose (singular_msg, removed, session->path() + "dead_sounds", space_adjusted, bprefix));
2901         }
2902
2903         dhbox.pack_start (*dimage, true, false, 5);
2904         dhbox.pack_start (txt, true, false, 5);
2905
2906         for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
2907                 TreeModel::Row row = *(results_model->append());
2908                 row[results_columns.visible_name] = *i;
2909                 row[results_columns.fullpath] = *i;
2910         }
2911         
2912         list_scroller.add (results_display);
2913         list_scroller.set_size_request (-1, 150);
2914         list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
2915
2916         dvbox.pack_start (dhbox, true, false, 5);
2917         dvbox.pack_start (list_scroller, true, false, 5);
2918         ddhbox.pack_start (dvbox, true, false, 5);
2919
2920         results.get_vbox()->pack_start (ddhbox, true, false, 5);
2921         results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
2922         results.set_default_response (RESPONSE_CLOSE);
2923         results.set_position (Gtk::WIN_POS_MOUSE);
2924         results.show_all_children ();
2925         results.set_resizable (false);
2926
2927         results.run ();
2928
2929 }
2930
2931 void
2932 ARDOUR_UI::cleanup ()
2933 {
2934         if (session == 0) {
2935                 /* shouldn't happen: menu item is insensitive */
2936                 return;
2937         }
2938
2939
2940         MessageDialog  checker (_("Are you sure you want to cleanup?"),
2941                                 true,
2942                                 Gtk::MESSAGE_QUESTION,
2943                                 (Gtk::ButtonsType)(Gtk::BUTTONS_NONE));
2944
2945         checker.set_secondary_text(_("Cleanup is a destructive operation.\n\
2946 ALL undo/redo information will be lost if you cleanup.\n\
2947 After cleanup, unused audio files will be moved to a \
2948 \"dead sounds\" location."));
2949         
2950         checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
2951         checker.add_button (_("Clean Up"), RESPONSE_ACCEPT);
2952         checker.set_default_response (RESPONSE_CANCEL);
2953
2954         checker.set_name (_("CleanupDialog"));
2955         checker.set_wmclass (X_("ardour_cleanup"), "Ardour");
2956         checker.set_position (Gtk::WIN_POS_MOUSE);
2957
2958         switch (checker.run()) {
2959         case RESPONSE_ACCEPT:
2960                 break;
2961         default:
2962                 return;
2963         }
2964
2965         Session::cleanup_report rep;
2966
2967         editor->prepare_for_cleanup ();
2968
2969         /* do not allow flush until a session is reloaded */
2970
2971         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
2972         if (act) {
2973                 act->set_sensitive (false);
2974         }
2975
2976         if (session->cleanup_sources (rep)) {
2977                 editor->finish_cleanup ();
2978                 return;
2979         }
2980         
2981         editor->finish_cleanup ();
2982
2983         checker.hide();
2984         display_cleanup_results (rep, 
2985                                  _("cleaned files"),
2986                                  _("\
2987 The following %1 files were not in use and \n\
2988 have been moved to:\n\
2989 %2. \n\n\
2990 Flushing the wastebasket will \n\
2991 release an additional\n\
2992 %3 %4bytes of disk space.\n"),
2993                                  _("\
2994 The following file was not in use and \n        \
2995 has been moved to:\n                            \
2996 %2. \n\n\
2997 Flushing the wastebasket will \n\
2998 release an additional\n\
2999 %3 %4bytes of disk space.\n"
3000                                          ));
3001
3002 }
3003
3004 void
3005 ARDOUR_UI::flush_trash ()
3006 {
3007         if (session == 0) {
3008                 /* shouldn't happen: menu item is insensitive */
3009                 return;
3010         }
3011
3012         Session::cleanup_report rep;
3013
3014         if (session->cleanup_trash_sources (rep)) {
3015                 return;
3016         }
3017
3018         display_cleanup_results (rep, 
3019                                  _("deleted file"),
3020                                  _("The following %1 files were deleted from\n\
3021 %2,\n\
3022 releasing %3 %4bytes of disk space"),
3023                                  _("The following file was deleted from\n\
3024 %2,\n\
3025 releasing %3 %4bytes of disk space"));
3026 }
3027
3028 void
3029 ARDOUR_UI::add_route (Gtk::Window* float_window)
3030 {
3031         int count;
3032
3033         if (!session) {
3034                 return;
3035         }
3036
3037         if (add_route_dialog == 0) {
3038                 add_route_dialog = new AddRouteDialog;
3039                 if (float_window) {
3040                         add_route_dialog->set_transient_for (*float_window);
3041                 }
3042         }
3043
3044         if (add_route_dialog->is_visible()) {
3045                 /* we're already doing this */
3046                 return;
3047         }
3048
3049         ResponseType r = (ResponseType) add_route_dialog->run ();
3050         
3051         add_route_dialog->hide();
3052
3053         switch (r) {
3054         case RESPONSE_ACCEPT:
3055                 break;
3056         default:
3057                 return;
3058                 break;
3059         }
3060
3061         if ((count = add_route_dialog->count()) <= 0) {
3062                 return;
3063         }
3064
3065         string template_path = add_route_dialog->track_template();
3066
3067         if (!template_path.empty()) {
3068           session->new_route_from_template (count, template_path);
3069           return;
3070         }
3071         
3072         uint32_t input_chan = add_route_dialog->channels ();
3073         uint32_t output_chan;
3074         string name_template = add_route_dialog->name_template ();
3075         bool track = add_route_dialog->track ();
3076
3077         AutoConnectOption oac = Config->get_output_auto_connect();
3078
3079         if (oac & AutoConnectMaster) {
3080                 output_chan = (session->master_out() ? session->master_out()->n_inputs() : input_chan);
3081         } else {
3082                 output_chan = input_chan;
3083         }
3084
3085         /* XXX do something with name template */
3086
3087         if (track) {
3088                 session_add_audio_track (input_chan, output_chan, add_route_dialog->mode(), count);
3089         } else {
3090                 session_add_audio_bus (input_chan, output_chan, count);
3091         }
3092 }
3093
3094 XMLNode*
3095 ARDOUR_UI::mixer_settings () const
3096 {
3097         XMLNode* node = 0;
3098
3099         if (session) {
3100                 node = session->instant_xml(X_("Mixer"), session->path());
3101         } else {
3102                 node = Config->instant_xml(X_("Mixer"), get_user_ardour_path());
3103         }
3104
3105         if (!node) {
3106                 node = new XMLNode (X_("Mixer"));
3107         }
3108
3109         return node;
3110 }
3111
3112 XMLNode*
3113 ARDOUR_UI::editor_settings () const
3114 {
3115         XMLNode* node = 0;
3116
3117         if (session) {
3118                 node = session->instant_xml(X_("Editor"), session->path());
3119         } else {
3120                 node = Config->instant_xml(X_("Editor"), get_user_ardour_path());
3121         }
3122         
3123         if (!node) {
3124                 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
3125                         node = Config->instant_xml(X_("Editor"), getenv("ARDOUR_INSTANT_XML_PATH"));
3126                 }
3127         }
3128
3129         if (!node) {
3130                 node = new XMLNode (X_("Editor"));
3131         }
3132         return node;
3133 }
3134
3135 XMLNode*
3136 ARDOUR_UI::keyboard_settings () const
3137 {
3138         XMLNode* node = 0;
3139
3140         node = Config->extra_xml(X_("Keyboard"));
3141         
3142         if (!node) {
3143                 node = new XMLNode (X_("Keyboard"));
3144         }
3145         return node;
3146 }
3147
3148 void
3149 ARDOUR_UI::create_xrun_marker(nframes_t where)
3150 {
3151         editor->mouse_add_new_marker (where, false, true);
3152 }
3153
3154 void
3155 ARDOUR_UI::halt_on_xrun_message ()
3156 {
3157         MessageDialog msg (*editor,
3158                            _("Recording was stopped because your system could not keep up."));
3159         msg.run ();
3160 }
3161
3162 void
3163 ARDOUR_UI::xrun_handler(nframes_t where)
3164 {
3165         if (!session) {
3166                 return;
3167         }
3168
3169         ENSURE_GUI_THREAD (bind(mem_fun(*this, &ARDOUR_UI::xrun_handler), where));
3170
3171         if (session && Config->get_create_xrun_marker() && session->actively_recording()) {
3172                 create_xrun_marker(where);
3173         }
3174
3175         if (session && Config->get_stop_recording_on_xrun() && session->actively_recording()) {
3176                 halt_on_xrun_message ();
3177         }
3178 }
3179
3180 bool
3181 ARDOUR_UI::preset_file_exists_handler ()
3182 {
3183         /* if driven from another thread, say "do not overwrite" and show the user nothing.
3184          */
3185
3186         if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {        \
3187                 return false;
3188         }
3189         
3190         HBox* hbox = new HBox();
3191         Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3192         Gtk::Dialog dialog (_("Preset Exists"), true, false);
3193         Label  message (_("\
3194 A preset with this name already exists for this plugin.\n\
3195 \n\
3196 What you would like to do?\n"));
3197         image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3198         hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3199         hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3200         dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3201         dialog.add_button (_("Overwrite the existing preset"), RESPONSE_ACCEPT);
3202         dialog.add_button (_("Leave the existing preset alone"), RESPONSE_REJECT);
3203         dialog.set_default_response (RESPONSE_ACCEPT);
3204         dialog.set_position (WIN_POS_MOUSE);
3205         dialog.set_type_hint (Gdk::WINDOW_TYPE_HINT_UTILITY); // need to make it float above the preset name dialog
3206
3207         message.show();
3208         image->show();
3209         hbox->show();
3210
3211         switch (dialog.run ()) {
3212         case RESPONSE_ACCEPT:
3213                 return true;
3214         default:
3215                 return false;
3216         }
3217 }
3218
3219 void
3220 ARDOUR_UI::push_buffer_stats (uint32_t capture, uint32_t playback)
3221 {
3222         time_t now;
3223         time (&now);
3224
3225         while (disk_buffer_stats.size() > 60) {
3226                 disk_buffer_stats.pop_front ();
3227         }
3228
3229         disk_buffer_stats.push_back (DiskBufferStat (now, capture, playback));
3230 }
3231
3232 void
3233 ARDOUR_UI::write_buffer_stats ()
3234 {
3235         std::ofstream fout;
3236         struct tm tm;
3237         char buf[64];
3238         char path[PATH_MAX+1];  int fd;
3239
3240         strcpy (path, "ardourBufferingXXXXXX");
3241
3242         if ((fd = mkstemp (path )) < 0) {
3243                 cerr << X_("cannot find temporary name for ardour buffer stats") << endl;
3244                 return;
3245         }
3246         
3247         fout.open (path);
3248         close (fd);
3249
3250         if (!fout) {
3251                 cerr << string_compose (X_("cannot open file %1 for ardour buffer stats"), path) << endl;
3252                 return;
3253         }
3254
3255         for (list<DiskBufferStat>::iterator i = disk_buffer_stats.begin(); i != disk_buffer_stats.end(); ++i) {
3256                 localtime_r (&(*i).when, &tm);
3257                 strftime (buf, sizeof (buf), "%T", &tm);
3258                 fout << buf << ' ' << (*i).capture << ' ' << (*i).playback << endl;
3259         }
3260         
3261         disk_buffer_stats.clear ();
3262
3263         fout.close ();
3264
3265         cerr << "Ardour buffering statistics can be found in: " << path << endl;
3266 }
3267
3268 void
3269 ARDOUR_UI::disk_overrun_handler ()
3270 {
3271
3272         ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::disk_overrun_handler));
3273
3274         write_buffer_stats ();
3275
3276         if (!have_disk_speed_dialog_displayed) {
3277                 have_disk_speed_dialog_displayed = true;
3278                 MessageDialog* msg = new MessageDialog (*editor, _("\
3279 The disk system on your computer\n\
3280 was not able to keep up with Ardour.\n\
3281 \n\
3282 Specifically, it failed to write data to disk\n\
3283 quickly enough to keep up with recording.\n"));
3284                 msg->signal_response().connect (bind (mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3285                 msg->show_all ();
3286         }
3287 }
3288
3289 void
3290 ARDOUR_UI::disk_underrun_handler ()
3291 {
3292
3293         ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::disk_underrun_handler));
3294
3295         write_buffer_stats ();
3296
3297         if (!have_disk_speed_dialog_displayed) {
3298                 have_disk_speed_dialog_displayed = true;
3299                 MessageDialog* msg = new MessageDialog (*editor,
3300                                    _("The disk system on your computer\n\
3301 was not able to keep up with Ardour.\n\
3302 \n\
3303 Specifically, it failed to read data from disk\n\
3304 quickly enough to keep up with playback.\n"));
3305                 msg->signal_response().connect (bind (mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3306                 msg->show_all ();
3307         } 
3308 }
3309
3310 void
3311 ARDOUR_UI::disk_speed_dialog_gone (int ignored_response, MessageDialog* msg)
3312 {
3313         have_disk_speed_dialog_displayed = false;
3314         delete msg;
3315 }
3316
3317 void
3318 ARDOUR_UI::session_dialog (std::string msg)
3319 {
3320         ENSURE_GUI_THREAD (bind (mem_fun(*this, &ARDOUR_UI::session_dialog), msg));
3321         
3322         MessageDialog* d;
3323
3324         if (editor) {
3325                 d = new MessageDialog (*editor, msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3326         } else {
3327                 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3328         }
3329
3330         d->show_all ();
3331         d->run ();
3332         delete d;
3333 }       
3334
3335 int
3336 ARDOUR_UI::pending_state_dialog ()
3337 {
3338         HBox* hbox = new HBox();
3339         Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3340         ArdourDialog dialog (_("Crash Recovery"), true);
3341         Label  message (_("\
3342 This session appears to have been in\n\
3343 middle of recording when ardour or\n\
3344 the computer was shutdown.\n\
3345 \n\
3346 Ardour can recover any captured audio for\n\
3347 you, or it can ignore it. Please decide\n\
3348 what you would like to do.\n"));
3349         image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3350         hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3351         hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3352         dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3353         dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
3354         dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
3355         dialog.set_default_response (RESPONSE_ACCEPT);
3356         dialog.set_position (WIN_POS_CENTER);
3357         message.show();
3358         image->show();
3359         hbox->show();
3360
3361         pop_back_splash ();
3362
3363         switch (dialog.run ()) {
3364         case RESPONSE_ACCEPT:
3365                 return 1;
3366         default:
3367                 return 0;
3368         }
3369 }
3370
3371 int
3372 ARDOUR_UI::sr_mismatch_dialog (nframes_t desired, nframes_t actual)
3373 {
3374         HBox* hbox = new HBox();
3375         Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3376         ArdourDialog dialog (_("Sample Rate Mismatch"), true);
3377         Label  message (string_compose (_("\
3378 This session was created with a sample rate of %1 Hz\n\
3379 \n\
3380 The audioengine is currently running at %2 Hz\n"), desired, actual));
3381
3382         image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3383         hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3384         hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3385         dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3386         dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
3387         dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
3388         dialog.set_default_response (RESPONSE_ACCEPT);
3389         dialog.set_position (WIN_POS_CENTER);
3390         message.show();
3391         image->show();
3392         hbox->show();
3393
3394         switch (dialog.run ()) {
3395         case RESPONSE_ACCEPT:
3396                 return 0;
3397         default:
3398                 return 1;
3399         }
3400 }
3401
3402         
3403 void
3404 ARDOUR_UI::disconnect_from_jack ()
3405 {
3406         if (engine) {
3407                 if( engine->disconnect_from_jack ()) {
3408                         MessageDialog msg (*editor, _("Could not disconnect from JACK"));
3409                         msg.run ();
3410                 }
3411
3412                 update_sample_rate (0);
3413         }
3414 }
3415
3416 void
3417 ARDOUR_UI::reconnect_to_jack ()
3418 {
3419         if (engine) {
3420                 if (engine->reconnect_to_jack ()) {
3421                         MessageDialog msg (*editor,  _("Could not reconnect to JACK"));
3422                         msg.run ();
3423                 }
3424
3425                 update_sample_rate (0);
3426         }
3427 }
3428
3429 void
3430 ARDOUR_UI::use_config ()
3431 {
3432         Glib::RefPtr<Action> act;
3433
3434         switch (Config->get_native_file_data_format ()) {
3435         case FormatFloat:
3436                 act = ActionManager::get_action (X_("options"), X_("FileDataFormatFloat"));
3437                 break;
3438         case FormatInt24:
3439                 act = ActionManager::get_action (X_("options"), X_("FileDataFormat24bit"));
3440                 break;
3441         case FormatInt16:
3442                 act = ActionManager::get_action (X_("options"), X_("FileDataFormat16bit"));
3443                 break;
3444         }
3445
3446         if (act) {
3447                 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic(act);
3448                 ract->set_active ();
3449         }       
3450
3451         switch (Config->get_native_file_header_format ()) {
3452         case BWF:
3453                 act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatBWF"));
3454                 break;
3455         case WAVE:
3456                 act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatWAVE"));
3457                 break;
3458         case WAVE64:
3459                 act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatWAVE64"));
3460                 break;
3461         case iXML:
3462                 act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatiXML"));
3463                 break;
3464         case RF64:
3465                 act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatRF64"));
3466                 break;
3467         case CAF:
3468                 act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatCAF"));
3469                 break;
3470         case AIFF:
3471                 act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatAIFF"));
3472                 break;
3473         }
3474
3475         if (act) {
3476                 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic(act);
3477                 ract->set_active ();
3478         }       
3479
3480         XMLNode* node = Config->extra_xml (X_("TransportControllables"));
3481         if (node) {
3482                 set_transport_controllable_state (*node);
3483         }
3484 }
3485
3486 void
3487 ARDOUR_UI::update_transport_clocks (nframes_t pos)
3488 {
3489         if (Config->get_primary_clock_delta_edit_cursor()) {
3490                 primary_clock.set (pos, false, editor->get_preferred_edit_position(), 1);
3491         } else {
3492                 primary_clock.set (pos, 0, true);
3493         }
3494
3495         if (Config->get_secondary_clock_delta_edit_cursor()) {
3496                 secondary_clock.set (pos, false, editor->get_preferred_edit_position(), 2);
3497         } else {
3498                 secondary_clock.set (pos);
3499         }
3500
3501         if (big_clock_window) {
3502                 big_clock.set (pos);
3503         }
3504 }
3505
3506 void
3507 ARDOUR_UI::record_state_changed ()
3508 {
3509         ENSURE_GUI_THREAD (mem_fun (*this, &ARDOUR_UI::record_state_changed));
3510
3511         if (!session || !big_clock_window) {
3512                 /* why bother - the clock isn't visible */
3513                 return;
3514         }
3515
3516         switch (session->record_status()) {
3517         case Session::Recording:
3518                 big_clock.set_widget_name ("BigClockRecording");
3519                 break;
3520         default:
3521                 big_clock.set_widget_name ("BigClockNonRecording");
3522                 break;
3523         }
3524 }
3525
3526 bool
3527 ARDOUR_UI::first_idle ()
3528 {
3529         if (session) {
3530                 session->allow_auto_play (true);
3531         }
3532
3533         if (editor) {
3534                 editor->first_idle();
3535         }
3536
3537         Keyboard::set_can_save_keybindings (true);
3538         return false;
3539 }
3540
3541 void
3542 ARDOUR_UI::store_clock_modes ()
3543 {
3544         XMLNode* node = new XMLNode(X_("ClockModes"));
3545
3546         for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
3547                 node->add_property ((*x)->name().c_str(), enum_2_string ((*x)->mode()));
3548         }
3549
3550         session->add_extra_xml (*node);
3551         session->set_dirty ();
3552 }
3553
3554
3555                 
3556 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
3557         : Controllable (name), ui (u), type(tp)
3558 {
3559         
3560 }
3561
3562 void
3563 ARDOUR_UI::TransportControllable::set_value (float val)
3564 {
3565         if (type == ShuttleControl) {
3566                 double fract;
3567
3568                 if (val == 0.5f) {
3569                         fract = 0.0;
3570                 } else {
3571                         if (val < 0.5f) {
3572                                 fract = -((0.5f - val)/0.5f);
3573                         } else {
3574                                 fract = ((val - 0.5f)/0.5f);
3575                         }
3576                 }
3577                 
3578                 ui.set_shuttle_fract (fract);
3579                 return;
3580         }
3581
3582         if (val < 0.5f) {
3583                 /* do nothing: these are radio-style actions */
3584                 return;
3585         }
3586
3587         const char *action = 0;
3588
3589         switch (type) {
3590         case Roll:
3591                 action = X_("Roll");
3592                 break;
3593         case Stop:
3594                 action = X_("Stop");
3595                 break;
3596         case GotoStart:
3597                 action = X_("Goto Start");
3598                 break;
3599         case GotoEnd:
3600                 action = X_("Goto End");
3601                 break;
3602         case AutoLoop:
3603                 action = X_("Loop");
3604                 break;
3605         case PlaySelection:
3606                 action = X_("Play Selection");
3607                 break;
3608         case RecordEnable:
3609                 action = X_("Record");
3610                 break;
3611         default:
3612                 break;
3613         }
3614
3615         if (action == 0) {
3616                 return;
3617         }
3618
3619         Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
3620
3621         if (act) {
3622                 act->activate ();
3623         }
3624 }
3625
3626 float
3627 ARDOUR_UI::TransportControllable::get_value (void) const
3628 {
3629         float val = 0.0f;
3630         
3631         switch (type) {
3632         case Roll:
3633                 break;
3634         case Stop:
3635                 break;
3636         case GotoStart:
3637                 break;
3638         case GotoEnd:
3639                 break;
3640         case AutoLoop:
3641                 break;
3642         case PlaySelection:
3643                 break;
3644         case RecordEnable:
3645                 break;
3646         case ShuttleControl:
3647                 break;
3648         default:
3649                 break;
3650         }
3651
3652         return val;
3653 }
3654
3655 void
3656 ARDOUR_UI::TransportControllable::set_id (const string& str)
3657 {
3658         _id = str;
3659 }
3660
3661 void
3662 ARDOUR_UI::setup_profile ()
3663 {
3664         if (gdk_screen_width() < 1200) {
3665                 Profile->set_small_screen ();
3666         }
3667
3668         if (getenv ("ARDOUR_SAE")) {
3669                 Profile->set_sae ();
3670                 Profile->set_single_package ();
3671         }
3672 }
3673