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