try to rationalize zoom/scroll ops for the canvas
[ardour.git] / gtk2_ardour / ardour_ui.cc
1 /*
2     Copyright (C) 1999-2002 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     $Id$
19 */
20
21 #include <algorithm>
22 #include <cmath>
23 #include <fcntl.h>
24 #include <signal.h>
25 #include <unistd.h>
26 #include <cerrno>
27 #include <fstream>
28
29 #include <iostream>
30
31 #include <gtkmm/messagedialog.h>
32 #include <gtkmm/accelmap.h>
33
34 #include <pbd/error.h>
35 #include <pbd/compose.h>
36 #include <pbd/pathscanner.h>
37 #include <pbd/failed_constructor.h>
38 #include <pbd/enumwriter.h>
39 #include <pbd/stacktrace.h>
40 #include <gtkmm2ext/gtk_ui.h>
41 #include <gtkmm2ext/utils.h>
42 #include <gtkmm2ext/click_box.h>
43 #include <gtkmm2ext/fastmeter.h>
44 #include <gtkmm2ext/stop_signal.h>
45 #include <gtkmm2ext/popup.h>
46
47 #include <midi++/port.h>
48 #include <midi++/mmc.h>
49
50 #include <ardour/ardour.h>
51 #include <ardour/session_route.h>
52 #include <ardour/port.h>
53 #include <ardour/audioengine.h>
54 #include <ardour/playlist.h>
55 #include <ardour/utils.h>
56 #include <ardour/audio_diskstream.h>
57 #include <ardour/audiofilesource.h>
58 #include <ardour/recent_sessions.h>
59 #include <ardour/port.h>
60 #include <ardour/audio_track.h>
61
62 #include "actions.h"
63 #include "ardour_ui.h"
64 #include "public_editor.h"
65 #include "audio_clock.h"
66 #include "keyboard.h"
67 #include "mixer_ui.h"
68 #include "prompter.h"
69 #include "opts.h"
70 #include "keyboard_target.h"
71 #include "add_route_dialog.h"
72 #include "new_session_dialog.h"
73 #include "about.h"
74 #include "utils.h"
75 #include "gui_thread.h"
76 #include "color_manager.h"
77
78 #include "i18n.h"
79
80 using namespace ARDOUR;
81 using namespace PBD;
82 using namespace Gtkmm2ext;
83 using namespace Gtk;
84 using namespace sigc;
85
86 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
87
88 sigc::signal<void,bool> ARDOUR_UI::Blink;
89 sigc::signal<void>      ARDOUR_UI::RapidScreenUpdate;
90 sigc::signal<void>      ARDOUR_UI::SuperRapidScreenUpdate;
91 sigc::signal<void,nframes_t> ARDOUR_UI::Clock;
92
93 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], string rcfile)
94
95         : Gtkmm2ext::UI ("ardour", argcp, argvp, rcfile),
96           
97           primary_clock (X_("primary"), false, X_("TransportClockDisplay"), true, false, true),
98           secondary_clock (X_("secondary"), false, X_("SecondaryClockDisplay"), true, false, true),
99           preroll_clock (X_("preroll"), false, X_("PreRollClock"), true, true),
100           postroll_clock (X_("postroll"), false, X_("PostRollClock"), true, true),
101
102           /* adjuster table */
103
104           adjuster_table (3, 3),
105
106           /* preroll stuff */
107
108           preroll_button (_("pre\nroll")),
109           postroll_button (_("post\nroll")),
110
111           /* big clock */
112
113           big_clock (X_("bigclock"), false, "BigClockNonRecording", false, false, true),
114
115           /* transport */
116
117           time_master_button (_("time\nmaster")),
118
119           shuttle_units_button (_("% ")),
120
121           punch_in_button (_("Punch In")),
122           punch_out_button (_("Punch Out")),
123           auto_return_button (_("Auto Return")),
124           auto_play_button (_("Autuo Play")),
125           auto_input_button (_("Auto Input")),
126           click_button (_("Click")),
127           auditioning_alert_button (_("AUDITION")),
128           solo_alert_button (_("SOLO")),
129           shown_flag (false)
130 {
131         using namespace Gtk::Menu_Helpers;
132
133         Gtkmm2ext::init();
134         
135         about = 0;
136
137         if (theArdourUI == 0) {
138                 theArdourUI = this;
139         }
140
141         /* load colors */
142
143         color_manager = new ColorManager();
144
145         std::string color_file = ARDOUR::find_config_file("ardour.colors");
146
147         color_manager->load (color_file);
148
149         editor = 0;
150         mixer = 0;
151         session = 0;
152         _session_is_new = false;
153         big_clock_window = 0;
154         session_selector_window = 0;
155         last_key_press_time = 0;
156         connection_editor = 0;
157         add_route_dialog = 0;
158         route_params = 0;
159         option_editor = 0;
160         location_ui = 0;
161         open_session_selector = 0;
162         have_configure_timeout = false;
163         have_disk_overrun_displayed = false;
164         have_disk_underrun_displayed = false;
165         _will_create_new_session_automatically = false;
166         session_loaded = false;
167         last_speed_displayed = -1.0f;
168         keybindings_path = ARDOUR::find_config_file ("ardour.bindings");
169
170         can_save_keybindings = false;
171         Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::first_idle));
172
173         last_configure_time.tv_sec = 0;
174         last_configure_time.tv_usec = 0;
175
176         shuttle_grabbed = false;
177         shuttle_fract = 0.0;
178         shuttle_max_speed = 8.0f;
179
180         shuttle_style_menu = 0;
181         shuttle_unit_menu = 0;
182
183         gettimeofday (&last_peak_grab, 0);
184         gettimeofday (&last_shuttle_request, 0);
185
186         ARDOUR::Diskstream::DiskOverrun.connect (mem_fun(*this, &ARDOUR_UI::disk_overrun_handler));
187         ARDOUR::Diskstream::DiskUnderrun.connect (mem_fun(*this, &ARDOUR_UI::disk_underrun_handler));
188
189         /* handle pending state with a dialog */
190
191         ARDOUR::Session::AskAboutPendingState.connect (mem_fun(*this, &ARDOUR_UI::pending_state_dialog));
192
193         /* have to wait for AudioEngine and Configuration before proceeding */
194 }
195
196 void
197 ARDOUR_UI::set_engine (AudioEngine& e)
198 {
199         engine = &e;
200
201         engine->Stopped.connect (mem_fun(*this, &ARDOUR_UI::engine_stopped));
202         engine->Running.connect (mem_fun(*this, &ARDOUR_UI::engine_running));
203         engine->Halted.connect (mem_fun(*this, &ARDOUR_UI::engine_halted));
204         engine->SampleRateChanged.connect (mem_fun(*this, &ARDOUR_UI::update_sample_rate));
205
206         ActionManager::init ();
207         new_session_dialog = new NewSessionDialog();
208
209         _tooltips.enable();
210
211         keyboard = new Keyboard;
212
213         if (setup_windows ()) {
214                 throw failed_constructor ();
215         }
216
217         if (GTK_ARDOUR::show_key_actions) {
218                 vector<string> names;
219                 vector<string> paths;
220                 vector<string> keys;
221                 vector<AccelKey> bindings;
222
223                 ActionManager::get_all_actions (names, paths, keys, bindings);
224
225                 vector<string>::iterator n;
226                 vector<string>::iterator k;
227                 for (n = names.begin(), k = keys.begin(); n != names.end(); ++n, ++k) {
228                         cerr << "Action: " << (*n) << " bound to " << (*k) << endl;
229                 }
230
231                 exit (0);
232         }
233
234         /* start with timecode, metering enabled
235         */
236         
237         blink_timeout_tag = -1;
238
239         /* the global configuration object is now valid */
240
241         use_config ();
242
243         /* this being a GUI and all, we want peakfiles */
244
245         AudioFileSource::set_build_peakfiles (true);
246         AudioFileSource::set_build_missing_peakfiles (true);
247
248         if (AudioSource::start_peak_thread ()) {
249                 throw failed_constructor();
250         }
251
252         /* set default clock modes */
253
254         primary_clock.set_mode (AudioClock::SMPTE);
255         secondary_clock.set_mode (AudioClock::BBT);
256
257         /* start the time-of-day-clock */
258         
259         update_wall_clock ();
260         Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::update_wall_clock), 60000);
261
262         update_disk_space ();
263         update_cpu_load ();
264         update_sample_rate (engine->frame_rate());
265
266         starting.connect (mem_fun(*this, &ARDOUR_UI::startup));
267         stopping.connect (mem_fun(*this, &ARDOUR_UI::shutdown));
268 }
269
270 ARDOUR_UI::~ARDOUR_UI ()
271 {
272         save_ardour_state ();
273
274         if (keyboard) {
275                 delete keyboard;
276         }
277
278         if (editor) {
279                 delete editor;
280         }
281
282         if (mixer) {
283                 delete mixer;
284         }
285
286         if (add_route_dialog) {
287                 delete add_route_dialog;
288         }
289
290         AudioSource::stop_peak_thread ();
291 }
292
293 gint
294 ARDOUR_UI::configure_timeout ()
295 {
296         struct timeval now;
297         struct timeval diff;
298
299         if (last_configure_time.tv_sec == 0 && last_configure_time.tv_usec == 0) {
300                 /* no configure events yet */
301                 return TRUE;
302         }
303
304         gettimeofday (&now, 0);
305         timersub (&now, &last_configure_time, &diff);
306
307         /* force a gap of 0.5 seconds since the last configure event
308          */
309
310         if (diff.tv_sec == 0 && diff.tv_usec < 500000) {
311                 return TRUE;
312         } else {
313                 have_configure_timeout = false;
314                 save_ardour_state ();
315                 return FALSE;
316         }
317 }
318
319 gboolean
320 ARDOUR_UI::configure_handler (GdkEventConfigure* conf)
321 {
322         if (have_configure_timeout) {
323                 gettimeofday (&last_configure_time, 0);
324         } else {
325                 Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
326                 have_configure_timeout = true;
327         }
328                 
329         return FALSE;
330 }
331
332 void
333 ARDOUR_UI::save_ardour_state ()
334 {
335         if (!keyboard || !mixer || !editor) {
336                 return;
337         }
338         
339         /* XXX this is all a bit dubious. add_extra_xml() uses
340            a different lifetime model from add_instant_xml().
341         */
342
343         XMLNode* node = new XMLNode (keyboard->get_state());
344         Config->add_extra_xml (*node);
345         Config->save_state();
346
347         XMLNode enode(static_cast<Stateful*>(editor)->get_state());
348         XMLNode mnode(mixer->get_state());
349
350         if (session) {
351                 session->add_instant_xml (enode, session->path());
352                 session->add_instant_xml (mnode, session->path());
353         } else {
354                 Config->add_instant_xml (enode, get_user_ardour_path());
355                 Config->add_instant_xml (mnode, get_user_ardour_path());
356         }
357
358         save_keybindings ();
359 }
360
361 void
362 ARDOUR_UI::startup ()
363 {
364         // relax
365 }
366
367 void
368 ARDOUR_UI::finish()
369 {
370         if (session && session->dirty()) {
371                 switch (ask_about_saving_session(_("quit"))) {
372                 case -1:
373                         return;
374                         break;
375                 case 1:
376                         /* use the default name */
377                         if (save_state_canfail ("")) {
378                                 /* failed - don't quit */
379                                 MessageDialog msg (*editor, 
380                                                _("\
381 Ardour was unable to save your session.\n\n\
382 If you still wish to quit, please use the\n\n\
383 \"Just quit\" option."));
384                                 msg.run ();
385                                 return;
386                         }
387                         break;
388                 case 0:
389                         break;
390                 }
391         }
392
393         if (session) {
394                 session->set_deletion_in_progress ();
395         }
396         engine->stop (true);
397         Config->save_state();
398         quit ();
399 }
400
401 int
402 ARDOUR_UI::ask_about_saving_session (const string & what)
403 {
404         ArdourDialog window (_("ardour: save session?"));
405         Gtk::HBox dhbox;  // the hbox for the image and text
406         Gtk::Label  prompt_label;
407         Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING,  Gtk::ICON_SIZE_DIALOG));
408
409         string msg;
410
411         msg = string_compose(_("Don't %1"), what);
412         window.add_button (msg, RESPONSE_REJECT);
413         msg = string_compose(_("Just %1"), what);
414         window.add_button (msg, RESPONSE_APPLY);
415         msg = string_compose(_("Save and %1"), what);
416         window.add_button (msg, RESPONSE_ACCEPT);
417
418         window.set_default_response (RESPONSE_ACCEPT);
419
420         Gtk::Button noquit_button (msg);
421         noquit_button.set_name ("EditorGTKButton");
422
423         string prompt;
424         string type;
425
426         if (session->snap_name() == session->name()) {
427                 type = _("session");
428         } else {
429                 type = _("snapshot");
430         }
431         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?"), 
432                          type, session->snap_name());
433         
434         prompt_label.set_text (prompt);
435         prompt_label.set_name (X_("PrompterLabel"));
436         prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
437
438         dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP)
439 ;
440         dhbox.set_homogeneous (false);
441         dhbox.pack_start (*dimage, false, false, 5);
442         dhbox.pack_start (prompt_label, true, false, 5);
443         window.get_vbox()->pack_start (dhbox);
444
445         window.set_name (_("Prompter"));
446         window.set_position (Gtk::WIN_POS_MOUSE);
447         window.set_modal (true);
448         window.set_resizable (false);
449         window.show_all ();
450
451         save_the_session = 0;
452
453         window.set_keep_above (true);
454         window.present ();
455
456         ResponseType r = (ResponseType) window.run();
457
458         window.hide ();
459
460         switch (r) {
461         case RESPONSE_ACCEPT: // save and get out of here
462                 return 1;
463         case RESPONSE_APPLY:  // get out of here
464                 return 0;
465         default:
466                 break;
467         }
468
469         return -1;
470 }
471         
472 gint
473 ARDOUR_UI::every_second ()
474 {
475         update_cpu_load ();
476         update_buffer_load ();
477         update_disk_space ();
478         return TRUE;
479 }
480
481 gint
482 ARDOUR_UI::every_point_one_seconds ()
483 {
484         update_speed_display ();
485         RapidScreenUpdate(); /* EMIT_SIGNAL */
486         return TRUE;
487 }
488
489 gint
490 ARDOUR_UI::every_point_zero_one_seconds ()
491 {
492         SuperRapidScreenUpdate(); /* EMIT_SIGNAL */
493         return TRUE;
494 }
495
496 void
497 ARDOUR_UI::update_sample_rate (nframes_t ignored)
498 {
499         char buf[32];
500
501         ENSURE_GUI_THREAD (bind (mem_fun(*this, &ARDOUR_UI::update_sample_rate), ignored));
502
503         if (!engine->connected()) {
504
505                 snprintf (buf, sizeof (buf), _("disconnected"));
506
507         } else {
508
509                 nframes_t rate = engine->frame_rate();
510                 
511                 if (fmod (rate, 1000.0) != 0.0) {
512                         snprintf (buf, sizeof (buf), _("%.1f kHz / %4.1f msecs"), 
513                                   (float) rate/1000.0f,
514                                   (engine->frames_per_cycle() / (float) rate) * 1000.0f);
515                 } else {
516                         snprintf (buf, sizeof (buf), _("%u kHz / %4.1f msecs"), 
517                                   rate/1000,
518                                   (engine->frames_per_cycle() / (float) rate) * 1000.0f);
519                 }
520         }
521
522         sample_rate_label.set_text (buf);
523 }
524
525 void
526 ARDOUR_UI::update_cpu_load ()
527 {
528         char buf[32];
529         snprintf (buf, sizeof (buf), _("DSP: %.1f%%"), engine->get_cpu_load());
530         cpu_load_label.set_text (buf);
531 }
532
533 void
534 ARDOUR_UI::update_buffer_load ()
535 {
536         char buf[64];
537
538         if (session) {
539                 snprintf (buf, sizeof (buf), _("Buffers p:%" PRIu32 "%% c:%" PRIu32 "%%"), 
540                           session->playback_load(), session->capture_load());
541                 buffer_load_label.set_text (buf);
542         } else {
543                 buffer_load_label.set_text ("");
544         }
545 }
546
547 void
548 ARDOUR_UI::count_recenabled_streams (Route& route)
549 {
550         Track* track = dynamic_cast<Track*>(&route);
551         if (track && track->diskstream()->record_enabled()) {
552                 rec_enabled_streams += track->n_inputs();
553         }
554 }
555
556 void
557 ARDOUR_UI::update_disk_space()
558 {
559         if (session == 0) {
560                 return;
561         }
562
563         nframes_t frames = session->available_capture_duration();
564         char buf[64];
565
566         if (frames == max_frames) {
567                 strcpy (buf, _("Disk: 24hrs+"));
568         } else {
569                 int hrs;
570                 int mins;
571                 int secs;
572                 nframes_t fr = session->frame_rate();
573                 
574                 rec_enabled_streams = 0;
575                 session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams);
576                 
577                 if (rec_enabled_streams) {
578                         frames /= rec_enabled_streams;
579                 }
580                 
581                 hrs  = frames / (fr * 3600);
582                 frames -= hrs * fr * 3600;
583                 mins = frames / (fr * 60);
584                 frames -= mins * fr * 60;
585                 secs = frames / fr;
586                 
587                 snprintf (buf, sizeof(buf), _("Disk: %02dh:%02dm:%02ds"), hrs, mins, secs);
588         }
589
590         disk_space_label.set_text (buf);
591 }                 
592
593 gint
594 ARDOUR_UI::update_wall_clock ()
595 {
596         time_t now;
597         struct tm *tm_now;
598         char buf[16];
599
600         time (&now);
601         tm_now = localtime (&now);
602
603         sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
604         wall_clock_label.set_text (buf);
605
606         return TRUE;
607 }
608 void
609 ARDOUR_UI::control_methods_adjusted ()
610
611 {
612         int which_method;
613
614         which_method = (int) online_control_button->adjustment.get_value();
615         switch (which_method) {
616         case 0:
617                 allow_mmc_and_local ();
618                 break;
619         case 1:
620                 allow_mmc_only ();
621                 break;
622         case 2:
623                 allow_local_only ();
624                 break;
625         default:
626                 fatal << _("programming error: impossible control method") << endmsg;
627         }
628 }
629         
630
631 void
632 ARDOUR_UI::mmc_device_id_adjusted ()
633
634 {
635 #if 0
636         if (mmc) {
637                 int dev_id = (int) mmc_id_button->adjustment.get_value();
638                 mmc->set_device_id (dev_id);
639         }
640 #endif
641 }
642
643 gint
644 ARDOUR_UI::session_menu (GdkEventButton *ev)
645 {
646         session_popup_menu->popup (0, 0);
647         return TRUE;
648 }
649
650 void
651 ARDOUR_UI::redisplay_recent_sessions ()
652 {
653         vector<string *> *sessions;
654         vector<string *>::iterator i;
655         RecentSessionsSorter cmp;
656         
657         recent_session_display.set_model (Glib::RefPtr<TreeModel>(0));
658         recent_session_model->clear ();
659
660         RecentSessions rs;
661         ARDOUR::read_recent_sessions (rs);
662
663         if (rs.empty()) {
664                 recent_session_display.set_model (recent_session_model);
665                 return;
666         }
667
668         /* sort them alphabetically */
669         sort (rs.begin(), rs.end(), cmp);
670         sessions = new vector<string*>;
671
672         for (RecentSessions::iterator i = rs.begin(); i != rs.end(); ++i) {
673                 sessions->push_back (new string ((*i).second));
674         }
675
676         for (i = sessions->begin(); i != sessions->end(); ++i) {
677
678                 vector<string*>* states;
679                 vector<const gchar*> item;
680                 string fullpath = *(*i);
681                 
682                 /* remove any trailing / */
683
684                 if (fullpath[fullpath.length()-1] == '/') {
685                         fullpath = fullpath.substr (0, fullpath.length()-1);
686                 }
687
688                 /* now get available states for this session */
689
690                 if ((states = Session::possible_states (fullpath)) == 0) {
691                         /* no state file? */
692                         continue;
693                 }
694
695                 TreeModel::Row row = *(recent_session_model->append());
696
697                 row[recent_session_columns.visible_name] = Glib::path_get_basename (fullpath);
698                 row[recent_session_columns.fullpath] = fullpath;
699
700                 if (states->size() > 1) {
701
702                         /* add the children */
703                         
704                         for (vector<string*>::iterator i2 = states->begin(); i2 != states->end(); ++i2) {
705                                 
706                                 TreeModel::Row child_row = *(recent_session_model->append (row.children()));
707
708                                 child_row[recent_session_columns.visible_name] = **i2;
709                                 child_row[recent_session_columns.fullpath] = fullpath;
710
711                                 delete *i2;
712                         }
713                 }
714
715                 delete states;
716         }
717
718         recent_session_display.set_model (recent_session_model);
719         delete sessions;
720 }
721
722 void
723 ARDOUR_UI::build_session_selector ()
724 {
725         session_selector_window = new ArdourDialog ("session selector");
726         
727         Gtk::ScrolledWindow *scroller = manage (new Gtk::ScrolledWindow);
728         
729         session_selector_window->add_button (Stock::CANCEL, RESPONSE_CANCEL);
730         session_selector_window->add_button (Stock::OPEN, RESPONSE_ACCEPT);
731         session_selector_window->set_default_response (RESPONSE_ACCEPT);
732         recent_session_model = TreeStore::create (recent_session_columns);
733         recent_session_display.set_model (recent_session_model);
734         recent_session_display.append_column (_("Recent Sessions"), recent_session_columns.visible_name);
735         recent_session_display.set_headers_visible (false);
736         recent_session_display.get_selection()->set_mode (SELECTION_SINGLE);
737
738         recent_session_display.signal_row_activated().connect (mem_fun (*this, &ARDOUR_UI::recent_session_row_activated));
739
740         scroller->add (recent_session_display);
741         scroller->set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
742
743         session_selector_window->set_name ("SessionSelectorWindow");
744         session_selector_window->set_size_request (200, 400);
745         session_selector_window->get_vbox()->pack_start (*scroller);
746         session_selector_window->show_all_children();
747 }
748
749 void
750 ARDOUR_UI::recent_session_row_activated (const TreePath& path, TreeViewColumn* col)
751 {
752         session_selector_window->response (RESPONSE_ACCEPT);
753 }
754
755 void
756 ARDOUR_UI::open_recent_session ()
757 {
758         /* popup selector window */
759
760         if (session_selector_window == 0) {
761                 build_session_selector ();
762         }
763
764         redisplay_recent_sessions ();
765
766         ResponseType r = (ResponseType) session_selector_window->run ();
767
768         session_selector_window->hide();
769
770         switch (r) {
771         case RESPONSE_ACCEPT:
772                 break;
773         default:
774                 return;
775         }
776
777         Gtk::TreeModel::iterator i = recent_session_display.get_selection()->get_selected();
778
779         if (i == recent_session_model->children().end()) {
780                 return;
781         }
782         
783         Glib::ustring path = (*i)[recent_session_columns.fullpath];
784         Glib::ustring state = (*i)[recent_session_columns.visible_name];
785
786         _session_is_new = false;
787
788         load_session (path, state);
789 }
790
791 bool
792 ARDOUR_UI::filter_ardour_session_dirs (const FileFilter::Info& info) 
793 {
794         struct stat statbuf;
795
796         if (stat (info.filename.c_str(), &statbuf) != 0) {
797                 return false;
798         }
799
800         if (!S_ISDIR(statbuf.st_mode)) {
801                 return false;
802         }
803
804         // XXX Portability
805         
806         string session_file = info.filename;
807         session_file += '/';
808         session_file += Glib::path_get_basename (info.filename);
809         session_file += ".ardour";
810         
811         if (stat (session_file.c_str(), &statbuf) != 0) {
812                 return false;
813         }
814
815         return S_ISREG (statbuf.st_mode);
816 }
817
818 void
819 ARDOUR_UI::open_session ()
820 {
821         /* popup selector window */
822
823         if (open_session_selector == 0) {
824
825                 /* ardour sessions are folders */
826
827                 open_session_selector = new Gtk::FileChooserDialog (_("open session"), FILE_CHOOSER_ACTION_OPEN);
828                 open_session_selector->add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
829                 open_session_selector->add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
830
831                 FileFilter session_filter;
832                 session_filter.add_pattern ("*.ardour");
833                 session_filter.set_name (_("Ardour sessions"));
834                 open_session_selector->add_filter (session_filter);
835                 open_session_selector->set_filter (session_filter);
836         }
837
838         int response = open_session_selector->run();
839         open_session_selector->hide ();
840
841         switch (response) {
842         case RESPONSE_ACCEPT:
843                 break;
844         default:
845                 open_session_selector->hide();
846                 return;
847         }
848
849         open_session_selector->hide();
850         string session_path = open_session_selector->get_filename();
851         string path, name;
852         bool isnew;
853
854         if (session_path.length() > 0) {
855                 if (Session::find_session (session_path, path, name, isnew) == 0) {
856                         _session_is_new = isnew;
857                         load_session (path, name);
858                 }
859         }
860 }
861
862
863 void
864 ARDOUR_UI::session_add_midi_track ()
865 {
866         cerr << _("Patience is a virtue.\n");
867 }
868
869 void
870 ARDOUR_UI::session_add_audio_route (bool track, int32_t input_channels, int32_t output_channels, ARDOUR::TrackMode mode, uint32_t how_many)
871 {
872         list<boost::shared_ptr<AudioTrack> > tracks;
873         Session::RouteList routes;
874
875         if (session == 0) {
876                 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
877                 return;
878         }
879
880         try { 
881                 if (track) {
882                         tracks = session->new_audio_track (input_channels, output_channels, mode, how_many);
883
884                         if (tracks.size() != how_many) {
885                                 if (how_many == 1) {
886                                         error << _("could not create a new audio track") << endmsg;
887                                 } else {
888                                         error << string_compose (_("could not create %1 new audio tracks"), how_many) << endmsg;
889                                 }
890                         }
891
892                 } else {
893
894                         routes = session->new_audio_route (input_channels, output_channels, how_many);
895
896                         if (routes.size() != how_many) {
897                                 if (how_many == 1) {
898                                         error << _("could not create a new audio track") << endmsg;
899                                 } else {
900                                         error << string_compose (_("could not create %1 new audio tracks"), how_many) << endmsg;
901                                 }
902                         }
903                 }
904                 
905 #if CONTROLOUTS
906                 if (need_control_room_outs) {
907                         pan_t pans[2];
908                         
909                         pans[0] = 0.5;
910                         pans[1] = 0.5;
911                         
912                         route->set_stereo_control_outs (control_lr_channels);
913                         route->control_outs()->set_stereo_pan (pans, this);
914                 }
915 #endif /* CONTROLOUTS */
916         }
917
918         catch (...) {
919                 MessageDialog msg (*editor, 
920                                    _("There are insufficient JACK ports available\n\
921 to create a new track or bus.\n\
922 You should save Ardour, exit and\n\
923 restart JACK with more ports."));
924                 msg.run ();
925         }
926 }
927
928 void
929 ARDOUR_UI::do_transport_locate (nframes_t new_position)
930 {
931         nframes_t _preroll = 0;
932
933         if (session) {
934                 // XXX CONFIG_CHANGE FIX - requires AnyTime handling
935                 // _preroll = session->convert_to_frames_at (new_position, Config->get_preroll());
936
937                 if (new_position > _preroll) {
938                         new_position -= _preroll;
939                 } else {
940                         new_position = 0;
941                 }
942
943                 session->request_locate (new_position);
944         }
945 }
946
947 void
948 ARDOUR_UI::transport_goto_start ()
949 {
950         if (session) {
951                 session->goto_start();
952
953                 
954                 /* force displayed area in editor to start no matter
955                    what "follow playhead" setting is.
956                 */
957                 
958                 if (editor) {
959                         editor->reset_x_origin (session->current_start_frame());
960                 }
961         }
962 }
963
964 void
965 ARDOUR_UI::transport_goto_zero ()
966 {
967         if (session) {
968                 session->request_locate (0);
969
970                 
971                 /* force displayed area in editor to start no matter
972                    what "follow playhead" setting is.
973                 */
974                 
975                 if (editor) {
976                         editor->reset_x_origin (0);
977                 }
978         }
979 }
980
981 void
982 ARDOUR_UI::transport_goto_end ()
983 {
984         if (session) {
985                 nframes_t frame = session->current_end_frame();
986                 session->request_locate (frame);
987
988                 /* force displayed area in editor to start no matter
989                    what "follow playhead" setting is.
990                 */
991                 
992                 if (editor) {
993                         editor->reset_x_origin (frame);
994                 }
995         }
996 }
997
998 void
999 ARDOUR_UI::transport_stop ()
1000 {
1001         if (!session) {
1002                 return;
1003         }
1004
1005         if (session->is_auditioning()) {
1006                 session->cancel_audition ();
1007                 return;
1008         }
1009         
1010         if (session->get_play_loop ()) {
1011                 session->request_play_loop (false);
1012         }
1013         
1014         session->request_stop ();
1015 }
1016
1017 void
1018 ARDOUR_UI::transport_stop_and_forget_capture ()
1019 {
1020         if (session) {
1021                 session->request_stop (true);
1022         }
1023 }
1024
1025 void
1026 ARDOUR_UI::remove_last_capture()
1027 {
1028         if (editor) {
1029                 editor->remove_last_capture();
1030         }
1031 }
1032
1033 void
1034 ARDOUR_UI::transport_record ()
1035 {
1036         if (session) {
1037                 switch (session->record_status()) {
1038                 case Session::Disabled:
1039                         if (session->ntracks() == 0) {
1040                                 MessageDialog msg (*editor, _("Please create 1 or more track\nbefore trying to record.\nCheck the Session menu."));
1041                                 msg.run ();
1042                                 return;
1043                         }
1044                         session->maybe_enable_record ();
1045                         break;
1046                 case Session::Recording:
1047                 case Session::Enabled:
1048                         session->disable_record (true);
1049                 }
1050         }
1051 }
1052
1053 void
1054 ARDOUR_UI::transport_roll ()
1055 {
1056         bool rolling;
1057
1058         if (!session) {
1059                 return;
1060         }
1061
1062         rolling = session->transport_rolling ();
1063
1064         if (session->get_play_loop()) {
1065                 session->request_play_loop (false);
1066                 auto_loop_button.set_active (false);
1067                 roll_button.set_active (true);
1068         } else if (session->get_play_range ()) {
1069                 session->request_play_range (false);
1070                 play_selection_button.set_active (false);
1071         } else if (rolling) {
1072                 session->request_locate (session->last_transport_start(), true);
1073         }
1074
1075         session->request_transport_speed (1.0f);
1076 }
1077
1078 void
1079 ARDOUR_UI::transport_loop()
1080 {
1081         if (session) {
1082                 if (session->get_play_loop()) {
1083                         if (session->transport_rolling()) {
1084                                 Location * looploc = session->locations()->auto_loop_location();
1085                                 if (looploc) {
1086                                         session->request_locate (looploc->start(), true);
1087                                 }
1088                         }
1089                 }
1090                 else {
1091                         session->request_play_loop (true);
1092                 }
1093         }
1094 }
1095
1096 void
1097 ARDOUR_UI::transport_play_selection ()
1098 {
1099         if (!session) {
1100                 return;
1101         }
1102
1103         if (!session->get_play_range()) {
1104                 session->request_stop ();
1105         }
1106
1107         editor->play_selection ();
1108 }
1109
1110 void
1111 ARDOUR_UI::transport_rewind (int option)
1112 {
1113         float current_transport_speed;
1114  
1115         if (session) {
1116                 current_transport_speed = session->transport_speed();
1117                 
1118                 if (current_transport_speed >= 0.0f) {
1119                         switch (option) {
1120                         case 0:
1121                                 session->request_transport_speed (-1.0f);
1122                                 break;
1123                         case 1:
1124                                 session->request_transport_speed (-4.0f);
1125                                 break;
1126                         case -1:
1127                                 session->request_transport_speed (-0.5f);
1128                                 break;
1129                         }
1130                 } else {
1131                         /* speed up */
1132                         session->request_transport_speed (current_transport_speed * 1.5f);
1133                 }
1134         }
1135 }
1136
1137 void
1138 ARDOUR_UI::transport_forward (int option)
1139 {
1140         float current_transport_speed;
1141         
1142         if (session) {
1143                 current_transport_speed = session->transport_speed();
1144                 
1145                 if (current_transport_speed <= 0.0f) {
1146                         switch (option) {
1147                         case 0:
1148                                 session->request_transport_speed (1.0f);
1149                                 break;
1150                         case 1:
1151                                 session->request_transport_speed (4.0f);
1152                                 break;
1153                         case -1:
1154                                 session->request_transport_speed (0.5f);
1155                                 break;
1156                         }
1157                 } else {
1158                         /* speed up */
1159                         session->request_transport_speed (current_transport_speed * 1.5f);
1160                 }
1161         }
1162 }
1163
1164 void
1165 ARDOUR_UI::toggle_record_enable (uint32_t dstream)
1166 {
1167         if (session == 0) {
1168                 return;
1169         }
1170
1171         boost::shared_ptr<Route> r;
1172         
1173         if ((r = session->route_by_remote_id (dstream)) != 0) {
1174
1175                 Track* t;
1176
1177                 if ((t = dynamic_cast<Track*>(r.get())) != 0) {
1178                         t->diskstream()->set_record_enabled (!t->diskstream()->record_enabled());
1179                 }
1180         }
1181         if (session == 0) {
1182                 return;
1183         }
1184 }
1185
1186 void
1187 ARDOUR_UI::queue_transport_change ()
1188 {
1189         Gtkmm2ext::UI::instance()->call_slot (mem_fun(*this, &ARDOUR_UI::map_transport_state));
1190 }
1191
1192 void
1193 ARDOUR_UI::map_transport_state ()
1194 {
1195         float sp = session->transport_speed();
1196
1197         if (sp == 1.0f) {
1198                 transport_rolling ();
1199         } else if (sp < 0.0f) {
1200                 transport_rewinding ();
1201         } else if (sp > 0.0f) {
1202                 transport_forwarding ();
1203         } else {
1204                 transport_stopped ();
1205         }
1206 }
1207
1208 void
1209 ARDOUR_UI::allow_local_only ()
1210 {
1211
1212 }
1213
1214 void
1215 ARDOUR_UI::allow_mmc_only ()
1216 {
1217
1218 }
1219
1220 void
1221 ARDOUR_UI::allow_mmc_and_local ()
1222 {
1223
1224 }
1225
1226 void
1227 ARDOUR_UI::GlobalClickBox::printer (char buf[32], Adjustment &adj, void *arg)
1228 {
1229         snprintf (buf, sizeof(buf), "%s", ((GlobalClickBox *) arg)->strings[
1230                 (int) adj.get_value()].c_str());
1231 }
1232
1233 void
1234 ARDOUR_UI::engine_stopped ()
1235 {
1236         ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::engine_stopped));
1237         ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1238         ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1239 }
1240
1241 void
1242 ARDOUR_UI::engine_running ()
1243 {
1244         ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::engine_running));
1245         ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, true);
1246         ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, false);
1247 }
1248
1249 void
1250 ARDOUR_UI::engine_halted ()
1251 {
1252         ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::engine_halted));
1253
1254         ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1255         ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1256
1257         update_sample_rate (0);
1258
1259         MessageDialog msg (*editor, 
1260                            _("\
1261 JACK has either been shutdown or it\n\
1262 disconnected Ardour because Ardour\n\
1263 was not fast enough. You can save the\n\
1264 session and/or try to reconnect to JACK ."));
1265         msg.run ();
1266 }
1267
1268 int32_t
1269 ARDOUR_UI::do_engine_start ()
1270 {
1271         try { 
1272                 engine->start();
1273         }
1274
1275         catch (...) {
1276                 engine->stop ();
1277                 error << _("Unable to start the session running")
1278                       << endmsg;
1279                 unload_session ();
1280                 return -2;
1281         }
1282         
1283         return 0;
1284 }
1285
1286 gint
1287 ARDOUR_UI::start_engine ()
1288 {
1289         if (do_engine_start () == 0) {
1290                 if (session && _session_is_new) {
1291                         /* we need to retain initial visual 
1292                            settings for a new session 
1293                         */
1294                         session->save_state ("");
1295                 }
1296         }
1297
1298         return FALSE;
1299 }
1300
1301 void
1302 ARDOUR_UI::update_clocks ()
1303 {
1304         if (!editor || !editor->dragging_playhead()) {
1305                 Clock (session->audible_frame()); /* EMIT_SIGNAL */
1306         }
1307 }
1308
1309 void
1310 ARDOUR_UI::start_clocking ()
1311 {
1312         clock_signal_connection = RapidScreenUpdate.connect (mem_fun(*this, &ARDOUR_UI::update_clocks));
1313 }
1314
1315 void
1316 ARDOUR_UI::stop_clocking ()
1317 {
1318         clock_signal_connection.disconnect ();
1319 }
1320         
1321 void
1322 ARDOUR_UI::toggle_clocking ()
1323 {
1324 #if 0
1325         if (clock_button.get_active()) {
1326                 start_clocking ();
1327         } else {
1328                 stop_clocking ();
1329         }
1330 #endif
1331 }
1332
1333 gint
1334 ARDOUR_UI::_blink (void *arg)
1335
1336 {
1337         ((ARDOUR_UI *) arg)->blink ();
1338         return TRUE;
1339 }
1340
1341 void
1342 ARDOUR_UI::blink ()
1343 {
1344          Blink (blink_on = !blink_on); /* EMIT_SIGNAL */
1345 }
1346
1347 void
1348 ARDOUR_UI::start_blinking ()
1349 {
1350         /* Start the blink signal. Everybody with a blinking widget
1351            uses Blink to drive the widget's state.
1352         */
1353
1354         if (blink_timeout_tag < 0) {
1355                 blink_on = false;       
1356                 blink_timeout_tag = g_timeout_add (240, _blink, this);
1357         }
1358 }
1359
1360 void
1361 ARDOUR_UI::stop_blinking ()
1362 {
1363         if (blink_timeout_tag >= 0) {
1364                 g_source_remove (blink_timeout_tag);
1365                 blink_timeout_tag = -1;
1366         }
1367 }
1368
1369 void
1370 ARDOUR_UI::name_io_setup (AudioEngine& engine, 
1371                           string& buf,
1372                           IO& io,
1373                           bool in)
1374 {
1375         if (in) {
1376                 if (io.n_inputs() == 0) {
1377                         buf = _("none");
1378                         return;
1379                 }
1380                 
1381                 /* XXX we're not handling multiple ports yet. */
1382
1383                 const char **connections = io.input(0)->get_connections();
1384                 
1385                 if (connections == 0 || connections[0] == '\0') {
1386                         buf = _("off");
1387                 } else {
1388                         buf = connections[0];
1389                 }
1390
1391                 free (connections);
1392
1393         } else {
1394
1395                 if (io.n_outputs() == 0) {
1396                         buf = _("none");
1397                         return;
1398                 }
1399                 
1400                 /* XXX we're not handling multiple ports yet. */
1401
1402                 const char **connections = io.output(0)->get_connections();
1403                 
1404                 if (connections == 0 || connections[0] == '\0') {
1405                         buf = _("off");
1406                 } else {
1407                         buf = connections[0];
1408                 }
1409
1410                 free (connections);
1411         }
1412 }
1413
1414 void
1415 ARDOUR_UI::snapshot_session ()
1416 {
1417         ArdourPrompter prompter (true);
1418         string snapname;
1419         string now;
1420         time_t n;
1421
1422         time (&n);
1423         now = ctime (&n);
1424         now = now.substr (20, 4) + now.substr (3, 16) + " (" + now.substr (0, 3) + ")";
1425
1426         prompter.set_name ("Prompter");
1427         prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1428         prompter.set_prompt (_("Name of New Snapshot"));
1429         prompter.set_initial_text (now);
1430         
1431         switch (prompter.run()) {
1432         case RESPONSE_ACCEPT:
1433                 prompter.get_result (snapname);
1434                 if (snapname.length()){
1435                         save_state (snapname);
1436                 }
1437                 break;
1438
1439         default:
1440                 break;
1441         }
1442 }
1443
1444 void
1445 ARDOUR_UI::save_state (const string & name)
1446 {
1447         (void) save_state_canfail (name);
1448 }
1449                 
1450 int
1451 ARDOUR_UI::save_state_canfail (string name)
1452 {
1453         if (session) {
1454                 int ret;
1455
1456                 if (name.length() == 0) {
1457                         name = session->snap_name();
1458                 }
1459
1460                 if ((ret = session->save_state (name)) != 0) {
1461                         return ret;
1462                 }
1463         }
1464         save_ardour_state (); /* XXX cannot fail? yeah, right ... */
1465         return 0;
1466 }
1467
1468 void
1469 ARDOUR_UI::restore_state (string name)
1470 {
1471         if (session) {
1472                 if (name.length() == 0) {
1473                         name = session->name();
1474                 }
1475                 session->restore_state (name);
1476         }
1477 }
1478
1479 void
1480 ARDOUR_UI::primary_clock_value_changed ()
1481 {
1482         if (session) {
1483                 session->request_locate (primary_clock.current_time ());
1484         }
1485 }
1486
1487 void
1488 ARDOUR_UI::secondary_clock_value_changed ()
1489 {
1490         if (session) {
1491                 session->request_locate (secondary_clock.current_time ());
1492         }
1493 }
1494
1495 void
1496 ARDOUR_UI::rec_enable_button_blink (bool onoff, AudioDiskstream *dstream, Widget *w)
1497 {
1498         if (session && dstream && dstream->record_enabled()) {
1499
1500                 Session::RecordState rs;
1501                 
1502                 rs = session->record_status ();
1503
1504                 switch (rs) {
1505                 case Session::Disabled:
1506                 case Session::Enabled:
1507                         if (w->get_state() != STATE_SELECTED) {
1508                                 w->set_state (STATE_SELECTED);
1509                         }
1510                         break;
1511
1512                 case Session::Recording:
1513                         if (w->get_state() != STATE_ACTIVE) {
1514                                 w->set_state (STATE_ACTIVE);
1515                         }
1516                         break;
1517                 }
1518
1519         } else {
1520                 if (w->get_state() != STATE_NORMAL) {
1521                         w->set_state (STATE_NORMAL);
1522                 }
1523         }
1524 }
1525
1526 void
1527 ARDOUR_UI::transport_rec_enable_blink (bool onoff) 
1528 {
1529         if (session == 0) {
1530                 return;
1531         }
1532         
1533         switch (session->record_status()) {
1534         case Session::Enabled:
1535                 if (onoff) {
1536                         rec_button.set_state (1);
1537                 } else {
1538                         rec_button.set_state (0);
1539                 }
1540                 break;
1541
1542         case Session::Recording:
1543                 rec_button.set_state (2);
1544                 break;
1545
1546         default:
1547                 rec_button.set_state (0);
1548                 break;
1549         }
1550 }
1551
1552 gint
1553 ARDOUR_UI::hide_and_quit (GdkEventAny *ev, ArdourDialog *window)
1554 {
1555         window->hide();
1556         Gtk::Main::quit ();
1557         return TRUE;
1558 }
1559
1560 void
1561 ARDOUR_UI::start_keyboard_prefix ()
1562 {
1563         keyboard->start_prefix();
1564 }
1565
1566 void
1567 ARDOUR_UI::save_template ()
1568
1569 {
1570         ArdourPrompter prompter (true);
1571         string name;
1572
1573         prompter.set_name (X_("Prompter"));
1574         prompter.set_prompt (_("Name for mix template:"));
1575         prompter.set_initial_text(session->name() + _("-template"));
1576         prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1577
1578         switch (prompter.run()) {
1579         case RESPONSE_ACCEPT:
1580                 prompter.get_result (name);
1581                 
1582                 if (name.length()) {
1583                         session->save_template (name);
1584                 }
1585                 break;
1586
1587         default:
1588                 break;
1589         }
1590 }
1591
1592 void
1593 ARDOUR_UI::new_session (std::string predetermined_path)
1594 {
1595         string session_name;
1596         string session_path;
1597
1598         int response = Gtk::RESPONSE_NONE;
1599
1600         new_session_dialog->set_modal(true);
1601         new_session_dialog->set_name (predetermined_path);
1602         new_session_dialog->reset_recent();
1603         new_session_dialog->show();
1604
1605         do {
1606                 response = new_session_dialog->run ();
1607                 
1608                 _session_is_new = false;
1609
1610                 if (response == Gtk::RESPONSE_CANCEL || response == Gtk::RESPONSE_DELETE_EVENT) {
1611
1612                         if (!session) {
1613                                 quit();
1614                         }
1615                         new_session_dialog->hide ();
1616                         return;
1617
1618                 } else if (response == Gtk::RESPONSE_NONE) {
1619
1620                         /* Clear was pressed */
1621                         new_session_dialog->reset();
1622
1623                 } else if (response == Gtk::RESPONSE_YES) {
1624
1625                         /* YES  == OPEN, but there's no enum for that */
1626
1627                         session_name = new_session_dialog->session_name();
1628                         
1629                         if (session_name.empty()) {
1630                                 response = Gtk::RESPONSE_NONE;
1631                                 continue;
1632                         } 
1633
1634                         if (session_name[0] == '/' || 
1635                             (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == '/') ||
1636                             (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == '/')) {
1637                                 load_session (Glib::path_get_dirname (session_name), session_name);
1638                         } else {
1639                                 session_path = new_session_dialog->session_folder();
1640                                 load_session (session_path, session_name);
1641                         }
1642                         
1643                 } else if (response == Gtk::RESPONSE_OK) {
1644
1645                         session_name = new_session_dialog->session_name();
1646                         
1647                         if (new_session_dialog->get_current_page() == 1) {
1648                   
1649                                 /* XXX this is a bit of a hack.. 
1650                                    i really want the new sesion dialog to return RESPONSE_YES
1651                                    if we're on page 1 (the load page)
1652                                    Unfortunately i can't see how atm.. 
1653                                 */
1654                                 
1655                                 if (session_name.empty()) {
1656                                         response = Gtk::RESPONSE_NONE;
1657                                         continue;
1658                                 } 
1659                                 
1660                                 if (session_name[0] == '/' || 
1661                                     (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == '/') ||
1662                                     (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == '/')) {
1663                                         load_session (Glib::path_get_dirname (session_name), session_name);
1664                                 } else {
1665                                         session_path = new_session_dialog->session_folder();
1666                                         load_session (session_path, session_name);
1667                                 }
1668                         
1669                         } else {
1670
1671                                 if (session_name.empty()) {
1672                                         response = Gtk::RESPONSE_NONE;
1673                                         continue;
1674                                 } 
1675
1676                                 if (session_name[0] == '/' || 
1677                                     (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == '/') ||
1678                                     (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == '/')) {
1679
1680                                         session_path = Glib::path_get_dirname (session_name);
1681                                         session_name = Glib::path_get_basename (session_name);
1682
1683                                 } else {
1684
1685                                         session_path = new_session_dialog->session_folder();
1686
1687                                 }
1688                                 
1689                                 //XXX This is needed because session constructor wants a 
1690                                 //non-existant path. hopefully this will be fixed at some point.
1691                                 
1692                                 session_path = Glib::build_filename (session_path, session_name);
1693                                                 
1694                                 if (g_file_test (session_path.c_str(), GFileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
1695
1696                                         Glib::ustring str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
1697
1698                                         MessageDialog msg (str,
1699                                                            false,
1700                                                            Gtk::MESSAGE_WARNING,
1701                                                            Gtk::BUTTONS_YES_NO,
1702                                                            true);
1703
1704
1705                                         msg.set_name (X_("CleanupDialog"));
1706                                         msg.set_wmclass (X_("existing_session"), "Ardour");
1707                                         msg.set_position (Gtk::WIN_POS_MOUSE);
1708                                         
1709                                         switch (msg.run()) {
1710                                         case RESPONSE_YES:
1711                                                 load_session (session_path, session_name);
1712                                                 goto done;
1713                                                 break;
1714                                         default:
1715                                                 response = RESPONSE_NONE;
1716                                                 new_session_dialog->reset ();
1717                                                 continue;
1718                                         }
1719                                 }
1720
1721                                 _session_is_new = true;
1722
1723                                 std::string template_name = new_session_dialog->session_template_name();
1724                                                 
1725                                 if (new_session_dialog->use_session_template()) {
1726                                                         
1727                                         load_session (session_path, session_name, &template_name);
1728                           
1729                                 } else {
1730                                                         
1731                                         uint32_t cchns;
1732                                         uint32_t mchns;
1733                                         AutoConnectOption iconnect;
1734                                         AutoConnectOption oconnect;
1735                                                         
1736                                         if (new_session_dialog->create_control_bus()) {
1737                                                 cchns = (uint32_t) new_session_dialog->control_channel_count();
1738                                         } else {
1739                                                 cchns = 0;
1740                                         }
1741                                                         
1742                                         if (new_session_dialog->create_master_bus()) {
1743                                                 mchns = (uint32_t) new_session_dialog->master_channel_count();
1744                                         } else {
1745                                                 mchns = 0;
1746                                         }
1747                                                         
1748                                         if (new_session_dialog->connect_inputs()) {
1749                                                 iconnect = AutoConnectPhysical;
1750                                         } else {
1751                                                 iconnect = AutoConnectOption (0);
1752                                         }
1753                                                         
1754                                         /// @todo some minor tweaks.
1755                                                         
1756                                         if (new_session_dialog->connect_outs_to_master()) {
1757                                                 oconnect = AutoConnectMaster;
1758                                         } else if (new_session_dialog->connect_outs_to_physical()) {
1759                                                 oconnect = AutoConnectPhysical;
1760                                         } else {
1761                                                 oconnect = AutoConnectOption (0);
1762                                         } 
1763                                                         
1764                                         uint32_t nphysin = (uint32_t) new_session_dialog->input_limit_count();
1765                                         uint32_t nphysout = (uint32_t) new_session_dialog->output_limit_count();
1766                                                         
1767                                         build_session (session_path,
1768                                                        session_name,
1769                                                        cchns,
1770                                                        mchns,
1771                                                        iconnect,
1772                                                        oconnect,
1773                                                        nphysin,
1774                                                        nphysout, 
1775                                                        engine->frame_rate() * 60 * 5);
1776                                 }
1777                         }
1778                 }
1779                 
1780         } while (response == Gtk::RESPONSE_NONE);
1781
1782   done:
1783         show();
1784         new_session_dialog->get_window()->set_cursor();
1785         new_session_dialog->hide();
1786 }
1787
1788 void
1789 ARDOUR_UI::close_session()
1790 {
1791         unload_session();
1792         new_session ();
1793 }
1794
1795 int
1796 ARDOUR_UI::load_session (const string & path, const string & snap_name, string* mix_template)
1797 {
1798         Session *new_session;
1799         int x;
1800         session_loaded = false;
1801         
1802         x = unload_session ();
1803
1804         if (x < 0) {
1805                 return -1;
1806         } else if (x > 0) {
1807                 return 0;
1808         }
1809
1810         /* if it already exists, we must have write access */
1811
1812         if (::access (path.c_str(), F_OK) == 0 && ::access (path.c_str(), W_OK)) {
1813                 MessageDialog msg (*editor, _("You do not have write access to this session.\n"
1814                                               "This prevents the session from being loaded."));
1815                 msg.run ();
1816                 return -1;
1817         }
1818
1819         try {
1820                 new_session = new Session (*engine, path, snap_name, mix_template);
1821         }
1822
1823         catch (...) {
1824
1825                 error << string_compose(_("Session \"%1 (snapshot %2)\" did not load successfully"), path, snap_name) << endmsg;
1826                 return -1;
1827         }
1828
1829         connect_to_session (new_session);
1830
1831         Config->set_current_owner (ConfigVariableBase::Interface);
1832
1833         session_loaded = true;
1834         
1835         goto_editor_window ();
1836
1837         if (session) {
1838                 session->set_clean ();
1839         }
1840
1841         return 0;
1842 }
1843
1844 int
1845 ARDOUR_UI::build_session (const string & path, const string & snap_name, 
1846                           uint32_t control_channels,
1847                           uint32_t master_channels, 
1848                           AutoConnectOption input_connect,
1849                           AutoConnectOption output_connect,
1850                           uint32_t nphysin,
1851                           uint32_t nphysout,
1852                           nframes_t initial_length)
1853 {
1854         Session *new_session;
1855         int x;
1856
1857         session_loaded = false;
1858         x = unload_session ();
1859         if (x < 0) {
1860                 return -1;
1861         } else if (x > 0) {
1862                 return 0;
1863         }
1864         
1865         _session_is_new = true;
1866
1867         try {
1868                 new_session = new Session (*engine, path, snap_name, input_connect, output_connect,
1869                                            control_channels, master_channels, nphysin, nphysout, initial_length);
1870         }
1871
1872         catch (...) {
1873
1874                 error << string_compose(_("Session \"%1 (snapshot %2)\" did not load successfully"), path, snap_name) << endmsg;
1875                 return -1;
1876         }
1877
1878         connect_to_session (new_session);
1879
1880         session_loaded = true;
1881         return 0;
1882 }
1883
1884 void
1885 ARDOUR_UI::show ()
1886 {
1887         if (editor) {
1888                 editor->show_window ();
1889                 
1890                 if (!shown_flag) {
1891                         editor->present ();
1892                 }
1893
1894                 shown_flag = true;
1895         }
1896 }
1897
1898 void
1899 ARDOUR_UI::show_splash ()
1900 {
1901         if (about == 0) {
1902                 about = new About();
1903                 about->signal_response().connect(mem_fun (*this, &ARDOUR_UI::about_signal_response) );
1904         }
1905         about->present();
1906         flush_pending ();
1907 }
1908
1909 void
1910 ARDOUR_UI::about_signal_response(int response)
1911 {
1912         hide_splash();
1913 }
1914
1915 void
1916 ARDOUR_UI::hide_splash ()
1917 {
1918         if (about) {
1919                 about->get_window()->set_cursor ();
1920                 about->hide();
1921         }
1922 }
1923
1924 void
1925 ARDOUR_UI::display_cleanup_results (Session::cleanup_report& rep, const gchar* list_title, const string & msg)
1926 {
1927         size_t removed;
1928
1929         removed = rep.paths.size();
1930
1931         if (removed == 0) {
1932                 MessageDialog msgd (*editor,
1933                                     _("No audio files were ready for cleanup"), 
1934                                     true,
1935                                     Gtk::MESSAGE_INFO,
1936                                     (Gtk::ButtonsType)(Gtk::BUTTONS_OK)  );
1937                 msgd.set_secondary_text (_("If this seems suprising, \n\
1938 check for any existing snapshots.\n\
1939 These may still include regions that\n\
1940 require some unused files to continue to exist."));
1941         
1942                 msgd.run ();
1943                 return;
1944         } 
1945
1946         ArdourDialog results (_("ardour: cleanup"), true, false);
1947         
1948         struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
1949             CleanupResultsModelColumns() { 
1950                     add (visible_name);
1951                     add (fullpath);
1952             }
1953             Gtk::TreeModelColumn<Glib::ustring> visible_name;
1954             Gtk::TreeModelColumn<Glib::ustring> fullpath;
1955         };
1956
1957         
1958         CleanupResultsModelColumns results_columns;
1959         Glib::RefPtr<Gtk::ListStore> results_model;
1960         Gtk::TreeView results_display;
1961         
1962         results_model = ListStore::create (results_columns);
1963         results_display.set_model (results_model);
1964         results_display.append_column (list_title, results_columns.visible_name);
1965
1966         results_display.set_name ("CleanupResultsList");
1967         results_display.set_headers_visible (true);
1968         results_display.set_headers_clickable (false);
1969         results_display.set_reorderable (false);
1970
1971         Gtk::ScrolledWindow list_scroller;
1972         Gtk::Label txt;
1973         Gtk::VBox dvbox;
1974         Gtk::HBox dhbox;  // the hbox for the image and text
1975         Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
1976         Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO,  Gtk::ICON_SIZE_DIALOG));
1977
1978         dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
1979
1980         if (rep.space < 1048576.0f) {
1981                 if (removed > 1) {
1982                   txt.set_text (string_compose (msg, removed, _("files were"), session->path() + "dead_sounds", (float) rep.space / 1024.0f, "kilo"));
1983                 } else {
1984                         txt.set_text (string_compose (msg, removed, _("file was"), session->path() + "dead_sounds", (float) rep.space / 1024.0f, "kilo"));
1985                 }
1986         } else {
1987                 if (removed > 1) {
1988                         txt.set_text (string_compose (msg, removed, _("files were"), session->path() + "dead_sounds", (float) rep.space / 1048576.0f, "mega"));
1989                 } else {
1990                         txt.set_text (string_compose (msg, removed, _("file was"), session->path() + "dead_sounds", (float) rep.space / 1048576.0f, "mega"));
1991                 }
1992         }
1993
1994         dhbox.pack_start (*dimage, true, false, 5);
1995         dhbox.pack_start (txt, true, false, 5);
1996
1997         for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
1998                 TreeModel::Row row = *(results_model->append());
1999                 row[results_columns.visible_name] = *i;
2000                 row[results_columns.fullpath] = *i;
2001         }
2002         
2003         list_scroller.add (results_display);
2004         list_scroller.set_size_request (-1, 150);
2005         list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
2006
2007         dvbox.pack_start (dhbox, true, false, 5);
2008         dvbox.pack_start (list_scroller, true, false, 5);
2009         ddhbox.pack_start (dvbox, true, false, 5);
2010
2011         results.get_vbox()->pack_start (ddhbox, true, false, 5);
2012         results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
2013         results.set_default_response (RESPONSE_CLOSE);
2014         results.set_position (Gtk::WIN_POS_MOUSE);
2015         results.show_all_children ();
2016         results.set_resizable (false);
2017
2018         results.run ();
2019
2020 }
2021
2022 void
2023 ARDOUR_UI::cleanup ()
2024 {
2025         if (session == 0) {
2026                 /* shouldn't happen: menu item is insensitive */
2027                 return;
2028         }
2029
2030
2031         MessageDialog  checker (_("Are you sure you want to cleanup?"),
2032                                 true,
2033                                 Gtk::MESSAGE_QUESTION,
2034                                 (Gtk::ButtonsType)(Gtk::BUTTONS_NONE));
2035
2036         checker.set_secondary_text(_("Cleanup is a destructive operation.\n\
2037 ALL undo/redo information will be lost if you cleanup.\n\
2038 After cleanup, unused audio files will be moved to a \
2039 \"dead sounds\" location."));
2040         
2041         checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
2042         checker.add_button (_("Clean Up"), RESPONSE_ACCEPT);
2043         checker.set_default_response (RESPONSE_CANCEL);
2044
2045         checker.set_name (_("CleanupDialog"));
2046         checker.set_wmclass (X_("ardour_cleanup"), "Ardour");
2047         checker.set_position (Gtk::WIN_POS_MOUSE);
2048
2049         switch (checker.run()) {
2050         case RESPONSE_ACCEPT:
2051                 break;
2052         default:
2053                 return;
2054         }
2055
2056         Session::cleanup_report rep;
2057
2058         editor->prepare_for_cleanup ();
2059
2060         if (session->cleanup_sources (rep)) {
2061                 return;
2062         }
2063         checker.hide();
2064         display_cleanup_results (rep, 
2065                                  _("cleaned files"),
2066                                  _("\
2067 The following %1 %2 not in use and \n\
2068 have been moved to:\n\
2069 %3. \n\n\
2070 Flushing the wastebasket will \n\
2071 release an additional\n\
2072 %4 %5bytes of disk space.\n"
2073                                          ));
2074 }
2075
2076 void
2077 ARDOUR_UI::flush_trash ()
2078 {
2079         if (session == 0) {
2080                 /* shouldn't happen: menu item is insensitive */
2081                 return;
2082         }
2083
2084         Session::cleanup_report rep;
2085
2086         if (session->cleanup_trash_sources (rep)) {
2087                 return;
2088         }
2089
2090         display_cleanup_results (rep, 
2091                                  _("deleted file"),
2092                                  _("The following %1 %2 deleted from\n\
2093 %3,\n\
2094 releasing %4 %5bytes of disk space"));
2095 }
2096
2097 void
2098 ARDOUR_UI::add_route ()
2099 {
2100         int count;
2101
2102         if (!session) {
2103                 return;
2104         }
2105
2106         if (add_route_dialog == 0) {
2107                 add_route_dialog = new AddRouteDialog;
2108                 editor->ensure_float (*add_route_dialog);
2109         }
2110
2111         if (add_route_dialog->is_visible()) {
2112                 /* we're already doing this */
2113                 return;
2114         }
2115
2116         ResponseType r = (ResponseType) add_route_dialog->run ();
2117         
2118         add_route_dialog->hide();
2119
2120         switch (r) {
2121         case RESPONSE_ACCEPT:
2122                 break;
2123         default:
2124                 return;
2125                 break;
2126         }
2127
2128         if ((count = add_route_dialog->count()) <= 0) {
2129                 return;
2130         }
2131
2132         uint32_t input_chan = add_route_dialog->channels ();
2133         uint32_t output_chan;
2134         string name_template = add_route_dialog->name_template ();
2135         bool track = add_route_dialog->track ();
2136
2137         AutoConnectOption oac = Config->get_output_auto_connect();
2138
2139         if (oac & AutoConnectMaster) {
2140                 output_chan = (session->master_out() ? session->master_out()->n_inputs() : input_chan);
2141         } else {
2142                 output_chan = input_chan;
2143         }
2144
2145         /* XXX do something with name template */
2146
2147         if (track) {
2148                 session_add_audio_track (input_chan, output_chan, add_route_dialog->mode(), count);
2149         } else {
2150                 session_add_audio_bus (input_chan, output_chan, count);
2151         }
2152 }
2153
2154 XMLNode*
2155 ARDOUR_UI::mixer_settings () const
2156 {
2157         XMLNode* node = 0;
2158
2159         if (session) {
2160                 node = session->instant_xml(X_("Mixer"), session->path());
2161         } else {
2162                 node = Config->instant_xml(X_("Mixer"), get_user_ardour_path());
2163         }
2164
2165         if (!node) {
2166                 node = new XMLNode (X_("Mixer"));
2167         }
2168
2169         return node;
2170 }
2171
2172 XMLNode*
2173 ARDOUR_UI::editor_settings () const
2174 {
2175         XMLNode* node = 0;
2176
2177         if (session) {
2178                 node = session->instant_xml(X_("Editor"), session->path());
2179         } else {
2180                 node = Config->instant_xml(X_("Editor"), get_user_ardour_path());
2181         }
2182
2183         if (!node) {
2184                 node = new XMLNode (X_("Editor"));
2185         }
2186         return node;
2187 }
2188
2189 XMLNode*
2190 ARDOUR_UI::keyboard_settings () const
2191 {
2192         XMLNode* node = 0;
2193
2194         node = Config->extra_xml(X_("Keyboard"));
2195         
2196         if (!node) {
2197                 node = new XMLNode (X_("Keyboard"));
2198         }
2199         return node;
2200 }
2201
2202 void
2203 ARDOUR_UI::halt_on_xrun_message ()
2204 {
2205         ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::halt_on_xrun_message));
2206
2207         MessageDialog msg (*editor,
2208                            _("Recording was stopped because your system could not keep up."));
2209         msg.run ();
2210 }
2211
2212 void
2213 ARDOUR_UI::disk_overrun_handler ()
2214 {
2215         ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::disk_underrun_handler));
2216
2217         if (!have_disk_overrun_displayed) {
2218                 have_disk_overrun_displayed = true;
2219                 MessageDialog msg (*editor, X_("diskrate dialog"), _("\
2220 The disk system on your computer\n\
2221 was not able to keep up with Ardour.\n\
2222 \n\
2223 Specifically, it failed to write data to disk\n\
2224 quickly enough to keep up with recording.\n"));
2225                 msg.run ();
2226                 have_disk_overrun_displayed = false;
2227         }
2228 }
2229
2230 void
2231 ARDOUR_UI::disk_underrun_handler ()
2232 {
2233         ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::disk_underrun_handler));
2234
2235         if (!have_disk_underrun_displayed) {
2236                 have_disk_underrun_displayed = true;
2237                 MessageDialog msg (*editor,
2238                         (_("The disk system on your computer\n\
2239 was not able to keep up with Ardour.\n\
2240 \n\
2241 Specifically, it failed to read data from disk\n\
2242 quickly enough to keep up with playback.\n")));
2243                 msg.run ();
2244                 have_disk_underrun_displayed = false;
2245         } 
2246 }
2247
2248 void
2249 ARDOUR_UI::disk_underrun_message_gone ()
2250 {
2251         have_disk_underrun_displayed = false;
2252 }
2253
2254 void
2255 ARDOUR_UI::disk_overrun_message_gone ()
2256 {
2257         have_disk_underrun_displayed = false;
2258 }
2259
2260 int
2261 ARDOUR_UI::pending_state_dialog ()
2262 {
2263         ArdourDialog dialog ("pending state dialog");
2264         Label  message (_("\
2265 This session appears to have been in\n\
2266 middle of recording when ardour or\n\
2267 the computer was shutdown.\n\
2268 \n\
2269 Ardour can recover any captured audio for\n\
2270 you, or it can ignore it. Please decide\n\
2271 what you would like to do.\n"));
2272
2273         dialog.get_vbox()->pack_start (message);
2274         dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
2275         dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
2276
2277         dialog.set_position (WIN_POS_CENTER);
2278         dialog.show_all ();
2279         
2280         switch (dialog.run ()) {
2281         case RESPONSE_ACCEPT:
2282                 return 1;
2283         default:
2284                 return 0;
2285         }
2286 }
2287         
2288 void
2289 ARDOUR_UI::disconnect_from_jack ()
2290 {
2291         if (engine) {
2292                 if( engine->disconnect_from_jack ()) {
2293                         MessageDialog msg (*editor, _("Could not disconnect from JACK"));
2294                         msg.run ();
2295                 }
2296
2297                 update_sample_rate (0);
2298         }
2299 }
2300
2301 void
2302 ARDOUR_UI::reconnect_to_jack ()
2303 {
2304         if (engine) {
2305                 if (engine->reconnect_to_jack ()) {
2306                         MessageDialog msg (*editor,  _("Could not reconnect to JACK"));
2307                         msg.run ();
2308                 }
2309
2310                 update_sample_rate (0);
2311         }
2312 }
2313
2314 void
2315 ARDOUR_UI::set_jack_buffer_size (nframes_t nframes)
2316 {
2317         engine->request_buffer_size (nframes);
2318         update_sample_rate (0);
2319 }
2320
2321 int
2322 ARDOUR_UI::cmdline_new_session (string path)
2323 {
2324         if (path[0] != '/') {
2325                 char buf[PATH_MAX+1];
2326                 string str;
2327
2328                 getcwd (buf, sizeof (buf));
2329                 str = buf;
2330                 str += '/';
2331                 str += path;
2332                 path = str;
2333         }
2334
2335         new_session (path);
2336
2337         _will_create_new_session_automatically = false; /* done it */
2338         return FALSE; /* don't call it again */
2339 }
2340
2341 void
2342 ARDOUR_UI::use_config ()
2343 {
2344         Glib::RefPtr<Action> act;
2345
2346         switch (Config->get_native_file_data_format ()) {
2347         case FormatFloat:
2348                 act = ActionManager::get_action (X_("options"), X_("FileDataFormatFloat"));
2349                 break;
2350         case FormatInt24:
2351                 act = ActionManager::get_action (X_("options"), X_("FileDataFormat24bit"));
2352                 break;
2353         }
2354
2355         if (act) {
2356                 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic(act);
2357                 ract->set_active ();
2358         }       
2359
2360         switch (Config->get_native_file_header_format ()) {
2361         case BWF:
2362                 act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatBWF"));
2363                 break;
2364         case WAVE:
2365                 act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatWAVE"));
2366                 break;
2367         case WAVE64:
2368                 act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatWAVE64"));
2369                 break;
2370         case iXML:
2371                 act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatiXML"));
2372                 break;
2373         case RF64:
2374                 act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatRF64"));
2375                 break;
2376         case CAF:
2377                 act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatCAF"));
2378                 break;
2379         case AIFF:
2380                 act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatAIFF"));
2381                 break;
2382         }
2383
2384         if (act) {
2385                 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic(act);
2386                 ract->set_active ();
2387         }       
2388 }
2389
2390 void
2391 ARDOUR_UI::update_transport_clocks (nframes_t pos)
2392 {
2393         primary_clock.set (pos);
2394         secondary_clock.set (pos);
2395
2396         if (big_clock_window) {
2397                 big_clock.set (pos);
2398         }
2399 }
2400
2401 void
2402 ARDOUR_UI::record_state_changed ()
2403 {
2404         ENSURE_GUI_THREAD (mem_fun (*this, &ARDOUR_UI::record_state_changed));
2405
2406         if (!session || !big_clock_window) {
2407                 /* why bother - the clock isn't visible */
2408                 return;
2409         }
2410
2411         switch (session->record_status()) {
2412         case Session::Recording:
2413                 big_clock.set_widget_name ("BigClockRecording");
2414                 break;
2415         default:
2416                 big_clock.set_widget_name ("BigClockNonRecording");
2417                 break;
2418         }
2419 }
2420
2421 void
2422 ARDOUR_UI::set_keybindings_path (string path)
2423 {
2424         keybindings_path = path;
2425 }
2426
2427 void
2428 ARDOUR_UI::save_keybindings ()
2429 {
2430         if (can_save_keybindings) {
2431                 AccelMap::save (keybindings_path);
2432         } 
2433 }
2434
2435 bool
2436 ARDOUR_UI::first_idle ()
2437 {
2438         can_save_keybindings = true;
2439         return false;
2440 }
2441
2442 void
2443 ARDOUR_UI::store_clock_modes ()
2444 {
2445         XMLNode* node = new XMLNode(X_("ClockModes"));
2446
2447         for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
2448                 node->add_property ((*x)->name().c_str(), enum_2_string ((*x)->mode()));
2449         }
2450
2451         session->add_extra_xml (*node);
2452         session->set_dirty ();
2453 }
2454
2455
2456