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