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