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