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