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