1e0b75d3cb2510e76e779d8331c4f6a0358b75f8
[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         /* Put the playhead at 0 and scroll fully left */
2840         new_session->instant_xml(X_("Editor"))->add_property (X_("playhead"), X_("0"));
2841         new_session->instant_xml(X_("Editor"))->add_property (X_("left-frame"), X_("0"));
2842
2843         set_session (new_session);
2844
2845         session_loaded = true;
2846
2847         new_session->save_state(new_session->name());
2848
2849         return 0;
2850 }
2851
2852 void
2853 ARDOUR_UI::launch_chat ()
2854 {
2855 #ifdef __APPLE__
2856         open_uri("http://webchat.freenode.net/?channels=ardour-osx");
2857 #else
2858         open_uri("http://webchat.freenode.net/?channels=ardour");
2859 #endif
2860 }
2861
2862 void
2863 ARDOUR_UI::show_about ()
2864 {
2865         if (about == 0) {
2866                 about = new About;
2867                 about->signal_response().connect(sigc::mem_fun (*this, &ARDOUR_UI::about_signal_response) );
2868         }
2869
2870         about->set_transient_for(*editor);
2871         about->show_all ();
2872 }
2873
2874 void
2875 ARDOUR_UI::launch_manual ()
2876 {
2877         PBD::open_uri("http://ardour.org/flossmanual");
2878 }
2879
2880 void
2881 ARDOUR_UI::launch_reference ()
2882 {
2883         PBD::open_uri("http://ardour.org/refmanual");
2884 }
2885
2886 void
2887 ARDOUR_UI::hide_about ()
2888 {
2889         if (about) {
2890                 about->get_window()->set_cursor ();
2891                 about->hide ();
2892         }
2893 }
2894
2895 void
2896 ARDOUR_UI::about_signal_response (int /*response*/)
2897 {
2898         hide_about();
2899 }
2900
2901 void
2902 ARDOUR_UI::show_splash ()
2903 {
2904         if (splash == 0) {
2905                 try {
2906                         splash = new Splash;
2907                 } catch (...) {
2908                         return;
2909                 }
2910         }
2911
2912         splash->show ();
2913         splash->present ();
2914         splash->queue_draw ();
2915         splash->get_window()->process_updates (true);
2916         flush_pending ();
2917 }
2918
2919 void
2920 ARDOUR_UI::hide_splash ()
2921 {
2922         if (splash) {
2923                 splash->hide();
2924         }
2925 }
2926
2927 void
2928 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title,
2929                                     const string& plural_msg, const string& singular_msg)
2930 {
2931         size_t removed;
2932
2933         removed = rep.paths.size();
2934
2935         if (removed == 0) {
2936                 MessageDialog msgd (*editor,
2937                                     _("No audio files were ready for cleanup"),
2938                                     true,
2939                                     Gtk::MESSAGE_INFO,
2940                                     (Gtk::ButtonsType)(Gtk::BUTTONS_OK)  );
2941                 msgd.set_secondary_text (_("If this seems suprising, \n\
2942 check for any existing snapshots.\n\
2943 These may still include regions that\n\
2944 require some unused files to continue to exist."));
2945
2946                 msgd.run ();
2947                 return;
2948         }
2949
2950         ArdourDialog results (_("Clean-up"), true, false);
2951
2952         struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
2953             CleanupResultsModelColumns() {
2954                     add (visible_name);
2955                     add (fullpath);
2956             }
2957             Gtk::TreeModelColumn<std::string> visible_name;
2958             Gtk::TreeModelColumn<std::string> fullpath;
2959         };
2960
2961
2962         CleanupResultsModelColumns results_columns;
2963         Glib::RefPtr<Gtk::ListStore> results_model;
2964         Gtk::TreeView results_display;
2965
2966         results_model = ListStore::create (results_columns);
2967         results_display.set_model (results_model);
2968         results_display.append_column (list_title, results_columns.visible_name);
2969
2970         results_display.set_name ("CleanupResultsList");
2971         results_display.set_headers_visible (true);
2972         results_display.set_headers_clickable (false);
2973         results_display.set_reorderable (false);
2974
2975         Gtk::ScrolledWindow list_scroller;
2976         Gtk::Label txt;
2977         Gtk::VBox dvbox;
2978         Gtk::HBox dhbox;  // the hbox for the image and text
2979         Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
2980         Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO,  Gtk::ICON_SIZE_DIALOG));
2981
2982         dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
2983
2984         const string dead_sound_directory = _session->session_directory().dead_sound_path().to_string();
2985
2986         /* subst:
2987            %1 - number of files removed
2988            %2 - location of "dead_sounds"
2989            %3 - size of files affected
2990            %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
2991         */
2992
2993         const char* bprefix;
2994         double space_adjusted = 0;
2995
2996         if (rep.space < 100000.0f) {
2997                 bprefix = X_("kilo");
2998         } else if (rep.space < 1000000.0f * 1000) {
2999                 bprefix = X_("mega");
3000                 space_adjusted = truncf((float)rep.space / 1000.0);
3001         } else {
3002                 bprefix = X_("giga");
3003                 space_adjusted = truncf((float)rep.space / (1000000.0 * 1000));
3004         }
3005
3006         if (removed > 1) {
3007                 txt.set_text (string_compose (plural_msg, removed, _session->path() + "dead_sounds", space_adjusted, bprefix));
3008         } else {
3009                 txt.set_text (string_compose (singular_msg, removed, _session->path() + "dead_sounds", space_adjusted, bprefix));
3010         }
3011
3012         dhbox.pack_start (*dimage, true, false, 5);
3013         dhbox.pack_start (txt, true, false, 5);
3014
3015         for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
3016                 TreeModel::Row row = *(results_model->append());
3017                 row[results_columns.visible_name] = *i;
3018                 row[results_columns.fullpath] = *i;
3019         }
3020
3021         list_scroller.add (results_display);
3022         list_scroller.set_size_request (-1, 150);
3023         list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
3024
3025         dvbox.pack_start (dhbox, true, false, 5);
3026         dvbox.pack_start (list_scroller, true, false, 5);
3027         ddhbox.pack_start (dvbox, true, false, 5);
3028
3029         results.get_vbox()->pack_start (ddhbox, true, false, 5);
3030         results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
3031         results.set_default_response (RESPONSE_CLOSE);
3032         results.set_position (Gtk::WIN_POS_MOUSE);
3033
3034         results_display.show();
3035         list_scroller.show();
3036         txt.show();
3037         dvbox.show();
3038         dhbox.show();
3039         ddhbox.show();
3040         dimage->show();
3041
3042         //results.get_vbox()->show();
3043         results.set_resizable (false);
3044
3045         results.run ();
3046
3047 }
3048
3049 void
3050 ARDOUR_UI::cleanup ()
3051 {
3052         if (_session == 0) {
3053                 /* shouldn't happen: menu item is insensitive */
3054                 return;
3055         }
3056
3057
3058         MessageDialog  checker (_("Are you sure you want to cleanup?"),
3059                                 true,
3060                                 Gtk::MESSAGE_QUESTION,
3061                                 (Gtk::ButtonsType)(Gtk::BUTTONS_NONE));
3062
3063         checker.set_secondary_text(_("Cleanup is a destructive operation.\n\
3064 ALL undo/redo information will be lost if you cleanup.\n\
3065 After cleanup, unused audio files will be moved to a \
3066 \"dead sounds\" location."));
3067
3068         checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3069         checker.add_button (_("Clean Up"), RESPONSE_ACCEPT);
3070         checker.set_default_response (RESPONSE_CANCEL);
3071
3072         checker.set_name (_("CleanupDialog"));
3073         checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3074         checker.set_position (Gtk::WIN_POS_MOUSE);
3075
3076         switch (checker.run()) {
3077         case RESPONSE_ACCEPT:
3078                 break;
3079         default:
3080                 return;
3081         }
3082
3083         ARDOUR::CleanupReport rep;
3084
3085         editor->prepare_for_cleanup ();
3086
3087         /* do not allow flush until a session is reloaded */
3088
3089         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3090         if (act) {
3091                 act->set_sensitive (false);
3092         }
3093
3094         if (_session->cleanup_sources (rep)) {
3095                 editor->finish_cleanup ();
3096                 return;
3097         }
3098
3099         editor->finish_cleanup ();
3100
3101         checker.hide();
3102         display_cleanup_results (rep,
3103                                  _("cleaned files"),
3104                                  _("\
3105 The following %1 files were not in use and \n\
3106 have been moved to:\n\
3107 %2. \n\n\
3108 Flushing the wastebasket will \n\
3109 release an additional\n\
3110 %3 %4bytes of disk space.\n"),
3111                                  _("\
3112 The following file was not in use and \n        \
3113 has been moved to:\n                            \
3114 %2. \n\n\
3115 Flushing the wastebasket will \n\
3116 release an additional\n\
3117 %3 %4bytes of disk space.\n"
3118                                          ));
3119
3120 }
3121
3122 void
3123 ARDOUR_UI::flush_trash ()
3124 {
3125         if (_session == 0) {
3126                 /* shouldn't happen: menu item is insensitive */
3127                 return;
3128         }
3129
3130         ARDOUR::CleanupReport rep;
3131
3132         if (_session->cleanup_trash_sources (rep)) {
3133                 return;
3134         }
3135
3136         display_cleanup_results (rep,
3137                                  _("deleted file"),
3138                                  _("The following %1 files were deleted from\n\
3139 %2,\n\
3140 releasing %3 %4bytes of disk space"),
3141                                  _("The following file was deleted from\n\
3142 %2,\n\
3143 releasing %3 %4bytes of disk space"));
3144 }
3145
3146 void
3147 ARDOUR_UI::add_route (Gtk::Window* float_window)
3148 {
3149         int count;
3150
3151         if (!_session) {
3152                 return;
3153         }
3154
3155         if (add_route_dialog == 0) {
3156                 add_route_dialog = new AddRouteDialog (_session);
3157                 if (float_window) {
3158                         add_route_dialog->set_transient_for (*float_window);
3159                 }
3160         }
3161
3162         if (add_route_dialog->is_visible()) {
3163                 /* we're already doing this */
3164                 return;
3165         }
3166
3167         ResponseType r = (ResponseType) add_route_dialog->run ();
3168
3169         add_route_dialog->hide();
3170
3171         switch (r) {
3172                 case RESPONSE_ACCEPT:
3173                         break;
3174                 default:
3175                         return;
3176                         break;
3177         }
3178
3179         if ((count = add_route_dialog->count()) <= 0) {
3180                 return;
3181         }
3182
3183         string template_path = add_route_dialog->track_template();
3184
3185         if (!template_path.empty()) {
3186                 _session->new_route_from_template (count, template_path);
3187                 return;
3188         }
3189
3190         uint32_t input_chan = add_route_dialog->channels ();
3191         uint32_t output_chan;
3192         string name_template = add_route_dialog->name_template ();
3193         bool track = add_route_dialog->track ();
3194         RouteGroup* route_group = add_route_dialog->route_group ();
3195
3196         AutoConnectOption oac = Config->get_output_auto_connect();
3197
3198         if (oac & AutoConnectMaster) {
3199                 output_chan = (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan);
3200         } else {
3201                 output_chan = input_chan;
3202         }
3203
3204         /* XXX do something with name template */
3205
3206         if (add_route_dialog->type() == ARDOUR::DataType::MIDI) {
3207                 if (track) {
3208                         session_add_midi_track (route_group, count);
3209                 } else  {
3210                         MessageDialog msg (*editor,
3211                                         _("Sorry, MIDI Busses are not supported at this time."));
3212                         msg.run ();
3213                         //session_add_midi_bus();
3214                 }
3215         } else {
3216                 if (track) {
3217                         session_add_audio_track (input_chan, output_chan, add_route_dialog->mode(), route_group, count);
3218                 } else {
3219                         session_add_audio_bus (input_chan, output_chan, route_group, count);
3220                 }
3221         }
3222 }
3223
3224 XMLNode*
3225 ARDOUR_UI::mixer_settings () const
3226 {
3227         XMLNode* node = 0;
3228
3229         if (_session) {
3230                 node = _session->instant_xml(X_("Mixer"));
3231         } else {
3232                 node = Config->instant_xml(X_("Mixer"));
3233         }
3234
3235         if (!node) {
3236                 node = new XMLNode (X_("Mixer"));
3237         }
3238
3239         return node;
3240 }
3241
3242 XMLNode*
3243 ARDOUR_UI::editor_settings () const
3244 {
3245         XMLNode* node = 0;
3246
3247         if (_session) {
3248                 node = _session->instant_xml(X_("Editor"));
3249         } else {
3250                 node = Config->instant_xml(X_("Editor"));
3251         }
3252         
3253         if (!node) {
3254                 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
3255                         node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
3256                 }
3257         }
3258
3259         if (!node) {
3260                 node = new XMLNode (X_("Editor"));
3261         }
3262
3263         return node;
3264 }
3265
3266 XMLNode*
3267 ARDOUR_UI::keyboard_settings () const
3268 {
3269         XMLNode* node = 0;
3270
3271         node = Config->extra_xml(X_("Keyboard"));
3272
3273         if (!node) {
3274                 node = new XMLNode (X_("Keyboard"));
3275         }
3276         return node;
3277 }
3278
3279 void
3280 ARDOUR_UI::create_xrun_marker (framepos_t where)
3281 {
3282         editor->mouse_add_new_marker (where, false, true);
3283 }
3284
3285 void
3286 ARDOUR_UI::halt_on_xrun_message ()
3287 {
3288         MessageDialog msg (*editor,
3289                            _("Recording was stopped because your system could not keep up."));
3290         msg.run ();
3291 }
3292
3293 void
3294 ARDOUR_UI::xrun_handler (framepos_t where)
3295 {
3296         if (!_session) {
3297                 return;
3298         }
3299
3300         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
3301
3302         if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
3303                 create_xrun_marker(where);
3304         }
3305
3306         if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
3307                 halt_on_xrun_message ();
3308         }
3309 }
3310
3311 void
3312 ARDOUR_UI::disk_overrun_handler ()
3313 {
3314         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
3315
3316         if (!have_disk_speed_dialog_displayed) {
3317                 have_disk_speed_dialog_displayed = true;
3318                 MessageDialog* msg = new MessageDialog (*editor, string_compose (_("\
3319 The disk system on your computer\n\
3320 was not able to keep up with %1.\n\
3321 \n\
3322 Specifically, it failed to write data to disk\n\
3323 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
3324                 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3325                 msg->show ();
3326         }
3327 }
3328
3329 void
3330 ARDOUR_UI::disk_underrun_handler ()
3331 {
3332         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
3333
3334         if (!have_disk_speed_dialog_displayed) {
3335                 have_disk_speed_dialog_displayed = true;
3336                 MessageDialog* msg = new MessageDialog (*editor,
3337                                                         string_compose (_("The disk system on your computer\n\
3338 was not able to keep up with %1.\n\
3339 \n\
3340 Specifically, it failed to read data from disk\n\
3341 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
3342                 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3343                 msg->show ();
3344         }
3345 }
3346
3347 void
3348 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
3349 {
3350         have_disk_speed_dialog_displayed = false;
3351         delete msg;
3352 }
3353
3354 void
3355 ARDOUR_UI::session_dialog (std::string msg)
3356 {
3357         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
3358
3359         MessageDialog* d;
3360
3361         if (editor) {
3362                 d = new MessageDialog (*editor, msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3363         } else {
3364                 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3365         }
3366
3367         d->show_all ();
3368         d->run ();
3369         delete d;
3370 }
3371
3372 int
3373 ARDOUR_UI::pending_state_dialog ()
3374 {
3375         HBox* hbox = new HBox();
3376         Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3377         ArdourDialog dialog (_("Crash Recovery"), true);
3378         Label  message (_("\
3379 This session appears to have been in\n\
3380 middle of recording when ardour or\n\
3381 the computer was shutdown.\n\
3382 \n\
3383 Ardour can recover any captured audio for\n\
3384 you, or it can ignore it. Please decide\n\
3385 what you would like to do.\n"));
3386         image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3387         hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3388         hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3389         dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3390         dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
3391         dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
3392         dialog.set_default_response (RESPONSE_ACCEPT);
3393         dialog.set_position (WIN_POS_CENTER);
3394         message.show();
3395         image->show();
3396         hbox->show();
3397
3398         switch (dialog.run ()) {
3399         case RESPONSE_ACCEPT:
3400                 return 1;
3401         default:
3402                 return 0;
3403         }
3404 }
3405
3406 int
3407 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
3408 {
3409         HBox* hbox = new HBox();
3410         Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3411         ArdourDialog dialog (_("Sample Rate Mismatch"), true);
3412         Label  message (string_compose (_("\
3413 This session was created with a sample rate of %1 Hz\n\
3414 \n\
3415 The audioengine is currently running at %2 Hz\n"), desired, actual));
3416
3417         image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3418         hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3419         hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3420         dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3421         dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
3422         dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
3423         dialog.set_default_response (RESPONSE_ACCEPT);
3424         dialog.set_position (WIN_POS_CENTER);
3425         message.show();
3426         image->show();
3427         hbox->show();
3428
3429         switch (dialog.run ()) {
3430         case RESPONSE_ACCEPT:
3431                 return 0;
3432         default:
3433                 return 1;
3434         }
3435 }
3436
3437
3438 void
3439 ARDOUR_UI::disconnect_from_jack ()
3440 {
3441         if (engine) {
3442                 if( engine->disconnect_from_jack ()) {
3443                         MessageDialog msg (*editor, _("Could not disconnect from JACK"));
3444                         msg.run ();
3445                 }
3446
3447                 update_sample_rate (0);
3448         }
3449 }
3450
3451 void
3452 ARDOUR_UI::reconnect_to_jack ()
3453 {
3454         if (engine) {
3455                 if (engine->reconnect_to_jack ()) {
3456                         MessageDialog msg (*editor,  _("Could not reconnect to JACK"));
3457                         msg.run ();
3458                 }
3459
3460                 update_sample_rate (0);
3461         }
3462 }
3463
3464 void
3465 ARDOUR_UI::use_config ()
3466 {
3467         XMLNode* node = Config->extra_xml (X_("TransportControllables"));
3468         if (node) {
3469                 set_transport_controllable_state (*node);
3470         }
3471 }
3472
3473 void
3474 ARDOUR_UI::update_transport_clocks (framepos_t pos)
3475 {
3476         if (Config->get_primary_clock_delta_edit_cursor()) {
3477                 primary_clock.set (pos, false, editor->get_preferred_edit_position(), 1);
3478         } else {
3479                 primary_clock.set (pos, 0, true);
3480         }
3481
3482         if (Config->get_secondary_clock_delta_edit_cursor()) {
3483                 secondary_clock.set (pos, false, editor->get_preferred_edit_position(), 2);
3484         } else {
3485                 secondary_clock.set (pos);
3486         }
3487
3488         if (big_clock_window->get()) {
3489                 big_clock.set (pos);
3490         }
3491 }
3492
3493
3494 void
3495 ARDOUR_UI::step_edit_status_change (bool yn)
3496 {
3497         // XXX should really store pre-step edit status of things
3498         // we make insensitive
3499
3500         if (yn) {
3501                 rec_button.set_visual_state (3);
3502                 rec_button.set_sensitive (false);
3503         } else {
3504                 rec_button.set_visual_state (0);
3505                 rec_button.set_sensitive (true);
3506         }
3507 }
3508
3509 void
3510 ARDOUR_UI::record_state_changed ()
3511 {
3512         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
3513
3514         if (!_session || !big_clock_window->get()) {
3515                 /* why bother - the clock isn't visible */
3516                 return;
3517         }
3518
3519         Session::RecordState const r = _session->record_status ();
3520         bool const h = _session->have_rec_enabled_track ();
3521
3522         if (r == Session::Recording && h)  {
3523                 big_clock.set_widget_name ("BigClockRecording");
3524         } else {
3525                 big_clock.set_widget_name ("BigClockNonRecording");
3526         }
3527 }
3528
3529 bool
3530 ARDOUR_UI::first_idle ()
3531 {
3532         if (_session) {
3533                 _session->allow_auto_play (true);
3534         }
3535
3536         if (editor) {
3537                 editor->first_idle();
3538         }
3539
3540         Keyboard::set_can_save_keybindings (true);
3541         return false;
3542 }
3543
3544 void
3545 ARDOUR_UI::store_clock_modes ()
3546 {
3547         XMLNode* node = new XMLNode(X_("ClockModes"));
3548
3549         for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
3550                 node->add_property ((*x)->name().c_str(), enum_2_string ((*x)->mode()));
3551         }
3552
3553         _session->add_extra_xml (*node);
3554         _session->set_dirty ();
3555 }
3556
3557
3558
3559 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
3560         : Controllable (name), ui (u), type(tp)
3561 {
3562
3563 }
3564
3565 void
3566 ARDOUR_UI::TransportControllable::set_value (double val)
3567 {
3568         if (type == ShuttleControl) {
3569                 double fract;
3570
3571                 if (val == 0.5) {
3572                         fract = 0.0;
3573                 } else {
3574                         if (val < 0.5) {
3575                                 fract = -((0.5 - val)/0.5);
3576                         } else {
3577                                 fract = ((val - 0.5)/0.5);
3578                         }
3579                 }
3580
3581                 ui.set_shuttle_fract (fract);
3582                 return;
3583         }
3584
3585         if (val < 0.5) {
3586                 /* do nothing: these are radio-style actions */
3587                 return;
3588         }
3589
3590         const char *action = 0;
3591
3592         switch (type) {
3593         case Roll:
3594                 action = X_("Roll");
3595                 break;
3596         case Stop:
3597                 action = X_("Stop");
3598                 break;
3599         case GotoStart:
3600                 action = X_("Goto Start");
3601                 break;
3602         case GotoEnd:
3603                 action = X_("Goto End");
3604                 break;
3605         case AutoLoop:
3606                 action = X_("Loop");
3607                 break;
3608         case PlaySelection:
3609                 action = X_("Play Selection");
3610                 break;
3611         case RecordEnable:
3612                 action = X_("Record");
3613                 break;
3614         default:
3615                 break;
3616         }
3617
3618         if (action == 0) {
3619                 return;
3620         }
3621
3622         Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
3623
3624         if (act) {
3625                 act->activate ();
3626         }
3627 }
3628
3629 double
3630 ARDOUR_UI::TransportControllable::get_value (void) const
3631 {
3632         float val = 0.0;
3633
3634         switch (type) {
3635         case Roll:
3636                 break;
3637         case Stop:
3638                 break;
3639         case GotoStart:
3640                 break;
3641         case GotoEnd:
3642                 break;
3643         case AutoLoop:
3644                 break;
3645         case PlaySelection:
3646                 break;
3647         case RecordEnable:
3648                 break;
3649         case ShuttleControl:
3650                 break;
3651         default:
3652                 break;
3653         }
3654
3655         return val;
3656 }
3657
3658 void
3659 ARDOUR_UI::TransportControllable::set_id (const string& str)
3660 {
3661         _id = str;
3662 }
3663
3664 void
3665 ARDOUR_UI::setup_profile ()
3666 {
3667         if (gdk_screen_width() < 1200) {
3668                 Profile->set_small_screen ();
3669         }
3670
3671
3672         if (getenv ("ARDOUR_SAE")) {
3673                 Profile->set_sae ();
3674                 Profile->set_single_package ();
3675         }
3676 }
3677
3678 void
3679 ARDOUR_UI::toggle_translations ()
3680 {
3681         using namespace Glib;
3682         
3683         RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("EnableTranslation"));
3684         if (act) {
3685                 RefPtr<ToggleAction> ract = RefPtr<ToggleAction>::cast_dynamic (act);
3686                 if (ract) {
3687                         
3688                         string i18n_killer = ARDOUR::translation_kill_path();
3689                         
3690                         bool already_enabled = !ARDOUR::translations_are_disabled ();
3691                         
3692                         if (ract->get_active ()) {
3693 /* we don't care about errors */
3694                                 int fd = ::open (i18n_killer.c_str(), O_RDONLY|O_CREAT, 0644);
3695                                 close (fd);
3696                         } else {
3697 /* we don't care about errors */
3698                                 unlink (i18n_killer.c_str());
3699                         }
3700                         
3701                         if (already_enabled != ract->get_active()) {
3702                                 MessageDialog win (already_enabled ? _("Translations disabled") : _("Translations enabled"),
3703                                                    false,
3704                                                    Gtk::MESSAGE_WARNING,
3705                                                    Gtk::BUTTONS_OK);
3706                                 win.set_secondary_text (string_compose (_("You must restart %1 for this to take effect."), PROGRAM_NAME));
3707                                 win.set_position (Gtk::WIN_POS_CENTER);
3708                                 win.present ();
3709                                 win.run ();
3710                         }
3711                 }
3712         }
3713 }        
3714
3715 /** Add a window proxy to our list, so that its state will be saved.
3716  *  This call also causes the window to be created and opened if its
3717  *  state was saved as `visible'.
3718  */
3719 void
3720 ARDOUR_UI::add_window_proxy (WindowProxyBase* p)
3721 {
3722         _window_proxies.push_back (p);
3723         p->maybe_show ();
3724 }
3725
3726 /** Remove a window proxy from our list.  Must be called if a WindowProxy
3727  *  is deleted, to prevent hanging pointers.
3728  */
3729 void
3730 ARDOUR_UI::remove_window_proxy (WindowProxyBase* p)
3731 {
3732         _window_proxies.remove (p);
3733 }
3734
3735 int
3736 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
3737 {
3738         MissingFileDialog dialog (s, str, type);
3739
3740         dialog.show ();
3741         dialog.present ();
3742
3743         int result = dialog.run ();
3744         dialog.hide ();
3745
3746         switch (result) {
3747         case RESPONSE_OK:
3748                 break;
3749         default:
3750                 return 1; // quit entire session load
3751         }
3752
3753         result = dialog.get_action ();
3754
3755         return result;
3756 }
3757
3758 int
3759 ARDOUR_UI::ambiguous_file (std::string file, std::string path, std::vector<std::string> hits)
3760 {
3761         AmbiguousFileDialog dialog (file, hits);
3762
3763         dialog.show ();
3764         dialog.present ();
3765
3766         dialog.run ();
3767         return dialog.get_which ();
3768 }