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