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