2 Copyright (C) 1999-2013 Paul Davis
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.
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.
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.
21 #include "gtk2ardour-config.h"
22 #include "gtk2ardour-version.h"
32 #ifndef PLATFORM_WINDOWS
33 #include <sys/resource.h>
43 #include "pbd/gstdio_compat.h"
45 #include <gtkmm/messagedialog.h>
46 #include <gtkmm/accelmap.h>
48 #include "pbd/error.h"
49 #include "pbd/basename.h"
50 #include "pbd/compose.h"
51 #include "pbd/convert.h"
52 #include "pbd/failed_constructor.h"
53 #include "pbd/enumwriter.h"
54 #include "pbd/memento_command.h"
55 #include "pbd/openuri.h"
56 #include "pbd/stl_delete.h"
57 #include "pbd/file_utils.h"
58 #include "pbd/localtime_r.h"
59 #include "pbd/pthread_utils.h"
60 #include "pbd/replace_all.h"
61 #include "pbd/xml++.h"
63 #include "gtkmm2ext/application.h"
64 #include "gtkmm2ext/bindings.h"
65 #include "gtkmm2ext/gtk_ui.h"
66 #include "gtkmm2ext/utils.h"
67 #include "gtkmm2ext/click_box.h"
68 #include "gtkmm2ext/fastmeter.h"
69 #include "gtkmm2ext/popup.h"
70 #include "gtkmm2ext/window_title.h"
72 #include "ardour/ardour.h"
73 #include "ardour/audio_backend.h"
74 #include "ardour/audio_track.h"
75 #include "ardour/audioengine.h"
76 #include "ardour/audiofilesource.h"
77 #include "ardour/automation_watch.h"
78 #include "ardour/diskstream.h"
79 #include "ardour/filename_extensions.h"
80 #include "ardour/filesystem_paths.h"
81 #include "ardour/ltc_file_reader.h"
82 #include "ardour/midi_track.h"
83 #include "ardour/port.h"
84 #include "ardour/plugin_manager.h"
85 #include "ardour/process_thread.h"
86 #include "ardour/profile.h"
87 #include "ardour/recent_sessions.h"
88 #include "ardour/session_directory.h"
89 #include "ardour/session_route.h"
90 #include "ardour/session_state_utils.h"
91 #include "ardour/session_utils.h"
92 #include "ardour/source_factory.h"
93 #include "ardour/slave.h"
94 #include "ardour/system_exec.h"
96 #include "LuaBridge/LuaBridge.h"
98 #ifdef WINDOWS_VST_SUPPORT
101 #ifdef AUDIOUNIT_SUPPORT
102 #include "ardour/audio_unit.h"
105 // fix for OSX (nsm.h has a check function, AU/Apple defines check)
110 #include "timecode/time.h"
112 typedef uint64_t microseconds_t;
117 #include "add_route_dialog.h"
118 #include "ambiguous_file_dialog.h"
119 #include "ardour_ui.h"
120 #include "audio_clock.h"
121 #include "audio_region_view.h"
122 #include "big_clock_window.h"
123 #include "bundle_manager.h"
124 #include "duplicate_routes_dialog.h"
126 #include "engine_dialog.h"
127 #include "export_video_dialog.h"
128 #include "export_video_infobox.h"
129 #include "gain_meter.h"
130 #include "global_port_matrix.h"
131 #include "gui_object.h"
132 #include "gui_thread.h"
133 #include "keyboard.h"
134 #include "keyeditor.h"
135 #include "location_ui.h"
136 #include "lua_script_manager.h"
137 #include "luawindow.h"
138 #include "main_clock.h"
139 #include "missing_file_dialog.h"
140 #include "missing_plugin_dialog.h"
141 #include "mixer_ui.h"
142 #include "meterbridge.h"
143 #include "mouse_cursors.h"
146 #include "pingback.h"
147 #include "processor_box.h"
148 #include "prompter.h"
149 #include "public_editor.h"
150 #include "rc_option_editor.h"
151 #include "route_time_axis.h"
152 #include "route_params_ui.h"
153 #include "save_as_dialog.h"
154 #include "script_selector.h"
155 #include "session_dialog.h"
156 #include "session_metadata_dialog.h"
157 #include "session_option_editor.h"
158 #include "shuttle_control.h"
159 #include "speaker_dialog.h"
162 #include "theme_manager.h"
163 #include "time_axis_view_item.h"
166 #include "video_server_dialog.h"
167 #include "add_video_dialog.h"
168 #include "transcode_video_dialog.h"
172 using namespace ARDOUR;
173 using namespace ARDOUR_UI_UTILS;
175 using namespace Gtkmm2ext;
178 using namespace Editing;
180 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
182 sigc::signal<void, framepos_t, bool, framepos_t> ARDOUR_UI::Clock;
183 sigc::signal<void> ARDOUR_UI::CloseAllDialogs;
186 ask_about_configuration_copy (string const & old_dir, string const & new_dir, int version)
188 MessageDialog msg (string_compose (_("%1 %2.x has discovered configuration files from %1 %3.x.\n\n"
189 "Would you like these files to be copied and used for %1 %2.x?\n\n"
190 "(This will require you to restart %1.)"),
191 PROGRAM_NAME, PROGRAM_VERSION, version),
192 false, /* no markup */
195 true /* modal, though it hardly matters since it is the only window */
198 msg.set_default_response (Gtk::RESPONSE_YES);
201 return (msg.run() == Gtk::RESPONSE_YES);
205 libxml_generic_error_func (void* /* parsing_context*/,
213 vsnprintf (buf, sizeof (buf), msg, ap);
214 error << buf << endmsg;
219 libxml_structured_error_func (void* /* parsing_context*/,
227 replace_all (msg, "\n", "");
230 if (err->file && err->line) {
231 error << X_("XML error: ") << msg << " in " << err->file << " at line " << err->line;
234 error << ':' << err->int2;
239 error << X_("XML error: ") << msg << endmsg;
245 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
246 : Gtkmm2ext::UI (PROGRAM_NAME, X_("gui"), argcp, argvp)
247 , session_loaded (false)
248 , gui_object_state (new GUIObjectState)
249 , primary_clock (new MainClock (X_("primary"), X_("transport"), true ))
250 , secondary_clock (new MainClock (X_("secondary"), X_("secondary"), false))
251 , big_clock (new AudioClock (X_("bigclock"), false, "big", true, true, false, false))
253 , global_actions (X_("global"))
254 , ignore_dual_punch (false)
259 , _mixer_on_top (false)
260 , _initial_verbose_plugin_scan (false)
261 , first_time_engine_run (true)
262 , roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll))
263 , stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop))
264 , goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart))
265 , goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd))
266 , auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop))
267 , play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection))
268 , rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable))
269 , auto_return_button (ArdourButton::led_default_elements)
270 , follow_edits_button (ArdourButton::led_default_elements)
271 , auto_input_button (ArdourButton::led_default_elements)
272 , auditioning_alert_button (_("Audition"))
273 , solo_alert_button (_("Solo"))
274 , feedback_alert_button (_("Feedback"))
275 , error_alert_button ( ArdourButton::just_led_default_elements )
277 , editor_meter_peak_display()
278 , _numpad_locate_happening (false)
279 , _session_is_new (false)
280 , last_key_press_time (0)
284 , rc_option_editor (0)
285 , speaker_config_window (X_("speaker-config"), _("Speaker Configuration"))
286 , add_route_dialog (X_("add-routes"), _("Add Tracks/Busses"))
287 , about (X_("about"), _("About"))
288 , location_ui (X_("locations"), _("Locations"))
289 , route_params (X_("inspector"), _("Tracks and Busses"))
290 , audio_midi_setup (X_("audio-midi-setup"), _("Audio/MIDI Setup"))
291 , export_video_dialog (X_("video-export"), _("Video Export Dialog"))
292 , lua_script_window (X_("script-manager"), _("Script Manager"))
293 , session_option_editor (X_("session-options-editor"), _("Properties"), boost::bind (&ARDOUR_UI::create_session_option_editor, this))
294 , add_video_dialog (X_("add-video"), _("Add Video"), boost::bind (&ARDOUR_UI::create_add_video_dialog, this))
295 , bundle_manager (X_("bundle-manager"), _("Bundle Manager"), boost::bind (&ARDOUR_UI::create_bundle_manager, this))
296 , big_clock_window (X_("big-clock"), _("Big Clock"), boost::bind (&ARDOUR_UI::create_big_clock_window, this))
297 , audio_port_matrix (X_("audio-connection-manager"), _("Audio Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::AUDIO))
298 , midi_port_matrix (X_("midi-connection-manager"), _("MIDI Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::MIDI))
299 , key_editor (X_("key-editor"), _("Bindings Editor"), boost::bind (&ARDOUR_UI::create_key_editor, this))
300 , video_server_process (0)
302 , have_configure_timeout (false)
303 , last_configure_time (0)
305 , have_disk_speed_dialog_displayed (false)
306 , _status_bar_visibility (X_("status-bar"))
307 , _feedback_exists (false)
308 , _log_not_acknowledged (LogLevelNone)
309 , duplicate_routes_dialog (0)
310 , editor_visibility_button (S_("Window|Editor"))
311 , mixer_visibility_button (S_("Window|Mixer"))
312 , prefs_visibility_button (S_("Window|Preferences"))
314 Gtkmm2ext::init (localedir);
316 UIConfiguration::instance().post_gui_init ();
318 if (ARDOUR::handle_old_configuration_files (boost::bind (ask_about_configuration_copy, _1, _2, _3))) {
319 MessageDialog msg (string_compose (_("Your configuration files were copied. You can now restart %1."), PROGRAM_NAME), true);
321 /* configuration was modified, exit immediately */
325 if (theArdourUI == 0) {
329 /* stop libxml from spewing to stdout/stderr */
331 xmlSetGenericErrorFunc (this, libxml_generic_error_func);
332 xmlSetStructuredErrorFunc (this, libxml_structured_error_func);
334 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::parameter_changed));
335 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
336 UIConfiguration::instance().map_parameters (pc);
338 roll_button.set_controllable (roll_controllable);
339 stop_button.set_controllable (stop_controllable);
340 goto_start_button.set_controllable (goto_start_controllable);
341 goto_end_button.set_controllable (goto_end_controllable);
342 auto_loop_button.set_controllable (auto_loop_controllable);
343 play_selection_button.set_controllable (play_selection_controllable);
344 rec_button.set_controllable (rec_controllable);
346 roll_button.set_name ("transport button");
347 stop_button.set_name ("transport button");
348 goto_start_button.set_name ("transport button");
349 goto_end_button.set_name ("transport button");
350 auto_loop_button.set_name ("transport button");
351 play_selection_button.set_name ("transport button");
352 rec_button.set_name ("transport recenable button");
353 midi_panic_button.set_name ("transport button");
355 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
356 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
358 ARDOUR::Session::VersionMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_format_mismatch, this, _1, _2), gui_context());
360 /* handle dialog requests */
362 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
364 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
366 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
368 /* handle Audio/MIDI setup when session requires it */
370 ARDOUR::Session::AudioEngineSetupRequired.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::do_audio_midi_setup, this, _1));
372 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
374 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
376 /* handle sr mismatch with a dialog - cross-thread from engine */
377 ARDOUR::Session::NotifyAboutSampleRateMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::sr_mismatch_message, this, _1, _2), gui_context ());
379 /* handle requests to quit (coming from JACK session) */
381 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::finish, this), gui_context ());
383 /* tell the user about feedback */
385 ARDOUR::Session::FeedbackDetected.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::feedback_detected, this), gui_context ());
386 ARDOUR::Session::SuccessfulGraphSort.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::successful_graph_sort, this), gui_context ());
388 /* handle requests to deal with missing files */
390 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
392 /* and ambiguous files */
394 ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2));
396 /* also plugin scan messages */
397 ARDOUR::PluginScanMessage.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_dialog, this, _1, _2, _3), gui_context());
398 ARDOUR::PluginScanTimeout.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_timeout, this, _1), gui_context());
400 ARDOUR::GUIIdle.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::gui_idle_handler, this), gui_context());
402 Config->ParameterChanged.connect ( forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::set_flat_buttons, this), gui_context() );
405 /* lets get this party started */
407 setup_gtk_ardour_enums ();
410 SessionEvent::create_per_thread_pool ("GUI", 4096);
412 /* we like keyboards */
414 keyboard = new ArdourKeyboard(*this);
416 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
418 keyboard->set_state (*node, Stateful::loading_state_version);
421 UIConfiguration::instance().reset_dpi ();
423 TimeAxisViewItem::set_constant_heights ();
425 /* Set this up so that our window proxies can register actions */
427 ActionManager::init ();
429 /* The following must happen after ARDOUR::init() so that Config is set up */
431 const XMLNode* ui_xml = Config->extra_xml (X_("UI"));
434 key_editor.set_state (*ui_xml, 0);
435 session_option_editor.set_state (*ui_xml, 0);
436 speaker_config_window.set_state (*ui_xml, 0);
437 about.set_state (*ui_xml, 0);
438 add_route_dialog.set_state (*ui_xml, 0);
439 add_video_dialog.set_state (*ui_xml, 0);
440 route_params.set_state (*ui_xml, 0);
441 bundle_manager.set_state (*ui_xml, 0);
442 location_ui.set_state (*ui_xml, 0);
443 big_clock_window.set_state (*ui_xml, 0);
444 audio_port_matrix.set_state (*ui_xml, 0);
445 midi_port_matrix.set_state (*ui_xml, 0);
446 export_video_dialog.set_state (*ui_xml, 0);
447 lua_script_window.set_state (*ui_xml, 0);
450 /* Separate windows */
452 WM::Manager::instance().register_window (&key_editor);
453 WM::Manager::instance().register_window (&session_option_editor);
454 WM::Manager::instance().register_window (&speaker_config_window);
455 WM::Manager::instance().register_window (&about);
456 WM::Manager::instance().register_window (&add_route_dialog);
457 WM::Manager::instance().register_window (&add_video_dialog);
458 WM::Manager::instance().register_window (&route_params);
459 WM::Manager::instance().register_window (&audio_midi_setup);
460 WM::Manager::instance().register_window (&export_video_dialog);
461 WM::Manager::instance().register_window (&lua_script_window);
462 WM::Manager::instance().register_window (&bundle_manager);
463 WM::Manager::instance().register_window (&location_ui);
464 WM::Manager::instance().register_window (&big_clock_window);
465 WM::Manager::instance().register_window (&audio_port_matrix);
466 WM::Manager::instance().register_window (&midi_port_matrix);
468 /* Trigger setting up the color scheme and loading the GTK RC file */
470 UIConfiguration::instance().load_rc_file (false);
472 _process_thread = new ProcessThread ();
473 _process_thread->init ();
475 UIConfiguration::instance().DPIReset.connect (sigc::mem_fun (*this, &ARDOUR_UI::resize_text_widgets));
480 GlobalPortMatrixWindow*
481 ARDOUR_UI::create_global_port_matrix (ARDOUR::DataType type)
486 return new GlobalPortMatrixWindow (_session, type);
490 ARDOUR_UI::attach_to_engine ()
492 AudioEngine::instance()->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
493 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
497 ARDOUR_UI::engine_stopped ()
499 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
500 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
501 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
502 update_sample_rate (0);
507 ARDOUR_UI::engine_running ()
509 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
510 if (first_time_engine_run) {
512 first_time_engine_run = false;
516 _session->reset_xrun_count ();
518 update_disk_space ();
520 update_xrun_count ();
521 update_sample_rate (AudioEngine::instance()->sample_rate());
522 update_timecode_format ();
523 update_peak_thread_work ();
524 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, true);
525 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, false);
529 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
531 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
532 /* we can't rely on the original string continuing to exist when we are called
533 again in the GUI thread, so make a copy and note that we need to
536 char *copy = strdup (reason);
537 Gtkmm2ext::UI::instance()->call_slot (MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
541 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
542 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
544 update_sample_rate (0);
548 /* if the reason is a non-empty string, it means that the backend was shutdown
549 rather than just Ardour.
552 if (strlen (reason)) {
553 msgstr = string_compose (_("The audio backend was shutdown because:\n\n%1"), reason);
555 msgstr = string_compose (_("\
556 The audio backend has either been shutdown or it\n\
557 disconnected %1 because %1\n\
558 was not fast enough. Try to restart\n\
559 the audio backend and save the session."), PROGRAM_NAME);
562 MessageDialog msg (_main_window, msgstr);
563 pop_back_splash (msg);
567 free (const_cast<char*> (reason));
572 ARDOUR_UI::post_engine ()
574 /* Things to be done once (and once ONLY) after we have a backend running in the AudioEngine
576 #ifdef AUDIOUNIT_SUPPORT
578 if (AUPluginInfo::au_get_crashlog(au_msg)) {
579 popup_error(_("Audio Unit Plugin Scan Failed. Automatic AU scanning has been disabled. Please see the log window for further details."));
580 error << _("Audio Unit Plugin Scan Failed:") << endmsg;
581 info << au_msg << endmsg;
585 ARDOUR::init_post_engine ();
587 /* connect to important signals */
589 AudioEngine::instance()->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
590 AudioEngine::instance()->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
591 AudioEngine::instance()->BufferSizeChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
592 AudioEngine::instance()->Halted.connect_same_thread (halt_connection, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
593 AudioEngine::instance()->BecameSilent.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::audioengine_became_silent, this), gui_context());
595 if (setup_windows ()) {
596 throw failed_constructor ();
599 /* Do this after setup_windows (), as that's when the _status_bar_visibility is created */
600 XMLNode* n = Config->extra_xml (X_("UI"));
602 _status_bar_visibility.set_state (*n);
605 check_memory_locking();
607 /* this is the first point at which all the possible actions are
608 * available, because some of the available actions are dependent on
609 * aspects of the engine/backend.
612 if (ARDOUR_COMMAND_LINE::show_key_actions) {
615 vector<string> paths;
616 vector<string> labels;
617 vector<string> tooltips;
619 vector<Glib::RefPtr<Gtk::Action> > actions;
621 Gtkmm2ext::ActionMap::get_all_actions (paths, labels, tooltips, keys, actions);
623 vector<string>::iterator k;
624 vector<string>::iterator p;
626 for (p = paths.begin(), k = keys.begin(); p != paths.end(); ++k, ++p) {
631 cout << *p << " => " << *k << endl;
635 halt_connection.disconnect ();
636 AudioEngine::instance()->stop ();
640 /* this being a GUI and all, we want peakfiles */
642 AudioFileSource::set_build_peakfiles (true);
643 AudioFileSource::set_build_missing_peakfiles (true);
645 /* set default clock modes */
647 primary_clock->set_mode (AudioClock::Timecode);
648 secondary_clock->set_mode (AudioClock::BBT);
650 /* start the time-of-day-clock */
653 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
654 update_wall_clock ();
655 Glib::signal_timeout().connect_seconds (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 1);
660 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
661 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
662 Config->map_parameters (pc);
664 UIConfiguration::instance().map_parameters (pc);
668 ARDOUR_UI::~ARDOUR_UI ()
670 UIConfiguration::instance().save_state();
674 if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
675 // don't bother at 'real' exit. the OS cleans up for us.
676 delete big_clock; big_clock = 0;
677 delete primary_clock; primary_clock = 0;
678 delete secondary_clock; secondary_clock = 0;
679 delete _process_thread; _process_thread = 0;
680 delete meterbridge; meterbridge = 0;
681 delete luawindow; luawindow = 0;
682 delete editor; editor = 0;
683 delete mixer; mixer = 0;
685 delete gui_object_state; gui_object_state = 0;
686 FastMeter::flush_pattern_cache ();
687 PixFader::flush_pattern_cache ();
691 /* Small trick to flush main-thread event pool.
692 * Other thread-pools are destroyed at pthread_exit(),
693 * but tmain thread termination is too late to trigger Pool::~Pool()
695 SessionEvent* ev = new SessionEvent (SessionEvent::SetTransportSpeed, SessionEvent::Clear, SessionEvent::Immediate, 0, 0); // get the pool reference, values don't matter since the event is never queued.
696 delete ev->event_pool();
701 ARDOUR_UI::pop_back_splash (Gtk::Window& win)
703 if (Splash::instance()) {
704 Splash::instance()->pop_back_for (win);
709 ARDOUR_UI::configure_timeout ()
711 if (last_configure_time == 0) {
712 /* no configure events yet */
716 /* force a gap of 0.5 seconds since the last configure event
719 if (get_microseconds() - last_configure_time < 500000) {
722 have_configure_timeout = false;
723 save_ardour_state ();
729 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
731 if (have_configure_timeout) {
732 last_configure_time = get_microseconds();
734 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
735 have_configure_timeout = true;
742 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
744 const XMLProperty* prop;
746 if ((prop = node.property ("roll")) != 0) {
747 roll_controllable->set_id (prop->value());
749 if ((prop = node.property ("stop")) != 0) {
750 stop_controllable->set_id (prop->value());
752 if ((prop = node.property ("goto-start")) != 0) {
753 goto_start_controllable->set_id (prop->value());
755 if ((prop = node.property ("goto-end")) != 0) {
756 goto_end_controllable->set_id (prop->value());
758 if ((prop = node.property ("auto-loop")) != 0) {
759 auto_loop_controllable->set_id (prop->value());
761 if ((prop = node.property ("play-selection")) != 0) {
762 play_selection_controllable->set_id (prop->value());
764 if ((prop = node.property ("rec")) != 0) {
765 rec_controllable->set_id (prop->value());
767 if ((prop = node.property ("shuttle")) != 0) {
768 shuttle_box->controllable()->set_id (prop->value());
773 ARDOUR_UI::get_transport_controllable_state ()
775 XMLNode* node = new XMLNode(X_("TransportControllables"));
778 roll_controllable->id().print (buf, sizeof (buf));
779 node->add_property (X_("roll"), buf);
780 stop_controllable->id().print (buf, sizeof (buf));
781 node->add_property (X_("stop"), buf);
782 goto_start_controllable->id().print (buf, sizeof (buf));
783 node->add_property (X_("goto_start"), buf);
784 goto_end_controllable->id().print (buf, sizeof (buf));
785 node->add_property (X_("goto_end"), buf);
786 auto_loop_controllable->id().print (buf, sizeof (buf));
787 node->add_property (X_("auto_loop"), buf);
788 play_selection_controllable->id().print (buf, sizeof (buf));
789 node->add_property (X_("play_selection"), buf);
790 rec_controllable->id().print (buf, sizeof (buf));
791 node->add_property (X_("rec"), buf);
792 shuttle_box->controllable()->id().print (buf, sizeof (buf));
793 node->add_property (X_("shuttle"), buf);
799 ARDOUR_UI::save_session_at_its_request (std::string snapshot_name)
802 _session->save_state (snapshot_name);
807 ARDOUR_UI::autosave_session ()
809 if (g_main_depth() > 1) {
810 /* inside a recursive main loop,
811 give up because we may not be able to
817 if (!Config->get_periodic_safety_backups()) {
822 _session->maybe_write_autosave();
829 ARDOUR_UI::session_dirty_changed ()
836 ARDOUR_UI::update_autosave ()
838 if (_session && _session->dirty()) {
839 if (_autosave_connection.connected()) {
840 _autosave_connection.disconnect();
843 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
844 Config->get_periodic_safety_backup_interval() * 1000);
847 if (_autosave_connection.connected()) {
848 _autosave_connection.disconnect();
854 ARDOUR_UI::check_announcements ()
857 string _annc_filename;
860 _annc_filename = PROGRAM_NAME "_announcements_osx_";
861 #elif defined PLATFORM_WINDOWS
862 _annc_filename = PROGRAM_NAME "_announcements_windows_";
864 _annc_filename = PROGRAM_NAME "_announcements_linux_";
866 _annc_filename.append (VERSIONSTRING);
868 _announce_string = "";
870 std::string path = Glib::build_filename (user_config_directory(), _annc_filename);
871 FILE* fin = g_fopen (path.c_str(), "rb");
873 while (!feof (fin)) {
876 if ((len = fread (tmp, sizeof(char), 1024, fin)) == 0 || ferror (fin)) {
879 _announce_string.append (tmp, len);
884 pingback (VERSIONSTRING, path);
889 _hide_splash (gpointer arg)
891 ((ARDOUR_UI*)arg)->hide_splash();
896 ARDOUR_UI::starting ()
898 Application* app = Application::instance ();
900 bool brand_new_user = ArdourStartup::required ();
902 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
903 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::load_from_application_api));
905 if (ARDOUR_COMMAND_LINE::check_announcements) {
906 check_announcements ();
911 /* we need to create this early because it may need to set the
912 * audio backend end up.
916 audio_midi_setup.get (true);
918 std::cerr << "audio-midi engine setup failed."<< std::endl;
922 if ((nsm_url = g_getenv ("NSM_URL")) != 0) {
923 nsm = new NSM_Client;
924 if (!nsm->init (nsm_url)) {
925 /* the ardour executable may have different names:
927 * waf's obj.target for distro versions: eg ardour4, ardourvst4
928 * Ardour4, Mixbus3 for bundled versions + full path on OSX & windows
929 * argv[0] does not apply since we need the wrapper-script (not the binary itself)
931 * The wrapper startup script should set the environment variable 'ARDOUR_SELF'
933 const char *process_name = g_getenv ("ARDOUR_SELF");
934 nsm->announce (PROGRAM_NAME, ":dirty:", process_name ? process_name : "ardour4");
937 // wait for announce reply from nsm server
938 for ( i = 0; i < 5000; ++i) {
942 if (nsm->is_active()) {
947 error << _("NSM server did not announce itself") << endmsg;
950 // wait for open command from nsm server
951 for ( i = 0; i < 5000; ++i) {
954 if (nsm->client_id ()) {
960 error << _("NSM: no client ID provided") << endmsg;
964 if (_session && nsm) {
965 _session->set_nsm_state( nsm->is_active() );
967 error << _("NSM: no session created") << endmsg;
971 // nsm requires these actions disabled
972 vector<string> action_names;
973 action_names.push_back("SaveAs");
974 action_names.push_back("Rename");
975 action_names.push_back("New");
976 action_names.push_back("Open");
977 action_names.push_back("Recent");
978 action_names.push_back("Close");
980 for (vector<string>::const_iterator n = action_names.begin(); n != action_names.end(); ++n) {
981 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), (*n).c_str());
983 act->set_sensitive (false);
990 error << _("NSM: initialization failed") << endmsg;
996 if (brand_new_user) {
997 _initial_verbose_plugin_scan = true;
1002 _initial_verbose_plugin_scan = false;
1003 switch (s.response ()) {
1004 case Gtk::RESPONSE_OK:
1011 #ifdef NO_PLUGIN_STATE
1013 ARDOUR::RecentSessions rs;
1014 ARDOUR::read_recent_sessions (rs);
1016 string path = Glib::build_filename (user_config_directory(), ".iknowaboutfreeversion");
1018 if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS) && !rs.empty()) {
1020 /* already used Ardour, have sessions ... warn about plugin state */
1022 ArdourDialog d (_("Free/Demo Version Warning"), true);
1024 Button b (string_compose (_("Subscribe and support development of %1"), PROGRAM_NAME));
1025 CheckButton c (_("Don't warn me about this again"));
1027 l.set_markup (string_compose (_("<span weight=\"bold\" size=\"large\">%1</span>\n\n<b>%2</b>\n\n<i>%3</i>\n\n%4"),
1028 string_compose (_("This is a free/demo version of %1"), PROGRAM_NAME),
1029 _("It will not restore OR save any plugin settings"),
1030 _("If you load an existing session with plugin settings\n"
1031 "they will not be used and will be lost."),
1032 _("To get full access to updates without this limitation\n"
1033 "consider becoming a subscriber for a low cost every month.")));
1034 l.set_justify (JUSTIFY_CENTER);
1036 b.signal_clicked().connect (mem_fun(*this, &ARDOUR_UI::launch_subscribe));
1038 d.get_vbox()->pack_start (l, true, true);
1039 d.get_vbox()->pack_start (b, false, false, 12);
1040 d.get_vbox()->pack_start (c, false, false, 12);
1042 d.add_button (_("Quit now"), RESPONSE_CANCEL);
1043 d.add_button (string_compose (_("Continue using %1"), PROGRAM_NAME), RESPONSE_OK);
1047 c.signal_toggled().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (toggle_file_existence), path)));
1049 if (d.run () != RESPONSE_OK) {
1055 /* go get a session */
1057 const bool new_session_required = (ARDOUR_COMMAND_LINE::new_session || brand_new_user);
1059 if (get_session_parameters (false, new_session_required, ARDOUR_COMMAND_LINE::load_template)) {
1060 std::cerr << "Cannot get session parameters."<< std::endl;
1067 WM::Manager::instance().show_visible ();
1069 /* We have to do this here since goto_editor_window() ends up calling show_all() on the
1070 * editor window, and we may want stuff to be hidden.
1072 _status_bar_visibility.update ();
1074 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
1076 if (splash && splash->is_visible()) {
1077 // in 1 second, hide the splash screen
1078 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
1081 /* all other dialogs are created conditionally */
1087 ARDOUR_UI::check_memory_locking ()
1089 #if defined(__APPLE__) || defined(PLATFORM_WINDOWS)
1090 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
1094 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
1096 if (AudioEngine::instance()->is_realtime() && memory_warning_node == 0) {
1098 struct rlimit limits;
1100 long pages, page_size;
1102 size_t pages_len=sizeof(pages);
1103 if ((page_size = getpagesize()) < 0 ||
1104 sysctlbyname("hw.availpages", &pages, &pages_len, NULL, 0))
1106 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0)
1111 ram = (int64_t) pages * (int64_t) page_size;
1114 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
1118 if (limits.rlim_cur != RLIM_INFINITY) {
1120 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
1124 _("WARNING: Your system has a limit for maximum amount of locked memory. "
1125 "This might cause %1 to run out of memory before your system "
1126 "runs out of memory. \n\n"
1127 "You can view the memory limit with 'ulimit -l', "
1128 "and it is normally controlled by %2"),
1131 X_("/etc/login.conf")
1133 X_(" /etc/security/limits.conf")
1137 msg.set_default_response (RESPONSE_OK);
1139 VBox* vbox = msg.get_vbox();
1141 CheckButton cb (_("Do not show this window again"));
1142 hbox.pack_start (cb, true, false);
1143 vbox->pack_start (hbox);
1148 pop_back_splash (msg);
1152 if (cb.get_active()) {
1153 XMLNode node (X_("no-memory-warning"));
1154 Config->add_instant_xml (node);
1159 #endif // !__APPLE__
1164 ARDOUR_UI::queue_finish ()
1166 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
1170 ARDOUR_UI::idle_finish ()
1173 return false; /* do not call again */
1180 ARDOUR_UI::instance()->video_timeline->sync_session_state();
1182 if (_session->dirty()) {
1183 vector<string> actions;
1184 actions.push_back (_("Don't quit"));
1185 actions.push_back (_("Just quit"));
1186 actions.push_back (_("Save and quit"));
1187 switch (ask_about_saving_session(actions)) {
1192 /* use the default name */
1193 if (save_state_canfail ("")) {
1194 /* failed - don't quit */
1195 MessageDialog msg (_main_window,
1196 string_compose (_("\
1197 %1 was unable to save your session.\n\n\
1198 If you still wish to quit, please use the\n\n\
1199 \"Just quit\" option."), PROGRAM_NAME));
1200 pop_back_splash(msg);
1210 second_connection.disconnect ();
1211 point_one_second_connection.disconnect ();
1212 point_zero_something_second_connection.disconnect();
1213 fps_connection.disconnect();
1216 delete ARDOUR_UI::instance()->video_timeline;
1217 ARDOUR_UI::instance()->video_timeline = NULL;
1218 stop_video_server();
1220 /* Save state before deleting the session, as that causes some
1221 windows to be destroyed before their visible state can be
1224 save_ardour_state ();
1226 close_all_dialogs ();
1229 _session->set_clean ();
1230 _session->remove_pending_capture_state ();
1235 halt_connection.disconnect ();
1236 AudioEngine::instance()->stop ();
1237 #ifdef WINDOWS_VST_SUPPORT
1238 fst_stop_threading();
1244 ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
1246 ArdourDialog window (_("Unsaved Session"));
1247 Gtk::HBox dhbox; // the hbox for the image and text
1248 Gtk::Label prompt_label;
1249 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
1253 assert (actions.size() >= 3);
1255 window.add_button (actions[0], RESPONSE_REJECT);
1256 window.add_button (actions[1], RESPONSE_APPLY);
1257 window.add_button (actions[2], RESPONSE_ACCEPT);
1259 window.set_default_response (RESPONSE_ACCEPT);
1261 Gtk::Button noquit_button (msg);
1262 noquit_button.set_name ("EditorGTKButton");
1266 if (_session->snap_name() == _session->name()) {
1267 prompt = string_compose(_("The session \"%1\"\nhas not been saved.\n\nAny changes made this time\nwill be lost unless you save it.\n\nWhat do you want to do?"),
1268 _session->snap_name());
1270 prompt = string_compose(_("The snapshot \"%1\"\nhas not been saved.\n\nAny changes made this time\nwill be lost unless you save it.\n\nWhat do you want to do?"),
1271 _session->snap_name());
1274 prompt_label.set_text (prompt);
1275 prompt_label.set_name (X_("PrompterLabel"));
1276 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
1278 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
1279 dhbox.set_homogeneous (false);
1280 dhbox.pack_start (*dimage, false, false, 5);
1281 dhbox.pack_start (prompt_label, true, false, 5);
1282 window.get_vbox()->pack_start (dhbox);
1284 window.set_name (_("Prompter"));
1285 window.set_modal (true);
1286 window.set_resizable (false);
1289 prompt_label.show();
1294 ResponseType r = (ResponseType) window.run();
1299 case RESPONSE_ACCEPT: // save and get out of here
1301 case RESPONSE_APPLY: // get out of here
1312 ARDOUR_UI::every_second ()
1315 update_xrun_count ();
1316 update_buffer_load ();
1317 update_disk_space ();
1318 update_timecode_format ();
1319 update_peak_thread_work ();
1321 if (nsm && nsm->is_active ()) {
1324 if (!_was_dirty && _session->dirty ()) {
1328 else if (_was_dirty && !_session->dirty ()){
1336 ARDOUR_UI::every_point_one_seconds ()
1338 // TODO get rid of this..
1339 // ShuttleControl is updated directly via TransportStateChange signal
1343 ARDOUR_UI::every_point_zero_something_seconds ()
1345 // august 2007: actual update frequency: 25Hz (40ms), not 100Hz
1347 if (editor_meter && UIConfiguration::instance().get_show_editor_meter()) {
1348 float mpeak = editor_meter->update_meters();
1349 if (mpeak > editor_meter_max_peak) {
1350 if (mpeak >= UIConfiguration::instance().get_meter_peak()) {
1351 editor_meter_peak_display.set_active_state ( Gtkmm2ext::ExplicitActive );
1358 ARDOUR_UI::set_fps_timeout_connection ()
1360 unsigned int interval = 40;
1361 if (!_session) return;
1362 if (_session->timecode_frames_per_second() != 0) {
1363 /* ideally we'll use a select() to sleep and not accumulate
1364 * idle time to provide a regular periodic signal.
1365 * See linux_vst_gui_support.cc 'elapsed_time_ms'.
1366 * However, that'll require a dedicated thread and cross-thread
1367 * signals to the GUI Thread..
1369 interval = floor(500. /* update twice per FPS, since Glib::signal_timeout is very irregular */
1370 * _session->frame_rate() / _session->nominal_frame_rate()
1371 / _session->timecode_frames_per_second()
1373 #ifdef PLATFORM_WINDOWS
1374 // the smallest windows scheduler time-slice is ~15ms.
1375 // periodic GUI timeouts shorter than that will cause
1376 // WaitForSingleObject to spinlock (100% of one CPU Core)
1377 // and gtk never enters idle mode.
1378 // also changing timeBeginPeriod(1) does not affect that in
1379 // any beneficial way, so we just limit the max rate for now.
1380 interval = std::max(30u, interval); // at most ~33Hz.
1382 interval = std::max(8u, interval); // at most 120Hz.
1385 fps_connection.disconnect();
1386 Timers::set_fps_interval (interval);
1390 ARDOUR_UI::update_sample_rate (framecnt_t)
1394 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
1396 if (!AudioEngine::instance()->connected()) {
1398 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1402 framecnt_t rate = AudioEngine::instance()->sample_rate();
1405 /* no sample rate available */
1406 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1409 if (fmod (rate, 1000.0) != 0.0) {
1410 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
1411 (float) rate / 1000.0f,
1412 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1414 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
1416 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1420 sample_rate_label.set_markup (buf);
1424 ARDOUR_UI::update_format ()
1427 format_label.set_text ("");
1432 s << _("File:") << X_(" <span foreground=\"green\">");
1434 switch (_session->config.get_native_file_header_format ()) {
1466 switch (_session->config.get_native_file_data_format ()) {
1480 format_label.set_markup (s.str ());
1484 ARDOUR_UI::update_xrun_count ()
1488 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1489 should also be changed.
1493 const unsigned int x = _session->get_xrun_count ();
1495 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">>10K</span>"), X_("red"));
1497 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">%u</span>"), x > 0 ? X_("red") : X_("green"), x);
1500 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">?</span>"), X_("yellow"));
1502 xrun_label.set_markup (buf);
1503 set_tip (xrun_label, _("Audio dropouts. Shift+click to reset"));
1507 ARDOUR_UI::update_cpu_load ()
1511 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1512 should also be changed.
1515 double const c = AudioEngine::instance()->get_dsp_load ();
1516 snprintf (buf, sizeof (buf), _("DSP: <span foreground=\"%s\">%5.1f%%</span>"), c >= 90 ? X_("red") : X_("green"), c);
1517 cpu_load_label.set_markup (buf);
1521 ARDOUR_UI::update_peak_thread_work ()
1524 const int c = SourceFactory::peak_work_queue_length ();
1526 snprintf (buf, sizeof (buf), _("PkBld: <span foreground=\"%s\">%d</span>"), c >= 2 ? X_("red") : X_("green"), c);
1527 peak_thread_work_label.set_markup (buf);
1529 peak_thread_work_label.set_markup (X_(""));
1534 ARDOUR_UI::update_buffer_load ()
1538 uint32_t const playback = _session ? _session->playback_load () : 100;
1539 uint32_t const capture = _session ? _session->capture_load () : 100;
1541 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1542 should also be changed.
1548 _("Buffers: <span foreground=\"green\">p:</span><span foreground=\"%s\">%" PRIu32 "%%</span> "
1549 "<span foreground=\"green\">c:</span><span foreground=\"%s\">%" PRIu32 "%%</span>"),
1550 playback <= 5 ? X_("red") : X_("green"),
1552 capture <= 5 ? X_("red") : X_("green"),
1556 buffer_load_label.set_markup (buf);
1558 buffer_load_label.set_text ("");
1563 ARDOUR_UI::count_recenabled_streams (Route& route)
1565 Track* track = dynamic_cast<Track*>(&route);
1566 if (track && track->record_enabled()) {
1567 rec_enabled_streams += track->n_inputs().n_total();
1572 ARDOUR_UI::update_disk_space()
1574 if (_session == 0) {
1578 boost::optional<framecnt_t> opt_frames = _session->available_capture_duration();
1580 framecnt_t fr = _session->frame_rate();
1583 /* skip update - no SR available */
1588 /* Available space is unknown */
1589 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">Unknown</span>"));
1590 } else if (opt_frames.get_value_or (0) == max_framecnt) {
1591 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">24hrs+</span>"));
1593 rec_enabled_streams = 0;
1594 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams, false);
1596 framecnt_t frames = opt_frames.get_value_or (0);
1598 if (rec_enabled_streams) {
1599 frames /= rec_enabled_streams;
1606 hrs = frames / (fr * 3600);
1609 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">>24 hrs</span>"));
1611 frames -= hrs * fr * 3600;
1612 mins = frames / (fr * 60);
1613 frames -= mins * fr * 60;
1616 bool const low = (hrs == 0 && mins <= 30);
1620 _("Disk: <span foreground=\"%s\">%02dh:%02dm:%02ds</span>"),
1621 low ? X_("red") : X_("green"),
1627 disk_space_label.set_markup (buf);
1631 ARDOUR_UI::update_timecode_format ()
1637 TimecodeSlave* tcslave;
1638 SyncSource sync_src = Config->get_sync_source();
1640 if ((sync_src == LTC || sync_src == MTC) && (tcslave = dynamic_cast<TimecodeSlave*>(_session->slave())) != 0) {
1641 matching = (tcslave->apparent_timecode_format() == _session->config.get_timecode_format());
1646 snprintf (buf, sizeof (buf), S_("Timecode|TC: <span foreground=\"%s\">%s</span>"),
1647 matching ? X_("green") : X_("red"),
1648 Timecode::timecode_format_name (_session->config.get_timecode_format()).c_str());
1650 snprintf (buf, sizeof (buf), "TC: n/a");
1653 timecode_format_label.set_markup (buf);
1657 ARDOUR_UI::update_wall_clock ()
1661 static int last_min = -1;
1664 tm_now = localtime (&now);
1665 if (last_min != tm_now->tm_min) {
1667 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1668 wall_clock_label.set_text (buf);
1669 last_min = tm_now->tm_min;
1676 ARDOUR_UI::open_recent_session ()
1678 bool can_return = (_session != 0);
1680 SessionDialog recent_session_dialog;
1684 ResponseType r = (ResponseType) recent_session_dialog.run ();
1687 case RESPONSE_ACCEPT:
1691 recent_session_dialog.hide();
1698 recent_session_dialog.hide();
1702 std::string path = recent_session_dialog.session_folder();
1703 std::string state = recent_session_dialog.session_name (should_be_new);
1705 if (should_be_new == true) {
1709 _session_is_new = false;
1711 if (load_session (path, state) == 0) {
1720 ARDOUR_UI::check_audioengine (Gtk::Window& parent)
1722 if (!AudioEngine::instance()->connected()) {
1723 MessageDialog msg (parent, string_compose (
1724 _("%1 is not connected to any audio backend.\n"
1725 "You cannot open or close sessions in this condition"),
1727 pop_back_splash (msg);
1735 ARDOUR_UI::open_session ()
1737 if (!check_audioengine (_main_window)) {
1741 /* ardour sessions are folders */
1742 Gtk::FileChooserDialog open_session_selector(_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1743 open_session_selector.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1744 open_session_selector.add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1745 open_session_selector.set_default_response(Gtk::RESPONSE_ACCEPT);
1748 string session_parent_dir = Glib::path_get_dirname(_session->path());
1749 open_session_selector.set_current_folder(session_parent_dir);
1751 open_session_selector.set_current_folder(Config->get_default_session_parent_dir());
1754 Gtkmm2ext::add_volume_shortcuts (open_session_selector);
1756 /* add_shortcut_folder throws an exception if the folder being added already has a shortcut */
1757 string default_session_folder = Config->get_default_session_parent_dir();
1758 open_session_selector.add_shortcut_folder (default_session_folder);
1760 catch (Glib::Error & e) {
1761 std::cerr << "open_session_selector.add_shortcut_folder() threw Glib::Error " << e.what() << std::endl;
1764 FileFilter session_filter;
1765 session_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::statefile_suffix));
1766 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1767 open_session_selector.add_filter (session_filter);
1768 open_session_selector.set_filter (session_filter);
1770 int response = open_session_selector.run();
1771 open_session_selector.hide ();
1773 if (response == Gtk::RESPONSE_CANCEL) {
1777 string session_path = open_session_selector.get_filename();
1781 if (session_path.length() > 0) {
1782 if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1783 _session_is_new = isnew;
1784 load_session (path, name);
1790 ARDOUR_UI::session_add_mixed_track (
1791 const ChanCount& input,
1792 const ChanCount& output,
1793 RouteGroup* route_group,
1795 const string& name_template,
1797 PluginInfoPtr instrument)
1799 list<boost::shared_ptr<MidiTrack> > tracks;
1801 if (_session == 0) {
1802 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1807 tracks = _session->new_midi_track (input, output, instrument, ARDOUR::Normal, route_group, how_many, name_template);
1809 if (tracks.size() != how_many) {
1810 error << string_compose(P_("could not create %1 new mixed track", "could not create %1 new mixed tracks", how_many), how_many) << endmsg;
1815 display_insufficient_ports_message ();
1820 for (list<boost::shared_ptr<MidiTrack> >::iterator i = tracks.begin(); i != tracks.end(); ++i) {
1821 (*i)->set_strict_io (true);
1827 ARDOUR_UI::session_add_midi_bus (
1828 RouteGroup* route_group,
1830 const string& name_template,
1832 PluginInfoPtr instrument)
1836 if (_session == 0) {
1837 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1842 routes = _session->new_midi_route (route_group, how_many, name_template, instrument);
1843 if (routes.size() != how_many) {
1844 error << string_compose(P_("could not create %1 new Midi Bus", "could not create %1 new Midi Busses", how_many), how_many) << endmsg;
1849 display_insufficient_ports_message ();
1854 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
1855 (*i)->set_strict_io (true);
1861 ARDOUR_UI::session_add_midi_route (
1863 RouteGroup* route_group,
1865 const string& name_template,
1867 PluginInfoPtr instrument)
1869 ChanCount one_midi_channel;
1870 one_midi_channel.set (DataType::MIDI, 1);
1873 session_add_mixed_track (one_midi_channel, one_midi_channel, route_group, how_many, name_template, strict_io, instrument);
1875 session_add_midi_bus (route_group, how_many, name_template, strict_io, instrument);
1880 ARDOUR_UI::session_add_audio_route (
1882 int32_t input_channels,
1883 int32_t output_channels,
1884 ARDOUR::TrackMode mode,
1885 RouteGroup* route_group,
1887 string const & name_template,
1891 list<boost::shared_ptr<AudioTrack> > tracks;
1894 if (_session == 0) {
1895 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1901 tracks = _session->new_audio_track (input_channels, output_channels, mode, route_group, how_many, name_template);
1903 if (tracks.size() != how_many) {
1904 error << string_compose (P_("could not create %1 new audio track", "could not create %1 new audio tracks", how_many), how_many)
1910 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template);
1912 if (routes.size() != how_many) {
1913 error << string_compose (P_("could not create %1 new audio bus", "could not create %1 new audio busses", how_many), how_many)
1920 display_insufficient_ports_message ();
1925 for (list<boost::shared_ptr<AudioTrack> >::iterator i = tracks.begin(); i != tracks.end(); ++i) {
1926 (*i)->set_strict_io (true);
1928 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
1929 (*i)->set_strict_io (true);
1935 ARDOUR_UI::display_insufficient_ports_message ()
1937 MessageDialog msg (_main_window,
1938 string_compose (_("There are insufficient ports available\n\
1939 to create a new track or bus.\n\
1940 You should save %1, exit and\n\
1941 restart with more ports."), PROGRAM_NAME));
1942 pop_back_splash (msg);
1947 ARDOUR_UI::transport_goto_start ()
1950 _session->goto_start();
1952 /* force displayed area in editor to start no matter
1953 what "follow playhead" setting is.
1957 editor->center_screen (_session->current_start_frame ());
1963 ARDOUR_UI::transport_goto_zero ()
1966 _session->request_locate (0);
1968 /* force displayed area in editor to start no matter
1969 what "follow playhead" setting is.
1973 editor->reset_x_origin (0);
1979 ARDOUR_UI::transport_goto_wallclock ()
1981 if (_session && editor) {
1988 localtime_r (&now, &tmnow);
1990 framecnt_t frame_rate = _session->frame_rate();
1992 if (frame_rate == 0) {
1993 /* no frame rate available */
1997 frames = tmnow.tm_hour * (60 * 60 * frame_rate);
1998 frames += tmnow.tm_min * (60 * frame_rate);
1999 frames += tmnow.tm_sec * frame_rate;
2001 _session->request_locate (frames, _session->transport_rolling ());
2003 /* force displayed area in editor to start no matter
2004 what "follow playhead" setting is.
2008 editor->center_screen (frames);
2014 ARDOUR_UI::transport_goto_end ()
2017 framepos_t const frame = _session->current_end_frame();
2018 _session->request_locate (frame);
2020 /* force displayed area in editor to start no matter
2021 what "follow playhead" setting is.
2025 editor->center_screen (frame);
2031 ARDOUR_UI::transport_stop ()
2037 if (_session->is_auditioning()) {
2038 _session->cancel_audition ();
2042 _session->request_stop (false, true);
2045 /** Check if any tracks are record enabled. If none are, record enable all of them.
2046 * @return true if track record-enabled status was changed, false otherwise.
2049 ARDOUR_UI::trx_record_enable_all_tracks ()
2055 boost::shared_ptr<RouteList> rl = _session->get_tracks ();
2056 bool none_record_enabled = true;
2058 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
2059 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*r);
2062 if (t->record_enabled()) {
2063 none_record_enabled = false;
2068 if (none_record_enabled) {
2069 _session->set_record_enabled (rl, true, Session::rt_cleanup);
2072 return none_record_enabled;
2076 ARDOUR_UI::transport_record (bool roll)
2079 switch (_session->record_status()) {
2080 case Session::Disabled:
2081 if (_session->ntracks() == 0) {
2082 MessageDialog msg (_main_window, _("Please create one or more tracks before trying to record.\nYou can do this with the \"Add Track or Bus\" option in the Session menu."));
2086 if (Profile->get_trx()) {
2087 roll = trx_record_enable_all_tracks ();
2089 _session->maybe_enable_record ();
2094 case Session::Recording:
2096 _session->request_stop();
2098 _session->disable_record (false, true);
2102 case Session::Enabled:
2103 _session->disable_record (false, true);
2109 ARDOUR_UI::transport_roll ()
2115 if (_session->is_auditioning()) {
2120 if (_session->config.get_external_sync()) {
2121 switch (Config->get_sync_source()) {
2125 /* transport controlled by the master */
2131 bool rolling = _session->transport_rolling();
2133 if (_session->get_play_loop()) {
2135 /* If loop playback is not a mode, then we should cancel
2136 it when this action is requested. If it is a mode
2137 we just leave it in place.
2140 if (!Config->get_loop_is_mode()) {
2141 /* XXX it is not possible to just leave seamless loop and keep
2142 playing at present (nov 4th 2009)
2144 if (!Config->get_seamless_loop()) {
2145 /* stop loop playback and stop rolling */
2146 _session->request_play_loop (false, true);
2147 } else if (rolling) {
2148 /* stop loop playback but keep rolling */
2149 _session->request_play_loop (false, false);
2153 } else if (_session->get_play_range () ) {
2154 /* stop playing a range if we currently are */
2155 _session->request_play_range (0, true);
2159 _session->request_transport_speed (1.0f);
2164 ARDOUR_UI::get_smart_mode() const
2166 return ( editor->get_smart_mode() );
2171 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
2177 if (_session->is_auditioning()) {
2178 _session->cancel_audition ();
2182 if (_session->config.get_external_sync()) {
2183 switch (Config->get_sync_source()) {
2187 /* transport controlled by the master */
2192 bool rolling = _session->transport_rolling();
2193 bool affect_transport = true;
2195 if (rolling && roll_out_of_bounded_mode) {
2196 /* drop out of loop/range playback but leave transport rolling */
2197 if (_session->get_play_loop()) {
2198 if (_session->actively_recording()) {
2200 /* just stop using the loop, then actually stop
2203 _session->request_play_loop (false, affect_transport);
2206 if (Config->get_seamless_loop()) {
2207 /* the disk buffers contain copies of the loop - we can't
2208 just keep playing, so stop the transport. the user
2209 can restart as they wish.
2211 affect_transport = true;
2213 /* disk buffers are normal, so we can keep playing */
2214 affect_transport = false;
2216 _session->request_play_loop (false, affect_transport);
2218 } else if (_session->get_play_range ()) {
2219 affect_transport = false;
2220 _session->request_play_range (0, true);
2224 if (affect_transport) {
2226 _session->request_stop (with_abort, true);
2228 /* the only external sync condition we can be in here
2229 * would be Engine (JACK) sync, in which case we still
2233 if (UIConfiguration::instance().get_follow_edits() && ( editor->get_selection().time.front().start == _session->transport_frame() ) ) { //if playhead is exactly at the start of a range, we can assume it was placed there by follow_edits
2234 _session->request_play_range (&editor->get_selection().time, true);
2235 _session->set_requested_return_frame( editor->get_selection().time.front().start ); //force an auto-return here
2237 _session->request_transport_speed (1.0f);
2243 ARDOUR_UI::toggle_session_auto_loop ()
2249 Location * looploc = _session->locations()->auto_loop_location();
2255 if (_session->get_play_loop()) {
2257 /* looping enabled, our job is to disable it */
2259 _session->request_play_loop (false);
2263 /* looping not enabled, our job is to enable it.
2265 loop-is-NOT-mode: this action always starts the transport rolling.
2266 loop-IS-mode: this action simply sets the loop play mechanism, but
2267 does not start transport.
2269 if (Config->get_loop_is_mode()) {
2270 _session->request_play_loop (true, false);
2272 _session->request_play_loop (true, true);
2276 //show the loop markers
2277 looploc->set_hidden (false, this);
2281 ARDOUR_UI::transport_play_selection ()
2287 editor->play_selection ();
2291 ARDOUR_UI::transport_play_preroll ()
2296 editor->play_with_preroll ();
2300 ARDOUR_UI::transport_rewind (int option)
2302 float current_transport_speed;
2305 current_transport_speed = _session->transport_speed();
2307 if (current_transport_speed >= 0.0f) {
2310 _session->request_transport_speed (-1.0f);
2313 _session->request_transport_speed (-4.0f);
2316 _session->request_transport_speed (-0.5f);
2321 _session->request_transport_speed (current_transport_speed * 1.5f);
2327 ARDOUR_UI::transport_forward (int option)
2333 float current_transport_speed = _session->transport_speed();
2335 if (current_transport_speed <= 0.0f) {
2338 _session->request_transport_speed (1.0f);
2341 _session->request_transport_speed (4.0f);
2344 _session->request_transport_speed (0.5f);
2349 _session->request_transport_speed (current_transport_speed * 1.5f);
2354 ARDOUR_UI::toggle_record_enable (uint32_t rid)
2360 boost::shared_ptr<Route> r;
2362 if ((r = _session->route_by_remote_id (rid)) != 0) {
2364 boost::shared_ptr<Track> t;
2366 if ((t = boost::dynamic_pointer_cast<Track>(r)) != 0) {
2367 t->set_record_enabled (!t->record_enabled(), Controllable::UseGroup);
2373 ARDOUR_UI::map_transport_state ()
2376 auto_loop_button.unset_active_state ();
2377 play_selection_button.unset_active_state ();
2378 roll_button.unset_active_state ();
2379 stop_button.set_active_state (Gtkmm2ext::ExplicitActive);
2383 shuttle_box->map_transport_state ();
2385 float sp = _session->transport_speed();
2391 if (_session->get_play_range()) {
2393 play_selection_button.set_active_state (Gtkmm2ext::ExplicitActive);
2394 roll_button.unset_active_state ();
2395 auto_loop_button.unset_active_state ();
2397 } else if (_session->get_play_loop ()) {
2399 auto_loop_button.set_active (true);
2400 play_selection_button.set_active (false);
2401 if (Config->get_loop_is_mode()) {
2402 roll_button.set_active (true);
2404 roll_button.set_active (false);
2409 roll_button.set_active (true);
2410 play_selection_button.set_active (false);
2411 auto_loop_button.set_active (false);
2414 if (UIConfiguration::instance().get_follow_edits() && !_session->config.get_external_sync()) {
2415 /* light up both roll and play-selection if they are joined */
2416 roll_button.set_active (true);
2417 play_selection_button.set_active (true);
2420 stop_button.set_active (false);
2424 stop_button.set_active (true);
2425 roll_button.set_active (false);
2426 play_selection_button.set_active (false);
2427 if (Config->get_loop_is_mode ()) {
2428 auto_loop_button.set_active (_session->get_play_loop());
2430 auto_loop_button.set_active (false);
2432 update_disk_space ();
2437 ARDOUR_UI::blink_handler (bool blink_on)
2439 transport_rec_enable_blink (blink_on);
2440 solo_blink (blink_on);
2441 sync_blink (blink_on);
2442 audition_blink (blink_on);
2443 feedback_blink (blink_on);
2444 error_blink (blink_on);
2448 ARDOUR_UI::update_clocks ()
2450 if (!_session) return;
2452 if (editor && !editor->dragging_playhead()) {
2453 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD)); /* EMIT_SIGNAL */
2458 ARDOUR_UI::start_clocking ()
2460 if (UIConfiguration::instance().get_super_rapid_clock_update()) {
2461 clock_signal_connection = Timers::fps_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2463 clock_signal_connection = Timers::rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2468 ARDOUR_UI::stop_clocking ()
2470 clock_signal_connection.disconnect ();
2474 ARDOUR_UI::save_as_progress_update (float fraction, int64_t cnt, int64_t total, Gtk::Label* label, Gtk::ProgressBar* bar)
2478 snprintf (buf, sizeof (buf), _("Copied %" PRId64 " of %" PRId64), cnt, total);
2480 label->set_text (buf);
2481 bar->set_fraction (fraction);
2483 /* process events, redraws, etc. */
2485 while (gtk_events_pending()) {
2486 gtk_main_iteration ();
2489 return true; /* continue with save-as */
2493 ARDOUR_UI::save_session_as ()
2499 if (!save_as_dialog) {
2500 save_as_dialog = new SaveAsDialog;
2503 save_as_dialog->set_name (_session->name());
2505 int response = save_as_dialog->run ();
2507 save_as_dialog->hide ();
2510 case Gtk::RESPONSE_OK:
2519 sa.new_parent_folder = save_as_dialog->new_parent_folder ();
2520 sa.new_name = save_as_dialog->new_name ();
2521 sa.switch_to = save_as_dialog->switch_to();
2522 sa.copy_media = save_as_dialog->copy_media();
2523 sa.copy_external = save_as_dialog->copy_external();
2524 sa.include_media = save_as_dialog->include_media ();
2526 /* Only bother with a progress dialog if we're going to copy
2527 media into the save-as target. Without that choice, this
2528 will be very fast because we're only talking about a few kB's to
2529 perhaps a couple of MB's of data.
2532 ArdourDialog progress_dialog (_("Save As"), true);
2534 if (sa.include_media && sa.copy_media) {
2537 Gtk::ProgressBar progress_bar;
2539 progress_dialog.get_vbox()->pack_start (label);
2540 progress_dialog.get_vbox()->pack_start (progress_bar);
2542 progress_bar.show ();
2544 /* this signal will be emitted from within this, the calling thread,
2545 * after every file is copied. It provides information on percentage
2546 * complete (in terms of total data to copy), the number of files
2547 * copied so far, and the total number to copy.
2552 sa.Progress.connect_same_thread (c, boost::bind (&ARDOUR_UI::save_as_progress_update, this, _1, _2, _3, &label, &progress_bar));
2554 progress_dialog.show_all ();
2555 progress_dialog.present ();
2558 if (_session->save_as (sa)) {
2560 MessageDialog msg (string_compose (_("Save As failed: %1"), sa.failure_message));
2564 if (!sa.include_media) {
2565 unload_session (false);
2566 load_session (sa.final_session_folder_name, sa.new_name);
2571 ARDOUR_UI::quick_snapshot_session (bool switch_to_it)
2575 struct tm local_time;
2578 localtime_r (&n, &local_time);
2579 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2581 save_state (timebuf, switch_to_it);
2586 ARDOUR_UI::process_snapshot_session_prompter (ArdourPrompter& prompter, bool switch_to_it)
2590 prompter.get_result (snapname);
2592 bool do_save = (snapname.length() != 0);
2595 char illegal = Session::session_name_is_legal(snapname);
2597 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2598 "snapshot names may not contain a '%1' character"), illegal));
2604 vector<std::string> p;
2605 get_state_files_in_directory (_session->session_directory().root_path(), p);
2606 vector<string> n = get_file_names_no_extension (p);
2608 if (find (n.begin(), n.end(), snapname) != n.end()) {
2610 do_save = overwrite_file_dialog (prompter,
2611 _("Confirm Snapshot Overwrite"),
2612 _("A snapshot already exists with that name. Do you want to overwrite it?"));
2616 save_state (snapname, switch_to_it);
2626 /** Ask the user for the name of a new snapshot and then take it.
2630 ARDOUR_UI::snapshot_session (bool switch_to_it)
2632 ArdourPrompter prompter (true);
2634 prompter.set_name ("Prompter");
2635 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2637 prompter.set_title (_("Snapshot and switch"));
2638 prompter.set_prompt (_("New session name"));
2640 prompter.set_title (_("Take Snapshot"));
2641 prompter.set_prompt (_("Name of new snapshot"));
2645 prompter.set_initial_text (_session->snap_name());
2649 struct tm local_time;
2652 localtime_r (&n, &local_time);
2653 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2654 prompter.set_initial_text (timebuf);
2657 bool finished = false;
2659 switch (prompter.run()) {
2660 case RESPONSE_ACCEPT:
2662 finished = process_snapshot_session_prompter (prompter, switch_to_it);
2673 /** Ask the user for a new session name and then rename the session to it.
2677 ARDOUR_UI::rename_session ()
2683 ArdourPrompter prompter (true);
2686 prompter.set_name ("Prompter");
2687 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2688 prompter.set_title (_("Rename Session"));
2689 prompter.set_prompt (_("New session name"));
2692 switch (prompter.run()) {
2693 case RESPONSE_ACCEPT:
2695 prompter.get_result (name);
2697 bool do_rename = (name.length() != 0);
2700 char illegal = Session::session_name_is_legal (name);
2703 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2704 "session names may not contain a '%1' character"), illegal));
2709 switch (_session->rename (name)) {
2711 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
2712 msg.set_position (WIN_POS_MOUSE);
2720 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
2721 msg.set_position (WIN_POS_MOUSE);
2737 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2739 if (!_session || _session->deletion_in_progress()) {
2743 XMLNode* node = new XMLNode (X_("UI"));
2745 WM::Manager::instance().add_state (*node);
2747 node->add_child_nocopy (gui_object_state->get_state());
2749 _session->add_extra_xml (*node);
2751 if (export_video_dialog) {
2752 _session->add_extra_xml (export_video_dialog->get_state());
2755 save_state_canfail (name, switch_to_it);
2759 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2764 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2769 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2774 ARDOUR_UI::primary_clock_value_changed ()
2777 _session->request_locate (primary_clock->current_time ());
2782 ARDOUR_UI::big_clock_value_changed ()
2785 _session->request_locate (big_clock->current_time ());
2790 ARDOUR_UI::secondary_clock_value_changed ()
2793 _session->request_locate (secondary_clock->current_time ());
2798 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2800 if (_session == 0) {
2804 if (_session->step_editing()) {
2808 Session::RecordState const r = _session->record_status ();
2809 bool const h = _session->have_rec_enabled_track ();
2811 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2813 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2815 rec_button.set_active_state (Gtkmm2ext::Off);
2817 } else if (r == Session::Recording && h) {
2818 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2820 rec_button.unset_active_state ();
2825 ARDOUR_UI::process_save_template_prompter (ArdourPrompter& prompter)
2829 prompter.get_result (name);
2831 if (name.length()) {
2832 int failed = _session->save_template (name);
2834 if (failed == -2) { /* file already exists. */
2835 bool overwrite = overwrite_file_dialog (prompter,
2836 _("Confirm Template Overwrite"),
2837 _("A template already exists with that name. Do you want to overwrite it?"));
2840 _session->save_template (name, true);
2852 ARDOUR_UI::save_template ()
2854 ArdourPrompter prompter (true);
2856 if (!check_audioengine (_main_window)) {
2860 prompter.set_name (X_("Prompter"));
2861 prompter.set_title (_("Save Template"));
2862 prompter.set_prompt (_("Name for template:"));
2863 prompter.set_initial_text(_session->name() + _("-template"));
2864 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2866 bool finished = false;
2868 switch (prompter.run()) {
2869 case RESPONSE_ACCEPT:
2870 finished = process_save_template_prompter (prompter);
2881 ARDOUR_UI::edit_metadata ()
2883 SessionMetadataEditor dialog;
2884 dialog.set_session (_session);
2885 dialog.grab_focus ();
2890 ARDOUR_UI::import_metadata ()
2892 SessionMetadataImporter dialog;
2893 dialog.set_session (_session);
2898 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
2900 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2902 MessageDialog msg (str,
2904 Gtk::MESSAGE_WARNING,
2905 Gtk::BUTTONS_YES_NO,
2909 msg.set_name (X_("OpenExistingDialog"));
2910 msg.set_title (_("Open Existing Session"));
2911 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
2912 msg.set_position (Gtk::WIN_POS_CENTER);
2913 pop_back_splash (msg);
2915 switch (msg.run()) {
2924 ARDOUR_UI::build_session_from_dialog (SessionDialog& sd, const std::string& session_path, const std::string& session_name)
2926 BusProfile bus_profile;
2930 bus_profile.master_out_channels = 2;
2931 bus_profile.input_ac = AutoConnectPhysical;
2932 bus_profile.output_ac = AutoConnectMaster;
2933 bus_profile.requested_physical_in = 0; // use all available
2934 bus_profile.requested_physical_out = 0; // use all available
2938 /* get settings from advanced section of NSD */
2940 if (sd.create_master_bus()) {
2941 bus_profile.master_out_channels = (uint32_t) sd.master_channel_count();
2943 bus_profile.master_out_channels = 0;
2946 if (sd.connect_inputs()) {
2947 bus_profile.input_ac = AutoConnectPhysical;
2949 bus_profile.input_ac = AutoConnectOption (0);
2952 bus_profile.output_ac = AutoConnectOption (0);
2954 if (sd.connect_outputs ()) {
2955 if (sd.connect_outs_to_master()) {
2956 bus_profile.output_ac = AutoConnectMaster;
2957 } else if (sd.connect_outs_to_physical()) {
2958 bus_profile.output_ac = AutoConnectPhysical;
2962 bus_profile.requested_physical_in = (uint32_t) sd.input_limit_count();
2963 bus_profile.requested_physical_out = (uint32_t) sd.output_limit_count();
2966 if (build_session (session_path, session_name, bus_profile)) {
2974 ARDOUR_UI::load_from_application_api (const std::string& path)
2976 ARDOUR_COMMAND_LINE::session_name = path;
2977 /* Cancel SessionDialog if it's visible to make OSX delegates work.
2979 * ARDOUR_UI::starting connects app->ShouldLoad signal and then shows a SessionDialog
2981 * - ShouldLoad does not arrive in time, ARDOUR_COMMAND_LINE::session_name is empty:
2982 * -> ARDOUR_UI::get_session_parameters starts a SessionDialog.
2983 * - ShouldLoad signal arrives, this function is called and sets ARDOUR_COMMAND_LINE::session_name
2984 * -> SessionDialog is not displayed
2987 if (_session_dialog) {
2988 std::string session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
2989 std::string session_path = path;
2990 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_REGULAR)) {
2991 session_path = Glib::path_get_dirname (session_path);
2993 // signal the existing dialog in ARDOUR_UI::get_session_parameters()
2994 _session_dialog->set_provided_session (session_name, session_path);
2995 _session_dialog->response (RESPONSE_NONE);
2996 _session_dialog->hide();
3001 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
3002 /* /path/to/foo => /path/to/foo, foo */
3003 rv = load_session (path, basename_nosuffix (path));
3005 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
3006 rv =load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
3009 // if load_session fails -> pop up SessionDialog.
3011 ARDOUR_COMMAND_LINE::session_name = "";
3013 if (get_session_parameters (true, false)) {
3019 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
3021 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
3023 string session_name;
3024 string session_path;
3025 string template_name;
3027 bool likely_new = false;
3028 bool cancel_not_quit;
3030 /* deal with any existing DIRTY session now, rather than later. don't
3031 * treat a non-dirty session this way, so that it stays visible
3032 * as we bring up the new session dialog.
3035 if (_session && ARDOUR_UI::instance()->video_timeline) {
3036 ARDOUR_UI::instance()->video_timeline->sync_session_state();
3039 /* if there is already a session, relabel the button
3040 on the SessionDialog so that we don't Quit directly
3042 cancel_not_quit = (_session != 0);
3044 if (_session && _session->dirty()) {
3045 if (unload_session (false)) {
3046 /* unload cancelled by user */
3049 ARDOUR_COMMAND_LINE::session_name = "";
3052 if (!load_template.empty()) {
3053 should_be_new = true;
3054 template_name = load_template;
3057 session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3058 session_path = ARDOUR_COMMAND_LINE::session_name;
3060 if (!session_path.empty()) {
3061 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_EXISTS)) {
3062 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_IS_REGULAR)) {
3063 /* session/snapshot file, change path to be dir */
3064 session_path = Glib::path_get_dirname (session_path);
3069 SessionDialog session_dialog (should_be_new, session_name, session_path, load_template, cancel_not_quit);
3071 _session_dialog = &session_dialog;
3074 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
3076 /* if they named a specific statefile, use it, otherwise they are
3077 just giving a session folder, and we want to use it as is
3078 to find the session.
3081 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
3083 if (suffix != string::npos) {
3084 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
3085 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
3086 session_name = Glib::path_get_basename (session_name);
3088 session_path = ARDOUR_COMMAND_LINE::session_name;
3089 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
3094 session_dialog.clear_given ();
3097 if (should_be_new || session_name.empty()) {
3098 /* need the dialog to get info from user */
3100 cerr << "run dialog\n";
3102 switch (session_dialog.run()) {
3103 case RESPONSE_ACCEPT:
3106 /* this is used for async * app->ShouldLoad(). */
3107 continue; // while loop
3110 if (quit_on_cancel) {
3111 // JE - Currently (July 2014) this section can only get reached if the
3112 // user quits from the main 'Session Setup' dialog (i.e. reaching this
3113 // point does NOT indicate an abnormal termination). Therefore, let's
3114 // behave gracefully (i.e. let's do some cleanup) before we call exit()
3116 pthread_cancel_all ();
3124 session_dialog.hide ();
3127 /* if we run the startup dialog again, offer more than just "new session" */
3129 should_be_new = false;
3131 session_name = session_dialog.session_name (likely_new);
3132 session_path = session_dialog.session_folder ();
3138 string::size_type suffix = session_name.find (statefile_suffix);
3140 if (suffix != string::npos) {
3141 session_name = session_name.substr (0, suffix);
3144 /* this shouldn't happen, but we catch it just in case it does */
3146 if (session_name.empty()) {
3150 if (session_dialog.use_session_template()) {
3151 template_name = session_dialog.session_template_name();
3152 _session_is_new = true;
3155 if (session_name[0] == G_DIR_SEPARATOR ||
3156 #ifdef PLATFORM_WINDOWS
3157 (session_name.length() > 3 && session_name[1] == ':' && session_name[2] == G_DIR_SEPARATOR)
3159 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
3160 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)
3165 /* absolute path or cwd-relative path specified for session name: infer session folder
3166 from what was given.
3169 session_path = Glib::path_get_dirname (session_name);
3170 session_name = Glib::path_get_basename (session_name);
3174 session_path = session_dialog.session_folder();
3176 char illegal = Session::session_name_is_legal (session_name);
3179 MessageDialog msg (session_dialog,
3180 string_compose (_("To ensure compatibility with various systems\n"
3181 "session names may not contain a '%1' character"),
3184 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3189 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
3192 if (likely_new && !nsm) {
3194 std::string existing = Glib::build_filename (session_path, session_name);
3196 if (!ask_about_loading_existing_session (existing)) {
3197 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3202 _session_is_new = false;
3207 pop_back_splash (session_dialog);
3208 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
3210 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3214 char illegal = Session::session_name_is_legal(session_name);
3217 pop_back_splash (session_dialog);
3218 MessageDialog msg (session_dialog, string_compose(_("To ensure compatibility with various systems\n"
3219 "session names may not contain a '%1' character"), illegal));
3221 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3225 _session_is_new = true;
3228 if (likely_new && template_name.empty()) {
3230 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3234 ret = load_session (session_path, session_name, template_name);
3237 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
3241 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
3242 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
3246 /* clear this to avoid endless attempts to load the
3250 ARDOUR_COMMAND_LINE::session_name = "";
3254 _session_dialog = NULL;
3260 ARDOUR_UI::close_session()
3262 if (!check_audioengine (_main_window)) {
3266 if (unload_session (true)) {
3270 ARDOUR_COMMAND_LINE::session_name = "";
3272 if (get_session_parameters (true, false)) {
3277 /** @param snap_name Snapshot name (without .ardour suffix).
3278 * @return -2 if the load failed because we are not connected to the AudioEngine.
3281 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
3283 Session *new_session;
3288 unload_status = unload_session ();
3290 if (unload_status < 0) {
3292 } else if (unload_status > 0) {
3298 session_loaded = false;
3300 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
3303 new_session = new Session (*AudioEngine::instance(), path, snap_name, 0, mix_template);
3306 /* this one is special */
3308 catch (AudioEngine::PortRegistrationFailure& err) {
3310 MessageDialog msg (err.what(),
3313 Gtk::BUTTONS_CLOSE);
3315 msg.set_title (_("Port Registration Error"));
3316 msg.set_secondary_text (_("Click the Close button to try again."));
3317 msg.set_position (Gtk::WIN_POS_CENTER);
3318 pop_back_splash (msg);
3321 int response = msg.run ();
3326 case RESPONSE_CANCEL:
3333 catch (SessionException e) {
3334 MessageDialog msg (string_compose(
3335 _("Session \"%1 (snapshot %2)\" did not load successfully: %3"),
3336 path, snap_name, e.what()),
3341 msg.set_title (_("Loading Error"));
3342 msg.set_position (Gtk::WIN_POS_CENTER);
3343 pop_back_splash (msg);
3355 MessageDialog msg (string_compose(
3356 _("Session \"%1 (snapshot %2)\" did not load successfully"),
3362 msg.set_title (_("Loading Error"));
3363 msg.set_position (Gtk::WIN_POS_CENTER);
3364 pop_back_splash (msg);
3376 list<string> const u = new_session->unknown_processors ();
3378 MissingPluginDialog d (_session, u);
3383 if (!new_session->writable()) {
3384 MessageDialog msg (_("This session has been opened in read-only mode.\n\nYou will not be able to record or save."),
3389 msg.set_title (_("Read-only Session"));
3390 msg.set_position (Gtk::WIN_POS_CENTER);
3391 pop_back_splash (msg);
3398 /* Now the session been created, add the transport controls */
3399 new_session->add_controllable(roll_controllable);
3400 new_session->add_controllable(stop_controllable);
3401 new_session->add_controllable(goto_start_controllable);
3402 new_session->add_controllable(goto_end_controllable);
3403 new_session->add_controllable(auto_loop_controllable);
3404 new_session->add_controllable(play_selection_controllable);
3405 new_session->add_controllable(rec_controllable);
3407 set_session (new_session);
3409 session_loaded = true;
3412 _session->set_clean ();
3415 #ifdef WINDOWS_VST_SUPPORT
3416 fst_stop_threading();
3420 Timers::TimerSuspender t;
3424 #ifdef WINDOWS_VST_SUPPORT
3425 fst_start_threading();
3434 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
3436 Session *new_session;
3439 session_loaded = false;
3440 x = unload_session ();
3448 _session_is_new = true;
3451 new_session = new Session (*AudioEngine::instance(), path, snap_name, &bus_profile);
3454 catch (SessionException e) {
3456 MessageDialog msg (string_compose(_("Could not create session in \"%1\": %2"), path, e.what()));
3457 msg.set_title (_("Loading Error"));
3458 msg.set_position (Gtk::WIN_POS_CENTER);
3459 pop_back_splash (msg);
3465 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
3466 msg.set_title (_("Loading Error"));
3467 msg.set_position (Gtk::WIN_POS_CENTER);
3468 pop_back_splash (msg);
3473 /* Give the new session the default GUI state, if such things exist */
3476 n = Config->instant_xml (X_("Editor"));
3478 n->remove_nodes_and_delete ("Selection"); // no not apply selection to new sessions.
3479 new_session->add_instant_xml (*n, false);
3481 n = Config->instant_xml (X_("Mixer"));
3483 new_session->add_instant_xml (*n, false);
3486 /* Put the playhead at 0 and scroll fully left */
3487 n = new_session->instant_xml (X_("Editor"));
3489 n->add_property (X_("playhead"), X_("0"));
3490 n->add_property (X_("left-frame"), X_("0"));
3493 set_session (new_session);
3495 session_loaded = true;
3497 new_session->save_state(new_session->name());
3503 ARDOUR_UI::launch_chat ()
3505 MessageDialog dialog(_("<b>Just ask and wait for an answer.\nIt may take from minutes to hours.</b>"), true);
3507 dialog.set_title (_("About the Chat"));
3508 dialog.set_secondary_text (_("When you're inside the chat just ask your question and wait for an answer. The chat is occupied by real people with real lives so many of them are passively online and might not read your question before minutes or hours later.\nSo please be patient and wait for an answer.\n\nYou should just leave the chat window open and check back regularly until someone has answered your question."));
3510 switch (dialog.run()) {
3513 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
3514 #elif defined PLATFORM_WINDOWS
3515 open_uri("http://webchat.freenode.net/?channels=ardour-windows");
3517 open_uri("http://webchat.freenode.net/?channels=ardour");
3526 ARDOUR_UI::launch_manual ()
3528 PBD::open_uri (Config->get_tutorial_manual_url());
3532 ARDOUR_UI::launch_reference ()
3534 PBD::open_uri (Config->get_reference_manual_url());
3538 ARDOUR_UI::launch_tracker ()
3540 PBD::open_uri ("http://tracker.ardour.org");
3544 ARDOUR_UI::launch_subscribe ()
3546 PBD::open_uri ("https://community.ardour.org/s/subscribe");
3550 ARDOUR_UI::launch_cheat_sheet ()
3553 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheat_sheet_osx.pdf");
3555 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheatsheet.pdf");
3560 ARDOUR_UI::launch_website ()
3562 PBD::open_uri ("http://ardour.org");
3566 ARDOUR_UI::launch_website_dev ()
3568 PBD::open_uri ("http://ardour.org/development.html");
3572 ARDOUR_UI::launch_forums ()
3574 PBD::open_uri ("https://community.ardour.org/forums");
3578 ARDOUR_UI::launch_howto_report ()
3580 PBD::open_uri ("http://ardour.org/reporting_bugs");
3584 ARDOUR_UI::loading_message (const std::string& msg)
3586 if (ARDOUR_COMMAND_LINE::no_splash) {
3594 splash->message (msg);
3598 ARDOUR_UI::show_splash ()
3602 splash = new Splash;
3612 ARDOUR_UI::hide_splash ()
3619 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title, const bool msg_delete)
3623 removed = rep.paths.size();
3626 MessageDialog msgd (_main_window,
3627 _("No files were ready for clean-up"),
3631 msgd.set_title (_("Clean-up"));
3632 msgd.set_secondary_text (_("If this seems suprising, \n\
3633 check for any existing snapshots.\n\
3634 These may still include regions that\n\
3635 require some unused files to continue to exist."));
3641 ArdourDialog results (_("Clean-up"), true, false);
3643 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
3644 CleanupResultsModelColumns() {
3648 Gtk::TreeModelColumn<std::string> visible_name;
3649 Gtk::TreeModelColumn<std::string> fullpath;
3653 CleanupResultsModelColumns results_columns;
3654 Glib::RefPtr<Gtk::ListStore> results_model;
3655 Gtk::TreeView results_display;
3657 results_model = ListStore::create (results_columns);
3658 results_display.set_model (results_model);
3659 results_display.append_column (list_title, results_columns.visible_name);
3661 results_display.set_name ("CleanupResultsList");
3662 results_display.set_headers_visible (true);
3663 results_display.set_headers_clickable (false);
3664 results_display.set_reorderable (false);
3666 Gtk::ScrolledWindow list_scroller;
3669 Gtk::HBox dhbox; // the hbox for the image and text
3670 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
3671 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
3673 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
3675 const string dead_directory = _session->session_directory().dead_path();
3678 %1 - number of files removed
3679 %2 - location of "dead"
3680 %3 - size of files affected
3681 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
3684 const char* bprefix;
3685 double space_adjusted = 0;
3687 if (rep.space < 1000) {
3689 space_adjusted = rep.space;
3690 } else if (rep.space < 1000000) {
3691 bprefix = _("kilo");
3692 space_adjusted = floorf((float)rep.space / 1000.0);
3693 } else if (rep.space < 1000000 * 1000) {
3694 bprefix = _("mega");
3695 space_adjusted = floorf((float)rep.space / (1000.0 * 1000.0));
3697 bprefix = _("giga");
3698 space_adjusted = floorf((float)rep.space / (1000.0 * 1000 * 1000.0));
3702 txt.set_markup (string_compose (P_("\
3703 The following file was deleted from %2,\n\
3704 releasing %3 %4bytes of disk space", "\
3705 The following %1 files were deleted from %2,\n\
3706 releasing %3 %4bytes of disk space", removed),
3707 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3709 txt.set_markup (string_compose (P_("\
3710 The following file was not in use and \n\
3711 has been moved to: %2\n\n\
3712 After a restart of %5\n\n\
3713 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3714 will release an additional %3 %4bytes of disk space.\n", "\
3715 The following %1 files were not in use and \n\
3716 have been moved to: %2\n\n\
3717 After a restart of %5\n\n\
3718 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3719 will release an additional %3 %4bytes of disk space.\n", removed),
3720 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3723 dhbox.pack_start (*dimage, true, false, 5);
3724 dhbox.pack_start (txt, true, false, 5);
3726 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
3727 TreeModel::Row row = *(results_model->append());
3728 row[results_columns.visible_name] = *i;
3729 row[results_columns.fullpath] = *i;
3732 list_scroller.add (results_display);
3733 list_scroller.set_size_request (-1, 150);
3734 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
3736 dvbox.pack_start (dhbox, true, false, 5);
3737 dvbox.pack_start (list_scroller, true, false, 5);
3738 ddhbox.pack_start (dvbox, true, false, 5);
3740 results.get_vbox()->pack_start (ddhbox, true, false, 5);
3741 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
3742 results.set_default_response (RESPONSE_CLOSE);
3743 results.set_position (Gtk::WIN_POS_MOUSE);
3745 results_display.show();
3746 list_scroller.show();
3753 //results.get_vbox()->show();
3754 results.set_resizable (false);
3761 ARDOUR_UI::cleanup ()
3763 if (_session == 0) {
3764 /* shouldn't happen: menu item is insensitive */
3769 MessageDialog checker (_("Are you sure you want to clean-up?"),
3771 Gtk::MESSAGE_QUESTION,
3774 checker.set_title (_("Clean-up"));
3776 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
3777 ALL undo/redo information will be lost if you clean-up.\n\
3778 Clean-up will move all unused files to a \"dead\" location."));
3780 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3781 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
3782 checker.set_default_response (RESPONSE_CANCEL);
3784 checker.set_name (_("CleanupDialog"));
3785 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3786 checker.set_position (Gtk::WIN_POS_MOUSE);
3788 switch (checker.run()) {
3789 case RESPONSE_ACCEPT:
3795 ARDOUR::CleanupReport rep;
3797 editor->prepare_for_cleanup ();
3799 /* do not allow flush until a session is reloaded */
3801 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3803 act->set_sensitive (false);
3806 if (_session->cleanup_sources (rep)) {
3807 editor->finish_cleanup ();
3811 editor->finish_cleanup ();
3814 display_cleanup_results (rep, _("Cleaned Files"), false);
3818 ARDOUR_UI::flush_trash ()
3820 if (_session == 0) {
3821 /* shouldn't happen: menu item is insensitive */
3825 ARDOUR::CleanupReport rep;
3827 if (_session->cleanup_trash_sources (rep)) {
3831 display_cleanup_results (rep, _("deleted file"), true);
3835 ARDOUR_UI::cleanup_peakfiles ()
3837 if (_session == 0) {
3838 /* shouldn't happen: menu item is insensitive */
3842 if (! _session->can_cleanup_peakfiles ()) {
3846 // get all region-views in this session
3848 TrackViewList empty;
3850 editor->get_regions_after(rs, (framepos_t) 0, empty);
3851 std::list<RegionView*> views = rs.by_layer();
3853 // remove displayed audio-region-views waveforms
3854 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
3855 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
3856 if (!arv) { continue ; }
3857 arv->delete_waves();
3860 // cleanup peak files:
3861 // - stop pending peakfile threads
3862 // - close peakfiles if any
3863 // - remove peak dir in session
3864 // - setup peakfiles (background thread)
3865 _session->cleanup_peakfiles ();
3867 // re-add waves to ARV
3868 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
3869 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
3870 if (!arv) { continue ; }
3871 arv->create_waves();
3876 ARDOUR_UI::setup_order_hint (AddRouteDialog::InsertAt place)
3878 uint32_t order_hint = UINT32_MAX;
3880 if (editor->get_selection().tracks.empty()) {
3885 we want the new routes to have their order keys set starting from
3886 the highest order key in the selection + 1 (if available).
3889 if (place == AddRouteDialog::AfterSelection) {
3890 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.back());
3892 order_hint = rtav->route()->order_key();
3895 } else if (place == AddRouteDialog::BeforeSelection) {
3896 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.front());
3898 order_hint = rtav->route()->order_key();
3900 } else if (place == AddRouteDialog::First) {
3903 /* leave order_hint at UINT32_MAX */
3906 if (order_hint == UINT32_MAX) {
3907 /** AddRouteDialog::Last or selection with first/last not a RouteTimeAxisView
3908 * not setting an order hint will place new routes last.
3913 _session->set_order_hint (order_hint);
3915 /* create a gap in the existing route order keys to accomodate new routes.*/
3916 boost::shared_ptr <RouteList> rd = _session->get_routes();
3917 for (RouteList::iterator ri = rd->begin(); ri != rd->end(); ++ri) {
3918 boost::shared_ptr<Route> rt (*ri);
3920 if (rt->is_monitor()) {
3924 if (rt->order_key () >= order_hint) {
3925 rt->set_order_key (rt->order_key () + add_route_dialog->count());
3931 ARDOUR_UI::start_duplicate_routes ()
3933 if (!duplicate_routes_dialog) {
3934 duplicate_routes_dialog = new DuplicateRouteDialog;
3937 if (duplicate_routes_dialog->restart (_session)) {
3941 duplicate_routes_dialog->present ();
3945 ARDOUR_UI::add_route (Gtk::Window* /* ignored */)
3953 if (add_route_dialog->is_visible()) {
3954 /* we're already doing this */
3958 ResponseType r = (ResponseType) add_route_dialog->run ();
3960 add_route_dialog->hide();
3963 case RESPONSE_ACCEPT:
3970 if ((count = add_route_dialog->count()) <= 0) {
3974 setup_order_hint(add_route_dialog->insert_at());
3975 string template_path = add_route_dialog->track_template();
3976 DisplaySuspender ds;
3978 if (!template_path.empty()) {
3979 if (add_route_dialog->name_template_is_default()) {
3980 _session->new_route_from_template (count, template_path, string());
3982 _session->new_route_from_template (count, template_path, add_route_dialog->name_template());
3987 ChanCount input_chan= add_route_dialog->channels ();
3988 ChanCount output_chan;
3989 string name_template = add_route_dialog->name_template ();
3990 PluginInfoPtr instrument = add_route_dialog->requested_instrument ();
3991 RouteGroup* route_group = add_route_dialog->route_group ();
3992 AutoConnectOption oac = Config->get_output_auto_connect();
3993 bool strict_io = add_route_dialog->use_strict_io ();
3995 if (oac & AutoConnectMaster) {
3996 output_chan.set (DataType::AUDIO, (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan.n_audio()));
3997 output_chan.set (DataType::MIDI, 0);
3999 output_chan = input_chan;
4002 /* XXX do something with name template */
4004 switch (add_route_dialog->type_wanted()) {
4005 case AddRouteDialog::AudioTrack:
4006 session_add_audio_track (input_chan.n_audio(), output_chan.n_audio(), add_route_dialog->mode(), route_group, count, name_template, strict_io);
4008 case AddRouteDialog::MidiTrack:
4009 session_add_midi_track (route_group, count, name_template, strict_io, instrument);
4011 case AddRouteDialog::MixedTrack:
4012 session_add_mixed_track (input_chan, output_chan, route_group, count, name_template, strict_io, instrument);
4014 case AddRouteDialog::AudioBus:
4015 session_add_audio_bus (input_chan.n_audio(), output_chan.n_audio(), route_group, count, name_template, strict_io);
4017 case AddRouteDialog::MidiBus:
4018 session_add_midi_bus (route_group, count, name_template, strict_io, instrument);
4024 ARDOUR_UI::add_lua_script ()
4030 LuaScriptInfoPtr spi;
4031 ScriptSelector ss ("Add Lua Session Script", LuaScriptInfo::Session);
4032 switch (ss.run ()) {
4033 case Gtk::RESPONSE_ACCEPT:
4041 std::string script = "";
4044 script = Glib::file_get_contents (spi->path);
4045 } catch (Glib::FileError e) {
4046 string msg = string_compose (_("Cannot read session script '%1': %2"), spi->path, e.what());
4047 MessageDialog am (msg);
4052 LuaScriptParamList lsp = LuaScriptParams::script_params (spi, "sess_params");
4053 std::vector<std::string> reg = _session->registered_lua_functions ();
4055 ScriptParameterDialog spd (_("Set Script Parameters"), spi, reg, lsp);
4056 switch (spd.run ()) {
4057 case Gtk::RESPONSE_ACCEPT:
4064 _session->register_lua_function (spd.name(), script, lsp);
4065 } catch (luabridge::LuaException const& e) {
4066 string msg = string_compose (_("Session script '%1' instantiation failed: %2"), spd.name(), e.what ());
4067 MessageDialog am (msg);
4069 } catch (SessionException e) {
4070 string msg = string_compose (_("Loading Session script '%1' failed: %2"), spd.name(), e.what ());
4071 MessageDialog am (msg);
4077 ARDOUR_UI::remove_lua_script ()
4082 if (_session->registered_lua_function_count () == 0) {
4083 string msg = _("There are no active Lua session scripts present in this session.");
4084 MessageDialog am (msg);
4089 std::vector<std::string> reg = _session->registered_lua_functions ();
4090 SessionScriptManager sm ("Remove Lua Session Script", reg);
4091 switch (sm.run ()) {
4092 case Gtk::RESPONSE_ACCEPT:
4098 _session->unregister_lua_function (sm.name());
4099 } catch (luabridge::LuaException const& e) {
4100 string msg = string_compose (_("Session script '%1' removal failed: %2"), sm.name(), e.what ());
4101 MessageDialog am (msg);
4107 ARDOUR_UI::stop_video_server (bool ask_confirm)
4109 if (!video_server_process && ask_confirm) {
4110 warning << string_compose (_("Video-Server was not launched by %1. The request to stop it is ignored."), PROGRAM_NAME) << endmsg;
4112 if (video_server_process) {
4114 ArdourDialog confirm (_("Stop Video-Server"), true);
4115 Label m (_("Do you really want to stop the Video Server?"));
4116 confirm.get_vbox()->pack_start (m, true, true);
4117 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
4118 confirm.add_button (_("Yes, Stop It"), Gtk::RESPONSE_ACCEPT);
4119 confirm.show_all ();
4120 if (confirm.run() == RESPONSE_CANCEL) {
4124 delete video_server_process;
4125 video_server_process =0;
4130 ARDOUR_UI::start_video_server_menu (Gtk::Window* float_window)
4132 ARDOUR_UI::start_video_server( float_window, true);
4136 ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg)
4142 if (ARDOUR_UI::instance()->video_timeline->check_server()) {
4143 if (video_server_process) {
4144 popup_error(_("The Video Server is already started."));
4146 popup_error(_("An external Video Server is configured and can be reached. Not starting a new instance."));
4152 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4154 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4156 VideoServerDialog *video_server_dialog = new VideoServerDialog (_session);
4158 video_server_dialog->set_transient_for (*float_window);
4161 if (!Config->get_show_video_server_dialog() && firsttime < 2) {
4162 video_server_dialog->hide();
4164 ResponseType r = (ResponseType) video_server_dialog->run ();
4165 video_server_dialog->hide();
4166 if (r != RESPONSE_ACCEPT) { return false; }
4167 if (video_server_dialog->show_again()) {
4168 Config->set_show_video_server_dialog(false);
4172 std::string icsd_exec = video_server_dialog->get_exec_path();
4173 std::string icsd_docroot = video_server_dialog->get_docroot();
4174 if (icsd_docroot.empty()) {
4175 #ifndef PLATFORM_WINDOWS
4176 icsd_docroot = X_("/");
4178 icsd_docroot = X_("C:\\");
4183 if (g_lstat (icsd_docroot.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode)) {
4184 warning << _("Specified docroot is not an existing directory.") << endmsg;
4187 #ifndef PLATFORM_WINDOWS
4188 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4189 || (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0 ) {
4190 warning << _("Given Video Server is not an executable file.") << endmsg;
4194 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4195 || (sb.st_mode & (S_IXUSR)) == 0 ) {
4196 warning << _("Given Video Server is not an executable file.") << endmsg;
4202 argp=(char**) calloc(9,sizeof(char*));
4203 argp[0] = strdup(icsd_exec.c_str());
4204 argp[1] = strdup("-P");
4205 argp[2] = (char*) calloc(16,sizeof(char)); snprintf(argp[2], 16, "%s", video_server_dialog->get_listenaddr().c_str());
4206 argp[3] = strdup("-p");
4207 argp[4] = (char*) calloc(6,sizeof(char)); snprintf(argp[4], 6, "%i", video_server_dialog->get_listenport());
4208 argp[5] = strdup("-C");
4209 argp[6] = (char*) calloc(6,sizeof(char)); snprintf(argp[6], 6, "%i", video_server_dialog->get_cachesize());
4210 argp[7] = strdup(icsd_docroot.c_str());
4212 stop_video_server();
4214 if (icsd_docroot == X_("/") || icsd_docroot == X_("C:\\")) {
4215 Config->set_video_advanced_setup(false);
4217 std::ostringstream osstream;
4218 osstream << "http://127.0.0.1:" << video_server_dialog->get_listenport() << "/";
4219 Config->set_video_server_url(osstream.str());
4220 Config->set_video_server_docroot(icsd_docroot);
4221 Config->set_video_advanced_setup(true);
4224 if (video_server_process) {
4225 delete video_server_process;
4228 video_server_process = new ARDOUR::SystemExec(icsd_exec, argp);
4229 if (video_server_process->start()) {
4230 warning << _("Cannot launch the video-server") << endmsg;
4233 int timeout = 120; // 6 sec
4234 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4235 Glib::usleep (50000);
4237 if (--timeout <= 0 || !video_server_process->is_running()) break;
4240 warning << _("Video-server was started but does not respond to requests...") << endmsg;
4242 if (!ARDOUR_UI::instance()->video_timeline->check_server_docroot()) {
4243 delete video_server_process;
4244 video_server_process = 0;
4252 ARDOUR_UI::add_video (Gtk::Window* float_window)
4258 if (!start_video_server(float_window, false)) {
4259 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4264 add_video_dialog->set_transient_for (*float_window);
4267 if (add_video_dialog->is_visible()) {
4268 /* we're already doing this */
4272 ResponseType r = (ResponseType) add_video_dialog->run ();
4273 add_video_dialog->hide();
4274 if (r != RESPONSE_ACCEPT) { return; }
4276 bool local_file, orig_local_file;
4277 std::string path = add_video_dialog->file_name(local_file);
4279 std::string orig_path = path;
4280 orig_local_file = local_file;
4282 bool auto_set_session_fps = add_video_dialog->auto_set_session_fps();
4284 if (local_file && !Glib::file_test(path, Glib::FILE_TEST_EXISTS)) {
4285 warning << string_compose(_("could not open %1"), path) << endmsg;
4288 if (!local_file && path.length() == 0) {
4289 warning << _("no video-file selected") << endmsg;
4293 std::string audio_from_video;
4294 bool detect_ltc = false;
4296 switch (add_video_dialog->import_option()) {
4297 case VTL_IMPORT_TRANSCODE:
4299 TranscodeVideoDialog *transcode_video_dialog;
4300 transcode_video_dialog = new TranscodeVideoDialog (_session, path);
4301 ResponseType r = (ResponseType) transcode_video_dialog->run ();
4302 transcode_video_dialog->hide();
4303 if (r != RESPONSE_ACCEPT) {
4304 delete transcode_video_dialog;
4308 audio_from_video = transcode_video_dialog->get_audiofile();
4310 if (!audio_from_video.empty() && transcode_video_dialog->detect_ltc()) {
4313 else if (!audio_from_video.empty()) {
4314 editor->embed_audio_from_video(
4316 video_timeline->get_offset(),
4317 (transcode_video_dialog->import_option() != VTL_IMPORT_NO_VIDEO)
4320 switch (transcode_video_dialog->import_option()) {
4321 case VTL_IMPORT_TRANSCODED:
4322 path = transcode_video_dialog->get_filename();
4325 case VTL_IMPORT_REFERENCE:
4328 delete transcode_video_dialog;
4331 delete transcode_video_dialog;
4335 case VTL_IMPORT_NONE:
4339 /* strip _session->session_directory().video_path() from video file if possible */
4340 if (local_file && !path.compare(0, _session->session_directory().video_path().size(), _session->session_directory().video_path())) {
4341 path=path.substr(_session->session_directory().video_path().size());
4342 if (path.at(0) == G_DIR_SEPARATOR) {
4343 path=path.substr(1);
4347 video_timeline->set_update_session_fps(auto_set_session_fps);
4349 if (video_timeline->video_file_info(path, local_file)) {
4350 XMLNode* node = new XMLNode(X_("Videotimeline"));
4351 node->add_property (X_("Filename"), path);
4352 node->add_property (X_("AutoFPS"), auto_set_session_fps?X_("1"):X_("0"));
4353 node->add_property (X_("LocalFile"), local_file?X_("1"):X_("0"));
4354 if (orig_local_file) {
4355 node->add_property (X_("OriginalVideoFile"), orig_path);
4357 node->remove_property (X_("OriginalVideoFile"));
4359 _session->add_extra_xml (*node);
4360 _session->set_dirty ();
4362 if (!audio_from_video.empty() && detect_ltc) {
4363 std::vector<LTCFileReader::LTCMap> ltc_seq;
4366 /* TODO ask user about TV standard (LTC alignment if any) */
4367 LTCFileReader ltcr (audio_from_video, video_timeline->get_video_file_fps());
4368 /* TODO ASK user which channel: 0 .. ltcr->channels() - 1 */
4370 ltc_seq = ltcr.read_ltc (/*channel*/ 0, /*max LTC frames to decode*/ 15);
4372 /* TODO seek near end of file, and read LTC until end.
4373 * if it fails to find any LTC frames, scan complete file
4375 * calculate drift of LTC compared to video-duration,
4376 * ask user for reference (timecode from start/mid/end)
4379 // LTCFileReader will have written error messages
4382 ::g_unlink(audio_from_video.c_str());
4384 if (ltc_seq.size() == 0) {
4385 PBD::error << _("No LTC detected, video will not be aligned.") << endmsg;
4387 /* the very first TC in the file is somteimes not aligned properly */
4388 int i = ltc_seq.size() -1;
4389 ARDOUR::frameoffset_t video_start_offset =
4390 _session->nominal_frame_rate() * (ltc_seq[i].timecode_sec - ltc_seq[i].framepos_sec);
4391 PBD::info << string_compose (_("Align video-start to %1 [samples]"), video_start_offset) << endmsg;
4392 video_timeline->set_offset(video_start_offset);
4396 _session->maybe_update_session_range(
4397 std::max(video_timeline->get_offset(), (ARDOUR::frameoffset_t) 0),
4398 std::max(video_timeline->get_offset() + video_timeline->get_duration(), (ARDOUR::frameoffset_t) 0));
4401 if (add_video_dialog->launch_xjadeo() && local_file) {
4402 editor->set_xjadeo_sensitive(true);
4403 editor->toggle_xjadeo_proc(1);
4405 editor->toggle_xjadeo_proc(0);
4407 editor->toggle_ruler_video(true);
4412 ARDOUR_UI::remove_video ()
4414 video_timeline->close_session();
4415 editor->toggle_ruler_video(false);
4418 video_timeline->set_offset_locked(false);
4419 video_timeline->set_offset(0);
4421 /* delete session state */
4422 XMLNode* node = new XMLNode(X_("Videotimeline"));
4423 _session->add_extra_xml(*node);
4424 node = new XMLNode(X_("Videomonitor"));
4425 _session->add_extra_xml(*node);
4426 node = new XMLNode(X_("Videoexport"));
4427 _session->add_extra_xml(*node);
4428 stop_video_server();
4432 ARDOUR_UI::flush_videotimeline_cache (bool localcacheonly)
4434 if (localcacheonly) {
4435 video_timeline->vmon_update();
4437 video_timeline->flush_cache();
4439 editor->queue_visual_videotimeline_update();
4443 ARDOUR_UI::export_video (bool range)
4445 if (ARDOUR::Config->get_show_video_export_info()) {
4446 ExportVideoInfobox infobox (_session);
4447 Gtk::ResponseType rv = (Gtk::ResponseType) infobox.run();
4448 if (infobox.show_again()) {
4449 ARDOUR::Config->set_show_video_export_info(false);
4452 case GTK_RESPONSE_YES:
4453 PBD::open_uri (ARDOUR::Config->get_reference_manual_url() + "/video-timeline/operations/#export");
4459 export_video_dialog->set_session (_session);
4460 export_video_dialog->apply_state(editor->get_selection().time, range);
4461 export_video_dialog->run ();
4462 export_video_dialog->hide ();
4466 ARDOUR_UI::mixer_settings () const
4471 node = _session->instant_xml(X_("Mixer"));
4473 node = Config->instant_xml(X_("Mixer"));
4477 node = new XMLNode (X_("Mixer"));
4484 ARDOUR_UI::main_window_settings () const
4489 node = _session->instant_xml(X_("Main"));
4491 node = Config->instant_xml(X_("Main"));
4495 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4496 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4501 node = new XMLNode (X_("Main"));
4508 ARDOUR_UI::editor_settings () const
4513 node = _session->instant_xml(X_("Editor"));
4515 node = Config->instant_xml(X_("Editor"));
4519 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4520 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4525 node = new XMLNode (X_("Editor"));
4532 ARDOUR_UI::keyboard_settings () const
4536 node = Config->extra_xml(X_("Keyboard"));
4539 node = new XMLNode (X_("Keyboard"));
4546 ARDOUR_UI::create_xrun_marker (framepos_t where)
4549 Location *location = new Location (*_session, where, where, _("xrun"), Location::IsMark);
4550 _session->locations()->add (location);
4555 ARDOUR_UI::halt_on_xrun_message ()
4557 cerr << "HALT on xrun\n";
4558 MessageDialog msg (_main_window, _("Recording was stopped because your system could not keep up."));
4563 ARDOUR_UI::xrun_handler (framepos_t where)
4569 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
4571 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
4572 create_xrun_marker(where);
4575 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
4576 halt_on_xrun_message ();
4581 ARDOUR_UI::disk_overrun_handler ()
4583 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
4585 if (!have_disk_speed_dialog_displayed) {
4586 have_disk_speed_dialog_displayed = true;
4587 MessageDialog* msg = new MessageDialog (_main_window, string_compose (_("\
4588 The disk system on your computer\n\
4589 was not able to keep up with %1.\n\
4591 Specifically, it failed to write data to disk\n\
4592 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
4593 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4599 /* TODO: this is getting elaborate enough to warrant being split into a dedicated class */
4600 static MessageDialog *scan_dlg = NULL;
4601 static ProgressBar *scan_pbar = NULL;
4602 static HBox *scan_tbox = NULL;
4603 static Gtk::Button *scan_timeout_button;
4606 ARDOUR_UI::cancel_plugin_scan ()
4608 PluginManager::instance().cancel_plugin_scan();
4612 ARDOUR_UI::cancel_plugin_timeout ()
4614 PluginManager::instance().cancel_plugin_timeout();
4615 scan_timeout_button->set_sensitive (false);
4619 ARDOUR_UI::plugin_scan_timeout (int timeout)
4621 if (!scan_dlg || !scan_dlg->is_mapped() || !scan_pbar) {
4625 scan_pbar->set_sensitive (false);
4626 scan_timeout_button->set_sensitive (true);
4627 scan_pbar->set_fraction ((float) timeout / (float) Config->get_vst_scan_timeout());
4630 scan_pbar->set_sensitive (false);
4631 scan_timeout_button->set_sensitive (false);
4637 ARDOUR_UI::plugin_scan_dialog (std::string type, std::string plugin, bool can_cancel)
4639 if (type == X_("closeme") && !(scan_dlg && scan_dlg->is_mapped())) {
4643 const bool cancelled = PluginManager::instance().cancelled();
4644 if (type != X_("closeme") && (!UIConfiguration::instance().get_show_plugin_scan_window()) && !_initial_verbose_plugin_scan) {
4645 if (cancelled && scan_dlg->is_mapped()) {
4650 if (cancelled || !can_cancel) {
4655 static Gtk::Button *cancel_button;
4657 scan_dlg = new MessageDialog("", false, MESSAGE_INFO, BUTTONS_NONE); // TODO manage
4658 VBox* vbox = scan_dlg->get_vbox();
4659 vbox->set_size_request(400,-1);
4660 scan_dlg->set_title (_("Scanning for plugins"));
4662 cancel_button = manage(new Gtk::Button(_("Cancel plugin scan")));
4663 cancel_button->set_name ("EditorGTKButton");
4664 cancel_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_scan) );
4665 cancel_button->show();
4667 scan_dlg->get_vbox()->pack_start ( *cancel_button, PACK_SHRINK);
4669 scan_tbox = manage( new HBox() );
4671 scan_timeout_button = manage(new Gtk::Button(_("Stop Timeout")));
4672 scan_timeout_button->set_name ("EditorGTKButton");
4673 scan_timeout_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_timeout) );
4674 scan_timeout_button->show();
4676 scan_pbar = manage(new ProgressBar());
4677 scan_pbar->set_orientation(Gtk::PROGRESS_RIGHT_TO_LEFT);
4678 scan_pbar->set_text(_("Scan Timeout"));
4681 scan_tbox->pack_start (*scan_pbar, PACK_EXPAND_WIDGET, 4);
4682 scan_tbox->pack_start (*scan_timeout_button, PACK_SHRINK, 4);
4684 scan_dlg->get_vbox()->pack_start (*scan_tbox, PACK_SHRINK, 4);
4687 assert(scan_dlg && scan_tbox && cancel_button);
4689 if (type == X_("closeme")) {
4693 scan_dlg->set_message(type + ": " + Glib::path_get_basename(plugin));
4696 if (!can_cancel || !cancelled) {
4697 scan_timeout_button->set_sensitive(false);
4699 cancel_button->set_sensitive(can_cancel && !cancelled);
4705 ARDOUR_UI::gui_idle_handler ()
4708 /* due to idle calls, gtk_events_pending() may always return true */
4709 while (gtk_events_pending() && --timeout) {
4710 gtk_main_iteration ();
4715 ARDOUR_UI::disk_underrun_handler ()
4717 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
4719 if (!have_disk_speed_dialog_displayed) {
4720 have_disk_speed_dialog_displayed = true;
4721 MessageDialog* msg = new MessageDialog (
4722 _main_window, string_compose (_("The disk system on your computer\n\
4723 was not able to keep up with %1.\n\
4725 Specifically, it failed to read data from disk\n\
4726 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
4727 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4733 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
4735 have_disk_speed_dialog_displayed = false;
4740 ARDOUR_UI::session_dialog (std::string msg)
4742 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
4746 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
4753 ARDOUR_UI::pending_state_dialog ()
4755 HBox* hbox = manage (new HBox());
4756 Image* image = manage (new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG));
4757 ArdourDialog dialog (_("Crash Recovery"), true);
4758 Label message (string_compose (_("\
4759 This session appears to have been in the\n\
4760 middle of recording when %1 or\n\
4761 the computer was shutdown.\n\
4763 %1 can recover any captured audio for\n\
4764 you, or it can ignore it. Please decide\n\
4765 what you would like to do.\n"), PROGRAM_NAME));
4766 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4767 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4768 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4769 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4770 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
4771 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
4772 dialog.set_default_response (RESPONSE_ACCEPT);
4773 dialog.set_position (WIN_POS_CENTER);
4778 switch (dialog.run ()) {
4779 case RESPONSE_ACCEPT:
4787 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
4789 HBox* hbox = new HBox();
4790 Image* image = new Image (Stock::DIALOG_WARNING, ICON_SIZE_DIALOG);
4791 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
4792 Label message (string_compose (_("\
4793 This session was created with a sample rate of %1 Hz, but\n\
4794 %2 is currently running at %3 Hz. If you load this session,\n\
4795 audio may be played at the wrong sample rate.\n"), desired, PROGRAM_NAME, actual));
4797 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4798 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4799 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4800 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4801 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
4802 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
4803 dialog.set_default_response (RESPONSE_ACCEPT);
4804 dialog.set_position (WIN_POS_CENTER);
4809 switch (dialog.run()) {
4810 case RESPONSE_ACCEPT:
4820 ARDOUR_UI::sr_mismatch_message (framecnt_t desired, framecnt_t actual)
4822 MessageDialog msg (string_compose (_("\
4823 This session was created with a sample rate of %1 Hz, but\n\
4824 %2 is currently running at %3 Hz.\n\
4825 Audio will be recorded and played at the wrong sample rate.\n\
4826 Re-Configure the Audio Engine in\n\
4827 Menu > Window > Audio/Midi Setup"),
4828 desired, PROGRAM_NAME, actual),
4830 Gtk::MESSAGE_WARNING);
4835 ARDOUR_UI::use_config ()
4837 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
4839 set_transport_controllable_state (*node);
4844 ARDOUR_UI::update_transport_clocks (framepos_t pos)
4846 if (UIConfiguration::instance().get_primary_clock_delta_edit_cursor()) {
4847 primary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
4849 primary_clock->set (pos);
4852 if (UIConfiguration::instance().get_secondary_clock_delta_edit_cursor()) {
4853 secondary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
4855 secondary_clock->set (pos);
4858 if (big_clock_window) {
4859 big_clock->set (pos);
4861 ARDOUR_UI::instance()->video_timeline->manual_seek_video_monitor(pos);
4865 ARDOUR_UI::step_edit_status_change (bool yn)
4867 // XXX should really store pre-step edit status of things
4868 // we make insensitive
4871 rec_button.set_active_state (Gtkmm2ext::ImplicitActive);
4872 rec_button.set_sensitive (false);
4874 rec_button.unset_active_state ();;
4875 rec_button.set_sensitive (true);
4880 ARDOUR_UI::record_state_changed ()
4882 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
4884 if (!_session || !big_clock_window) {
4885 /* why bother - the clock isn't visible */
4889 if (_session->record_status () == Session::Recording && _session->have_rec_enabled_track ()) {
4890 big_clock->set_active (true);
4892 big_clock->set_active (false);
4897 ARDOUR_UI::first_idle ()
4900 _session->allow_auto_play (true);
4904 editor->first_idle();
4907 Keyboard::set_can_save_keybindings (true);
4912 ARDOUR_UI::store_clock_modes ()
4914 XMLNode* node = new XMLNode(X_("ClockModes"));
4916 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
4917 XMLNode* child = new XMLNode (X_("Clock"));
4919 child->add_property (X_("name"), (*x)->name());
4920 child->add_property (X_("mode"), enum_2_string ((*x)->mode()));
4921 child->add_property (X_("on"), ((*x)->off() ? X_("no") : X_("yes")));
4923 node->add_child_nocopy (*child);
4926 _session->add_extra_xml (*node);
4927 _session->set_dirty ();
4930 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
4931 : Controllable (name), ui (u), type(tp)
4937 ARDOUR_UI::TransportControllable::set_value (double val, PBD::Controllable::GroupControlDisposition /*group_override*/)
4940 /* do nothing: these are radio-style actions */
4944 const char *action = 0;
4948 action = X_("Roll");
4951 action = X_("Stop");
4954 action = X_("GotoStart");
4957 action = X_("GotoEnd");
4960 action = X_("Loop");
4963 action = X_("PlaySelection");
4966 action = X_("Record");
4976 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
4984 ARDOUR_UI::TransportControllable::get_value (void) const
5011 ARDOUR_UI::setup_profile ()
5013 if (gdk_screen_width() < 1200 || getenv ("ARDOUR_NARROW_SCREEN")) {
5014 Profile->set_small_screen ();
5017 if (g_getenv ("TRX")) {
5018 Profile->set_trx ();
5021 if (g_getenv ("MIXBUS")) {
5022 Profile->set_mixbus ();
5027 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
5029 MissingFileDialog dialog (s, str, type);
5034 int result = dialog.run ();
5041 return 1; // quit entire session load
5044 result = dialog.get_action ();
5050 ARDOUR_UI::ambiguous_file (std::string file, std::vector<std::string> hits)
5052 AmbiguousFileDialog dialog (file, hits);
5059 return dialog.get_which ();
5062 /** Allocate our thread-local buffers */
5064 ARDOUR_UI::get_process_buffers ()
5066 _process_thread->get_buffers ();
5069 /** Drop our thread-local buffers */
5071 ARDOUR_UI::drop_process_buffers ()
5073 _process_thread->drop_buffers ();
5077 ARDOUR_UI::feedback_detected ()
5079 _feedback_exists = true;
5083 ARDOUR_UI::successful_graph_sort ()
5085 _feedback_exists = false;
5089 ARDOUR_UI::midi_panic ()
5092 _session->midi_panic();
5097 ARDOUR_UI::session_format_mismatch (std::string xml_path, std::string backup_path)
5099 const char* start_big = "<span size=\"x-large\" weight=\"bold\">";
5100 const char* end_big = "</span>";
5101 const char* start_mono = "<tt>";
5102 const char* end_mono = "</tt>";
5104 MessageDialog msg (string_compose (_("%4This is a session from an older version of %3%5\n\n"
5105 "%3 has copied the old session file\n\n%6%1%7\n\nto\n\n%6%2%7\n\n"
5106 "From now on, use the -2000 version with older versions of %3"),
5107 xml_path, backup_path, PROGRAM_NAME,
5109 start_mono, end_mono), true);
5116 ARDOUR_UI::reset_peak_display ()
5118 if (!_session || !_session->master_out() || !editor_meter) return;
5119 editor_meter->clear_meters();
5120 editor_meter_max_peak = -INFINITY;
5121 editor_meter_peak_display.set_active_state ( Gtkmm2ext::Off );
5125 ARDOUR_UI::reset_group_peak_display (RouteGroup* group)
5127 if (!_session || !_session->master_out()) return;
5128 if (group == _session->master_out()->route_group()) {
5129 reset_peak_display ();
5134 ARDOUR_UI::reset_route_peak_display (Route* route)
5136 if (!_session || !_session->master_out()) return;
5137 if (_session->master_out().get() == route) {
5138 reset_peak_display ();
5143 ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate)
5145 audio_midi_setup->set_desired_sample_rate (desired_sample_rate);
5146 audio_midi_setup->set_position (WIN_POS_CENTER);
5148 if (Config->get_try_autostart_engine () || getenv ("TRY_AUTOSTART_ENGINE")) {
5149 audio_midi_setup->try_autostart ();
5150 if (ARDOUR::AudioEngine::instance()->running()) {
5156 int response = audio_midi_setup->run();
5158 case Gtk::RESPONSE_OK:
5159 if (!AudioEngine::instance()->running()) {
5173 ARDOUR_UI::transport_numpad_timeout ()
5175 _numpad_locate_happening = false;
5176 if (_numpad_timeout_connection.connected() )
5177 _numpad_timeout_connection.disconnect();
5182 ARDOUR_UI::transport_numpad_decimal ()
5184 _numpad_timeout_connection.disconnect();
5186 if (_numpad_locate_happening) {
5187 if (editor) editor->goto_nth_marker(_pending_locate_num - 1);
5188 _numpad_locate_happening = false;
5190 _pending_locate_num = 0;
5191 _numpad_locate_happening = true;
5192 _numpad_timeout_connection = Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::transport_numpad_timeout), 2*1000);
5197 ARDOUR_UI::transport_numpad_event (int num)
5199 if ( _numpad_locate_happening ) {
5200 _pending_locate_num = _pending_locate_num*10 + num;
5203 case 0: toggle_roll(false, false); break;
5204 case 1: transport_rewind(1); break;
5205 case 2: transport_forward(1); break;
5206 case 3: transport_record(true); break;
5207 case 4: toggle_session_auto_loop(); break;
5208 case 5: transport_record(false); toggle_session_auto_loop(); break;
5209 case 6: toggle_punch(); break;
5210 case 7: toggle_click(); break;
5211 case 8: toggle_auto_return(); break;
5212 case 9: toggle_follow_edits(); break;
5218 ARDOUR_UI::set_flat_buttons ()
5220 CairoWidget::set_flat_buttons( UIConfiguration::instance().get_flat_buttons() );
5224 ARDOUR_UI::audioengine_became_silent ()
5226 MessageDialog msg (string_compose (_("This is a free/demo copy of %1. It has just switched to silent mode."), PROGRAM_NAME),
5228 Gtk::MESSAGE_WARNING,
5232 msg.set_title (string_compose (_("%1 is now silent"), PROGRAM_NAME));
5234 Gtk::Label pay_label (string_compose (_("Please consider paying for a copy of %1 - you can pay whatever you want."), PROGRAM_NAME));
5235 Gtk::Label subscribe_label (_("Better yet become a subscriber - subscriptions start at US$1 per month."));
5236 Gtk::Button pay_button (_("Pay for a copy (via the web)"));
5237 Gtk::Button subscribe_button (_("Become a subscriber (via the web)"));
5238 Gtk::HBox pay_button_box;
5239 Gtk::HBox subscribe_button_box;
5241 pay_button_box.pack_start (pay_button, true, false);
5242 subscribe_button_box.pack_start (subscribe_button, true, false);
5244 bool (*openuri)(const char*) = PBD::open_uri; /* this forces selection of the const char* variant of PBD::open_uri(), which we need to avoid ambiguity below */
5246 pay_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://ardour.org/download")));
5247 subscribe_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://community.ardour.org/s/subscribe")));
5249 msg.get_vbox()->pack_start (pay_label);
5250 msg.get_vbox()->pack_start (pay_button_box);
5251 msg.get_vbox()->pack_start (subscribe_label);
5252 msg.get_vbox()->pack_start (subscribe_button_box);
5254 msg.get_vbox()->show_all ();
5256 msg.add_button (_("Remain silent"), Gtk::RESPONSE_CANCEL);
5257 msg.add_button (_("Save and quit"), Gtk::RESPONSE_NO);
5258 msg.add_button (_("Give me more time"), Gtk::RESPONSE_YES);
5263 case Gtk::RESPONSE_YES:
5264 AudioEngine::instance()->reset_silence_countdown ();
5267 case Gtk::RESPONSE_NO:
5269 save_state_canfail ("");
5273 case Gtk::RESPONSE_CANCEL:
5275 /* don't reset, save session and exit */
5281 ARDOUR_UI::hide_application ()
5283 Application::instance ()-> hide ();
5287 ARDOUR_UI::setup_toplevel_window (Gtk::Window& window, const string& name, void* owner)
5289 /* icons, titles, WM stuff */
5291 static list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
5293 if (window_icons.empty()) {
5294 Glib::RefPtr<Gdk::Pixbuf> icon;
5295 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
5296 window_icons.push_back (icon);
5298 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
5299 window_icons.push_back (icon);
5301 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
5302 window_icons.push_back (icon);
5304 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
5305 window_icons.push_back (icon);
5309 if (!window_icons.empty()) {
5310 window.set_default_icon_list (window_icons);
5313 Gtkmm2ext::WindowTitle title (Glib::get_application_name());
5315 if (!name.empty()) {
5319 window.set_title (title.get_string());
5320 window.set_wmclass (string_compose (X_("%1_%1"), downcase (PROGRAM_NAME), downcase (name)), PROGRAM_NAME);
5322 window.set_flags (CAN_FOCUS);
5323 window.add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
5325 /* This is a hack to ensure that GTK-accelerators continue to
5326 * work. Once we switch over to entirely native bindings, this will be
5327 * unnecessary and should be removed
5329 window.add_accel_group (ActionManager::ui_manager->get_accel_group());
5331 window.signal_configure_event().connect (sigc::mem_fun (*this, &ARDOUR_UI::configure_handler));
5332 window.signal_window_state_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::tabbed_window_state_event_handler), owner));
5333 window.signal_key_press_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5334 window.signal_key_release_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5338 ARDOUR_UI::key_event_handler (GdkEventKey* ev, Gtk::Window* event_window)
5340 Gtkmm2ext::Bindings* bindings = 0;
5341 Gtk::Window* window = 0;
5343 /* until we get ardour bindings working, we are not handling key
5347 if (ev->type != GDK_KEY_PRESS) {
5351 if (event_window == &_main_window) {
5353 window = event_window;
5355 /* find current tab contents */
5357 Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page());
5359 /* see if it uses the ardour binding system */
5362 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(w->get_data ("ardour-bindings"));
5365 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("main window key event, bindings = %1, global = %2\n", bindings, &global_bindings));
5369 window = event_window;
5371 /* see if window uses ardour binding system */
5373 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(window->get_data ("ardour-bindings"));
5376 /* An empty binding set is treated as if it doesn't exist */
5378 if (bindings && bindings->empty()) {
5382 return key_press_focus_accelerator_handler (*window, ev, bindings);
5385 static Gtkmm2ext::Bindings*
5386 get_bindings_from_widget_heirarchy (GtkWidget* w)
5391 if ((p = g_object_get_data (G_OBJECT(w), "ardour-bindings")) != 0) {
5394 w = gtk_widget_get_parent (w);
5397 return reinterpret_cast<Gtkmm2ext::Bindings*> (p);
5401 ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev, Gtkmm2ext::Bindings* bindings)
5403 GtkWindow* win = window.gobj();
5404 GtkWidget* focus = gtk_window_get_focus (win);
5405 bool special_handling_of_unmodified_accelerators = false;
5406 const guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK));
5410 /* some widget has keyboard focus */
5412 if (GTK_IS_ENTRY(focus) || Keyboard::some_magic_widget_has_focus()) {
5414 /* A particular kind of focusable widget currently has keyboard
5415 * focus. All unmodified key events should go to that widget
5416 * first and not be used as an accelerator by default
5419 special_handling_of_unmodified_accelerators = true;
5423 Gtkmm2ext::Bindings* focus_bindings = get_bindings_from_widget_heirarchy (focus);
5424 if (focus_bindings) {
5425 bindings = focus_bindings;
5426 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Switch bindings based on focus widget, now using %1\n", bindings->name()));
5431 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Win = %1 [title = %9] focus = %7 (%8) Key event: code = %2 state = %3 special handling ? %4 magic widget focus ? %5 focus widget %6 named %7 mods ? %8\n",
5434 show_gdk_event_state (ev->state),
5435 special_handling_of_unmodified_accelerators,
5436 Keyboard::some_magic_widget_has_focus(),
5438 (focus ? gtk_widget_get_name (focus) : "no focus widget"),
5439 ((ev->state & mask) ? "yes" : "no"),
5440 window.get_title()));
5442 /* This exists to allow us to override the way GTK handles
5443 key events. The normal sequence is:
5445 a) event is delivered to a GtkWindow
5446 b) accelerators/mnemonics are activated
5447 c) if (b) didn't handle the event, propagate to
5448 the focus widget and/or focus chain
5450 The problem with this is that if the accelerators include
5451 keys without modifiers, such as the space bar or the
5452 letter "e", then pressing the key while typing into
5453 a text entry widget results in the accelerator being
5454 activated, instead of the desired letter appearing
5457 There is no good way of fixing this, but this
5458 represents a compromise. The idea is that
5459 key events involving modifiers (not Shift)
5460 get routed into the activation pathway first, then
5461 get propagated to the focus widget if necessary.
5463 If the key event doesn't involve modifiers,
5464 we deliver to the focus widget first, thus allowing
5465 it to get "normal text" without interference
5468 Of course, this can also be problematic: if there
5469 is a widget with focus, then it will swallow
5470 all "normal text" accelerators.
5474 if (!special_handling_of_unmodified_accelerators || (ev->state & mask)) {
5476 /* no special handling or there are modifiers in effect: accelerate first */
5478 DEBUG_TRACE (DEBUG::Accelerators, "\tactivate, then propagate\n");
5479 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tevent send-event:%1 time:%2 length:%3 name %7 string:%4 hardware_keycode:%5 group:%6\n",
5480 ev->send_event, ev->time, ev->length, ev->string, ev->hardware_keycode, ev->group, gdk_keyval_name (ev->keyval)));
5482 DEBUG_TRACE (DEBUG::Accelerators, "\tsending to window\n");
5483 KeyboardKey k (ev->state, ev->keyval);
5487 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tusing Ardour bindings %1 @ %2 for this event\n", bindings->name(), bindings));
5489 if (bindings->activate (k, Bindings::Press)) {
5490 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5495 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5497 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5498 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5502 DEBUG_TRACE (DEBUG::Accelerators, "\tnot accelerated, now propagate\n");
5504 if (gtk_window_propagate_key_event (win, ev)) {
5505 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate handled\n");
5511 /* no modifiers, propagate first */
5513 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate, then activate\n");
5515 if (gtk_window_propagate_key_event (win, ev)) {
5516 DEBUG_TRACE (DEBUG::Accelerators, "\thandled by propagate\n");
5520 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagation didn't handle, so activate\n");
5521 KeyboardKey k (ev->state, ev->keyval);
5525 DEBUG_TRACE (DEBUG::Accelerators, "\tusing Ardour bindings for this window\n");
5528 if (bindings->activate (k, Bindings::Press)) {
5529 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5535 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5537 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5538 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5543 DEBUG_TRACE (DEBUG::Accelerators, "\tnot handled\n");
5548 ARDOUR_UI::load_bindings ()
5550 if ((global_bindings = Bindings::get_bindings (X_("Global"), global_actions)) == 0) {
5551 error << _("Global keybindings are missing") << endmsg;
5556 ARDOUR_UI::cancel_solo ()
5559 if (_session->soloing()) {
5560 _session->set_solo (_session->get_routes(), false);
5561 } else if (_session->listening()) {
5562 _session->set_listen (_session->get_routes(), false);
5565 _session->clear_all_solo_state (_session->get_routes()); // safeguard, ideally this won't do anything, check the log-window