First go at saving window visibility and position state across saves.
[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         save_state_canfail (name, switch_to_it);
2104 }
2105
2106 int
2107 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2108 {
2109         if (_session) {
2110                 int ret;
2111
2112                 if (name.length() == 0) {
2113                         name = _session->snap_name();
2114                 }
2115
2116                 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2117                         return ret;
2118                 }
2119         }
2120         cerr << "SS canfail\n";
2121         save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2122         return 0;
2123 }
2124
2125 void
2126 ARDOUR_UI::primary_clock_value_changed ()
2127 {
2128         if (_session) {
2129                 _session->request_locate (primary_clock.current_time ());
2130         }
2131 }
2132
2133 void
2134 ARDOUR_UI::big_clock_value_changed ()
2135 {
2136         if (_session) {
2137                 _session->request_locate (big_clock.current_time ());
2138         }
2139 }
2140
2141 void
2142 ARDOUR_UI::secondary_clock_value_changed ()
2143 {
2144         if (_session) {
2145                 _session->request_locate (secondary_clock.current_time ());
2146         }
2147 }
2148
2149 void
2150 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2151 {
2152         if (_session == 0) {
2153                 return;
2154         }
2155
2156         if (_session->step_editing()) {
2157                 return;
2158         }
2159
2160         Session::RecordState const r = _session->record_status ();
2161         bool const h = _session->have_rec_enabled_track ();
2162
2163         if (r == Session::Enabled || (r == Session::Recording && !h)) {
2164                 if (onoff) {
2165                         rec_button.set_visual_state (2);
2166                 } else {
2167                         rec_button.set_visual_state (0);
2168                 }
2169         } else if (r == Session::Recording && h) {
2170                 rec_button.set_visual_state (1);
2171         } else {
2172                 rec_button.set_visual_state (0);
2173         }
2174 }
2175
2176 void
2177 ARDOUR_UI::save_template ()
2178 {
2179         ArdourPrompter prompter (true);
2180         string name;
2181
2182         if (!check_audioengine()) {
2183                 return;
2184         }
2185
2186         prompter.set_name (X_("Prompter"));
2187         prompter.set_title (_("Save Mix Template"));
2188         prompter.set_prompt (_("Name for mix template:"));
2189         prompter.set_initial_text(_session->name() + _("-template"));
2190         prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2191
2192         switch (prompter.run()) {
2193         case RESPONSE_ACCEPT:
2194                 prompter.get_result (name);
2195
2196                 if (name.length()) {
2197                         _session->save_template (name);
2198                 }
2199                 break;
2200
2201         default:
2202                 break;
2203         }
2204 }
2205
2206 void
2207 ARDOUR_UI::edit_metadata ()
2208 {
2209         SessionMetadataEditor dialog;
2210         dialog.set_session (_session);
2211         editor->ensure_float (dialog);
2212         dialog.run ();
2213 }
2214
2215 void
2216 ARDOUR_UI::import_metadata ()
2217 {
2218         SessionMetadataImporter dialog;
2219         dialog.set_session (_session);
2220         editor->ensure_float (dialog);
2221         dialog.run ();
2222 }
2223
2224 void
2225 ARDOUR_UI::fontconfig_dialog ()
2226 {
2227 #ifdef GTKOSX
2228         /* X11 users will always have fontconfig info around, but new GTK-OSX users
2229            may not and it can take a while to build it. Warn them.
2230         */
2231
2232         Glib::ustring fontconfig = Glib::build_filename (Glib::get_home_dir(), ".fontconfig");
2233
2234         if (!Glib::file_test (fontconfig, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_DIR)) {
2235                 MessageDialog msg (*_startup,
2236                                    string_compose (_("Welcome to %1.\n\n"
2237                                                      "The program will take a bit longer to start up\n"
2238                                                      "while the system fonts are checked.\n\n"
2239                                                      "This will only be done once, and you will\n"
2240                                                      "not see this message again\n"), PROGRAM_NAME),
2241                                    true,
2242                                    Gtk::MESSAGE_INFO,
2243                                    Gtk::BUTTONS_OK);
2244                 pop_back_splash ();
2245                 msg.show_all ();
2246                 msg.present ();
2247                 msg.run ();
2248         }
2249 #endif
2250 }
2251
2252 void
2253 ARDOUR_UI::parse_cmdline_path (const Glib::ustring& cmdline_path, Glib::ustring& session_name, Glib::ustring& session_path, bool& existing_session)
2254 {
2255         existing_session = false;
2256
2257         if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_DIR)) {
2258                 session_path = cmdline_path;
2259                 existing_session = true;
2260         } else if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_REGULAR)) {
2261                 session_path = Glib::path_get_dirname (string (cmdline_path));
2262                 existing_session = true;
2263         } else {
2264                 /* it doesn't exist, assume the best */
2265                 session_path = Glib::path_get_dirname (string (cmdline_path));
2266         }
2267
2268         session_name = basename_nosuffix (string (cmdline_path));
2269 }
2270
2271 int
2272 ARDOUR_UI::load_cmdline_session (const Glib::ustring& session_name, const Glib::ustring& session_path, bool& existing_session)
2273 {
2274         /* when this is called, the backend audio system must be running */
2275
2276         /* the main idea here is to deal with the fact that a cmdline argument for the session
2277            can be interpreted in different ways - it could be a directory or a file, and before
2278            we load, we need to know both the session directory and the snapshot (statefile) within it
2279            that we are supposed to use.
2280         */
2281
2282         if (session_name.length() == 0 || session_path.length() == 0) {
2283                 return false;
2284         }
2285
2286         if (Glib::file_test (session_path, Glib::FILE_TEST_IS_DIR)) {
2287
2288                 Glib::ustring predicted_session_file;
2289
2290                 predicted_session_file = session_path;
2291                 predicted_session_file += '/';
2292                 predicted_session_file += session_name;
2293                 predicted_session_file += ARDOUR::statefile_suffix;
2294
2295                 if (Glib::file_test (predicted_session_file, Glib::FILE_TEST_EXISTS)) {
2296                         existing_session = true;
2297                 }
2298
2299         } else if (Glib::file_test (session_path, Glib::FILE_TEST_EXISTS)) {
2300
2301                 if (session_path.find (ARDOUR::statefile_suffix) == session_path.length() - 7) {
2302                         /* existing .ardour file */
2303                         existing_session = true;
2304                 }
2305
2306         } else {
2307                 existing_session = false;
2308         }
2309
2310         /* lets just try to load it */
2311
2312         if (create_engine ()) {
2313                 backend_audio_error (false, _startup);
2314                 return -1;
2315         }
2316
2317         return load_session (session_path, session_name);
2318 }
2319
2320 bool
2321 ARDOUR_UI::ask_about_loading_existing_session (const Glib::ustring& session_path)
2322 {
2323         Glib::ustring str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2324
2325         MessageDialog msg (str,
2326                            false,
2327                            Gtk::MESSAGE_WARNING,
2328                            Gtk::BUTTONS_YES_NO,
2329                            true);
2330
2331
2332         msg.set_name (X_("OpenExistingDialog"));
2333         msg.set_title (_("Open Existing Session"));
2334         msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
2335         msg.set_position (Gtk::WIN_POS_MOUSE);
2336         pop_back_splash ();
2337
2338         switch (msg.run()) {
2339         case RESPONSE_YES:
2340                 return true;
2341                 break;
2342         }
2343         return false;
2344 }
2345
2346 int
2347 ARDOUR_UI::build_session_from_nsd (const Glib::ustring& session_path, const Glib::ustring& session_name)
2348 {
2349         BusProfile bus_profile;
2350
2351         if (Profile->get_sae()) {
2352
2353                 bus_profile.master_out_channels = 2;
2354                 bus_profile.input_ac = AutoConnectPhysical;
2355                 bus_profile.output_ac = AutoConnectMaster;
2356                 bus_profile.requested_physical_in = 0; // use all available
2357                 bus_profile.requested_physical_out = 0; // use all available
2358
2359         } else {
2360
2361                 /* get settings from advanced section of NSD */
2362
2363                 if (_startup->create_master_bus()) {
2364                         bus_profile.master_out_channels = (uint32_t) _startup->master_channel_count();
2365                 } else {
2366                         bus_profile.master_out_channels = 0;
2367                 }
2368
2369                 if (_startup->connect_inputs()) {
2370                         bus_profile.input_ac = AutoConnectPhysical;
2371                 } else {
2372                         bus_profile.input_ac = AutoConnectOption (0);
2373                 }
2374
2375                 /// @todo some minor tweaks.
2376                 
2377                 bus_profile.output_ac = AutoConnectOption (0);
2378
2379                 if (_startup->connect_outputs ()) {
2380                         if (_startup->connect_outs_to_master()) {
2381                                 bus_profile.output_ac = AutoConnectMaster;
2382                         } else if (_startup->connect_outs_to_physical()) {
2383                                 bus_profile.output_ac = AutoConnectPhysical;
2384                         }
2385                 }
2386
2387                 bus_profile.requested_physical_in = (uint32_t) _startup->input_limit_count();
2388                 bus_profile.requested_physical_out = (uint32_t) _startup->output_limit_count();
2389         }
2390
2391         if (build_session (session_path, session_name, bus_profile)) {
2392                 return -1;
2393         }
2394
2395         return 0;
2396 }
2397
2398 void
2399 ARDOUR_UI::idle_load (const Glib::ustring& path)
2400 {
2401         if (_session) {
2402                 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2403                         /* /path/to/foo => /path/to/foo, foo */
2404                         load_session (path, basename_nosuffix (path));
2405                 } else {
2406                         /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2407                         load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2408                 }
2409         } else {
2410
2411                 ARDOUR_COMMAND_LINE::session_name = path;
2412
2413                 /*
2414                  * new_session_dialog doens't exist in A3
2415                  * Try to remove all references to it to
2416                  * see if it will compile.  NOTE: this will
2417                  * likely cause a runtime issue is my somewhat
2418                  * uneducated guess.
2419                  */
2420
2421                 //if (new_session_dialog) {
2422
2423
2424                         /* make it break out of Dialog::run() and
2425                            start again.
2426                          */
2427
2428                         //new_session_dialog->response (1);
2429                 //}
2430         }
2431 }
2432
2433 void
2434 ARDOUR_UI::end_loading_messages ()
2435 {
2436         // hide_splash ();
2437 }
2438
2439 void
2440 ARDOUR_UI::loading_message (const std::string& /*msg*/)
2441 {
2442         // show_splash ();
2443         // splash->message (msg);
2444         flush_pending ();
2445 }
2446
2447 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
2448 int
2449 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
2450 {
2451         Glib::ustring session_name;
2452         Glib::ustring session_path;
2453         Glib::ustring template_name;
2454         int ret = -1;
2455         bool likely_new = false;
2456
2457         if (! load_template.empty()) {
2458             should_be_new = true;
2459             template_name = load_template;
2460         }
2461
2462         while (ret != 0) {
2463
2464                 if (!should_be_new && !ARDOUR_COMMAND_LINE::session_name.empty()) {
2465
2466                         /* if they named a specific statefile, use it, otherwise they are
2467                            just giving a session folder, and we want to use it as is
2468                            to find the session.
2469                         */
2470
2471                         if (ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix) != string::npos) {
2472                                 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
2473                         } else {
2474                                 session_path = ARDOUR_COMMAND_LINE::session_name;
2475                         }
2476
2477                         session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
2478
2479                 } else {
2480
2481                         bool const apply = run_startup (should_be_new, load_template);
2482                         if (!apply) {
2483                                 if (quit_on_cancel) {
2484                                         exit (1);
2485                                 } else {
2486                                         return ret;
2487                                 }
2488                         }
2489
2490                         /* if we run the startup dialog again, offer more than just "new session" */
2491
2492                         should_be_new = false;
2493
2494                         session_name = _startup->session_name (likely_new);
2495
2496                         /* this shouldn't happen, but we catch it just in case it does */
2497
2498                         if (session_name.empty()) {
2499                                 break;
2500                         }
2501                         if (_startup->use_session_template()) {
2502                                 template_name = _startup->session_template_name();
2503                                 _session_is_new = true;
2504                         }
2505
2506                         if (session_name[0] == '/' ||
2507                             (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == '/') ||
2508                             (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == '/')) {
2509
2510                                 /* absolute path or cwd-relative path specified for session name: infer session folder
2511                                    from what was given.
2512                                 */
2513                                 
2514                                 session_path = Glib::path_get_dirname (session_name);
2515                                 session_name = Glib::path_get_basename (session_name);
2516
2517                         } else {
2518
2519                                 session_path = _startup->session_folder();
2520                         }
2521                 }
2522
2523                 if (create_engine ()) {
2524                         break;
2525                 }
2526
2527                 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
2528
2529                         if (likely_new) {
2530
2531                                 Glib::ustring existing = Glib::build_filename (session_path, session_name);
2532
2533                                 if (!ask_about_loading_existing_session (existing)) {
2534                                         ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2535                                         continue;
2536                                 }
2537                         }
2538
2539                         _session_is_new = false;
2540
2541                 } else {
2542
2543                         if (!likely_new) {
2544                                 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
2545                                 msg.run ();
2546                                 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2547                                 continue;
2548                         }
2549
2550                         if (session_name.find ('/') != Glib::ustring::npos) {
2551                                 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2552                                                                           "session names may not contain a '/' character"));
2553                                 msg.run ();
2554                                 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2555                                 continue;
2556                         }
2557
2558                         if (session_name.find ('\\') != Glib::ustring::npos) {
2559                                 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2560                                                                           "session names may not contain a '\\' character"));
2561                                 msg.run ();
2562                                 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2563                                 continue;
2564                         }
2565
2566                         _session_is_new = true;
2567                 }
2568
2569                 if (likely_new && template_name.empty()) {
2570
2571                         ret = build_session_from_nsd (session_path, session_name);
2572
2573                 } else {
2574
2575                         ret = load_session (session_path, session_name, template_name);
2576                         if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
2577                                 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
2578                                 exit (1);
2579                         }
2580                 }
2581         }
2582
2583         return ret;
2584 }
2585
2586 void
2587 ARDOUR_UI::close_session()
2588 {
2589         if (!check_audioengine()) {
2590                 return;
2591         }
2592
2593         if (unload_session (true)) {
2594                 return;
2595         }
2596
2597         ARDOUR_COMMAND_LINE::session_name = "";
2598
2599         if (get_session_parameters (true, false)) {
2600                 exit (1);
2601         }
2602
2603         goto_editor_window ();
2604 }
2605
2606 int
2607 ARDOUR_UI::load_session (const Glib::ustring& path, const Glib::ustring& snap_name, Glib::ustring mix_template)
2608 {
2609         Session *new_session;
2610         int unload_status;
2611         int retval = -1;
2612
2613         session_loaded = false;
2614
2615         if (!check_audioengine()) {
2616                 return -1;
2617         }
2618
2619         unload_status = unload_session ();
2620
2621         if (unload_status < 0) {
2622                 goto out;
2623         } else if (unload_status > 0) {
2624                 retval = 0;
2625                 goto out;
2626         }
2627
2628         loading_message (string_compose (_("Please wait while %1loads your session"), PROGRAM_NAME));
2629
2630         try {
2631                 new_session = new Session (*engine, path, snap_name, 0, mix_template);
2632         }
2633
2634         /* this one is special */
2635
2636         catch (AudioEngine::PortRegistrationFailure& err) {
2637
2638                 MessageDialog msg (err.what(),
2639                                    true,
2640                                    Gtk::MESSAGE_INFO,
2641                                    Gtk::BUTTONS_CLOSE);
2642
2643                 msg.set_title (_("Port Registration Error"));
2644                 msg.set_secondary_text (_("Click the Close button to try again."));
2645                 msg.set_position (Gtk::WIN_POS_CENTER);
2646                 pop_back_splash ();
2647                 msg.present ();
2648
2649                 int response = msg.run ();
2650
2651                 msg.hide ();
2652
2653                 switch (response) {
2654                 case RESPONSE_CANCEL:
2655                         exit (1);
2656                 default:
2657                         break;
2658                 }
2659                 goto out;
2660         }
2661
2662         catch (...) {
2663
2664                 MessageDialog msg (string_compose(_("Session \"%1 (snapshot %2)\" did not load successfully"), path, snap_name),
2665                                    true,
2666                                    Gtk::MESSAGE_INFO,
2667                                    Gtk::BUTTONS_CLOSE);
2668
2669                 msg.set_title (_("Loading Error"));
2670                 msg.set_secondary_text (_("Click the Close button to try again."));
2671                 msg.set_position (Gtk::WIN_POS_CENTER);
2672                 pop_back_splash ();
2673                 msg.present ();
2674
2675                 int response = msg.run ();
2676
2677                 msg.hide ();
2678
2679                 switch (response) {
2680                 case RESPONSE_CANCEL:
2681                         exit (1);
2682                 default:
2683                         break;
2684                 }
2685                 goto out;
2686         }
2687
2688         /* Now the session been created, add the transport controls */
2689         new_session->add_controllable(roll_controllable);
2690         new_session->add_controllable(stop_controllable);
2691         new_session->add_controllable(goto_start_controllable);
2692         new_session->add_controllable(goto_end_controllable);
2693         new_session->add_controllable(auto_loop_controllable);
2694         new_session->add_controllable(play_selection_controllable);
2695         new_session->add_controllable(rec_controllable);
2696
2697         set_session (new_session);
2698
2699         session_loaded = true;
2700
2701         goto_editor_window ();
2702
2703         if (_session) {
2704                 _session->set_clean ();
2705         }
2706
2707         flush_pending ();
2708         retval = 0;
2709
2710   out:
2711         return retval;
2712 }
2713
2714 int
2715 ARDOUR_UI::build_session (const Glib::ustring& path, const Glib::ustring& snap_name, BusProfile& bus_profile)
2716 {
2717         Session *new_session;
2718         int x;
2719
2720         if (!check_audioengine()) {
2721                 return -1;
2722         }
2723
2724         session_loaded = false;
2725
2726         x = unload_session ();
2727
2728         if (x < 0) {
2729                 return -1;
2730         } else if (x > 0) {
2731                 return 0;
2732         }
2733
2734         _session_is_new = true;
2735
2736         try {
2737                 new_session = new Session (*engine, path, snap_name, &bus_profile);
2738         }
2739
2740         catch (...) {
2741
2742                 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
2743                 pop_back_splash ();
2744                 msg.run ();
2745                 return -1;
2746         }
2747
2748         set_session (new_session);
2749
2750         session_loaded = true;
2751
2752         new_session->save_state(new_session->name());
2753
2754         return 0;
2755 }
2756
2757 void
2758 ARDOUR_UI::launch_chat ()
2759 {
2760 #ifdef __APPLE__
2761         open_uri("http://webchat.freenode.net/?channels=ardour-osx");
2762 #else
2763         open_uri("http://webchat.freenode.net/?channels=ardour");
2764 #endif
2765 }
2766
2767 void
2768 ARDOUR_UI::show_about ()
2769 {
2770         if (about == 0) {
2771                 about = new About;
2772                 about->signal_response().connect(sigc::mem_fun (*this, &ARDOUR_UI::about_signal_response) );
2773         }
2774
2775         about->set_transient_for(*editor);
2776         about->show_all ();
2777 }
2778
2779 void
2780 ARDOUR_UI::launch_manual ()
2781 {
2782         PBD::open_uri("http://ardour.org/flossmanual");
2783 }
2784
2785 void
2786 ARDOUR_UI::launch_reference ()
2787 {
2788         PBD::open_uri("http://ardour.org/refmanual");
2789 }
2790
2791 void
2792 ARDOUR_UI::hide_about ()
2793 {
2794         if (about) {
2795                 about->get_window()->set_cursor ();
2796                 about->hide ();
2797         }
2798 }
2799
2800 void
2801 ARDOUR_UI::about_signal_response (int /*response*/)
2802 {
2803         hide_about();
2804 }
2805
2806 void
2807 ARDOUR_UI::show_splash ()
2808 {
2809         if (splash == 0) {
2810                 try {
2811                         splash = new Splash;
2812                 } catch (...) {
2813                         return;
2814                 }
2815         }
2816
2817         splash->show ();
2818         splash->present ();
2819         splash->queue_draw ();
2820         splash->get_window()->process_updates (true);
2821         flush_pending ();
2822 }
2823
2824 void
2825 ARDOUR_UI::hide_splash ()
2826 {
2827         if (splash) {
2828                 splash->hide();
2829         }
2830 }
2831
2832 void
2833 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title,
2834                                     const string& plural_msg, const string& singular_msg)
2835 {
2836         size_t removed;
2837
2838         removed = rep.paths.size();
2839
2840         if (removed == 0) {
2841                 MessageDialog msgd (*editor,
2842                                     _("No audio files were ready for cleanup"),
2843                                     true,
2844                                     Gtk::MESSAGE_INFO,
2845                                     (Gtk::ButtonsType)(Gtk::BUTTONS_OK)  );
2846                 msgd.set_secondary_text (_("If this seems suprising, \n\
2847 check for any existing snapshots.\n\
2848 These may still include regions that\n\
2849 require some unused files to continue to exist."));
2850
2851                 msgd.run ();
2852                 return;
2853         }
2854
2855         ArdourDialog results (_("Clean-up"), true, false);
2856
2857         struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
2858             CleanupResultsModelColumns() {
2859                     add (visible_name);
2860                     add (fullpath);
2861             }
2862             Gtk::TreeModelColumn<Glib::ustring> visible_name;
2863             Gtk::TreeModelColumn<Glib::ustring> fullpath;
2864         };
2865
2866
2867         CleanupResultsModelColumns results_columns;
2868         Glib::RefPtr<Gtk::ListStore> results_model;
2869         Gtk::TreeView results_display;
2870
2871         results_model = ListStore::create (results_columns);
2872         results_display.set_model (results_model);
2873         results_display.append_column (list_title, results_columns.visible_name);
2874
2875         results_display.set_name ("CleanupResultsList");
2876         results_display.set_headers_visible (true);
2877         results_display.set_headers_clickable (false);
2878         results_display.set_reorderable (false);
2879
2880         Gtk::ScrolledWindow list_scroller;
2881         Gtk::Label txt;
2882         Gtk::VBox dvbox;
2883         Gtk::HBox dhbox;  // the hbox for the image and text
2884         Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
2885         Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO,  Gtk::ICON_SIZE_DIALOG));
2886
2887         dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
2888
2889         const string dead_sound_directory = _session->session_directory().dead_sound_path().to_string();
2890
2891         /* subst:
2892            %1 - number of files removed
2893            %2 - location of "dead_sounds"
2894            %3 - size of files affected
2895            %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
2896         */
2897
2898         const char* bprefix;
2899         double space_adjusted = 0;
2900
2901         if (rep.space < 100000.0f) {
2902                 bprefix = X_("kilo");
2903         } else if (rep.space < 1000000.0f * 1000) {
2904                 bprefix = X_("mega");
2905                 space_adjusted = truncf((float)rep.space / 1000.0);
2906         } else {
2907                 bprefix = X_("giga");
2908                 space_adjusted = truncf((float)rep.space / (1000000.0 * 1000));
2909         }
2910
2911         if (removed > 1) {
2912                 txt.set_text (string_compose (plural_msg, removed, _session->path() + "dead_sounds", space_adjusted, bprefix));
2913         } else {
2914                 txt.set_text (string_compose (singular_msg, removed, _session->path() + "dead_sounds", space_adjusted, bprefix));
2915         }
2916
2917         dhbox.pack_start (*dimage, true, false, 5);
2918         dhbox.pack_start (txt, true, false, 5);
2919
2920         for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
2921                 TreeModel::Row row = *(results_model->append());
2922                 row[results_columns.visible_name] = *i;
2923                 row[results_columns.fullpath] = *i;
2924         }
2925
2926         list_scroller.add (results_display);
2927         list_scroller.set_size_request (-1, 150);
2928         list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
2929
2930         dvbox.pack_start (dhbox, true, false, 5);
2931         dvbox.pack_start (list_scroller, true, false, 5);
2932         ddhbox.pack_start (dvbox, true, false, 5);
2933
2934         results.get_vbox()->pack_start (ddhbox, true, false, 5);
2935         results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
2936         results.set_default_response (RESPONSE_CLOSE);
2937         results.set_position (Gtk::WIN_POS_MOUSE);
2938
2939         results_display.show();
2940         list_scroller.show();
2941         txt.show();
2942         dvbox.show();
2943         dhbox.show();
2944         ddhbox.show();
2945         dimage->show();
2946
2947         //results.get_vbox()->show();
2948         results.set_resizable (false);
2949
2950         results.run ();
2951
2952 }
2953
2954 void
2955 ARDOUR_UI::cleanup ()
2956 {
2957         if (_session == 0) {
2958                 /* shouldn't happen: menu item is insensitive */
2959                 return;
2960         }
2961
2962
2963         MessageDialog  checker (_("Are you sure you want to cleanup?"),
2964                                 true,
2965                                 Gtk::MESSAGE_QUESTION,
2966                                 (Gtk::ButtonsType)(Gtk::BUTTONS_NONE));
2967
2968         checker.set_secondary_text(_("Cleanup is a destructive operation.\n\
2969 ALL undo/redo information will be lost if you cleanup.\n\
2970 After cleanup, unused audio files will be moved to a \
2971 \"dead sounds\" location."));
2972
2973         checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
2974         checker.add_button (_("Clean Up"), RESPONSE_ACCEPT);
2975         checker.set_default_response (RESPONSE_CANCEL);
2976
2977         checker.set_name (_("CleanupDialog"));
2978         checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
2979         checker.set_position (Gtk::WIN_POS_MOUSE);
2980
2981         switch (checker.run()) {
2982         case RESPONSE_ACCEPT:
2983                 break;
2984         default:
2985                 return;
2986         }
2987
2988         ARDOUR::CleanupReport rep;
2989
2990         editor->prepare_for_cleanup ();
2991
2992         /* do not allow flush until a session is reloaded */
2993
2994         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
2995         if (act) {
2996                 act->set_sensitive (false);
2997         }
2998
2999         if (_session->cleanup_sources (rep)) {
3000                 editor->finish_cleanup ();
3001                 return;
3002         }
3003
3004         editor->finish_cleanup ();
3005
3006         checker.hide();
3007         display_cleanup_results (rep,
3008                                  _("cleaned files"),
3009                                  _("\
3010 The following %1 files were not in use and \n\
3011 have been moved to:\n\
3012 %2. \n\n\
3013 Flushing the wastebasket will \n\
3014 release an additional\n\
3015 %3 %4bytes of disk space.\n"),
3016                                  _("\
3017 The following file was not in use and \n        \
3018 has been moved to:\n                            \
3019 %2. \n\n\
3020 Flushing the wastebasket will \n\
3021 release an additional\n\
3022 %3 %4bytes of disk space.\n"
3023                                          ));
3024
3025 }
3026
3027 void
3028 ARDOUR_UI::flush_trash ()
3029 {
3030         if (_session == 0) {
3031                 /* shouldn't happen: menu item is insensitive */
3032                 return;
3033         }
3034
3035         ARDOUR::CleanupReport rep;
3036
3037         if (_session->cleanup_trash_sources (rep)) {
3038                 return;
3039         }
3040
3041         display_cleanup_results (rep,
3042                                  _("deleted file"),
3043                                  _("The following %1 files were deleted from\n\
3044 %2,\n\
3045 releasing %3 %4bytes of disk space"),
3046                                  _("The following file was deleted from\n\
3047 %2,\n\
3048 releasing %3 %4bytes of disk space"));
3049 }
3050
3051 void
3052 ARDOUR_UI::add_route (Gtk::Window* float_window)
3053 {
3054         int count;
3055
3056         if (!_session) {
3057                 return;
3058         }
3059
3060         if (add_route_dialog == 0) {
3061                 add_route_dialog = new AddRouteDialog (_session);
3062                 if (float_window) {
3063                         add_route_dialog->set_transient_for (*float_window);
3064                 }
3065         }
3066
3067         if (add_route_dialog->is_visible()) {
3068                 /* we're already doing this */
3069                 return;
3070         }
3071
3072         ResponseType r = (ResponseType) add_route_dialog->run ();
3073
3074         add_route_dialog->hide();
3075
3076         switch (r) {
3077                 case RESPONSE_ACCEPT:
3078                         break;
3079                 default:
3080                         return;
3081                         break;
3082         }
3083
3084         if ((count = add_route_dialog->count()) <= 0) {
3085                 return;
3086         }
3087
3088         string template_path = add_route_dialog->track_template();
3089
3090         if (!template_path.empty()) {
3091                 _session->new_route_from_template (count, template_path);
3092                 return;
3093         }
3094
3095         uint32_t input_chan = add_route_dialog->channels ();
3096         uint32_t output_chan;
3097         string name_template = add_route_dialog->name_template ();
3098         bool track = add_route_dialog->track ();
3099         bool aux = !track && add_route_dialog->aux();
3100         RouteGroup* route_group = add_route_dialog->route_group ();
3101
3102         AutoConnectOption oac = Config->get_output_auto_connect();
3103
3104         if (oac & AutoConnectMaster) {
3105                 output_chan = (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan);
3106         } else {
3107                 output_chan = input_chan;
3108         }
3109
3110         /* XXX do something with name template */
3111
3112         if (add_route_dialog->type() == ARDOUR::DataType::MIDI) {
3113                 if (track) {
3114                         session_add_midi_track (route_group, count);
3115                 } else  {
3116                         MessageDialog msg (*editor,
3117                                         _("Sorry, MIDI Busses are not supported at this time."));
3118                         msg.run ();
3119                         //session_add_midi_bus();
3120                 }
3121         } else {
3122                 if (track) {
3123                         session_add_audio_track (input_chan, output_chan, add_route_dialog->mode(), route_group, count);
3124                 } else {
3125                         session_add_audio_bus (aux, input_chan, output_chan, route_group, count);
3126                 }
3127         }
3128 }
3129
3130 XMLNode*
3131 ARDOUR_UI::mixer_settings () const
3132 {
3133         XMLNode* node = 0;
3134
3135         if (_session) {
3136                 node = _session->instant_xml(X_("Mixer"));
3137         } else {
3138                 node = Config->instant_xml(X_("Mixer"));
3139         }
3140
3141         if (!node) {
3142                 node = new XMLNode (X_("Mixer"));
3143         }
3144
3145         return node;
3146 }
3147
3148 XMLNode*
3149 ARDOUR_UI::editor_settings () const
3150 {
3151         XMLNode* node = 0;
3152
3153         if (_session) {
3154                 node = _session->instant_xml(X_("Editor"));
3155         } else {
3156                 node = Config->instant_xml(X_("Editor"));
3157         }
3158
3159         if (!node) {
3160                 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
3161                         node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
3162                 }
3163         }
3164
3165         if (!node) {
3166                 node = new XMLNode (X_("Editor"));
3167         }
3168
3169         return node;
3170 }
3171
3172 XMLNode*
3173 ARDOUR_UI::keyboard_settings () const
3174 {
3175         XMLNode* node = 0;
3176
3177         node = Config->extra_xml(X_("Keyboard"));
3178
3179         if (!node) {
3180                 node = new XMLNode (X_("Keyboard"));
3181         }
3182         return node;
3183 }
3184
3185 void
3186 ARDOUR_UI::create_xrun_marker(nframes_t where)
3187 {
3188         editor->mouse_add_new_marker (where, false, true);
3189 }
3190
3191 void
3192 ARDOUR_UI::halt_on_xrun_message ()
3193 {
3194         MessageDialog msg (*editor,
3195                            _("Recording was stopped because your system could not keep up."));
3196         msg.run ();
3197 }
3198
3199 void
3200 ARDOUR_UI::xrun_handler(nframes_t where)
3201 {
3202         if (!_session) {
3203                 return;
3204         }
3205
3206         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
3207
3208         if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
3209                 create_xrun_marker(where);
3210         }
3211
3212         if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
3213                 halt_on_xrun_message ();
3214         }
3215 }
3216
3217 void
3218 ARDOUR_UI::disk_overrun_handler ()
3219 {
3220         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
3221
3222         if (!have_disk_speed_dialog_displayed) {
3223                 have_disk_speed_dialog_displayed = true;
3224                 MessageDialog* msg = new MessageDialog (*editor, string_compose (_("\
3225 The disk system on your computer\n\
3226 was not able to keep up with %1.\n\
3227 \n\
3228 Specifically, it failed to write data to disk\n\
3229 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
3230                 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3231                 msg->show ();
3232         }
3233 }
3234
3235 void
3236 ARDOUR_UI::disk_underrun_handler ()
3237 {
3238         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
3239
3240         if (!have_disk_speed_dialog_displayed) {
3241                 have_disk_speed_dialog_displayed = true;
3242                 MessageDialog* msg = new MessageDialog (*editor,
3243                                                         string_compose (_("The disk system on your computer\n\
3244 was not able to keep up with %1.\n\
3245 \n\
3246 Specifically, it failed to read data from disk\n\
3247 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
3248                 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3249                 msg->show ();
3250         }
3251 }
3252
3253 void
3254 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
3255 {
3256         have_disk_speed_dialog_displayed = false;
3257         delete msg;
3258 }
3259
3260 void
3261 ARDOUR_UI::session_dialog (std::string msg)
3262 {
3263         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
3264
3265         MessageDialog* d;
3266
3267         if (editor) {
3268                 d = new MessageDialog (*editor, msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3269         } else {
3270                 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3271         }
3272
3273         d->show_all ();
3274         d->run ();
3275         delete d;
3276 }
3277
3278 int
3279 ARDOUR_UI::pending_state_dialog ()
3280 {
3281         HBox* hbox = new HBox();
3282         Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3283         ArdourDialog dialog (_("Crash Recovery"), true);
3284         Label  message (_("\
3285 This session appears to have been in\n\
3286 middle of recording when ardour or\n\
3287 the computer was shutdown.\n\
3288 \n\
3289 Ardour can recover any captured audio for\n\
3290 you, or it can ignore it. Please decide\n\
3291 what you would like to do.\n"));
3292         image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3293         hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3294         hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3295         dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3296         dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
3297         dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
3298         dialog.set_default_response (RESPONSE_ACCEPT);
3299         dialog.set_position (WIN_POS_CENTER);
3300         message.show();
3301         image->show();
3302         hbox->show();
3303
3304         switch (dialog.run ()) {
3305         case RESPONSE_ACCEPT:
3306                 return 1;
3307         default:
3308                 return 0;
3309         }
3310 }
3311
3312 int
3313 ARDOUR_UI::sr_mismatch_dialog (nframes_t desired, nframes_t actual)
3314 {
3315         HBox* hbox = new HBox();
3316         Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3317         ArdourDialog dialog (_("Sample Rate Mismatch"), true);
3318         Label  message (string_compose (_("\
3319 This session was created with a sample rate of %1 Hz\n\
3320 \n\
3321 The audioengine is currently running at %2 Hz\n"), desired, actual));
3322
3323         image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3324         hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3325         hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3326         dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3327         dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
3328         dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
3329         dialog.set_default_response (RESPONSE_ACCEPT);
3330         dialog.set_position (WIN_POS_CENTER);
3331         message.show();
3332         image->show();
3333         hbox->show();
3334
3335         switch (dialog.run ()) {
3336         case RESPONSE_ACCEPT:
3337                 return 0;
3338         default:
3339                 return 1;
3340         }
3341 }
3342
3343
3344 void
3345 ARDOUR_UI::disconnect_from_jack ()
3346 {
3347         if (engine) {
3348                 if( engine->disconnect_from_jack ()) {
3349                         MessageDialog msg (*editor, _("Could not disconnect from JACK"));
3350                         msg.run ();
3351                 }
3352
3353                 update_sample_rate (0);
3354         }
3355 }
3356
3357 void
3358 ARDOUR_UI::reconnect_to_jack ()
3359 {
3360         if (engine) {
3361                 if (engine->reconnect_to_jack ()) {
3362                         MessageDialog msg (*editor,  _("Could not reconnect to JACK"));
3363                         msg.run ();
3364                 }
3365
3366                 update_sample_rate (0);
3367         }
3368 }
3369
3370 void
3371 ARDOUR_UI::use_config ()
3372 {
3373         XMLNode* node = Config->extra_xml (X_("TransportControllables"));
3374         if (node) {
3375                 set_transport_controllable_state (*node);
3376         }
3377 }
3378
3379 void
3380 ARDOUR_UI::update_transport_clocks (nframes_t pos)
3381 {
3382         if (Config->get_primary_clock_delta_edit_cursor()) {
3383                 primary_clock.set (pos, false, editor->get_preferred_edit_position(), 1);
3384         } else {
3385                 primary_clock.set (pos, 0, true);
3386         }
3387
3388         if (Config->get_secondary_clock_delta_edit_cursor()) {
3389                 secondary_clock.set (pos, false, editor->get_preferred_edit_position(), 2);
3390         } else {
3391                 secondary_clock.set (pos);
3392         }
3393
3394         if (big_clock_window->get()) {
3395                 big_clock.set (pos);
3396         }
3397 }
3398
3399
3400 void
3401 ARDOUR_UI::step_edit_status_change (bool yn)
3402 {
3403         // XXX should really store pre-step edit status of things
3404         // we make insensitive
3405
3406         if (yn) {
3407                 rec_button.set_visual_state (3);
3408                 rec_button.set_sensitive (false);
3409         } else {
3410                 rec_button.set_visual_state (0);
3411                 rec_button.set_sensitive (true);
3412         }
3413 }
3414
3415 void
3416 ARDOUR_UI::record_state_changed ()
3417 {
3418         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
3419
3420         if (!_session || !big_clock_window->get()) {
3421                 /* why bother - the clock isn't visible */
3422                 return;
3423         }
3424
3425         Session::RecordState const r = _session->record_status ();
3426         bool const h = _session->have_rec_enabled_track ();
3427
3428         if (r == Session::Recording && h)  {
3429                 big_clock.set_widget_name ("BigClockRecording");
3430         } else {
3431                 big_clock.set_widget_name ("BigClockNonRecording");
3432         }
3433 }
3434
3435 bool
3436 ARDOUR_UI::first_idle ()
3437 {
3438         if (_session) {
3439                 _session->allow_auto_play (true);
3440         }
3441
3442         if (editor) {
3443                 editor->first_idle();
3444         }
3445
3446         Keyboard::set_can_save_keybindings (true);
3447         return false;
3448 }
3449
3450 void
3451 ARDOUR_UI::store_clock_modes ()
3452 {
3453         XMLNode* node = new XMLNode(X_("ClockModes"));
3454
3455         for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
3456                 node->add_property ((*x)->name().c_str(), enum_2_string ((*x)->mode()));
3457         }
3458
3459         _session->add_extra_xml (*node);
3460         _session->set_dirty ();
3461 }
3462
3463
3464
3465 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
3466         : Controllable (name), ui (u), type(tp)
3467 {
3468
3469 }
3470
3471 void
3472 ARDOUR_UI::TransportControllable::set_value (double val)
3473 {
3474         if (type == ShuttleControl) {
3475                 double fract;
3476
3477                 if (val == 0.5) {
3478                         fract = 0.0;
3479                 } else {
3480                         if (val < 0.5) {
3481                                 fract = -((0.5 - val)/0.5);
3482                         } else {
3483                                 fract = ((val - 0.5)/0.5);
3484                         }
3485                 }
3486
3487                 ui.set_shuttle_fract (fract);
3488                 return;
3489         }
3490
3491         if (val < 0.5) {
3492                 /* do nothing: these are radio-style actions */
3493                 return;
3494         }
3495
3496         const char *action = 0;
3497
3498         switch (type) {
3499         case Roll:
3500                 action = X_("Roll");
3501                 break;
3502         case Stop:
3503                 action = X_("Stop");
3504                 break;
3505         case GotoStart:
3506                 action = X_("Goto Start");
3507                 break;
3508         case GotoEnd:
3509                 action = X_("Goto End");
3510                 break;
3511         case AutoLoop:
3512                 action = X_("Loop");
3513                 break;
3514         case PlaySelection:
3515                 action = X_("Play Selection");
3516                 break;
3517         case RecordEnable:
3518                 action = X_("Record");
3519                 break;
3520         default:
3521                 break;
3522         }
3523
3524         if (action == 0) {
3525                 return;
3526         }
3527
3528         Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
3529
3530         if (act) {
3531                 act->activate ();
3532         }
3533 }
3534
3535 double
3536 ARDOUR_UI::TransportControllable::get_value (void) const
3537 {
3538         float val = 0.0;
3539
3540         switch (type) {
3541         case Roll:
3542                 break;
3543         case Stop:
3544                 break;
3545         case GotoStart:
3546                 break;
3547         case GotoEnd:
3548                 break;
3549         case AutoLoop:
3550                 break;
3551         case PlaySelection:
3552                 break;
3553         case RecordEnable:
3554                 break;
3555         case ShuttleControl:
3556                 break;
3557         default:
3558                 break;
3559         }
3560
3561         return val;
3562 }
3563
3564 void
3565 ARDOUR_UI::TransportControllable::set_id (const string& str)
3566 {
3567         _id = str;
3568 }
3569
3570 void
3571 ARDOUR_UI::setup_profile ()
3572 {
3573         if (gdk_screen_width() < 1200) {
3574                 Profile->set_small_screen ();
3575         }
3576
3577
3578         if (getenv ("ARDOUR_SAE")) {
3579                 Profile->set_sae ();
3580                 Profile->set_single_package ();
3581         }
3582 }
3583
3584 void
3585 ARDOUR_UI::toggle_translations ()
3586 {
3587         using namespace Glib;
3588         
3589         RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("EnableTranslation"));
3590         if (act) {
3591                 RefPtr<ToggleAction> ract = RefPtr<ToggleAction>::cast_dynamic (act);
3592                 if (ract) {
3593                         
3594                         string i18n_killer = ARDOUR::translation_kill_path();
3595                         
3596                         bool already_enabled = !ARDOUR::translations_are_disabled ();
3597                         
3598                         if (ract->get_active ()) {
3599 /* we don't care about errors */
3600                                 int fd = ::open (i18n_killer.c_str(), O_RDONLY|O_CREAT, 0644);
3601                                 close (fd);
3602                         } else {
3603 /* we don't care about errors */
3604                                 unlink (i18n_killer.c_str());
3605                         }
3606                         
3607                         if (already_enabled != ract->get_active()) {
3608                                 MessageDialog win (already_enabled ? _("Translations disabled") : _("Translations enabled"),
3609                                                    false,
3610                                                    Gtk::MESSAGE_WARNING,
3611                                                    Gtk::BUTTONS_OK);
3612                                 win.set_secondary_text (string_compose (_("You must restart %1 for this to take effect."), PROGRAM_NAME));
3613                                 win.set_position (Gtk::WIN_POS_CENTER);
3614                                 win.present ();
3615                                 win.run ();
3616                         }
3617                 }
3618         }
3619 }        
3620
3621 /** Add a window proxy to our list, so that its state will be saved.
3622  *  This call also causes the window to be created and opened if its
3623  *  state was saved as `visible'.
3624  */
3625 void
3626 ARDOUR_UI::add_window_proxy (WindowProxyBase* p)
3627 {
3628         _window_proxies.push_back (p);
3629         p->maybe_show ();
3630 }
3631
3632 /** Remove a window proxy from our list.  Must be called if a WindowProxy
3633  *  is deleted, to prevent hanging pointers.
3634  */
3635 void
3636 ARDOUR_UI::remove_window_proxy (WindowProxyBase* p)
3637 {
3638         _window_proxies.remove (p);
3639 }