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