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