Add dialogue to ask user about ambiguous source files. Fixes #3603.
[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, bool aux, 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 (aux, 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 (_session->config.get_external_sync()) {
1592                 switch (_session->config.get_sync_source()) {
1593                 case JACK:
1594                         break;
1595                 default:
1596                         /* transport controlled by the master */
1597                         return;
1598                 }
1599         }
1600
1601         bool rolling = _session->transport_rolling();
1602
1603         if (_session->get_play_loop()) {
1604                 /* XXX it is not possible to just leave seamless loop and keep
1605                    playing at present (nov 4th 2009)
1606                 */
1607                 if (!Config->get_seamless_loop()) {
1608                         _session->request_play_loop (false, true);
1609                 }
1610         } else if (_session->get_play_range () && !join_play_range_button.get_active()) {
1611                 /* stop playing a range if we currently are */
1612                 _session->request_play_range (0, true);
1613         }
1614
1615         if (join_play_range_button.get_active()) {
1616                 _session->request_play_range (&editor->get_selection().time, true);
1617         }
1618
1619         if (!rolling) {
1620                 _session->request_transport_speed (1.0f);
1621         }
1622 }
1623
1624 void
1625 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
1626 {
1627         
1628         if (!_session) {
1629                 return;
1630         }
1631
1632         if (_session->is_auditioning()) {
1633                 _session->cancel_audition ();
1634                 return;
1635         }
1636
1637         if (_session->config.get_external_sync()) {
1638                 switch (_session->config.get_sync_source()) {
1639                 case JACK:
1640                         break;
1641                 default:
1642                         /* transport controlled by the master */
1643                         return;
1644                 }
1645         }
1646
1647         bool rolling = _session->transport_rolling();
1648         bool affect_transport = true;
1649
1650         if (rolling && roll_out_of_bounded_mode) {
1651                 /* drop out of loop/range playback but leave transport rolling */
1652                 if (_session->get_play_loop()) {
1653                         if (Config->get_seamless_loop()) {
1654                                 /* the disk buffers contain copies of the loop - we can't 
1655                                    just keep playing, so stop the transport. the user
1656                                    can restart as they wish.
1657                                 */
1658                                 affect_transport = true;
1659                         } else {
1660                                 /* disk buffers are normal, so we can keep playing */
1661                                 affect_transport = false;
1662                         }
1663                         _session->request_play_loop (false, true);
1664                 } else if (_session->get_play_range ()) {
1665                         affect_transport = false;
1666                         _session->request_play_range (0, true);
1667                 } 
1668         } 
1669
1670         if (affect_transport) {
1671                 if (rolling) {
1672                         _session->request_stop (with_abort, true);
1673                 } else {
1674                         if (join_play_range_button.get_active()) {
1675                                 _session->request_play_range (&editor->get_selection().time, true);
1676                         }
1677                         
1678                         _session->request_transport_speed (1.0f);
1679                 }
1680         }
1681 }
1682
1683 void
1684 ARDOUR_UI::toggle_session_auto_loop ()
1685 {
1686         if (_session) {
1687                 if (_session->get_play_loop()) {
1688                         if (_session->transport_rolling()) {
1689                                 Location * looploc = _session->locations()->auto_loop_location();
1690                                 if (looploc) {
1691                                         _session->request_locate (looploc->start(), true);
1692                                 }
1693                         } else {
1694                                 _session->request_play_loop (false);
1695                         }
1696                 } else {
1697                         Location * looploc = _session->locations()->auto_loop_location();
1698                         if (looploc) {
1699                                 _session->request_play_loop (true);
1700                         }
1701                 }
1702         }
1703 }
1704
1705 void
1706 ARDOUR_UI::transport_play_selection ()
1707 {
1708         if (!_session) {
1709                 return;
1710         }
1711
1712         editor->play_selection ();
1713 }
1714
1715 void
1716 ARDOUR_UI::transport_rewind (int option)
1717 {
1718         float current_transport_speed;
1719
1720         if (_session) {
1721                 current_transport_speed = _session->transport_speed();
1722
1723                 if (current_transport_speed >= 0.0f) {
1724                         switch (option) {
1725                         case 0:
1726                                 _session->request_transport_speed (-1.0f);
1727                                 break;
1728                         case 1:
1729                                 _session->request_transport_speed (-4.0f);
1730                                 break;
1731                         case -1:
1732                                 _session->request_transport_speed (-0.5f);
1733                                 break;
1734                         }
1735                 } else {
1736                         /* speed up */
1737                         _session->request_transport_speed (current_transport_speed * 1.5f);
1738                 }
1739         }
1740 }
1741
1742 void
1743 ARDOUR_UI::transport_forward (int option)
1744 {
1745         float current_transport_speed;
1746
1747         if (_session) {
1748                 current_transport_speed = _session->transport_speed();
1749
1750                 if (current_transport_speed <= 0.0f) {
1751                         switch (option) {
1752                         case 0:
1753                                 _session->request_transport_speed (1.0f);
1754                                 break;
1755                         case 1:
1756                                 _session->request_transport_speed (4.0f);
1757                                 break;
1758                         case -1:
1759                                 _session->request_transport_speed (0.5f);
1760                                 break;
1761                         }
1762                 } else {
1763                         /* speed up */
1764                         _session->request_transport_speed (current_transport_speed * 1.5f);
1765                 }
1766
1767         }
1768 }
1769
1770 void
1771 ARDOUR_UI::toggle_record_enable (uint32_t rid)
1772 {
1773         if (_session == 0) {
1774                 return;
1775         }
1776
1777         boost::shared_ptr<Route> r;
1778
1779         if ((r = _session->route_by_remote_id (rid)) != 0) {
1780
1781                 Track* t;
1782
1783                 if ((t = dynamic_cast<Track*>(r.get())) != 0) {
1784                         t->set_record_enabled (!t->record_enabled(), this);
1785                 }
1786         }
1787         if (_session == 0) {
1788                 return;
1789         }
1790 }
1791
1792 void
1793 ARDOUR_UI::map_transport_state ()
1794 {
1795         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::map_transport_state)
1796
1797         if (!_session) {
1798                 auto_loop_button.set_visual_state (0);
1799                 play_selection_button.set_visual_state (0);
1800                 roll_button.set_visual_state (0);
1801                 stop_button.set_visual_state (1);
1802                 return;
1803         }
1804
1805         float sp = _session->transport_speed();
1806
1807         if (sp == 1.0f) {
1808                 shuttle_fract = SHUTTLE_FRACT_SPEED1;  /* speed = 1.0, believe it or not */
1809                 shuttle_box.queue_draw ();
1810         } else if (sp == 0.0f) {
1811                 shuttle_fract = 0;
1812                 shuttle_box.queue_draw ();
1813                 update_disk_space ();
1814         }
1815
1816         if (sp != 0.0) {
1817
1818                 /* we're rolling */
1819
1820                 if (_session->get_play_range()) {
1821
1822                         play_selection_button.set_visual_state (1);
1823                         roll_button.set_visual_state (0);
1824                         auto_loop_button.set_visual_state (0);
1825
1826                 } else if (_session->get_play_loop ()) {
1827                         
1828                         auto_loop_button.set_visual_state (1);
1829                         play_selection_button.set_visual_state (0);
1830                         roll_button.set_visual_state (0);
1831
1832                 } else {
1833                         
1834                         roll_button.set_visual_state (1);
1835                         play_selection_button.set_visual_state (0);
1836                         auto_loop_button.set_visual_state (0);
1837                 }
1838
1839                 if (join_play_range_button.get_active()) {
1840                         /* light up both roll and play-selection if they are joined */
1841                         roll_button.set_visual_state (1);
1842                         play_selection_button.set_visual_state (1);
1843                 }
1844
1845                 stop_button.set_visual_state (0);
1846
1847         } else {
1848
1849                 stop_button.set_visual_state (1);
1850                 roll_button.set_visual_state (0);
1851                 play_selection_button.set_visual_state (0);
1852                 auto_loop_button.set_visual_state (0);
1853         }
1854 }
1855
1856 void
1857 ARDOUR_UI::engine_stopped ()
1858 {
1859         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
1860         ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1861         ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1862 }
1863
1864 void
1865 ARDOUR_UI::engine_running ()
1866 {
1867         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
1868         ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, true);
1869         ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, false);
1870
1871         Glib::RefPtr<Action> action;
1872         const char* action_name = 0;
1873
1874         switch (engine->frames_per_cycle()) {
1875         case 32:
1876                 action_name = X_("JACKLatency32");
1877                 break;
1878         case 64:
1879                 action_name = X_("JACKLatency64");
1880                 break;
1881         case 128:
1882                 action_name = X_("JACKLatency128");
1883                 break;
1884         case 512:
1885                 action_name = X_("JACKLatency512");
1886                 break;
1887         case 1024:
1888                 action_name = X_("JACKLatency1024");
1889                 break;
1890         case 2048:
1891                 action_name = X_("JACKLatency2048");
1892                 break;
1893         case 4096:
1894                 action_name = X_("JACKLatency4096");
1895                 break;
1896         case 8192:
1897                 action_name = X_("JACKLatency8192");
1898                 break;
1899         default:
1900                 /* XXX can we do anything useful ? */
1901                 break;
1902         }
1903
1904         if (action_name) {
1905
1906                 action = ActionManager::get_action (X_("JACK"), action_name);
1907
1908                 if (action) {
1909                         Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (action);
1910                         ract->set_active ();
1911                 }
1912         }
1913 }
1914
1915 void
1916 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
1917 {
1918         if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
1919                 /* we can't rely on the original string continuing to exist when we are called
1920                    again in the GUI thread, so make a copy and note that we need to
1921                    free it later.
1922                 */
1923                 char *copy = strdup (reason);
1924                 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
1925                 return;
1926         }
1927
1928         ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1929         ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1930
1931         update_sample_rate (0);
1932
1933         string msgstr;
1934
1935         /* if the reason is a non-empty string, it means that the backend was shutdown
1936            rather than just Ardour.
1937         */
1938
1939         if (strlen (reason)) {
1940                 msgstr = string_compose (_("The audio backend (JACK) was shutdown because:\n\n%1"), reason);
1941         } else {
1942                 msgstr = string_compose (_("\
1943 JACK has either been shutdown or it\n\
1944 disconnected %1 because %1\n\
1945 was not fast enough. Try to restart\n\
1946 JACK, reconnect and save the session."), PROGRAM_NAME);
1947         }
1948
1949         MessageDialog msg (*editor, msgstr);
1950         pop_back_splash ();
1951         msg.run ();
1952
1953         if (free_reason) {
1954                 free ((char*) reason);
1955         }
1956 }
1957
1958 int32_t
1959 ARDOUR_UI::do_engine_start ()
1960 {
1961         try {
1962                 engine->start();
1963         }
1964
1965         catch (...) {
1966                 engine->stop ();
1967                 error << _("Unable to start the session running")
1968                       << endmsg;
1969                 unload_session ();
1970                 return -2;
1971         }
1972
1973         return 0;
1974 }
1975
1976 void
1977 ARDOUR_UI::setup_theme ()
1978 {
1979         theme_manager->setup_theme();
1980 }
1981
1982 void
1983 ARDOUR_UI::update_clocks ()
1984 {
1985         if (!editor || !editor->dragging_playhead()) {
1986                 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position()); /* EMIT_SIGNAL */
1987         }
1988 }
1989
1990 void
1991 ARDOUR_UI::start_clocking ()
1992 {
1993         clock_signal_connection = RapidScreenUpdate.connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
1994 }
1995
1996 void
1997 ARDOUR_UI::stop_clocking ()
1998 {
1999         clock_signal_connection.disconnect ();
2000 }
2001
2002 void
2003 ARDOUR_UI::toggle_clocking ()
2004 {
2005 #if 0
2006         if (clock_button.get_active()) {
2007                 start_clocking ();
2008         } else {
2009                 stop_clocking ();
2010         }
2011 #endif
2012 }
2013
2014 gint
2015 ARDOUR_UI::_blink (void *arg)
2016
2017 {
2018         ((ARDOUR_UI *) arg)->blink ();
2019         return TRUE;
2020 }
2021
2022 void
2023 ARDOUR_UI::blink ()
2024 {
2025         Blink (blink_on = !blink_on); /* EMIT_SIGNAL */
2026 }
2027
2028 void
2029 ARDOUR_UI::start_blinking ()
2030 {
2031         /* Start the blink signal. Everybody with a blinking widget
2032            uses Blink to drive the widget's state.
2033         */
2034
2035         if (blink_timeout_tag < 0) {
2036                 blink_on = false;
2037                 blink_timeout_tag = g_timeout_add (240, _blink, this);
2038         }
2039 }
2040
2041 void
2042 ARDOUR_UI::stop_blinking ()
2043 {
2044         if (blink_timeout_tag >= 0) {
2045                 g_source_remove (blink_timeout_tag);
2046                 blink_timeout_tag = -1;
2047         }
2048 }
2049
2050
2051 /** Ask the user for the name of a new shapshot and then take it.
2052  */
2053
2054 void
2055 ARDOUR_UI::snapshot_session (bool switch_to_it)
2056 {
2057         ArdourPrompter prompter (true);
2058         string snapname;
2059
2060         prompter.set_name ("Prompter");
2061         prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2062         prompter.set_title (_("Take Snapshot"));
2063         prompter.set_title (_("Take Snapshot"));
2064         prompter.set_prompt (_("Name of new snapshot"));
2065
2066         if (!switch_to_it) {
2067                 char timebuf[128];
2068                 time_t n;
2069                 struct tm local_time;
2070                 
2071                 time (&n);
2072                 localtime_r (&n, &local_time);
2073                 strftime (timebuf, sizeof(timebuf), "%FT%T", &local_time);
2074                 prompter.set_initial_text (timebuf);
2075         }
2076
2077   again:
2078         switch (prompter.run()) {
2079         case RESPONSE_ACCEPT:
2080         {
2081                 prompter.get_result (snapname);
2082
2083                 bool do_save = (snapname.length() != 0);
2084
2085                 if (do_save) {
2086                         if (snapname.find ('/') != string::npos) {
2087                                 MessageDialog msg (_("To ensure compatibility with various systems\n"
2088                                                      "snapshot names may not contain a '/' character"));
2089                                 msg.run ();
2090                                 goto again;
2091                         }
2092                         if (snapname.find ('\\') != string::npos) {
2093                                 MessageDialog msg (_("To ensure compatibility with various systems\n"
2094                                                      "snapshot names may not contain a '\\' character"));
2095                                 msg.run ();
2096                                 goto again;
2097                         }
2098                 }
2099
2100                 vector<sys::path> p;
2101                 get_state_files_in_directory (_session->session_directory().root_path(), p);
2102                 vector<string> n = get_file_names_no_extension (p);
2103                 if (find (n.begin(), n.end(), snapname) != n.end()) {
2104
2105                         ArdourDialog confirm (_("Confirm Snapshot Overwrite"), true);
2106                         Label m (_("A snapshot already exists with that name.  Do you want to overwrite it?"));
2107                         confirm.get_vbox()->pack_start (m, true, true);
2108                         confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2109                         confirm.add_button (_("Overwrite"), Gtk::RESPONSE_ACCEPT);
2110                         confirm.show_all ();
2111                         switch (confirm.run()) {
2112                         case RESPONSE_CANCEL:
2113                                 do_save = false;
2114                         }
2115                 }
2116
2117                 if (do_save) {
2118                         save_state (snapname, switch_to_it);
2119                 }
2120                 break;
2121         }
2122
2123         default:
2124                 break;
2125         }
2126 }
2127
2128 void
2129 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2130 {
2131         XMLNode* node = new XMLNode (X_("UI"));
2132
2133         for (list<WindowProxyBase*>::iterator i = _window_proxies.begin(); i != _window_proxies.end(); ++i) {
2134                 if (!(*i)->rc_configured()) {
2135                         node->add_child_nocopy (*((*i)->get_state ()));
2136                 }
2137         }
2138
2139         _session->add_extra_xml (*node);
2140         
2141         save_state_canfail (name, switch_to_it);
2142 }
2143
2144 int
2145 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2146 {
2147         if (_session) {
2148                 int ret;
2149
2150                 if (name.length() == 0) {
2151                         name = _session->snap_name();
2152                 }
2153
2154                 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2155                         return ret;
2156                 }
2157         }
2158         cerr << "SS canfail\n";
2159         save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2160         return 0;
2161 }
2162
2163 void
2164 ARDOUR_UI::primary_clock_value_changed ()
2165 {
2166         if (_session) {
2167                 _session->request_locate (primary_clock.current_time ());
2168         }
2169 }
2170
2171 void
2172 ARDOUR_UI::big_clock_value_changed ()
2173 {
2174         if (_session) {
2175                 _session->request_locate (big_clock.current_time ());
2176         }
2177 }
2178
2179 void
2180 ARDOUR_UI::secondary_clock_value_changed ()
2181 {
2182         if (_session) {
2183                 _session->request_locate (secondary_clock.current_time ());
2184         }
2185 }
2186
2187 void
2188 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2189 {
2190         if (_session == 0) {
2191                 return;
2192         }
2193
2194         if (_session->step_editing()) {
2195                 return;
2196         }
2197
2198         Session::RecordState const r = _session->record_status ();
2199         bool const h = _session->have_rec_enabled_track ();
2200
2201         if (r == Session::Enabled || (r == Session::Recording && !h)) {
2202                 if (onoff) {
2203                         rec_button.set_visual_state (2);
2204                 } else {
2205                         rec_button.set_visual_state (0);
2206                 }
2207         } else if (r == Session::Recording && h) {
2208                 rec_button.set_visual_state (1);
2209         } else {
2210                 rec_button.set_visual_state (0);
2211         }
2212 }
2213
2214 void
2215 ARDOUR_UI::save_template ()
2216 {
2217         ArdourPrompter prompter (true);
2218         string name;
2219
2220         if (!check_audioengine()) {
2221                 return;
2222         }
2223
2224         prompter.set_name (X_("Prompter"));
2225         prompter.set_title (_("Save Mix Template"));
2226         prompter.set_prompt (_("Name for mix template:"));
2227         prompter.set_initial_text(_session->name() + _("-template"));
2228         prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2229
2230         switch (prompter.run()) {
2231         case RESPONSE_ACCEPT:
2232                 prompter.get_result (name);
2233
2234                 if (name.length()) {
2235                         _session->save_template (name);
2236                 }
2237                 break;
2238
2239         default:
2240                 break;
2241         }
2242 }
2243
2244 void
2245 ARDOUR_UI::edit_metadata ()
2246 {
2247         SessionMetadataEditor dialog;
2248         dialog.set_session (_session);
2249         editor->ensure_float (dialog);
2250         dialog.run ();
2251 }
2252
2253 void
2254 ARDOUR_UI::import_metadata ()
2255 {
2256         SessionMetadataImporter dialog;
2257         dialog.set_session (_session);
2258         editor->ensure_float (dialog);
2259         dialog.run ();
2260 }
2261
2262 void
2263 ARDOUR_UI::fontconfig_dialog ()
2264 {
2265 #ifdef GTKOSX
2266         /* X11 users will always have fontconfig info around, but new GTK-OSX users
2267            may not and it can take a while to build it. Warn them.
2268         */
2269
2270         std::string fontconfig = Glib::build_filename (Glib::get_home_dir(), ".fontconfig");
2271
2272         if (!Glib::file_test (fontconfig, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_DIR)) {
2273                 MessageDialog msg (*_startup,
2274                                    string_compose (_("Welcome to %1.\n\n"
2275                                                      "The program will take a bit longer to start up\n"
2276                                                      "while the system fonts are checked.\n\n"
2277                                                      "This will only be done once, and you will\n"
2278                                                      "not see this message again\n"), PROGRAM_NAME),
2279                                    true,
2280                                    Gtk::MESSAGE_INFO,
2281                                    Gtk::BUTTONS_OK);
2282                 pop_back_splash ();
2283                 msg.show_all ();
2284                 msg.present ();
2285                 msg.run ();
2286         }
2287 #endif
2288 }
2289
2290 void
2291 ARDOUR_UI::parse_cmdline_path (const std::string& cmdline_path, std::string& session_name, std::string& session_path, bool& existing_session)
2292 {
2293         existing_session = false;
2294
2295         if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_DIR)) {
2296                 session_path = cmdline_path;
2297                 existing_session = true;
2298         } else if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_REGULAR)) {
2299                 session_path = Glib::path_get_dirname (string (cmdline_path));
2300                 existing_session = true;
2301         } else {
2302                 /* it doesn't exist, assume the best */
2303                 session_path = Glib::path_get_dirname (string (cmdline_path));
2304         }
2305
2306         session_name = basename_nosuffix (string (cmdline_path));
2307 }
2308
2309 int
2310 ARDOUR_UI::load_cmdline_session (const std::string& session_name, const std::string& session_path, bool& existing_session)
2311 {
2312         /* when this is called, the backend audio system must be running */
2313
2314         /* the main idea here is to deal with the fact that a cmdline argument for the session
2315            can be interpreted in different ways - it could be a directory or a file, and before
2316            we load, we need to know both the session directory and the snapshot (statefile) within it
2317            that we are supposed to use.
2318         */
2319
2320         if (session_name.length() == 0 || session_path.length() == 0) {
2321                 return false;
2322         }
2323
2324         if (Glib::file_test (session_path, Glib::FILE_TEST_IS_DIR)) {
2325
2326                 std::string predicted_session_file;
2327
2328                 predicted_session_file = session_path;
2329                 predicted_session_file += '/';
2330                 predicted_session_file += session_name;
2331                 predicted_session_file += ARDOUR::statefile_suffix;
2332
2333                 if (Glib::file_test (predicted_session_file, Glib::FILE_TEST_EXISTS)) {
2334                         existing_session = true;
2335                 }
2336
2337         } else if (Glib::file_test (session_path, Glib::FILE_TEST_EXISTS)) {
2338
2339                 if (session_path.find (ARDOUR::statefile_suffix) == session_path.length() - 7) {
2340                         /* existing .ardour file */
2341                         existing_session = true;
2342                 }
2343
2344         } else {
2345                 existing_session = false;
2346         }
2347
2348         /* lets just try to load it */
2349
2350         if (create_engine ()) {
2351                 backend_audio_error (false, _startup);
2352                 return -1;
2353         }
2354
2355         return load_session (session_path, session_name);
2356 }
2357
2358 bool
2359 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
2360 {
2361         std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2362
2363         MessageDialog msg (str,
2364                            false,
2365                            Gtk::MESSAGE_WARNING,
2366                            Gtk::BUTTONS_YES_NO,
2367                            true);
2368
2369
2370         msg.set_name (X_("OpenExistingDialog"));
2371         msg.set_title (_("Open Existing Session"));
2372         msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
2373         msg.set_position (Gtk::WIN_POS_MOUSE);
2374         pop_back_splash ();
2375
2376         switch (msg.run()) {
2377         case RESPONSE_YES:
2378                 return true;
2379                 break;
2380         }
2381         return false;
2382 }
2383
2384 int
2385 ARDOUR_UI::build_session_from_nsd (const std::string& session_path, const std::string& session_name)
2386 {
2387         BusProfile bus_profile;
2388
2389         if (Profile->get_sae()) {
2390
2391                 bus_profile.master_out_channels = 2;
2392                 bus_profile.input_ac = AutoConnectPhysical;
2393                 bus_profile.output_ac = AutoConnectMaster;
2394                 bus_profile.requested_physical_in = 0; // use all available
2395                 bus_profile.requested_physical_out = 0; // use all available
2396
2397         } else {
2398
2399                 /* get settings from advanced section of NSD */
2400
2401                 if (_startup->create_master_bus()) {
2402                         bus_profile.master_out_channels = (uint32_t) _startup->master_channel_count();
2403                 } else {
2404                         bus_profile.master_out_channels = 0;
2405                 }
2406
2407                 if (_startup->connect_inputs()) {
2408                         bus_profile.input_ac = AutoConnectPhysical;
2409                 } else {
2410                         bus_profile.input_ac = AutoConnectOption (0);
2411                 }
2412
2413                 /// @todo some minor tweaks.
2414                 
2415                 bus_profile.output_ac = AutoConnectOption (0);
2416
2417                 if (_startup->connect_outputs ()) {
2418                         if (_startup->connect_outs_to_master()) {
2419                                 bus_profile.output_ac = AutoConnectMaster;
2420                         } else if (_startup->connect_outs_to_physical()) {
2421                                 bus_profile.output_ac = AutoConnectPhysical;
2422                         }
2423                 }
2424
2425                 bus_profile.requested_physical_in = (uint32_t) _startup->input_limit_count();
2426                 bus_profile.requested_physical_out = (uint32_t) _startup->output_limit_count();
2427         }
2428
2429         if (build_session (session_path, session_name, bus_profile)) {
2430                 return -1;
2431         }
2432
2433         return 0;
2434 }
2435
2436 void
2437 ARDOUR_UI::idle_load (const std::string& path)
2438 {
2439         if (_session) {
2440                 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2441                         /* /path/to/foo => /path/to/foo, foo */
2442                         load_session (path, basename_nosuffix (path));
2443                 } else {
2444                         /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2445                         load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2446                 }
2447         } else {
2448
2449                 ARDOUR_COMMAND_LINE::session_name = path;
2450
2451                 /*
2452                  * new_session_dialog doens't exist in A3
2453                  * Try to remove all references to it to
2454                  * see if it will compile.  NOTE: this will
2455                  * likely cause a runtime issue is my somewhat
2456                  * uneducated guess.
2457                  */
2458
2459                 //if (new_session_dialog) {
2460
2461
2462                         /* make it break out of Dialog::run() and
2463                            start again.
2464                          */
2465
2466                         //new_session_dialog->response (1);
2467                 //}
2468         }
2469 }
2470
2471 void
2472 ARDOUR_UI::end_loading_messages ()
2473 {
2474         // hide_splash ();
2475 }
2476
2477 void
2478 ARDOUR_UI::loading_message (const std::string& /*msg*/)
2479 {
2480         // show_splash ();
2481         // splash->message (msg);
2482         flush_pending ();
2483 }
2484
2485 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
2486 int
2487 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
2488 {
2489         string session_name;
2490         string session_path;
2491         string template_name;
2492         int ret = -1;
2493         bool likely_new = false;
2494
2495         if (! load_template.empty()) {
2496                 should_be_new = true;
2497                 template_name = load_template;
2498         }
2499
2500         while (ret != 0) {
2501
2502                 if (!should_be_new && !ARDOUR_COMMAND_LINE::session_name.empty()) {
2503
2504                         /* if they named a specific statefile, use it, otherwise they are
2505                            just giving a session folder, and we want to use it as is
2506                            to find the session.
2507                         */
2508
2509                         if (ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix) != string::npos) {
2510                                 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
2511                         } else {
2512                                 session_path = ARDOUR_COMMAND_LINE::session_name;
2513                         }
2514
2515                         session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
2516
2517                 } else {
2518
2519                         bool const apply = run_startup (should_be_new, load_template);
2520
2521                         if (!apply) {
2522                                 if (quit_on_cancel) {
2523                                         exit (1);
2524                                 } else {
2525                                         return ret;
2526                                 }
2527                         }
2528
2529                         /* if we run the startup dialog again, offer more than just "new session" */
2530
2531                         should_be_new = false;
2532
2533                         session_name = _startup->session_name (likely_new);
2534
2535                         /* this shouldn't happen, but we catch it just in case it does */
2536
2537                         if (session_name.empty()) {
2538                                 continue;
2539                         }
2540
2541                         if (_startup->use_session_template()) {
2542                                 template_name = _startup->session_template_name();
2543                                 _session_is_new = true;
2544                         }
2545
2546                         if (session_name[0] == G_DIR_SEPARATOR ||
2547                             (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
2548                             (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)) {
2549
2550                                 /* absolute path or cwd-relative path specified for session name: infer session folder
2551                                    from what was given.
2552                                 */
2553                                 
2554                                 session_path = Glib::path_get_dirname (session_name);
2555                                 session_name = Glib::path_get_basename (session_name);
2556
2557                         } else {
2558
2559                                 session_path = _startup->session_folder();
2560
2561                                 if (session_name.find ('/') != string::npos) {
2562                                         MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2563                                                                         "session names may not contain a '/' character"));
2564                                         msg.run ();
2565                                         ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2566                                         continue;
2567                                 }
2568                                 
2569                                 if (session_name.find ('\\') != string::npos) {
2570                                         MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2571                                                                         "session names may not contain a '\\' character"));
2572                                         msg.run ();
2573                                         ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2574                                         continue;
2575                                 }
2576                         }
2577                 }
2578
2579                 if (create_engine ()) {
2580                         break;
2581                 }
2582
2583                 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
2584
2585                         if (likely_new) {
2586
2587                                 std::string existing = Glib::build_filename (session_path, session_name);
2588
2589                                 if (!ask_about_loading_existing_session (existing)) {
2590                                         ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2591                                         continue;
2592                                 }
2593                         }
2594
2595                         _session_is_new = false;
2596
2597                 } else {
2598
2599                         if (!likely_new) {
2600                                 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
2601                                 msg.run ();
2602                                 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2603                                 continue;
2604                         }
2605
2606                         if (session_name.find ('/') != std::string::npos) {
2607                                 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2608                                                                 "session names may not contain a '/' character"));
2609                                 msg.run ();
2610                                 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2611                                 continue;
2612                         }
2613
2614                         if (session_name.find ('\\') != std::string::npos) {
2615                                 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2616                                                                 "session names may not contain a '\\' character"));
2617                                 msg.run ();
2618                                 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2619                                 continue;
2620                         }
2621
2622                         _session_is_new = true;
2623                 }
2624
2625                 if (likely_new && template_name.empty()) {
2626
2627                         ret = build_session_from_nsd (session_path, session_name);
2628
2629                 } else {
2630
2631                         ret = load_session (session_path, session_name, template_name);
2632                         if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
2633                                 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
2634                                 exit (1);
2635                         }
2636                 }
2637         }
2638
2639         return ret;
2640 }
2641
2642 void
2643 ARDOUR_UI::close_session()
2644 {
2645         if (!check_audioengine()) {
2646                 return;
2647         }
2648
2649         if (unload_session (true)) {
2650                 return;
2651         }
2652
2653         ARDOUR_COMMAND_LINE::session_name = "";
2654
2655         if (get_session_parameters (true, false)) {
2656                 exit (1);
2657         }
2658
2659         goto_editor_window ();
2660 }
2661
2662 int
2663 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
2664 {
2665         Session *new_session;
2666         int unload_status;
2667         int retval = -1;
2668
2669         session_loaded = false;
2670
2671         if (!check_audioengine()) {
2672                 return -1;
2673         }
2674
2675         unload_status = unload_session ();
2676
2677         if (unload_status < 0) {
2678                 goto out;
2679         } else if (unload_status > 0) {
2680                 retval = 0;
2681                 goto out;
2682         }
2683
2684         loading_message (string_compose (_("Please wait while %1loads your session"), PROGRAM_NAME));
2685
2686         try {
2687                 new_session = new Session (*engine, path, snap_name, 0, mix_template);
2688         }
2689
2690         /* this one is special */
2691
2692         catch (AudioEngine::PortRegistrationFailure& err) {
2693
2694                 MessageDialog msg (err.what(),
2695                                    true,
2696                                    Gtk::MESSAGE_INFO,
2697                                    Gtk::BUTTONS_CLOSE);
2698
2699                 msg.set_title (_("Port Registration Error"));
2700                 msg.set_secondary_text (_("Click the Close button to try again."));
2701                 msg.set_position (Gtk::WIN_POS_CENTER);
2702                 pop_back_splash ();
2703                 msg.present ();
2704
2705                 int response = msg.run ();
2706
2707                 msg.hide ();
2708
2709                 switch (response) {
2710                 case RESPONSE_CANCEL:
2711                         exit (1);
2712                 default:
2713                         break;
2714                 }
2715                 goto out;
2716         }
2717
2718         catch (...) {
2719
2720                 MessageDialog msg (string_compose(_("Session \"%1 (snapshot %2)\" did not load successfully"),path, snap_name),
2721                                    true,
2722                                    Gtk::MESSAGE_INFO,
2723                                    BUTTONS_OK);
2724
2725                 msg.set_title (_("Loading Error"));
2726                 msg.set_secondary_text (_("Click the Refresh button to try again."));
2727                 msg.add_button (Stock::REFRESH, 1);
2728                 msg.set_position (Gtk::WIN_POS_CENTER);
2729                 pop_back_splash ();
2730                 msg.present ();
2731
2732                 int response = msg.run ();
2733
2734                 switch (response) {
2735                 case 1:
2736                         break;
2737                 default:
2738                         exit (1);
2739                 }
2740
2741                 msg.hide ();
2742
2743                 goto out;
2744         }
2745
2746         {
2747                 list<string> const u = new_session->unknown_processors ();
2748                 if (!u.empty()) {
2749                         MissingPluginDialog d (_session, u);
2750                         d.run ();
2751                 }
2752         }
2753
2754         /* Now the session been created, add the transport controls */
2755         new_session->add_controllable(roll_controllable);
2756         new_session->add_controllable(stop_controllable);
2757         new_session->add_controllable(goto_start_controllable);
2758         new_session->add_controllable(goto_end_controllable);
2759         new_session->add_controllable(auto_loop_controllable);
2760         new_session->add_controllable(play_selection_controllable);
2761         new_session->add_controllable(rec_controllable);
2762
2763         set_session (new_session);
2764
2765         session_loaded = true;
2766
2767         goto_editor_window ();
2768
2769         if (_session) {
2770                 _session->set_clean ();
2771         }
2772
2773         flush_pending ();
2774         retval = 0;
2775
2776   out:
2777         return retval;
2778 }
2779
2780 int
2781 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
2782 {
2783         Session *new_session;
2784         int x;
2785
2786         if (!check_audioengine()) {
2787                 return -1;
2788         }
2789
2790         session_loaded = false;
2791
2792         x = unload_session ();
2793
2794         if (x < 0) {
2795                 return -1;
2796         } else if (x > 0) {
2797                 return 0;
2798         }
2799
2800         _session_is_new = true;
2801
2802         try {
2803                 new_session = new Session (*engine, path, snap_name, &bus_profile);
2804         }
2805
2806         catch (...) {
2807
2808                 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
2809                 pop_back_splash ();
2810                 msg.run ();
2811                 return -1;
2812         }
2813
2814         /* Give the new session the default GUI state, if such things exist */
2815
2816         XMLNode* n;
2817         n = Config->instant_xml (X_("Editor"));
2818         if (n) {
2819                 new_session->add_instant_xml (*n, false);
2820         }
2821         n = Config->instant_xml (X_("Mixer"));
2822         if (n) {
2823                 new_session->add_instant_xml (*n, false);
2824         }
2825
2826         set_session (new_session);
2827
2828         session_loaded = true;
2829
2830         new_session->save_state(new_session->name());
2831
2832         return 0;
2833 }
2834
2835 void
2836 ARDOUR_UI::launch_chat ()
2837 {
2838 #ifdef __APPLE__
2839         open_uri("http://webchat.freenode.net/?channels=ardour-osx");
2840 #else
2841         open_uri("http://webchat.freenode.net/?channels=ardour");
2842 #endif
2843 }
2844
2845 void
2846 ARDOUR_UI::show_about ()
2847 {
2848         if (about == 0) {
2849                 about = new About;
2850                 about->signal_response().connect(sigc::mem_fun (*this, &ARDOUR_UI::about_signal_response) );
2851         }
2852
2853         about->set_transient_for(*editor);
2854         about->show_all ();
2855 }
2856
2857 void
2858 ARDOUR_UI::launch_manual ()
2859 {
2860         PBD::open_uri("http://ardour.org/flossmanual");
2861 }
2862
2863 void
2864 ARDOUR_UI::launch_reference ()
2865 {
2866         PBD::open_uri("http://ardour.org/refmanual");
2867 }
2868
2869 void
2870 ARDOUR_UI::hide_about ()
2871 {
2872         if (about) {
2873                 about->get_window()->set_cursor ();
2874                 about->hide ();
2875         }
2876 }
2877
2878 void
2879 ARDOUR_UI::about_signal_response (int /*response*/)
2880 {
2881         hide_about();
2882 }
2883
2884 void
2885 ARDOUR_UI::show_splash ()
2886 {
2887         if (splash == 0) {
2888                 try {
2889                         splash = new Splash;
2890                 } catch (...) {
2891                         return;
2892                 }
2893         }
2894
2895         splash->show ();
2896         splash->present ();
2897         splash->queue_draw ();
2898         splash->get_window()->process_updates (true);
2899         flush_pending ();
2900 }
2901
2902 void
2903 ARDOUR_UI::hide_splash ()
2904 {
2905         if (splash) {
2906                 splash->hide();
2907         }
2908 }
2909
2910 void
2911 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title,
2912                                     const string& plural_msg, const string& singular_msg)
2913 {
2914         size_t removed;
2915
2916         removed = rep.paths.size();
2917
2918         if (removed == 0) {
2919                 MessageDialog msgd (*editor,
2920                                     _("No audio files were ready for cleanup"),
2921                                     true,
2922                                     Gtk::MESSAGE_INFO,
2923                                     (Gtk::ButtonsType)(Gtk::BUTTONS_OK)  );
2924                 msgd.set_secondary_text (_("If this seems suprising, \n\
2925 check for any existing snapshots.\n\
2926 These may still include regions that\n\
2927 require some unused files to continue to exist."));
2928
2929                 msgd.run ();
2930                 return;
2931         }
2932
2933         ArdourDialog results (_("Clean-up"), true, false);
2934
2935         struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
2936             CleanupResultsModelColumns() {
2937                     add (visible_name);
2938                     add (fullpath);
2939             }
2940             Gtk::TreeModelColumn<std::string> visible_name;
2941             Gtk::TreeModelColumn<std::string> fullpath;
2942         };
2943
2944
2945         CleanupResultsModelColumns results_columns;
2946         Glib::RefPtr<Gtk::ListStore> results_model;
2947         Gtk::TreeView results_display;
2948
2949         results_model = ListStore::create (results_columns);
2950         results_display.set_model (results_model);
2951         results_display.append_column (list_title, results_columns.visible_name);
2952
2953         results_display.set_name ("CleanupResultsList");
2954         results_display.set_headers_visible (true);
2955         results_display.set_headers_clickable (false);
2956         results_display.set_reorderable (false);
2957
2958         Gtk::ScrolledWindow list_scroller;
2959         Gtk::Label txt;
2960         Gtk::VBox dvbox;
2961         Gtk::HBox dhbox;  // the hbox for the image and text
2962         Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
2963         Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO,  Gtk::ICON_SIZE_DIALOG));
2964
2965         dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
2966
2967         const string dead_sound_directory = _session->session_directory().dead_sound_path().to_string();
2968
2969         /* subst:
2970            %1 - number of files removed
2971            %2 - location of "dead_sounds"
2972            %3 - size of files affected
2973            %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
2974         */
2975
2976         const char* bprefix;
2977         double space_adjusted = 0;
2978
2979         if (rep.space < 100000.0f) {
2980                 bprefix = X_("kilo");
2981         } else if (rep.space < 1000000.0f * 1000) {
2982                 bprefix = X_("mega");
2983                 space_adjusted = truncf((float)rep.space / 1000.0);
2984         } else {
2985                 bprefix = X_("giga");
2986                 space_adjusted = truncf((float)rep.space / (1000000.0 * 1000));
2987         }
2988
2989         if (removed > 1) {
2990                 txt.set_text (string_compose (plural_msg, removed, _session->path() + "dead_sounds", space_adjusted, bprefix));
2991         } else {
2992                 txt.set_text (string_compose (singular_msg, removed, _session->path() + "dead_sounds", space_adjusted, bprefix));
2993         }
2994
2995         dhbox.pack_start (*dimage, true, false, 5);
2996         dhbox.pack_start (txt, true, false, 5);
2997
2998         for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
2999                 TreeModel::Row row = *(results_model->append());
3000                 row[results_columns.visible_name] = *i;
3001                 row[results_columns.fullpath] = *i;
3002         }
3003
3004         list_scroller.add (results_display);
3005         list_scroller.set_size_request (-1, 150);
3006         list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
3007
3008         dvbox.pack_start (dhbox, true, false, 5);
3009         dvbox.pack_start (list_scroller, true, false, 5);
3010         ddhbox.pack_start (dvbox, true, false, 5);
3011
3012         results.get_vbox()->pack_start (ddhbox, true, false, 5);
3013         results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
3014         results.set_default_response (RESPONSE_CLOSE);
3015         results.set_position (Gtk::WIN_POS_MOUSE);
3016
3017         results_display.show();
3018         list_scroller.show();
3019         txt.show();
3020         dvbox.show();
3021         dhbox.show();
3022         ddhbox.show();
3023         dimage->show();
3024
3025         //results.get_vbox()->show();
3026         results.set_resizable (false);
3027
3028         results.run ();
3029
3030 }
3031
3032 void
3033 ARDOUR_UI::cleanup ()
3034 {
3035         if (_session == 0) {
3036                 /* shouldn't happen: menu item is insensitive */
3037                 return;
3038         }
3039
3040
3041         MessageDialog  checker (_("Are you sure you want to cleanup?"),
3042                                 true,
3043                                 Gtk::MESSAGE_QUESTION,
3044                                 (Gtk::ButtonsType)(Gtk::BUTTONS_NONE));
3045
3046         checker.set_secondary_text(_("Cleanup is a destructive operation.\n\
3047 ALL undo/redo information will be lost if you cleanup.\n\
3048 After cleanup, unused audio files will be moved to a \
3049 \"dead sounds\" location."));
3050
3051         checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3052         checker.add_button (_("Clean Up"), RESPONSE_ACCEPT);
3053         checker.set_default_response (RESPONSE_CANCEL);
3054
3055         checker.set_name (_("CleanupDialog"));
3056         checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3057         checker.set_position (Gtk::WIN_POS_MOUSE);
3058
3059         switch (checker.run()) {
3060         case RESPONSE_ACCEPT:
3061                 break;
3062         default:
3063                 return;
3064         }
3065
3066         ARDOUR::CleanupReport rep;
3067
3068         editor->prepare_for_cleanup ();
3069
3070         /* do not allow flush until a session is reloaded */
3071
3072         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3073         if (act) {
3074                 act->set_sensitive (false);
3075         }
3076
3077         if (_session->cleanup_sources (rep)) {
3078                 editor->finish_cleanup ();
3079                 return;
3080         }
3081
3082         editor->finish_cleanup ();
3083
3084         checker.hide();
3085         display_cleanup_results (rep,
3086                                  _("cleaned files"),
3087                                  _("\
3088 The following %1 files were not in use and \n\
3089 have been moved to:\n\
3090 %2. \n\n\
3091 Flushing the wastebasket will \n\
3092 release an additional\n\
3093 %3 %4bytes of disk space.\n"),
3094                                  _("\
3095 The following file was not in use and \n        \
3096 has been moved to:\n                            \
3097 %2. \n\n\
3098 Flushing the wastebasket will \n\
3099 release an additional\n\
3100 %3 %4bytes of disk space.\n"
3101                                          ));
3102
3103 }
3104
3105 void
3106 ARDOUR_UI::flush_trash ()
3107 {
3108         if (_session == 0) {
3109                 /* shouldn't happen: menu item is insensitive */
3110                 return;
3111         }
3112
3113         ARDOUR::CleanupReport rep;
3114
3115         if (_session->cleanup_trash_sources (rep)) {
3116                 return;
3117         }
3118
3119         display_cleanup_results (rep,
3120                                  _("deleted file"),
3121                                  _("The following %1 files were deleted from\n\
3122 %2,\n\
3123 releasing %3 %4bytes of disk space"),
3124                                  _("The following file was deleted from\n\
3125 %2,\n\
3126 releasing %3 %4bytes of disk space"));
3127 }
3128
3129 void
3130 ARDOUR_UI::add_route (Gtk::Window* float_window)
3131 {
3132         int count;
3133
3134         if (!_session) {
3135                 return;
3136         }
3137
3138         if (add_route_dialog == 0) {
3139                 add_route_dialog = new AddRouteDialog (_session);
3140                 if (float_window) {
3141                         add_route_dialog->set_transient_for (*float_window);
3142                 }
3143         }
3144
3145         if (add_route_dialog->is_visible()) {
3146                 /* we're already doing this */
3147                 return;
3148         }
3149
3150         ResponseType r = (ResponseType) add_route_dialog->run ();
3151
3152         add_route_dialog->hide();
3153
3154         switch (r) {
3155                 case RESPONSE_ACCEPT:
3156                         break;
3157                 default:
3158                         return;
3159                         break;
3160         }
3161
3162         if ((count = add_route_dialog->count()) <= 0) {
3163                 return;
3164         }
3165
3166         string template_path = add_route_dialog->track_template();
3167
3168         if (!template_path.empty()) {
3169                 _session->new_route_from_template (count, template_path);
3170                 return;
3171         }
3172
3173         uint32_t input_chan = add_route_dialog->channels ();
3174         uint32_t output_chan;
3175         string name_template = add_route_dialog->name_template ();
3176         bool track = add_route_dialog->track ();
3177         bool aux = !track && add_route_dialog->aux();
3178         RouteGroup* route_group = add_route_dialog->route_group ();
3179
3180         AutoConnectOption oac = Config->get_output_auto_connect();
3181
3182         if (oac & AutoConnectMaster) {
3183                 output_chan = (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan);
3184         } else {
3185                 output_chan = input_chan;
3186         }
3187
3188         /* XXX do something with name template */
3189
3190         if (add_route_dialog->type() == ARDOUR::DataType::MIDI) {
3191                 if (track) {
3192                         session_add_midi_track (route_group, count);
3193                 } else  {
3194                         MessageDialog msg (*editor,
3195                                         _("Sorry, MIDI Busses are not supported at this time."));
3196                         msg.run ();
3197                         //session_add_midi_bus();
3198                 }
3199         } else {
3200                 if (track) {
3201                         session_add_audio_track (input_chan, output_chan, add_route_dialog->mode(), route_group, count);
3202                 } else {
3203                         session_add_audio_bus (aux, input_chan, output_chan, route_group, count);
3204                 }
3205         }
3206 }
3207
3208 XMLNode*
3209 ARDOUR_UI::mixer_settings () const
3210 {
3211         XMLNode* node = 0;
3212
3213         if (_session) {
3214                 node = _session->instant_xml(X_("Mixer"));
3215         } else {
3216                 node = Config->instant_xml(X_("Mixer"));
3217         }
3218
3219         if (!node) {
3220                 node = new XMLNode (X_("Mixer"));
3221         }
3222
3223         return node;
3224 }
3225
3226 XMLNode*
3227 ARDOUR_UI::editor_settings () const
3228 {
3229         XMLNode* node = 0;
3230
3231         if (_session) {
3232                 node = _session->instant_xml(X_("Editor"));
3233         } else {
3234                 node = Config->instant_xml(X_("Editor"));
3235         }
3236         
3237         if (!node) {
3238                 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
3239                         node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
3240                 }
3241         }
3242
3243         if (!node) {
3244                 node = new XMLNode (X_("Editor"));
3245         }
3246
3247         return node;
3248 }
3249
3250 XMLNode*
3251 ARDOUR_UI::keyboard_settings () const
3252 {
3253         XMLNode* node = 0;
3254
3255         node = Config->extra_xml(X_("Keyboard"));
3256
3257         if (!node) {
3258                 node = new XMLNode (X_("Keyboard"));
3259         }
3260         return node;
3261 }
3262
3263 void
3264 ARDOUR_UI::create_xrun_marker (framepos_t where)
3265 {
3266         editor->mouse_add_new_marker (where, false, true);
3267 }
3268
3269 void
3270 ARDOUR_UI::halt_on_xrun_message ()
3271 {
3272         MessageDialog msg (*editor,
3273                            _("Recording was stopped because your system could not keep up."));
3274         msg.run ();
3275 }
3276
3277 void
3278 ARDOUR_UI::xrun_handler (framepos_t where)
3279 {
3280         if (!_session) {
3281                 return;
3282         }
3283
3284         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
3285
3286         if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
3287                 create_xrun_marker(where);
3288         }
3289
3290         if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
3291                 halt_on_xrun_message ();
3292         }
3293 }
3294
3295 void
3296 ARDOUR_UI::disk_overrun_handler ()
3297 {
3298         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
3299
3300         if (!have_disk_speed_dialog_displayed) {
3301                 have_disk_speed_dialog_displayed = true;
3302                 MessageDialog* msg = new MessageDialog (*editor, string_compose (_("\
3303 The disk system on your computer\n\
3304 was not able to keep up with %1.\n\
3305 \n\
3306 Specifically, it failed to write data to disk\n\
3307 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
3308                 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3309                 msg->show ();
3310         }
3311 }
3312
3313 void
3314 ARDOUR_UI::disk_underrun_handler ()
3315 {
3316         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
3317
3318         if (!have_disk_speed_dialog_displayed) {
3319                 have_disk_speed_dialog_displayed = true;
3320                 MessageDialog* msg = new MessageDialog (*editor,
3321                                                         string_compose (_("The disk system on your computer\n\
3322 was not able to keep up with %1.\n\
3323 \n\
3324 Specifically, it failed to read data from disk\n\
3325 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
3326                 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3327                 msg->show ();
3328         }
3329 }
3330
3331 void
3332 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
3333 {
3334         have_disk_speed_dialog_displayed = false;
3335         delete msg;
3336 }
3337
3338 void
3339 ARDOUR_UI::session_dialog (std::string msg)
3340 {
3341         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
3342
3343         MessageDialog* d;
3344
3345         if (editor) {
3346                 d = new MessageDialog (*editor, msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3347         } else {
3348                 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3349         }
3350
3351         d->show_all ();
3352         d->run ();
3353         delete d;
3354 }
3355
3356 int
3357 ARDOUR_UI::pending_state_dialog ()
3358 {
3359         HBox* hbox = new HBox();
3360         Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3361         ArdourDialog dialog (_("Crash Recovery"), true);
3362         Label  message (_("\
3363 This session appears to have been in\n\
3364 middle of recording when ardour or\n\
3365 the computer was shutdown.\n\
3366 \n\
3367 Ardour can recover any captured audio for\n\
3368 you, or it can ignore it. Please decide\n\
3369 what you would like to do.\n"));
3370         image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3371         hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3372         hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3373         dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3374         dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
3375         dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
3376         dialog.set_default_response (RESPONSE_ACCEPT);
3377         dialog.set_position (WIN_POS_CENTER);
3378         message.show();
3379         image->show();
3380         hbox->show();
3381
3382         switch (dialog.run ()) {
3383         case RESPONSE_ACCEPT:
3384                 return 1;
3385         default:
3386                 return 0;
3387         }
3388 }
3389
3390 int
3391 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
3392 {
3393         HBox* hbox = new HBox();
3394         Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3395         ArdourDialog dialog (_("Sample Rate Mismatch"), true);
3396         Label  message (string_compose (_("\
3397 This session was created with a sample rate of %1 Hz\n\
3398 \n\
3399 The audioengine is currently running at %2 Hz\n"), desired, actual));
3400
3401         image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3402         hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3403         hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3404         dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3405         dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
3406         dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
3407         dialog.set_default_response (RESPONSE_ACCEPT);
3408         dialog.set_position (WIN_POS_CENTER);
3409         message.show();
3410         image->show();
3411         hbox->show();
3412
3413         switch (dialog.run ()) {
3414         case RESPONSE_ACCEPT:
3415                 return 0;
3416         default:
3417                 return 1;
3418         }
3419 }
3420
3421
3422 void
3423 ARDOUR_UI::disconnect_from_jack ()
3424 {
3425         if (engine) {
3426                 if( engine->disconnect_from_jack ()) {
3427                         MessageDialog msg (*editor, _("Could not disconnect from JACK"));
3428                         msg.run ();
3429                 }
3430
3431                 update_sample_rate (0);
3432         }
3433 }
3434
3435 void
3436 ARDOUR_UI::reconnect_to_jack ()
3437 {
3438         if (engine) {
3439                 if (engine->reconnect_to_jack ()) {
3440                         MessageDialog msg (*editor,  _("Could not reconnect to JACK"));
3441                         msg.run ();
3442                 }
3443
3444                 update_sample_rate (0);
3445         }
3446 }
3447
3448 void
3449 ARDOUR_UI::use_config ()
3450 {
3451         XMLNode* node = Config->extra_xml (X_("TransportControllables"));
3452         if (node) {
3453                 set_transport_controllable_state (*node);
3454         }
3455 }
3456
3457 void
3458 ARDOUR_UI::update_transport_clocks (framepos_t pos)
3459 {
3460         if (Config->get_primary_clock_delta_edit_cursor()) {
3461                 primary_clock.set (pos, false, editor->get_preferred_edit_position(), 1);
3462         } else {
3463                 primary_clock.set (pos, 0, true);
3464         }
3465
3466         if (Config->get_secondary_clock_delta_edit_cursor()) {
3467                 secondary_clock.set (pos, false, editor->get_preferred_edit_position(), 2);
3468         } else {
3469                 secondary_clock.set (pos);
3470         }
3471
3472         if (big_clock_window->get()) {
3473                 big_clock.set (pos);
3474         }
3475 }
3476
3477
3478 void
3479 ARDOUR_UI::step_edit_status_change (bool yn)
3480 {
3481         // XXX should really store pre-step edit status of things
3482         // we make insensitive
3483
3484         if (yn) {
3485                 rec_button.set_visual_state (3);
3486                 rec_button.set_sensitive (false);
3487         } else {
3488                 rec_button.set_visual_state (0);
3489                 rec_button.set_sensitive (true);
3490         }
3491 }
3492
3493 void
3494 ARDOUR_UI::record_state_changed ()
3495 {
3496         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
3497
3498         if (!_session || !big_clock_window->get()) {
3499                 /* why bother - the clock isn't visible */
3500                 return;
3501         }
3502
3503         Session::RecordState const r = _session->record_status ();
3504         bool const h = _session->have_rec_enabled_track ();
3505
3506         if (r == Session::Recording && h)  {
3507                 big_clock.set_widget_name ("BigClockRecording");
3508         } else {
3509                 big_clock.set_widget_name ("BigClockNonRecording");
3510         }
3511 }
3512
3513 bool
3514 ARDOUR_UI::first_idle ()
3515 {
3516         if (_session) {
3517                 _session->allow_auto_play (true);
3518         }
3519
3520         if (editor) {
3521                 editor->first_idle();
3522         }
3523
3524         Keyboard::set_can_save_keybindings (true);
3525         return false;
3526 }
3527
3528 void
3529 ARDOUR_UI::store_clock_modes ()
3530 {
3531         XMLNode* node = new XMLNode(X_("ClockModes"));
3532
3533         for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
3534                 node->add_property ((*x)->name().c_str(), enum_2_string ((*x)->mode()));
3535         }
3536
3537         _session->add_extra_xml (*node);
3538         _session->set_dirty ();
3539 }
3540
3541
3542
3543 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
3544         : Controllable (name), ui (u), type(tp)
3545 {
3546
3547 }
3548
3549 void
3550 ARDOUR_UI::TransportControllable::set_value (double val)
3551 {
3552         if (type == ShuttleControl) {
3553                 double fract;
3554
3555                 if (val == 0.5) {
3556                         fract = 0.0;
3557                 } else {
3558                         if (val < 0.5) {
3559                                 fract = -((0.5 - val)/0.5);
3560                         } else {
3561                                 fract = ((val - 0.5)/0.5);
3562                         }
3563                 }
3564
3565                 ui.set_shuttle_fract (fract);
3566                 return;
3567         }
3568
3569         if (val < 0.5) {
3570                 /* do nothing: these are radio-style actions */
3571                 return;
3572         }
3573
3574         const char *action = 0;
3575
3576         switch (type) {
3577         case Roll:
3578                 action = X_("Roll");
3579                 break;
3580         case Stop:
3581                 action = X_("Stop");
3582                 break;
3583         case GotoStart:
3584                 action = X_("Goto Start");
3585                 break;
3586         case GotoEnd:
3587                 action = X_("Goto End");
3588                 break;
3589         case AutoLoop:
3590                 action = X_("Loop");
3591                 break;
3592         case PlaySelection:
3593                 action = X_("Play Selection");
3594                 break;
3595         case RecordEnable:
3596                 action = X_("Record");
3597                 break;
3598         default:
3599                 break;
3600         }
3601
3602         if (action == 0) {
3603                 return;
3604         }
3605
3606         Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
3607
3608         if (act) {
3609                 act->activate ();
3610         }
3611 }
3612
3613 double
3614 ARDOUR_UI::TransportControllable::get_value (void) const
3615 {
3616         float val = 0.0;
3617
3618         switch (type) {
3619         case Roll:
3620                 break;
3621         case Stop:
3622                 break;
3623         case GotoStart:
3624                 break;
3625         case GotoEnd:
3626                 break;
3627         case AutoLoop:
3628                 break;
3629         case PlaySelection:
3630                 break;
3631         case RecordEnable:
3632                 break;
3633         case ShuttleControl:
3634                 break;
3635         default:
3636                 break;
3637         }
3638
3639         return val;
3640 }
3641
3642 void
3643 ARDOUR_UI::TransportControllable::set_id (const string& str)
3644 {
3645         _id = str;
3646 }
3647
3648 void
3649 ARDOUR_UI::setup_profile ()
3650 {
3651         if (gdk_screen_width() < 1200) {
3652                 Profile->set_small_screen ();
3653         }
3654
3655
3656         if (getenv ("ARDOUR_SAE")) {
3657                 Profile->set_sae ();
3658                 Profile->set_single_package ();
3659         }
3660 }
3661
3662 void
3663 ARDOUR_UI::toggle_translations ()
3664 {
3665         using namespace Glib;
3666         
3667         RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("EnableTranslation"));
3668         if (act) {
3669                 RefPtr<ToggleAction> ract = RefPtr<ToggleAction>::cast_dynamic (act);
3670                 if (ract) {
3671                         
3672                         string i18n_killer = ARDOUR::translation_kill_path();
3673                         
3674                         bool already_enabled = !ARDOUR::translations_are_disabled ();
3675                         
3676                         if (ract->get_active ()) {
3677 /* we don't care about errors */
3678                                 int fd = ::open (i18n_killer.c_str(), O_RDONLY|O_CREAT, 0644);
3679                                 close (fd);
3680                         } else {
3681 /* we don't care about errors */
3682                                 unlink (i18n_killer.c_str());
3683                         }
3684                         
3685                         if (already_enabled != ract->get_active()) {
3686                                 MessageDialog win (already_enabled ? _("Translations disabled") : _("Translations enabled"),
3687                                                    false,
3688                                                    Gtk::MESSAGE_WARNING,
3689                                                    Gtk::BUTTONS_OK);
3690                                 win.set_secondary_text (string_compose (_("You must restart %1 for this to take effect."), PROGRAM_NAME));
3691                                 win.set_position (Gtk::WIN_POS_CENTER);
3692                                 win.present ();
3693                                 win.run ();
3694                         }
3695                 }
3696         }
3697 }        
3698
3699 /** Add a window proxy to our list, so that its state will be saved.
3700  *  This call also causes the window to be created and opened if its
3701  *  state was saved as `visible'.
3702  */
3703 void
3704 ARDOUR_UI::add_window_proxy (WindowProxyBase* p)
3705 {
3706         _window_proxies.push_back (p);
3707         p->maybe_show ();
3708 }
3709
3710 /** Remove a window proxy from our list.  Must be called if a WindowProxy
3711  *  is deleted, to prevent hanging pointers.
3712  */
3713 void
3714 ARDOUR_UI::remove_window_proxy (WindowProxyBase* p)
3715 {
3716         _window_proxies.remove (p);
3717 }
3718
3719 int
3720 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
3721 {
3722         MissingFileDialog dialog (s, str, type);
3723
3724         dialog.show ();
3725         dialog.present ();
3726
3727         int result = dialog.run ();
3728         dialog.hide ();
3729
3730         switch (result) {
3731         case RESPONSE_OK:
3732                 break;
3733         default:
3734                 return 1; // quit entire session load
3735         }
3736
3737         result = dialog.get_action ();
3738
3739         return result;
3740 }
3741
3742 int
3743 ARDOUR_UI::ambiguous_file (std::string file, std::string path, std::vector<std::string> hits)
3744 {
3745         AmbiguousFileDialog dialog (file, hits);
3746
3747         dialog.show ();
3748         dialog.present ();
3749
3750         dialog.run ();
3751         return dialog.get_which ();
3752 }