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