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