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