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", "");
229 if (err->file && err->line) {
230 error << X_("XML error: ") << msg << " in " << err->file << " at line " << err->line;
233 error << ':' << err->int2;
240 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
241 : Gtkmm2ext::UI (PROGRAM_NAME, X_("gui"), argcp, argvp)
242 , session_loaded (false)
243 , gui_object_state (new GUIObjectState)
244 , primary_clock (new MainClock (X_("primary"), X_("transport"), true ))
245 , secondary_clock (new MainClock (X_("secondary"), X_("secondary"), false))
246 , big_clock (new AudioClock (X_("bigclock"), false, "big", true, true, false, false))
248 , global_actions (X_("global"))
249 , ignore_dual_punch (false)
254 , _mixer_on_top (false)
255 , _initial_verbose_plugin_scan (false)
256 , first_time_engine_run (true)
257 , roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll))
258 , stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop))
259 , goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart))
260 , goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd))
261 , auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop))
262 , play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection))
263 , rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable))
264 , auto_return_button (ArdourButton::led_default_elements)
265 , follow_edits_button (ArdourButton::led_default_elements)
266 , auto_input_button (ArdourButton::led_default_elements)
267 , auditioning_alert_button (_("Audition"))
268 , solo_alert_button (_("Solo"))
269 , feedback_alert_button (_("Feedback"))
270 , error_alert_button ( ArdourButton::just_led_default_elements )
272 , editor_meter_peak_display()
273 , _numpad_locate_happening (false)
274 , _session_is_new (false)
275 , last_key_press_time (0)
279 , rc_option_editor (0)
280 , speaker_config_window (X_("speaker-config"), _("Speaker Configuration"))
281 , add_route_dialog (X_("add-routes"), _("Add Tracks/Busses"))
282 , about (X_("about"), _("About"))
283 , location_ui (X_("locations"), _("Locations"))
284 , route_params (X_("inspector"), _("Tracks and Busses"))
285 , audio_midi_setup (X_("audio-midi-setup"), _("Audio/MIDI Setup"))
286 , export_video_dialog (X_("video-export"), _("Video Export Dialog"))
287 , lua_script_window (X_("script-manager"), _("Script Manager"))
288 , session_option_editor (X_("session-options-editor"), _("Properties"), boost::bind (&ARDOUR_UI::create_session_option_editor, this))
289 , add_video_dialog (X_("add-video"), _("Add Video"), boost::bind (&ARDOUR_UI::create_add_video_dialog, this))
290 , bundle_manager (X_("bundle-manager"), _("Bundle Manager"), boost::bind (&ARDOUR_UI::create_bundle_manager, this))
291 , big_clock_window (X_("big-clock"), _("Big Clock"), boost::bind (&ARDOUR_UI::create_big_clock_window, this))
292 , audio_port_matrix (X_("audio-connection-manager"), _("Audio Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::AUDIO))
293 , midi_port_matrix (X_("midi-connection-manager"), _("MIDI Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::MIDI))
294 , key_editor (X_("key-editor"), _("Bindings Editor"), boost::bind (&ARDOUR_UI::create_key_editor, this))
295 , video_server_process (0)
297 , have_configure_timeout (false)
298 , last_configure_time (0)
300 , have_disk_speed_dialog_displayed (false)
301 , _status_bar_visibility (X_("status-bar"))
302 , _feedback_exists (false)
303 , _log_not_acknowledged (LogLevelNone)
304 , duplicate_routes_dialog (0)
305 , editor_visibility_button (S_("Window|Editor"))
306 , mixer_visibility_button (S_("Window|Mixer"))
307 , prefs_visibility_button (S_("Window|Preferences"))
309 Gtkmm2ext::init (localedir);
311 UIConfiguration::instance().post_gui_init ();
313 if (ARDOUR::handle_old_configuration_files (boost::bind (ask_about_configuration_copy, _1, _2, _3))) {
314 MessageDialog msg (string_compose (_("Your configuration files were copied. You can now restart %1."), PROGRAM_NAME), true);
316 /* configuration was modified, exit immediately */
320 if (theArdourUI == 0) {
324 /* stop libxml from spewing to stdout/stderr */
326 xmlSetGenericErrorFunc (this, libxml_generic_error_func);
327 xmlSetStructuredErrorFunc (this, libxml_structured_error_func);
329 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::parameter_changed));
330 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
331 UIConfiguration::instance().map_parameters (pc);
333 roll_button.set_controllable (roll_controllable);
334 stop_button.set_controllable (stop_controllable);
335 goto_start_button.set_controllable (goto_start_controllable);
336 goto_end_button.set_controllable (goto_end_controllable);
337 auto_loop_button.set_controllable (auto_loop_controllable);
338 play_selection_button.set_controllable (play_selection_controllable);
339 rec_button.set_controllable (rec_controllable);
341 roll_button.set_name ("transport button");
342 stop_button.set_name ("transport button");
343 goto_start_button.set_name ("transport button");
344 goto_end_button.set_name ("transport button");
345 auto_loop_button.set_name ("transport button");
346 play_selection_button.set_name ("transport button");
347 rec_button.set_name ("transport recenable button");
348 midi_panic_button.set_name ("transport button");
350 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
351 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
353 ARDOUR::Session::VersionMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_format_mismatch, this, _1, _2), gui_context());
355 /* handle dialog requests */
357 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
359 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
361 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
363 /* handle Audio/MIDI setup when session requires it */
365 ARDOUR::Session::AudioEngineSetupRequired.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::do_audio_midi_setup, this, _1));
367 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
369 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
371 /* handle requests to quit (coming from JACK session) */
373 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::finish, this), gui_context ());
375 /* tell the user about feedback */
377 ARDOUR::Session::FeedbackDetected.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::feedback_detected, this), gui_context ());
378 ARDOUR::Session::SuccessfulGraphSort.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::successful_graph_sort, this), gui_context ());
380 /* handle requests to deal with missing files */
382 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
384 /* and ambiguous files */
386 ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2));
388 /* also plugin scan messages */
389 ARDOUR::PluginScanMessage.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_dialog, this, _1, _2, _3), gui_context());
390 ARDOUR::PluginScanTimeout.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_timeout, this, _1), gui_context());
392 ARDOUR::GUIIdle.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::gui_idle_handler, this), gui_context());
394 Config->ParameterChanged.connect ( forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::set_flat_buttons, this), gui_context() );
397 /* lets get this party started */
399 setup_gtk_ardour_enums ();
402 SessionEvent::create_per_thread_pool ("GUI", 4096);
404 /* we like keyboards */
406 keyboard = new ArdourKeyboard(*this);
408 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
410 keyboard->set_state (*node, Stateful::loading_state_version);
413 UIConfiguration::instance().reset_dpi ();
415 TimeAxisViewItem::set_constant_heights ();
417 /* Set this up so that our window proxies can register actions */
419 ActionManager::init ();
421 /* The following must happen after ARDOUR::init() so that Config is set up */
423 const XMLNode* ui_xml = Config->extra_xml (X_("UI"));
426 key_editor.set_state (*ui_xml, 0);
427 session_option_editor.set_state (*ui_xml, 0);
428 speaker_config_window.set_state (*ui_xml, 0);
429 about.set_state (*ui_xml, 0);
430 add_route_dialog.set_state (*ui_xml, 0);
431 add_video_dialog.set_state (*ui_xml, 0);
432 route_params.set_state (*ui_xml, 0);
433 bundle_manager.set_state (*ui_xml, 0);
434 location_ui.set_state (*ui_xml, 0);
435 big_clock_window.set_state (*ui_xml, 0);
436 audio_port_matrix.set_state (*ui_xml, 0);
437 midi_port_matrix.set_state (*ui_xml, 0);
438 export_video_dialog.set_state (*ui_xml, 0);
439 lua_script_window.set_state (*ui_xml, 0);
442 /* Separate windows */
444 WM::Manager::instance().register_window (&key_editor);
445 WM::Manager::instance().register_window (&session_option_editor);
446 WM::Manager::instance().register_window (&speaker_config_window);
447 WM::Manager::instance().register_window (&about);
448 WM::Manager::instance().register_window (&add_route_dialog);
449 WM::Manager::instance().register_window (&add_video_dialog);
450 WM::Manager::instance().register_window (&route_params);
451 WM::Manager::instance().register_window (&audio_midi_setup);
452 WM::Manager::instance().register_window (&export_video_dialog);
453 WM::Manager::instance().register_window (&lua_script_window);
454 WM::Manager::instance().register_window (&bundle_manager);
455 WM::Manager::instance().register_window (&location_ui);
456 WM::Manager::instance().register_window (&big_clock_window);
457 WM::Manager::instance().register_window (&audio_port_matrix);
458 WM::Manager::instance().register_window (&midi_port_matrix);
460 /* Trigger setting up the color scheme and loading the GTK RC file */
462 UIConfiguration::instance().load_rc_file (false);
464 _process_thread = new ProcessThread ();
465 _process_thread->init ();
467 UIConfiguration::instance().DPIReset.connect (sigc::mem_fun (*this, &ARDOUR_UI::resize_text_widgets));
472 GlobalPortMatrixWindow*
473 ARDOUR_UI::create_global_port_matrix (ARDOUR::DataType type)
478 return new GlobalPortMatrixWindow (_session, type);
482 ARDOUR_UI::attach_to_engine ()
484 AudioEngine::instance()->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
485 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
489 ARDOUR_UI::engine_stopped ()
491 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
492 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
493 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
494 update_sample_rate (0);
499 ARDOUR_UI::engine_running ()
501 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
502 if (first_time_engine_run) {
504 first_time_engine_run = false;
508 _session->reset_xrun_count ();
510 update_disk_space ();
512 update_xrun_count ();
513 update_sample_rate (AudioEngine::instance()->sample_rate());
514 update_timecode_format ();
515 update_peak_thread_work ();
516 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, true);
517 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, false);
521 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
523 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
524 /* we can't rely on the original string continuing to exist when we are called
525 again in the GUI thread, so make a copy and note that we need to
528 char *copy = strdup (reason);
529 Gtkmm2ext::UI::instance()->call_slot (MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
533 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
534 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
536 update_sample_rate (0);
540 /* if the reason is a non-empty string, it means that the backend was shutdown
541 rather than just Ardour.
544 if (strlen (reason)) {
545 msgstr = string_compose (_("The audio backend was shutdown because:\n\n%1"), reason);
547 msgstr = string_compose (_("\
548 The audio backend has either been shutdown or it\n\
549 disconnected %1 because %1\n\
550 was not fast enough. Try to restart\n\
551 the audio backend and save the session."), PROGRAM_NAME);
554 MessageDialog msg (_main_window, msgstr);
555 pop_back_splash (msg);
559 free (const_cast<char*> (reason));
564 ARDOUR_UI::post_engine ()
566 /* Things to be done once (and once ONLY) after we have a backend running in the AudioEngine
568 #ifdef AUDIOUNIT_SUPPORT
570 if (AUPluginInfo::au_get_crashlog(au_msg)) {
571 popup_error(_("Audio Unit Plugin Scan Failed. Automatic AU scanning has been disabled. Please see the log window for further details."));
572 error << _("Audio Unit Plugin Scan Failed:") << endmsg;
573 info << au_msg << endmsg;
577 ARDOUR::init_post_engine ();
579 /* connect to important signals */
581 AudioEngine::instance()->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
582 AudioEngine::instance()->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
583 AudioEngine::instance()->BufferSizeChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
584 AudioEngine::instance()->Halted.connect_same_thread (halt_connection, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
585 AudioEngine::instance()->BecameSilent.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::audioengine_became_silent, this), gui_context());
587 if (setup_windows ()) {
588 throw failed_constructor ();
591 /* Do this after setup_windows (), as that's when the _status_bar_visibility is created */
592 XMLNode* n = Config->extra_xml (X_("UI"));
594 _status_bar_visibility.set_state (*n);
597 check_memory_locking();
599 /* this is the first point at which all the possible actions are
600 * available, because some of the available actions are dependent on
601 * aspects of the engine/backend.
604 if (ARDOUR_COMMAND_LINE::show_key_actions) {
607 vector<string> paths;
608 vector<string> labels;
609 vector<string> tooltips;
611 vector<Glib::RefPtr<Gtk::Action> > actions;
613 Gtkmm2ext::ActionMap::get_all_actions (paths, labels, tooltips, keys, actions);
615 vector<string>::iterator k;
616 vector<string>::iterator p;
618 for (p = paths.begin(), k = keys.begin(); p != paths.end(); ++k, ++p) {
623 cout << *p << " => " << *k << endl;
627 halt_connection.disconnect ();
628 AudioEngine::instance()->stop ();
632 /* this being a GUI and all, we want peakfiles */
634 AudioFileSource::set_build_peakfiles (true);
635 AudioFileSource::set_build_missing_peakfiles (true);
637 /* set default clock modes */
639 primary_clock->set_mode (AudioClock::Timecode);
640 secondary_clock->set_mode (AudioClock::BBT);
642 /* start the time-of-day-clock */
645 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
646 update_wall_clock ();
647 Glib::signal_timeout().connect_seconds (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 1);
652 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
653 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
654 Config->map_parameters (pc);
656 UIConfiguration::instance().map_parameters (pc);
660 ARDOUR_UI::~ARDOUR_UI ()
662 UIConfiguration::instance().save_state();
666 if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
667 // don't bother at 'real' exit. the OS cleans up for us.
668 delete big_clock; big_clock = 0;
669 delete primary_clock; primary_clock = 0;
670 delete secondary_clock; secondary_clock = 0;
671 delete _process_thread; _process_thread = 0;
672 delete meterbridge; meterbridge = 0;
673 delete luawindow; luawindow = 0;
674 delete editor; editor = 0;
675 delete mixer; mixer = 0;
677 delete gui_object_state; gui_object_state = 0;
678 FastMeter::flush_pattern_cache ();
679 PixFader::flush_pattern_cache ();
683 /* Small trick to flush main-thread event pool.
684 * Other thread-pools are destroyed at pthread_exit(),
685 * but tmain thread termination is too late to trigger Pool::~Pool()
687 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.
688 delete ev->event_pool();
693 ARDOUR_UI::pop_back_splash (Gtk::Window& win)
695 if (Splash::instance()) {
696 Splash::instance()->pop_back_for (win);
701 ARDOUR_UI::configure_timeout ()
703 if (last_configure_time == 0) {
704 /* no configure events yet */
708 /* force a gap of 0.5 seconds since the last configure event
711 if (get_microseconds() - last_configure_time < 500000) {
714 have_configure_timeout = false;
715 save_ardour_state ();
721 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
723 if (have_configure_timeout) {
724 last_configure_time = get_microseconds();
726 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
727 have_configure_timeout = true;
734 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
736 const XMLProperty* prop;
738 if ((prop = node.property ("roll")) != 0) {
739 roll_controllable->set_id (prop->value());
741 if ((prop = node.property ("stop")) != 0) {
742 stop_controllable->set_id (prop->value());
744 if ((prop = node.property ("goto-start")) != 0) {
745 goto_start_controllable->set_id (prop->value());
747 if ((prop = node.property ("goto-end")) != 0) {
748 goto_end_controllable->set_id (prop->value());
750 if ((prop = node.property ("auto-loop")) != 0) {
751 auto_loop_controllable->set_id (prop->value());
753 if ((prop = node.property ("play-selection")) != 0) {
754 play_selection_controllable->set_id (prop->value());
756 if ((prop = node.property ("rec")) != 0) {
757 rec_controllable->set_id (prop->value());
759 if ((prop = node.property ("shuttle")) != 0) {
760 shuttle_box->controllable()->set_id (prop->value());
765 ARDOUR_UI::get_transport_controllable_state ()
767 XMLNode* node = new XMLNode(X_("TransportControllables"));
770 roll_controllable->id().print (buf, sizeof (buf));
771 node->add_property (X_("roll"), buf);
772 stop_controllable->id().print (buf, sizeof (buf));
773 node->add_property (X_("stop"), buf);
774 goto_start_controllable->id().print (buf, sizeof (buf));
775 node->add_property (X_("goto_start"), buf);
776 goto_end_controllable->id().print (buf, sizeof (buf));
777 node->add_property (X_("goto_end"), buf);
778 auto_loop_controllable->id().print (buf, sizeof (buf));
779 node->add_property (X_("auto_loop"), buf);
780 play_selection_controllable->id().print (buf, sizeof (buf));
781 node->add_property (X_("play_selection"), buf);
782 rec_controllable->id().print (buf, sizeof (buf));
783 node->add_property (X_("rec"), buf);
784 shuttle_box->controllable()->id().print (buf, sizeof (buf));
785 node->add_property (X_("shuttle"), buf);
791 ARDOUR_UI::save_session_at_its_request (std::string snapshot_name)
794 _session->save_state (snapshot_name);
799 ARDOUR_UI::autosave_session ()
801 if (g_main_depth() > 1) {
802 /* inside a recursive main loop,
803 give up because we may not be able to
809 if (!Config->get_periodic_safety_backups()) {
814 _session->maybe_write_autosave();
821 ARDOUR_UI::session_dirty_changed ()
828 ARDOUR_UI::update_autosave ()
830 if (_session && _session->dirty()) {
831 if (_autosave_connection.connected()) {
832 _autosave_connection.disconnect();
835 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
836 Config->get_periodic_safety_backup_interval() * 1000);
839 if (_autosave_connection.connected()) {
840 _autosave_connection.disconnect();
846 ARDOUR_UI::check_announcements ()
849 string _annc_filename;
852 _annc_filename = PROGRAM_NAME "_announcements_osx_";
853 #elif defined PLATFORM_WINDOWS
854 _annc_filename = PROGRAM_NAME "_announcements_windows_";
856 _annc_filename = PROGRAM_NAME "_announcements_linux_";
858 _annc_filename.append (VERSIONSTRING);
860 _announce_string = "";
862 std::string path = Glib::build_filename (user_config_directory(), _annc_filename);
863 FILE* fin = g_fopen (path.c_str(), "rb");
865 while (!feof (fin)) {
868 if ((len = fread (tmp, sizeof(char), 1024, fin)) == 0 || ferror (fin)) {
871 _announce_string.append (tmp, len);
876 pingback (VERSIONSTRING, path);
881 _hide_splash (gpointer arg)
883 ((ARDOUR_UI*)arg)->hide_splash();
888 ARDOUR_UI::starting ()
890 Application* app = Application::instance ();
892 bool brand_new_user = ArdourStartup::required ();
894 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
895 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::load_from_application_api));
897 if (ARDOUR_COMMAND_LINE::check_announcements) {
898 check_announcements ();
903 /* we need to create this early because it may need to set the
904 * audio backend end up.
908 audio_midi_setup.get (true);
910 std::cerr << "audio-midi engine setup failed."<< std::endl;
914 if ((nsm_url = g_getenv ("NSM_URL")) != 0) {
915 nsm = new NSM_Client;
916 if (!nsm->init (nsm_url)) {
917 /* the ardour executable may have different names:
919 * waf's obj.target for distro versions: eg ardour4, ardourvst4
920 * Ardour4, Mixbus3 for bundled versions + full path on OSX & windows
921 * argv[0] does not apply since we need the wrapper-script (not the binary itself)
923 * The wrapper startup script should set the environment variable 'ARDOUR_SELF'
925 const char *process_name = g_getenv ("ARDOUR_SELF");
926 nsm->announce (PROGRAM_NAME, ":dirty:", process_name ? process_name : "ardour4");
929 // wait for announce reply from nsm server
930 for ( i = 0; i < 5000; ++i) {
934 if (nsm->is_active()) {
939 error << _("NSM server did not announce itself") << endmsg;
942 // wait for open command from nsm server
943 for ( i = 0; i < 5000; ++i) {
946 if (nsm->client_id ()) {
952 error << _("NSM: no client ID provided") << endmsg;
956 if (_session && nsm) {
957 _session->set_nsm_state( nsm->is_active() );
959 error << _("NSM: no session created") << endmsg;
963 // nsm requires these actions disabled
964 vector<string> action_names;
965 action_names.push_back("SaveAs");
966 action_names.push_back("Rename");
967 action_names.push_back("New");
968 action_names.push_back("Open");
969 action_names.push_back("Recent");
970 action_names.push_back("Close");
972 for (vector<string>::const_iterator n = action_names.begin(); n != action_names.end(); ++n) {
973 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), (*n).c_str());
975 act->set_sensitive (false);
982 error << _("NSM: initialization failed") << endmsg;
988 if (brand_new_user) {
989 _initial_verbose_plugin_scan = true;
994 _initial_verbose_plugin_scan = false;
995 switch (s.response ()) {
996 case Gtk::RESPONSE_OK:
1003 #ifdef NO_PLUGIN_STATE
1005 ARDOUR::RecentSessions rs;
1006 ARDOUR::read_recent_sessions (rs);
1008 string path = Glib::build_filename (user_config_directory(), ".iknowaboutfreeversion");
1010 if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS) && !rs.empty()) {
1012 /* already used Ardour, have sessions ... warn about plugin state */
1014 ArdourDialog d (_("Free/Demo Version Warning"), true);
1016 Button b (string_compose (_("Subscribe and support development of %1"), PROGRAM_NAME));
1017 CheckButton c (_("Don't warn me about this again"));
1019 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"),
1020 string_compose (_("This is a free/demo version of %1"), PROGRAM_NAME),
1021 _("It will not restore OR save any plugin settings"),
1022 _("If you load an existing session with plugin settings\n"
1023 "they will not be used and will be lost."),
1024 _("To get full access to updates without this limitation\n"
1025 "consider becoming a subscriber for a low cost every month.")));
1026 l.set_justify (JUSTIFY_CENTER);
1028 b.signal_clicked().connect (mem_fun(*this, &ARDOUR_UI::launch_subscribe));
1030 d.get_vbox()->pack_start (l, true, true);
1031 d.get_vbox()->pack_start (b, false, false, 12);
1032 d.get_vbox()->pack_start (c, false, false, 12);
1034 d.add_button (_("Quit now"), RESPONSE_CANCEL);
1035 d.add_button (string_compose (_("Continue using %1"), PROGRAM_NAME), RESPONSE_OK);
1039 c.signal_toggled().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (toggle_file_existence), path)));
1041 if (d.run () != RESPONSE_OK) {
1047 /* go get a session */
1049 const bool new_session_required = (ARDOUR_COMMAND_LINE::new_session || brand_new_user);
1051 if (get_session_parameters (false, new_session_required, ARDOUR_COMMAND_LINE::load_template)) {
1052 std::cerr << "Cannot get session parameters."<< std::endl;
1059 WM::Manager::instance().show_visible ();
1061 /* We have to do this here since goto_editor_window() ends up calling show_all() on the
1062 * editor window, and we may want stuff to be hidden.
1064 _status_bar_visibility.update ();
1066 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
1068 if (splash && splash->is_visible()) {
1069 // in 1 second, hide the splash screen
1070 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
1073 /* all other dialogs are created conditionally */
1079 ARDOUR_UI::check_memory_locking ()
1081 #if defined(__APPLE__) || defined(PLATFORM_WINDOWS)
1082 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
1086 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
1088 if (AudioEngine::instance()->is_realtime() && memory_warning_node == 0) {
1090 struct rlimit limits;
1092 long pages, page_size;
1094 size_t pages_len=sizeof(pages);
1095 if ((page_size = getpagesize()) < 0 ||
1096 sysctlbyname("hw.availpages", &pages, &pages_len, NULL, 0))
1098 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0)
1103 ram = (int64_t) pages * (int64_t) page_size;
1106 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
1110 if (limits.rlim_cur != RLIM_INFINITY) {
1112 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
1116 _("WARNING: Your system has a limit for maximum amount of locked memory. "
1117 "This might cause %1 to run out of memory before your system "
1118 "runs out of memory. \n\n"
1119 "You can view the memory limit with 'ulimit -l', "
1120 "and it is normally controlled by %2"),
1123 X_("/etc/login.conf")
1125 X_(" /etc/security/limits.conf")
1129 msg.set_default_response (RESPONSE_OK);
1131 VBox* vbox = msg.get_vbox();
1133 CheckButton cb (_("Do not show this window again"));
1134 hbox.pack_start (cb, true, false);
1135 vbox->pack_start (hbox);
1140 pop_back_splash (msg);
1144 if (cb.get_active()) {
1145 XMLNode node (X_("no-memory-warning"));
1146 Config->add_instant_xml (node);
1151 #endif // !__APPLE__
1156 ARDOUR_UI::queue_finish ()
1158 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
1162 ARDOUR_UI::idle_finish ()
1165 return false; /* do not call again */
1172 ARDOUR_UI::instance()->video_timeline->sync_session_state();
1174 if (_session->dirty()) {
1175 vector<string> actions;
1176 actions.push_back (_("Don't quit"));
1177 actions.push_back (_("Just quit"));
1178 actions.push_back (_("Save and quit"));
1179 switch (ask_about_saving_session(actions)) {
1184 /* use the default name */
1185 if (save_state_canfail ("")) {
1186 /* failed - don't quit */
1187 MessageDialog msg (_main_window,
1188 string_compose (_("\
1189 %1 was unable to save your session.\n\n\
1190 If you still wish to quit, please use the\n\n\
1191 \"Just quit\" option."), PROGRAM_NAME));
1192 pop_back_splash(msg);
1202 second_connection.disconnect ();
1203 point_one_second_connection.disconnect ();
1204 point_zero_something_second_connection.disconnect();
1205 fps_connection.disconnect();
1208 delete ARDOUR_UI::instance()->video_timeline;
1209 ARDOUR_UI::instance()->video_timeline = NULL;
1210 stop_video_server();
1212 /* Save state before deleting the session, as that causes some
1213 windows to be destroyed before their visible state can be
1216 save_ardour_state ();
1218 close_all_dialogs ();
1221 _session->set_clean ();
1222 _session->remove_pending_capture_state ();
1227 halt_connection.disconnect ();
1228 AudioEngine::instance()->stop ();
1229 #ifdef WINDOWS_VST_SUPPORT
1230 fst_stop_threading();
1236 ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
1238 ArdourDialog window (_("Unsaved Session"));
1239 Gtk::HBox dhbox; // the hbox for the image and text
1240 Gtk::Label prompt_label;
1241 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
1245 assert (actions.size() >= 3);
1247 window.add_button (actions[0], RESPONSE_REJECT);
1248 window.add_button (actions[1], RESPONSE_APPLY);
1249 window.add_button (actions[2], RESPONSE_ACCEPT);
1251 window.set_default_response (RESPONSE_ACCEPT);
1253 Gtk::Button noquit_button (msg);
1254 noquit_button.set_name ("EditorGTKButton");
1258 if (_session->snap_name() == _session->name()) {
1259 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?"),
1260 _session->snap_name());
1262 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?"),
1263 _session->snap_name());
1266 prompt_label.set_text (prompt);
1267 prompt_label.set_name (X_("PrompterLabel"));
1268 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
1270 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
1271 dhbox.set_homogeneous (false);
1272 dhbox.pack_start (*dimage, false, false, 5);
1273 dhbox.pack_start (prompt_label, true, false, 5);
1274 window.get_vbox()->pack_start (dhbox);
1276 window.set_name (_("Prompter"));
1277 window.set_modal (true);
1278 window.set_resizable (false);
1281 prompt_label.show();
1286 ResponseType r = (ResponseType) window.run();
1291 case RESPONSE_ACCEPT: // save and get out of here
1293 case RESPONSE_APPLY: // get out of here
1304 ARDOUR_UI::every_second ()
1307 update_xrun_count ();
1308 update_buffer_load ();
1309 update_disk_space ();
1310 update_timecode_format ();
1311 update_peak_thread_work ();
1313 if (nsm && nsm->is_active ()) {
1316 if (!_was_dirty && _session->dirty ()) {
1320 else if (_was_dirty && !_session->dirty ()){
1328 ARDOUR_UI::every_point_one_seconds ()
1330 // TODO get rid of this..
1331 // ShuttleControl is updated directly via TransportStateChange signal
1335 ARDOUR_UI::every_point_zero_something_seconds ()
1337 // august 2007: actual update frequency: 25Hz (40ms), not 100Hz
1339 if (editor_meter && UIConfiguration::instance().get_show_editor_meter()) {
1340 float mpeak = editor_meter->update_meters();
1341 if (mpeak > editor_meter_max_peak) {
1342 if (mpeak >= UIConfiguration::instance().get_meter_peak()) {
1343 editor_meter_peak_display.set_active_state ( Gtkmm2ext::ExplicitActive );
1350 ARDOUR_UI::set_fps_timeout_connection ()
1352 unsigned int interval = 40;
1353 if (!_session) return;
1354 if (_session->timecode_frames_per_second() != 0) {
1355 /* ideally we'll use a select() to sleep and not accumulate
1356 * idle time to provide a regular periodic signal.
1357 * See linux_vst_gui_support.cc 'elapsed_time_ms'.
1358 * However, that'll require a dedicated thread and cross-thread
1359 * signals to the GUI Thread..
1361 interval = floor(500. /* update twice per FPS, since Glib::signal_timeout is very irregular */
1362 * _session->frame_rate() / _session->nominal_frame_rate()
1363 / _session->timecode_frames_per_second()
1365 #ifdef PLATFORM_WINDOWS
1366 // the smallest windows scheduler time-slice is ~15ms.
1367 // periodic GUI timeouts shorter than that will cause
1368 // WaitForSingleObject to spinlock (100% of one CPU Core)
1369 // and gtk never enters idle mode.
1370 // also changing timeBeginPeriod(1) does not affect that in
1371 // any beneficial way, so we just limit the max rate for now.
1372 interval = std::max(30u, interval); // at most ~33Hz.
1374 interval = std::max(8u, interval); // at most 120Hz.
1377 fps_connection.disconnect();
1378 Timers::set_fps_interval (interval);
1382 ARDOUR_UI::update_sample_rate (framecnt_t)
1386 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
1388 if (!AudioEngine::instance()->connected()) {
1390 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1394 framecnt_t rate = AudioEngine::instance()->sample_rate();
1397 /* no sample rate available */
1398 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1401 if (fmod (rate, 1000.0) != 0.0) {
1402 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
1403 (float) rate / 1000.0f,
1404 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1406 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
1408 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1412 sample_rate_label.set_markup (buf);
1416 ARDOUR_UI::update_format ()
1419 format_label.set_text ("");
1424 s << _("File:") << X_(" <span foreground=\"green\">");
1426 switch (_session->config.get_native_file_header_format ()) {
1458 switch (_session->config.get_native_file_data_format ()) {
1472 format_label.set_markup (s.str ());
1476 ARDOUR_UI::update_xrun_count ()
1480 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1481 should also be changed.
1485 const unsigned int x = _session->get_xrun_count ();
1487 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">>10K</span>"), X_("red"));
1489 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">%u</span>"), x > 0 ? X_("red") : X_("green"), x);
1492 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">?</span>"), X_("yellow"));
1494 xrun_label.set_markup (buf);
1495 set_tip (xrun_label, _("Audio dropouts. Shift+click to reset"));
1499 ARDOUR_UI::update_cpu_load ()
1503 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1504 should also be changed.
1507 double const c = AudioEngine::instance()->get_dsp_load ();
1508 snprintf (buf, sizeof (buf), _("DSP: <span foreground=\"%s\">%5.1f%%</span>"), c >= 90 ? X_("red") : X_("green"), c);
1509 cpu_load_label.set_markup (buf);
1513 ARDOUR_UI::update_peak_thread_work ()
1516 const int c = SourceFactory::peak_work_queue_length ();
1518 snprintf (buf, sizeof (buf), _("PkBld: <span foreground=\"%s\">%d</span>"), c >= 2 ? X_("red") : X_("green"), c);
1519 peak_thread_work_label.set_markup (buf);
1521 peak_thread_work_label.set_markup (X_(""));
1526 ARDOUR_UI::update_buffer_load ()
1530 uint32_t const playback = _session ? _session->playback_load () : 100;
1531 uint32_t const capture = _session ? _session->capture_load () : 100;
1533 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1534 should also be changed.
1540 _("Buffers: <span foreground=\"green\">p:</span><span foreground=\"%s\">%" PRIu32 "%%</span> "
1541 "<span foreground=\"green\">c:</span><span foreground=\"%s\">%" PRIu32 "%%</span>"),
1542 playback <= 5 ? X_("red") : X_("green"),
1544 capture <= 5 ? X_("red") : X_("green"),
1548 buffer_load_label.set_markup (buf);
1550 buffer_load_label.set_text ("");
1555 ARDOUR_UI::count_recenabled_streams (Route& route)
1557 Track* track = dynamic_cast<Track*>(&route);
1558 if (track && track->record_enabled()) {
1559 rec_enabled_streams += track->n_inputs().n_total();
1564 ARDOUR_UI::update_disk_space()
1566 if (_session == 0) {
1570 boost::optional<framecnt_t> opt_frames = _session->available_capture_duration();
1572 framecnt_t fr = _session->frame_rate();
1575 /* skip update - no SR available */
1580 /* Available space is unknown */
1581 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">Unknown</span>"));
1582 } else if (opt_frames.get_value_or (0) == max_framecnt) {
1583 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">24hrs+</span>"));
1585 rec_enabled_streams = 0;
1586 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams, false);
1588 framecnt_t frames = opt_frames.get_value_or (0);
1590 if (rec_enabled_streams) {
1591 frames /= rec_enabled_streams;
1598 hrs = frames / (fr * 3600);
1601 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">>24 hrs</span>"));
1603 frames -= hrs * fr * 3600;
1604 mins = frames / (fr * 60);
1605 frames -= mins * fr * 60;
1608 bool const low = (hrs == 0 && mins <= 30);
1612 _("Disk: <span foreground=\"%s\">%02dh:%02dm:%02ds</span>"),
1613 low ? X_("red") : X_("green"),
1619 disk_space_label.set_markup (buf);
1623 ARDOUR_UI::update_timecode_format ()
1629 TimecodeSlave* tcslave;
1630 SyncSource sync_src = Config->get_sync_source();
1632 if ((sync_src == LTC || sync_src == MTC) && (tcslave = dynamic_cast<TimecodeSlave*>(_session->slave())) != 0) {
1633 matching = (tcslave->apparent_timecode_format() == _session->config.get_timecode_format());
1638 snprintf (buf, sizeof (buf), S_("Timecode|TC: <span foreground=\"%s\">%s</span>"),
1639 matching ? X_("green") : X_("red"),
1640 Timecode::timecode_format_name (_session->config.get_timecode_format()).c_str());
1642 snprintf (buf, sizeof (buf), "TC: n/a");
1645 timecode_format_label.set_markup (buf);
1649 ARDOUR_UI::update_wall_clock ()
1653 static int last_min = -1;
1656 tm_now = localtime (&now);
1657 if (last_min != tm_now->tm_min) {
1659 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1660 wall_clock_label.set_text (buf);
1661 last_min = tm_now->tm_min;
1668 ARDOUR_UI::open_recent_session ()
1670 bool can_return = (_session != 0);
1672 SessionDialog recent_session_dialog;
1676 ResponseType r = (ResponseType) recent_session_dialog.run ();
1679 case RESPONSE_ACCEPT:
1683 recent_session_dialog.hide();
1690 recent_session_dialog.hide();
1694 std::string path = recent_session_dialog.session_folder();
1695 std::string state = recent_session_dialog.session_name (should_be_new);
1697 if (should_be_new == true) {
1701 _session_is_new = false;
1703 if (load_session (path, state) == 0) {
1712 ARDOUR_UI::check_audioengine (Gtk::Window& parent)
1714 if (!AudioEngine::instance()->connected()) {
1715 MessageDialog msg (parent, string_compose (
1716 _("%1 is not connected to any audio backend.\n"
1717 "You cannot open or close sessions in this condition"),
1719 pop_back_splash (msg);
1727 ARDOUR_UI::open_session ()
1729 if (!check_audioengine (_main_window)) {
1733 /* ardour sessions are folders */
1734 Gtk::FileChooserDialog open_session_selector(_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1735 open_session_selector.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1736 open_session_selector.add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1737 open_session_selector.set_default_response(Gtk::RESPONSE_ACCEPT);
1740 string session_parent_dir = Glib::path_get_dirname(_session->path());
1741 open_session_selector.set_current_folder(session_parent_dir);
1743 open_session_selector.set_current_folder(Config->get_default_session_parent_dir());
1746 Gtkmm2ext::add_volume_shortcuts (open_session_selector);
1748 /* add_shortcut_folder throws an exception if the folder being added already has a shortcut */
1749 string default_session_folder = Config->get_default_session_parent_dir();
1750 open_session_selector.add_shortcut_folder (default_session_folder);
1752 catch (Glib::Error & e) {
1753 std::cerr << "open_session_selector.add_shortcut_folder() threw Glib::Error " << e.what() << std::endl;
1756 FileFilter session_filter;
1757 session_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::statefile_suffix));
1758 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1759 open_session_selector.add_filter (session_filter);
1760 open_session_selector.set_filter (session_filter);
1762 int response = open_session_selector.run();
1763 open_session_selector.hide ();
1765 if (response == Gtk::RESPONSE_CANCEL) {
1769 string session_path = open_session_selector.get_filename();
1773 if (session_path.length() > 0) {
1774 if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1775 _session_is_new = isnew;
1776 load_session (path, name);
1782 ARDOUR_UI::session_add_mixed_track (
1783 const ChanCount& input,
1784 const ChanCount& output,
1785 RouteGroup* route_group,
1787 const string& name_template,
1789 PluginInfoPtr instrument)
1791 list<boost::shared_ptr<MidiTrack> > tracks;
1793 if (_session == 0) {
1794 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1799 tracks = _session->new_midi_track (input, output, instrument, ARDOUR::Normal, route_group, how_many, name_template);
1801 if (tracks.size() != how_many) {
1802 error << string_compose(P_("could not create %1 new mixed track", "could not create %1 new mixed tracks", how_many), how_many) << endmsg;
1807 display_insufficient_ports_message ();
1812 for (list<boost::shared_ptr<MidiTrack> >::iterator i = tracks.begin(); i != tracks.end(); ++i) {
1813 (*i)->set_strict_io (true);
1819 ARDOUR_UI::session_add_midi_bus (
1820 RouteGroup* route_group,
1822 const string& name_template,
1824 PluginInfoPtr instrument)
1828 if (_session == 0) {
1829 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1834 routes = _session->new_midi_route (route_group, how_many, name_template, instrument);
1835 if (routes.size() != how_many) {
1836 error << string_compose(P_("could not create %1 new Midi Bus", "could not create %1 new Midi Busses", how_many), how_many) << endmsg;
1841 display_insufficient_ports_message ();
1846 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
1847 (*i)->set_strict_io (true);
1853 ARDOUR_UI::session_add_midi_route (
1855 RouteGroup* route_group,
1857 const string& name_template,
1859 PluginInfoPtr instrument)
1861 ChanCount one_midi_channel;
1862 one_midi_channel.set (DataType::MIDI, 1);
1865 session_add_mixed_track (one_midi_channel, one_midi_channel, route_group, how_many, name_template, strict_io, instrument);
1867 session_add_midi_bus (route_group, how_many, name_template, strict_io, instrument);
1872 ARDOUR_UI::session_add_audio_route (
1874 int32_t input_channels,
1875 int32_t output_channels,
1876 ARDOUR::TrackMode mode,
1877 RouteGroup* route_group,
1879 string const & name_template,
1883 list<boost::shared_ptr<AudioTrack> > tracks;
1886 if (_session == 0) {
1887 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1893 tracks = _session->new_audio_track (input_channels, output_channels, mode, route_group, how_many, name_template);
1895 if (tracks.size() != how_many) {
1896 error << string_compose (P_("could not create %1 new audio track", "could not create %1 new audio tracks", how_many), how_many)
1902 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template);
1904 if (routes.size() != how_many) {
1905 error << string_compose (P_("could not create %1 new audio bus", "could not create %1 new audio busses", how_many), how_many)
1912 display_insufficient_ports_message ();
1917 for (list<boost::shared_ptr<AudioTrack> >::iterator i = tracks.begin(); i != tracks.end(); ++i) {
1918 (*i)->set_strict_io (true);
1920 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
1921 (*i)->set_strict_io (true);
1927 ARDOUR_UI::display_insufficient_ports_message ()
1929 MessageDialog msg (_main_window,
1930 string_compose (_("There are insufficient ports available\n\
1931 to create a new track or bus.\n\
1932 You should save %1, exit and\n\
1933 restart with more ports."), PROGRAM_NAME));
1934 pop_back_splash (msg);
1939 ARDOUR_UI::transport_goto_start ()
1942 _session->goto_start();
1944 /* force displayed area in editor to start no matter
1945 what "follow playhead" setting is.
1949 editor->center_screen (_session->current_start_frame ());
1955 ARDOUR_UI::transport_goto_zero ()
1958 _session->request_locate (0);
1960 /* force displayed area in editor to start no matter
1961 what "follow playhead" setting is.
1965 editor->reset_x_origin (0);
1971 ARDOUR_UI::transport_goto_wallclock ()
1973 if (_session && editor) {
1980 localtime_r (&now, &tmnow);
1982 framecnt_t frame_rate = _session->frame_rate();
1984 if (frame_rate == 0) {
1985 /* no frame rate available */
1989 frames = tmnow.tm_hour * (60 * 60 * frame_rate);
1990 frames += tmnow.tm_min * (60 * frame_rate);
1991 frames += tmnow.tm_sec * frame_rate;
1993 _session->request_locate (frames, _session->transport_rolling ());
1995 /* force displayed area in editor to start no matter
1996 what "follow playhead" setting is.
2000 editor->center_screen (frames);
2006 ARDOUR_UI::transport_goto_end ()
2009 framepos_t const frame = _session->current_end_frame();
2010 _session->request_locate (frame);
2012 /* force displayed area in editor to start no matter
2013 what "follow playhead" setting is.
2017 editor->center_screen (frame);
2023 ARDOUR_UI::transport_stop ()
2029 if (_session->is_auditioning()) {
2030 _session->cancel_audition ();
2034 _session->request_stop (false, true);
2037 /** Check if any tracks are record enabled. If none are, record enable all of them.
2038 * @return true if track record-enabled status was changed, false otherwise.
2041 ARDOUR_UI::trx_record_enable_all_tracks ()
2047 boost::shared_ptr<RouteList> rl = _session->get_tracks ();
2048 bool none_record_enabled = true;
2050 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
2051 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*r);
2054 if (t->record_enabled()) {
2055 none_record_enabled = false;
2060 if (none_record_enabled) {
2061 _session->set_record_enabled (rl, true, Session::rt_cleanup);
2064 return none_record_enabled;
2068 ARDOUR_UI::transport_record (bool roll)
2071 switch (_session->record_status()) {
2072 case Session::Disabled:
2073 if (_session->ntracks() == 0) {
2074 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."));
2078 if (Profile->get_trx()) {
2079 roll = trx_record_enable_all_tracks ();
2081 _session->maybe_enable_record ();
2086 case Session::Recording:
2088 _session->request_stop();
2090 _session->disable_record (false, true);
2094 case Session::Enabled:
2095 _session->disable_record (false, true);
2101 ARDOUR_UI::transport_roll ()
2107 if (_session->is_auditioning()) {
2112 if (_session->config.get_external_sync()) {
2113 switch (Config->get_sync_source()) {
2117 /* transport controlled by the master */
2123 bool rolling = _session->transport_rolling();
2125 if (_session->get_play_loop()) {
2127 /* If loop playback is not a mode, then we should cancel
2128 it when this action is requested. If it is a mode
2129 we just leave it in place.
2132 if (!Config->get_loop_is_mode()) {
2133 /* XXX it is not possible to just leave seamless loop and keep
2134 playing at present (nov 4th 2009)
2136 if (!Config->get_seamless_loop()) {
2137 /* stop loop playback and stop rolling */
2138 _session->request_play_loop (false, true);
2139 } else if (rolling) {
2140 /* stop loop playback but keep rolling */
2141 _session->request_play_loop (false, false);
2145 } else if (_session->get_play_range () ) {
2146 /* stop playing a range if we currently are */
2147 _session->request_play_range (0, true);
2151 _session->request_transport_speed (1.0f);
2156 ARDOUR_UI::get_smart_mode() const
2158 return ( editor->get_smart_mode() );
2163 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
2169 if (_session->is_auditioning()) {
2170 _session->cancel_audition ();
2174 if (_session->config.get_external_sync()) {
2175 switch (Config->get_sync_source()) {
2179 /* transport controlled by the master */
2184 bool rolling = _session->transport_rolling();
2185 bool affect_transport = true;
2187 if (rolling && roll_out_of_bounded_mode) {
2188 /* drop out of loop/range playback but leave transport rolling */
2189 if (_session->get_play_loop()) {
2190 if (_session->actively_recording()) {
2192 /* just stop using the loop, then actually stop
2195 _session->request_play_loop (false, affect_transport);
2198 if (Config->get_seamless_loop()) {
2199 /* the disk buffers contain copies of the loop - we can't
2200 just keep playing, so stop the transport. the user
2201 can restart as they wish.
2203 affect_transport = true;
2205 /* disk buffers are normal, so we can keep playing */
2206 affect_transport = false;
2208 _session->request_play_loop (false, affect_transport);
2210 } else if (_session->get_play_range ()) {
2211 affect_transport = false;
2212 _session->request_play_range (0, true);
2216 if (affect_transport) {
2218 _session->request_stop (with_abort, true);
2220 /* the only external sync condition we can be in here
2221 * would be Engine (JACK) sync, in which case we still
2225 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
2226 _session->request_play_range (&editor->get_selection().time, true);
2227 _session->set_requested_return_frame( editor->get_selection().time.front().start ); //force an auto-return here
2229 _session->request_transport_speed (1.0f);
2235 ARDOUR_UI::toggle_session_auto_loop ()
2241 Location * looploc = _session->locations()->auto_loop_location();
2247 if (_session->get_play_loop()) {
2249 /* looping enabled, our job is to disable it */
2251 _session->request_play_loop (false);
2255 /* looping not enabled, our job is to enable it.
2257 loop-is-NOT-mode: this action always starts the transport rolling.
2258 loop-IS-mode: this action simply sets the loop play mechanism, but
2259 does not start transport.
2261 if (Config->get_loop_is_mode()) {
2262 _session->request_play_loop (true, false);
2264 _session->request_play_loop (true, true);
2268 //show the loop markers
2269 looploc->set_hidden (false, this);
2273 ARDOUR_UI::transport_play_selection ()
2279 editor->play_selection ();
2283 ARDOUR_UI::transport_play_preroll ()
2288 editor->play_with_preroll ();
2292 ARDOUR_UI::transport_rewind (int option)
2294 float current_transport_speed;
2297 current_transport_speed = _session->transport_speed();
2299 if (current_transport_speed >= 0.0f) {
2302 _session->request_transport_speed (-1.0f);
2305 _session->request_transport_speed (-4.0f);
2308 _session->request_transport_speed (-0.5f);
2313 _session->request_transport_speed (current_transport_speed * 1.5f);
2319 ARDOUR_UI::transport_forward (int option)
2325 float current_transport_speed = _session->transport_speed();
2327 if (current_transport_speed <= 0.0f) {
2330 _session->request_transport_speed (1.0f);
2333 _session->request_transport_speed (4.0f);
2336 _session->request_transport_speed (0.5f);
2341 _session->request_transport_speed (current_transport_speed * 1.5f);
2346 ARDOUR_UI::toggle_record_enable (uint32_t rid)
2352 boost::shared_ptr<Route> r;
2354 if ((r = _session->route_by_remote_id (rid)) != 0) {
2356 boost::shared_ptr<Track> t;
2358 if ((t = boost::dynamic_pointer_cast<Track>(r)) != 0) {
2359 t->set_record_enabled (!t->record_enabled(), Controllable::UseGroup);
2365 ARDOUR_UI::map_transport_state ()
2368 auto_loop_button.unset_active_state ();
2369 play_selection_button.unset_active_state ();
2370 roll_button.unset_active_state ();
2371 stop_button.set_active_state (Gtkmm2ext::ExplicitActive);
2375 shuttle_box->map_transport_state ();
2377 float sp = _session->transport_speed();
2383 if (_session->get_play_range()) {
2385 play_selection_button.set_active_state (Gtkmm2ext::ExplicitActive);
2386 roll_button.unset_active_state ();
2387 auto_loop_button.unset_active_state ();
2389 } else if (_session->get_play_loop ()) {
2391 auto_loop_button.set_active (true);
2392 play_selection_button.set_active (false);
2393 if (Config->get_loop_is_mode()) {
2394 roll_button.set_active (true);
2396 roll_button.set_active (false);
2401 roll_button.set_active (true);
2402 play_selection_button.set_active (false);
2403 auto_loop_button.set_active (false);
2406 if (UIConfiguration::instance().get_follow_edits() && !_session->config.get_external_sync()) {
2407 /* light up both roll and play-selection if they are joined */
2408 roll_button.set_active (true);
2409 play_selection_button.set_active (true);
2412 stop_button.set_active (false);
2416 stop_button.set_active (true);
2417 roll_button.set_active (false);
2418 play_selection_button.set_active (false);
2419 if (Config->get_loop_is_mode ()) {
2420 auto_loop_button.set_active (_session->get_play_loop());
2422 auto_loop_button.set_active (false);
2424 update_disk_space ();
2429 ARDOUR_UI::blink_handler (bool blink_on)
2431 transport_rec_enable_blink (blink_on);
2432 solo_blink (blink_on);
2433 sync_blink (blink_on);
2434 audition_blink (blink_on);
2435 feedback_blink (blink_on);
2436 error_blink (blink_on);
2440 ARDOUR_UI::update_clocks ()
2442 if (!_session) return;
2444 if (editor && !editor->dragging_playhead()) {
2445 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD)); /* EMIT_SIGNAL */
2450 ARDOUR_UI::start_clocking ()
2452 if (UIConfiguration::instance().get_super_rapid_clock_update()) {
2453 clock_signal_connection = Timers::fps_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2455 clock_signal_connection = Timers::rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2460 ARDOUR_UI::stop_clocking ()
2462 clock_signal_connection.disconnect ();
2466 ARDOUR_UI::save_as_progress_update (float fraction, int64_t cnt, int64_t total, Gtk::Label* label, Gtk::ProgressBar* bar)
2470 snprintf (buf, sizeof (buf), _("Copied %" PRId64 " of %" PRId64), cnt, total);
2472 label->set_text (buf);
2473 bar->set_fraction (fraction);
2475 /* process events, redraws, etc. */
2477 while (gtk_events_pending()) {
2478 gtk_main_iteration ();
2481 return true; /* continue with save-as */
2485 ARDOUR_UI::save_session_as ()
2491 if (!save_as_dialog) {
2492 save_as_dialog = new SaveAsDialog;
2495 save_as_dialog->set_name (_session->name());
2497 int response = save_as_dialog->run ();
2499 save_as_dialog->hide ();
2502 case Gtk::RESPONSE_OK:
2511 sa.new_parent_folder = save_as_dialog->new_parent_folder ();
2512 sa.new_name = save_as_dialog->new_name ();
2513 sa.switch_to = save_as_dialog->switch_to();
2514 sa.copy_media = save_as_dialog->copy_media();
2515 sa.copy_external = save_as_dialog->copy_external();
2516 sa.include_media = save_as_dialog->include_media ();
2518 /* Only bother with a progress dialog if we're going to copy
2519 media into the save-as target. Without that choice, this
2520 will be very fast because we're only talking about a few kB's to
2521 perhaps a couple of MB's of data.
2524 ArdourDialog progress_dialog (_("Save As"), true);
2526 if (sa.include_media && sa.copy_media) {
2529 Gtk::ProgressBar progress_bar;
2531 progress_dialog.get_vbox()->pack_start (label);
2532 progress_dialog.get_vbox()->pack_start (progress_bar);
2534 progress_bar.show ();
2536 /* this signal will be emitted from within this, the calling thread,
2537 * after every file is copied. It provides information on percentage
2538 * complete (in terms of total data to copy), the number of files
2539 * copied so far, and the total number to copy.
2544 sa.Progress.connect_same_thread (c, boost::bind (&ARDOUR_UI::save_as_progress_update, this, _1, _2, _3, &label, &progress_bar));
2546 progress_dialog.show_all ();
2547 progress_dialog.present ();
2550 if (_session->save_as (sa)) {
2552 MessageDialog msg (string_compose (_("Save As failed: %1"), sa.failure_message));
2556 if (!sa.include_media) {
2557 unload_session (false);
2558 load_session (sa.final_session_folder_name, sa.new_name);
2563 ARDOUR_UI::quick_snapshot_session (bool switch_to_it)
2567 struct tm local_time;
2570 localtime_r (&n, &local_time);
2571 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2573 save_state (timebuf, switch_to_it);
2578 ARDOUR_UI::process_snapshot_session_prompter (ArdourPrompter& prompter, bool switch_to_it)
2582 prompter.get_result (snapname);
2584 bool do_save = (snapname.length() != 0);
2587 char illegal = Session::session_name_is_legal(snapname);
2589 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2590 "snapshot names may not contain a '%1' character"), illegal));
2596 vector<std::string> p;
2597 get_state_files_in_directory (_session->session_directory().root_path(), p);
2598 vector<string> n = get_file_names_no_extension (p);
2600 if (find (n.begin(), n.end(), snapname) != n.end()) {
2602 do_save = overwrite_file_dialog (prompter,
2603 _("Confirm Snapshot Overwrite"),
2604 _("A snapshot already exists with that name. Do you want to overwrite it?"));
2608 save_state (snapname, switch_to_it);
2618 /** Ask the user for the name of a new snapshot and then take it.
2622 ARDOUR_UI::snapshot_session (bool switch_to_it)
2624 ArdourPrompter prompter (true);
2626 prompter.set_name ("Prompter");
2627 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2629 prompter.set_title (_("Save as..."));
2630 prompter.set_prompt (_("New session name"));
2632 prompter.set_title (_("Take Snapshot"));
2633 prompter.set_prompt (_("Name of new snapshot"));
2637 prompter.set_initial_text (_session->snap_name());
2641 struct tm local_time;
2644 localtime_r (&n, &local_time);
2645 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2646 prompter.set_initial_text (timebuf);
2649 bool finished = false;
2651 switch (prompter.run()) {
2652 case RESPONSE_ACCEPT:
2654 finished = process_snapshot_session_prompter (prompter, switch_to_it);
2665 /** Ask the user for a new session name and then rename the session to it.
2669 ARDOUR_UI::rename_session ()
2675 ArdourPrompter prompter (true);
2678 prompter.set_name ("Prompter");
2679 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2680 prompter.set_title (_("Rename Session"));
2681 prompter.set_prompt (_("New session name"));
2684 switch (prompter.run()) {
2685 case RESPONSE_ACCEPT:
2687 prompter.get_result (name);
2689 bool do_rename = (name.length() != 0);
2692 char illegal = Session::session_name_is_legal (name);
2695 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2696 "session names may not contain a '%1' character"), illegal));
2701 switch (_session->rename (name)) {
2703 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
2704 msg.set_position (WIN_POS_MOUSE);
2712 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
2713 msg.set_position (WIN_POS_MOUSE);
2729 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2731 if (!_session || _session->deletion_in_progress()) {
2735 XMLNode* node = new XMLNode (X_("UI"));
2737 WM::Manager::instance().add_state (*node);
2739 node->add_child_nocopy (gui_object_state->get_state());
2741 _session->add_extra_xml (*node);
2743 if (export_video_dialog) {
2744 _session->add_extra_xml (export_video_dialog->get_state());
2747 save_state_canfail (name, switch_to_it);
2751 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2756 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2761 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2766 ARDOUR_UI::primary_clock_value_changed ()
2769 _session->request_locate (primary_clock->current_time ());
2774 ARDOUR_UI::big_clock_value_changed ()
2777 _session->request_locate (big_clock->current_time ());
2782 ARDOUR_UI::secondary_clock_value_changed ()
2785 _session->request_locate (secondary_clock->current_time ());
2790 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2792 if (_session == 0) {
2796 if (_session->step_editing()) {
2800 Session::RecordState const r = _session->record_status ();
2801 bool const h = _session->have_rec_enabled_track ();
2803 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2805 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2807 rec_button.set_active_state (Gtkmm2ext::Off);
2809 } else if (r == Session::Recording && h) {
2810 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2812 rec_button.unset_active_state ();
2817 ARDOUR_UI::process_save_template_prompter (ArdourPrompter& prompter)
2821 prompter.get_result (name);
2823 if (name.length()) {
2824 int failed = _session->save_template (name);
2826 if (failed == -2) { /* file already exists. */
2827 bool overwrite = overwrite_file_dialog (prompter,
2828 _("Confirm Template Overwrite"),
2829 _("A template already exists with that name. Do you want to overwrite it?"));
2832 _session->save_template (name, true);
2844 ARDOUR_UI::save_template ()
2846 ArdourPrompter prompter (true);
2848 if (!check_audioengine (_main_window)) {
2852 prompter.set_name (X_("Prompter"));
2853 prompter.set_title (_("Save Template"));
2854 prompter.set_prompt (_("Name for template:"));
2855 prompter.set_initial_text(_session->name() + _("-template"));
2856 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2858 bool finished = false;
2860 switch (prompter.run()) {
2861 case RESPONSE_ACCEPT:
2862 finished = process_save_template_prompter (prompter);
2873 ARDOUR_UI::edit_metadata ()
2875 SessionMetadataEditor dialog;
2876 dialog.set_session (_session);
2877 dialog.grab_focus ();
2882 ARDOUR_UI::import_metadata ()
2884 SessionMetadataImporter dialog;
2885 dialog.set_session (_session);
2890 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
2892 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2894 MessageDialog msg (str,
2896 Gtk::MESSAGE_WARNING,
2897 Gtk::BUTTONS_YES_NO,
2901 msg.set_name (X_("OpenExistingDialog"));
2902 msg.set_title (_("Open Existing Session"));
2903 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
2904 msg.set_position (Gtk::WIN_POS_CENTER);
2905 pop_back_splash (msg);
2907 switch (msg.run()) {
2916 ARDOUR_UI::build_session_from_dialog (SessionDialog& sd, const std::string& session_path, const std::string& session_name)
2918 BusProfile bus_profile;
2922 bus_profile.master_out_channels = 2;
2923 bus_profile.input_ac = AutoConnectPhysical;
2924 bus_profile.output_ac = AutoConnectMaster;
2925 bus_profile.requested_physical_in = 0; // use all available
2926 bus_profile.requested_physical_out = 0; // use all available
2930 /* get settings from advanced section of NSD */
2932 if (sd.create_master_bus()) {
2933 bus_profile.master_out_channels = (uint32_t) sd.master_channel_count();
2935 bus_profile.master_out_channels = 0;
2938 if (sd.connect_inputs()) {
2939 bus_profile.input_ac = AutoConnectPhysical;
2941 bus_profile.input_ac = AutoConnectOption (0);
2944 bus_profile.output_ac = AutoConnectOption (0);
2946 if (sd.connect_outputs ()) {
2947 if (sd.connect_outs_to_master()) {
2948 bus_profile.output_ac = AutoConnectMaster;
2949 } else if (sd.connect_outs_to_physical()) {
2950 bus_profile.output_ac = AutoConnectPhysical;
2954 bus_profile.requested_physical_in = (uint32_t) sd.input_limit_count();
2955 bus_profile.requested_physical_out = (uint32_t) sd.output_limit_count();
2958 if (build_session (session_path, session_name, bus_profile)) {
2966 ARDOUR_UI::load_from_application_api (const std::string& path)
2968 ARDOUR_COMMAND_LINE::session_name = path;
2969 /* Cancel SessionDialog if it's visible to make OSX delegates work.
2971 * ARDOUR_UI::starting connects app->ShouldLoad signal and then shows a SessionDialog
2973 * - ShouldLoad does not arrive in time, ARDOUR_COMMAND_LINE::session_name is empty:
2974 * -> ARDOUR_UI::get_session_parameters starts a SessionDialog.
2975 * - ShouldLoad signal arrives, this function is called and sets ARDOUR_COMMAND_LINE::session_name
2976 * -> SessionDialog is not displayed
2979 if (_session_dialog) {
2980 std::string session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
2981 std::string session_path = path;
2982 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_REGULAR)) {
2983 session_path = Glib::path_get_dirname (session_path);
2985 // signal the existing dialog in ARDOUR_UI::get_session_parameters()
2986 _session_dialog->set_provided_session (session_name, session_path);
2987 _session_dialog->response (RESPONSE_NONE);
2988 _session_dialog->hide();
2993 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2994 /* /path/to/foo => /path/to/foo, foo */
2995 rv = load_session (path, basename_nosuffix (path));
2997 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2998 rv =load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
3001 // if load_session fails -> pop up SessionDialog.
3003 ARDOUR_COMMAND_LINE::session_name = "";
3005 if (get_session_parameters (true, false)) {
3011 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
3013 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
3015 string session_name;
3016 string session_path;
3017 string template_name;
3019 bool likely_new = false;
3020 bool cancel_not_quit;
3022 /* deal with any existing DIRTY session now, rather than later. don't
3023 * treat a non-dirty session this way, so that it stays visible
3024 * as we bring up the new session dialog.
3027 if (_session && ARDOUR_UI::instance()->video_timeline) {
3028 ARDOUR_UI::instance()->video_timeline->sync_session_state();
3031 /* if there is already a session, relabel the button
3032 on the SessionDialog so that we don't Quit directly
3034 cancel_not_quit = (_session != 0);
3036 if (_session && _session->dirty()) {
3037 if (unload_session (false)) {
3038 /* unload cancelled by user */
3041 ARDOUR_COMMAND_LINE::session_name = "";
3044 if (!load_template.empty()) {
3045 should_be_new = true;
3046 template_name = load_template;
3049 session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3050 session_path = ARDOUR_COMMAND_LINE::session_name;
3052 if (!session_path.empty()) {
3053 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_EXISTS)) {
3054 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_IS_REGULAR)) {
3055 /* session/snapshot file, change path to be dir */
3056 session_path = Glib::path_get_dirname (session_path);
3061 SessionDialog session_dialog (should_be_new, session_name, session_path, load_template, cancel_not_quit);
3063 _session_dialog = &session_dialog;
3066 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
3068 /* if they named a specific statefile, use it, otherwise they are
3069 just giving a session folder, and we want to use it as is
3070 to find the session.
3073 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
3075 if (suffix != string::npos) {
3076 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
3077 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
3078 session_name = Glib::path_get_basename (session_name);
3080 session_path = ARDOUR_COMMAND_LINE::session_name;
3081 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
3086 session_dialog.clear_given ();
3089 if (should_be_new || session_name.empty()) {
3090 /* need the dialog to get info from user */
3092 cerr << "run dialog\n";
3094 switch (session_dialog.run()) {
3095 case RESPONSE_ACCEPT:
3098 /* this is used for async * app->ShouldLoad(). */
3099 continue; // while loop
3102 if (quit_on_cancel) {
3103 // JE - Currently (July 2014) this section can only get reached if the
3104 // user quits from the main 'Session Setup' dialog (i.e. reaching this
3105 // point does NOT indicate an abnormal termination). Therefore, let's
3106 // behave gracefully (i.e. let's do some cleanup) before we call exit()
3108 pthread_cancel_all ();
3116 session_dialog.hide ();
3119 /* if we run the startup dialog again, offer more than just "new session" */
3121 should_be_new = false;
3123 session_name = session_dialog.session_name (likely_new);
3124 session_path = session_dialog.session_folder ();
3130 string::size_type suffix = session_name.find (statefile_suffix);
3132 if (suffix != string::npos) {
3133 session_name = session_name.substr (0, suffix);
3136 /* this shouldn't happen, but we catch it just in case it does */
3138 if (session_name.empty()) {
3142 if (session_dialog.use_session_template()) {
3143 template_name = session_dialog.session_template_name();
3144 _session_is_new = true;
3147 if (session_name[0] == G_DIR_SEPARATOR ||
3148 #ifdef PLATFORM_WINDOWS
3149 (session_name.length() > 3 && session_name[1] == ':' && session_name[2] == G_DIR_SEPARATOR)
3151 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
3152 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)
3157 /* absolute path or cwd-relative path specified for session name: infer session folder
3158 from what was given.
3161 session_path = Glib::path_get_dirname (session_name);
3162 session_name = Glib::path_get_basename (session_name);
3166 session_path = session_dialog.session_folder();
3168 char illegal = Session::session_name_is_legal (session_name);
3171 MessageDialog msg (session_dialog,
3172 string_compose (_("To ensure compatibility with various systems\n"
3173 "session names may not contain a '%1' character"),
3176 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3181 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
3184 if (likely_new && !nsm) {
3186 std::string existing = Glib::build_filename (session_path, session_name);
3188 if (!ask_about_loading_existing_session (existing)) {
3189 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3194 _session_is_new = false;
3199 pop_back_splash (session_dialog);
3200 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
3202 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3206 char illegal = Session::session_name_is_legal(session_name);
3209 pop_back_splash (session_dialog);
3210 MessageDialog msg (session_dialog, string_compose(_("To ensure compatibility with various systems\n"
3211 "session names may not contain a '%1' character"), illegal));
3213 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3217 _session_is_new = true;
3220 if (likely_new && template_name.empty()) {
3222 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3226 ret = load_session (session_path, session_name, template_name);
3229 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
3233 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
3234 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
3238 /* clear this to avoid endless attempts to load the
3242 ARDOUR_COMMAND_LINE::session_name = "";
3246 _session_dialog = NULL;
3252 ARDOUR_UI::close_session()
3254 if (!check_audioengine (_main_window)) {
3258 if (unload_session (true)) {
3262 ARDOUR_COMMAND_LINE::session_name = "";
3264 if (get_session_parameters (true, false)) {
3269 /** @param snap_name Snapshot name (without .ardour suffix).
3270 * @return -2 if the load failed because we are not connected to the AudioEngine.
3273 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
3275 Session *new_session;
3280 unload_status = unload_session ();
3282 if (unload_status < 0) {
3284 } else if (unload_status > 0) {
3290 session_loaded = false;
3292 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
3295 new_session = new Session (*AudioEngine::instance(), path, snap_name, 0, mix_template);
3298 /* this one is special */
3300 catch (AudioEngine::PortRegistrationFailure& err) {
3302 MessageDialog msg (err.what(),
3305 Gtk::BUTTONS_CLOSE);
3307 msg.set_title (_("Port Registration Error"));
3308 msg.set_secondary_text (_("Click the Close button to try again."));
3309 msg.set_position (Gtk::WIN_POS_CENTER);
3310 pop_back_splash (msg);
3313 int response = msg.run ();
3318 case RESPONSE_CANCEL:
3325 catch (SessionException e) {
3326 MessageDialog msg (string_compose(
3327 _("Session \"%1 (snapshot %2)\" did not load successfully: %3"),
3328 path, snap_name, e.what()),
3333 msg.set_title (_("Loading Error"));
3334 msg.set_position (Gtk::WIN_POS_CENTER);
3335 pop_back_splash (msg);
3347 MessageDialog msg (string_compose(
3348 _("Session \"%1 (snapshot %2)\" did not load successfully"),
3354 msg.set_title (_("Loading Error"));
3355 msg.set_position (Gtk::WIN_POS_CENTER);
3356 pop_back_splash (msg);
3368 list<string> const u = new_session->unknown_processors ();
3370 MissingPluginDialog d (_session, u);
3375 if (!new_session->writable()) {
3376 MessageDialog msg (_("This session has been opened in read-only mode.\n\nYou will not be able to record or save."),
3381 msg.set_title (_("Read-only Session"));
3382 msg.set_position (Gtk::WIN_POS_CENTER);
3383 pop_back_splash (msg);
3390 /* Now the session been created, add the transport controls */
3391 new_session->add_controllable(roll_controllable);
3392 new_session->add_controllable(stop_controllable);
3393 new_session->add_controllable(goto_start_controllable);
3394 new_session->add_controllable(goto_end_controllable);
3395 new_session->add_controllable(auto_loop_controllable);
3396 new_session->add_controllable(play_selection_controllable);
3397 new_session->add_controllable(rec_controllable);
3399 set_session (new_session);
3401 session_loaded = true;
3404 _session->set_clean ();
3407 #ifdef WINDOWS_VST_SUPPORT
3408 fst_stop_threading();
3412 Timers::TimerSuspender t;
3416 #ifdef WINDOWS_VST_SUPPORT
3417 fst_start_threading();
3426 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
3428 Session *new_session;
3431 session_loaded = false;
3432 x = unload_session ();
3440 _session_is_new = true;
3443 new_session = new Session (*AudioEngine::instance(), path, snap_name, &bus_profile);
3446 catch (SessionException e) {
3448 MessageDialog msg (string_compose(_("Could not create session in \"%1\": %2"), path, e.what()));
3449 msg.set_title (_("Loading Error"));
3450 msg.set_position (Gtk::WIN_POS_CENTER);
3451 pop_back_splash (msg);
3457 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
3458 msg.set_title (_("Loading Error"));
3459 msg.set_position (Gtk::WIN_POS_CENTER);
3460 pop_back_splash (msg);
3465 /* Give the new session the default GUI state, if such things exist */
3468 n = Config->instant_xml (X_("Editor"));
3470 n->remove_nodes_and_delete ("Selection"); // no not apply selection to new sessions.
3471 new_session->add_instant_xml (*n, false);
3473 n = Config->instant_xml (X_("Mixer"));
3475 new_session->add_instant_xml (*n, false);
3478 /* Put the playhead at 0 and scroll fully left */
3479 n = new_session->instant_xml (X_("Editor"));
3481 n->add_property (X_("playhead"), X_("0"));
3482 n->add_property (X_("left-frame"), X_("0"));
3485 set_session (new_session);
3487 session_loaded = true;
3489 new_session->save_state(new_session->name());
3495 ARDOUR_UI::launch_chat ()
3497 MessageDialog dialog(_("<b>Just ask and wait for an answer.\nIt may take from minutes to hours.</b>"), true);
3499 dialog.set_title (_("About the Chat"));
3500 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."));
3502 switch (dialog.run()) {
3505 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
3506 #elif defined PLATFORM_WINDOWS
3507 open_uri("http://webchat.freenode.net/?channels=ardour-windows");
3509 open_uri("http://webchat.freenode.net/?channels=ardour");
3518 ARDOUR_UI::launch_manual ()
3520 PBD::open_uri (Config->get_tutorial_manual_url());
3524 ARDOUR_UI::launch_reference ()
3526 PBD::open_uri (Config->get_reference_manual_url());
3530 ARDOUR_UI::launch_tracker ()
3532 PBD::open_uri ("http://tracker.ardour.org");
3536 ARDOUR_UI::launch_subscribe ()
3538 PBD::open_uri ("https://community.ardour.org/s/subscribe");
3542 ARDOUR_UI::launch_cheat_sheet ()
3545 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheat_sheet_osx.pdf");
3547 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheatsheet.pdf");
3552 ARDOUR_UI::launch_website ()
3554 PBD::open_uri ("http://ardour.org");
3558 ARDOUR_UI::launch_website_dev ()
3560 PBD::open_uri ("http://ardour.org/development.html");
3564 ARDOUR_UI::launch_forums ()
3566 PBD::open_uri ("https://community.ardour.org/forums");
3570 ARDOUR_UI::launch_howto_report ()
3572 PBD::open_uri ("http://ardour.org/reporting_bugs");
3576 ARDOUR_UI::loading_message (const std::string& msg)
3578 if (ARDOUR_COMMAND_LINE::no_splash) {
3586 splash->message (msg);
3590 ARDOUR_UI::show_splash ()
3594 splash = new Splash;
3604 ARDOUR_UI::hide_splash ()
3611 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title, const bool msg_delete)
3615 removed = rep.paths.size();
3618 MessageDialog msgd (_main_window,
3619 _("No files were ready for clean-up"),
3623 msgd.set_title (_("Clean-up"));
3624 msgd.set_secondary_text (_("If this seems suprising, \n\
3625 check for any existing snapshots.\n\
3626 These may still include regions that\n\
3627 require some unused files to continue to exist."));
3633 ArdourDialog results (_("Clean-up"), true, false);
3635 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
3636 CleanupResultsModelColumns() {
3640 Gtk::TreeModelColumn<std::string> visible_name;
3641 Gtk::TreeModelColumn<std::string> fullpath;
3645 CleanupResultsModelColumns results_columns;
3646 Glib::RefPtr<Gtk::ListStore> results_model;
3647 Gtk::TreeView results_display;
3649 results_model = ListStore::create (results_columns);
3650 results_display.set_model (results_model);
3651 results_display.append_column (list_title, results_columns.visible_name);
3653 results_display.set_name ("CleanupResultsList");
3654 results_display.set_headers_visible (true);
3655 results_display.set_headers_clickable (false);
3656 results_display.set_reorderable (false);
3658 Gtk::ScrolledWindow list_scroller;
3661 Gtk::HBox dhbox; // the hbox for the image and text
3662 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
3663 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
3665 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
3667 const string dead_directory = _session->session_directory().dead_path();
3670 %1 - number of files removed
3671 %2 - location of "dead"
3672 %3 - size of files affected
3673 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
3676 const char* bprefix;
3677 double space_adjusted = 0;
3679 if (rep.space < 1000) {
3681 space_adjusted = rep.space;
3682 } else if (rep.space < 1000000) {
3683 bprefix = _("kilo");
3684 space_adjusted = floorf((float)rep.space / 1000.0);
3685 } else if (rep.space < 1000000 * 1000) {
3686 bprefix = _("mega");
3687 space_adjusted = floorf((float)rep.space / (1000.0 * 1000.0));
3689 bprefix = _("giga");
3690 space_adjusted = floorf((float)rep.space / (1000.0 * 1000 * 1000.0));
3694 txt.set_markup (string_compose (P_("\
3695 The following file was deleted from %2,\n\
3696 releasing %3 %4bytes of disk space", "\
3697 The following %1 files were deleted from %2,\n\
3698 releasing %3 %4bytes of disk space", removed),
3699 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3701 txt.set_markup (string_compose (P_("\
3702 The following file was not in use and \n\
3703 has been moved to: %2\n\n\
3704 After a restart of %5\n\n\
3705 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3706 will release an additional %3 %4bytes of disk space.\n", "\
3707 The following %1 files were not in use and \n\
3708 have been moved to: %2\n\n\
3709 After a restart of %5\n\n\
3710 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3711 will release an additional %3 %4bytes of disk space.\n", removed),
3712 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3715 dhbox.pack_start (*dimage, true, false, 5);
3716 dhbox.pack_start (txt, true, false, 5);
3718 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
3719 TreeModel::Row row = *(results_model->append());
3720 row[results_columns.visible_name] = *i;
3721 row[results_columns.fullpath] = *i;
3724 list_scroller.add (results_display);
3725 list_scroller.set_size_request (-1, 150);
3726 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
3728 dvbox.pack_start (dhbox, true, false, 5);
3729 dvbox.pack_start (list_scroller, true, false, 5);
3730 ddhbox.pack_start (dvbox, true, false, 5);
3732 results.get_vbox()->pack_start (ddhbox, true, false, 5);
3733 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
3734 results.set_default_response (RESPONSE_CLOSE);
3735 results.set_position (Gtk::WIN_POS_MOUSE);
3737 results_display.show();
3738 list_scroller.show();
3745 //results.get_vbox()->show();
3746 results.set_resizable (false);
3753 ARDOUR_UI::cleanup ()
3755 if (_session == 0) {
3756 /* shouldn't happen: menu item is insensitive */
3761 MessageDialog checker (_("Are you sure you want to clean-up?"),
3763 Gtk::MESSAGE_QUESTION,
3766 checker.set_title (_("Clean-up"));
3768 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
3769 ALL undo/redo information will be lost if you clean-up.\n\
3770 Clean-up will move all unused files to a \"dead\" location."));
3772 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3773 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
3774 checker.set_default_response (RESPONSE_CANCEL);
3776 checker.set_name (_("CleanupDialog"));
3777 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3778 checker.set_position (Gtk::WIN_POS_MOUSE);
3780 switch (checker.run()) {
3781 case RESPONSE_ACCEPT:
3787 ARDOUR::CleanupReport rep;
3789 editor->prepare_for_cleanup ();
3791 /* do not allow flush until a session is reloaded */
3793 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3795 act->set_sensitive (false);
3798 if (_session->cleanup_sources (rep)) {
3799 editor->finish_cleanup ();
3803 editor->finish_cleanup ();
3806 display_cleanup_results (rep, _("Cleaned Files"), false);
3810 ARDOUR_UI::flush_trash ()
3812 if (_session == 0) {
3813 /* shouldn't happen: menu item is insensitive */
3817 ARDOUR::CleanupReport rep;
3819 if (_session->cleanup_trash_sources (rep)) {
3823 display_cleanup_results (rep, _("deleted file"), true);
3827 ARDOUR_UI::cleanup_peakfiles ()
3829 if (_session == 0) {
3830 /* shouldn't happen: menu item is insensitive */
3834 if (! _session->can_cleanup_peakfiles ()) {
3838 // get all region-views in this session
3840 TrackViewList empty;
3842 editor->get_regions_after(rs, (framepos_t) 0, empty);
3843 std::list<RegionView*> views = rs.by_layer();
3845 // remove displayed audio-region-views waveforms
3846 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
3847 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
3848 if (!arv) { continue ; }
3849 arv->delete_waves();
3852 // cleanup peak files:
3853 // - stop pending peakfile threads
3854 // - close peakfiles if any
3855 // - remove peak dir in session
3856 // - setup peakfiles (background thread)
3857 _session->cleanup_peakfiles ();
3859 // re-add waves to ARV
3860 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
3861 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
3862 if (!arv) { continue ; }
3863 arv->create_waves();
3868 ARDOUR_UI::setup_order_hint (AddRouteDialog::InsertAt place)
3870 uint32_t order_hint = UINT32_MAX;
3872 if (editor->get_selection().tracks.empty()) {
3877 we want the new routes to have their order keys set starting from
3878 the highest order key in the selection + 1 (if available).
3881 if (place == AddRouteDialog::AfterSelection) {
3882 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.back());
3884 order_hint = rtav->route()->order_key();
3887 } else if (place == AddRouteDialog::BeforeSelection) {
3888 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.front());
3890 order_hint = rtav->route()->order_key();
3892 } else if (place == AddRouteDialog::First) {
3895 /* leave order_hint at UINT32_MAX */
3898 if (order_hint == UINT32_MAX) {
3899 /** AddRouteDialog::Last or selection with first/last not a RouteTimeAxisView
3900 * not setting an order hint will place new routes last.
3905 _session->set_order_hint (order_hint);
3907 /* create a gap in the existing route order keys to accomodate new routes.*/
3908 boost::shared_ptr <RouteList> rd = _session->get_routes();
3909 for (RouteList::iterator ri = rd->begin(); ri != rd->end(); ++ri) {
3910 boost::shared_ptr<Route> rt (*ri);
3912 if (rt->is_monitor()) {
3916 if (rt->order_key () >= order_hint) {
3917 rt->set_order_key (rt->order_key () + add_route_dialog->count());
3923 ARDOUR_UI::start_duplicate_routes ()
3925 if (!duplicate_routes_dialog) {
3926 duplicate_routes_dialog = new DuplicateRouteDialog;
3929 if (duplicate_routes_dialog->restart (_session)) {
3933 duplicate_routes_dialog->present ();
3937 ARDOUR_UI::add_route (Gtk::Window* /* ignored */)
3945 if (add_route_dialog->is_visible()) {
3946 /* we're already doing this */
3950 ResponseType r = (ResponseType) add_route_dialog->run ();
3952 add_route_dialog->hide();
3955 case RESPONSE_ACCEPT:
3962 if ((count = add_route_dialog->count()) <= 0) {
3966 setup_order_hint(add_route_dialog->insert_at());
3967 string template_path = add_route_dialog->track_template();
3968 DisplaySuspender ds;
3970 if (!template_path.empty()) {
3971 if (add_route_dialog->name_template_is_default()) {
3972 _session->new_route_from_template (count, template_path, string());
3974 _session->new_route_from_template (count, template_path, add_route_dialog->name_template());
3979 ChanCount input_chan= add_route_dialog->channels ();
3980 ChanCount output_chan;
3981 string name_template = add_route_dialog->name_template ();
3982 PluginInfoPtr instrument = add_route_dialog->requested_instrument ();
3983 RouteGroup* route_group = add_route_dialog->route_group ();
3984 AutoConnectOption oac = Config->get_output_auto_connect();
3985 bool strict_io = add_route_dialog->use_strict_io ();
3987 if (oac & AutoConnectMaster) {
3988 output_chan.set (DataType::AUDIO, (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan.n_audio()));
3989 output_chan.set (DataType::MIDI, 0);
3991 output_chan = input_chan;
3994 /* XXX do something with name template */
3996 switch (add_route_dialog->type_wanted()) {
3997 case AddRouteDialog::AudioTrack:
3998 session_add_audio_track (input_chan.n_audio(), output_chan.n_audio(), add_route_dialog->mode(), route_group, count, name_template, strict_io);
4000 case AddRouteDialog::MidiTrack:
4001 session_add_midi_track (route_group, count, name_template, strict_io, instrument);
4003 case AddRouteDialog::MixedTrack:
4004 session_add_mixed_track (input_chan, output_chan, route_group, count, name_template, strict_io, instrument);
4006 case AddRouteDialog::AudioBus:
4007 session_add_audio_bus (input_chan.n_audio(), output_chan.n_audio(), route_group, count, name_template, strict_io);
4009 case AddRouteDialog::MidiBus:
4010 session_add_midi_bus (route_group, count, name_template, strict_io, instrument);
4016 ARDOUR_UI::add_lua_script ()
4022 LuaScriptInfoPtr spi;
4023 ScriptSelector ss ("Add Lua Session Script", LuaScriptInfo::Session);
4024 switch (ss.run ()) {
4025 case Gtk::RESPONSE_ACCEPT:
4033 std::string script = "";
4036 script = Glib::file_get_contents (spi->path);
4037 } catch (Glib::FileError e) {
4038 string msg = string_compose (_("Cannot read session script '%1': %2"), spi->path, e.what());
4039 MessageDialog am (msg);
4044 LuaScriptParamList lsp = LuaScriptParams::script_params (spi, "sess_params");
4045 std::vector<std::string> reg = _session->registered_lua_functions ();
4047 ScriptParameterDialog spd (_("Set Script Parameters"), spi, reg, lsp);
4048 switch (spd.run ()) {
4049 case Gtk::RESPONSE_ACCEPT:
4056 _session->register_lua_function (spd.name(), script, lsp);
4057 } catch (luabridge::LuaException const& e) {
4058 string msg = string_compose (_("Session script '%1' instantiation failed: %2"), spd.name(), e.what ());
4059 MessageDialog am (msg);
4061 } catch (SessionException e) {
4062 string msg = string_compose (_("Loading Session script '%1' failed: %2"), spd.name(), e.what ());
4063 MessageDialog am (msg);
4069 ARDOUR_UI::remove_lua_script ()
4074 if (_session->registered_lua_function_count () == 0) {
4075 string msg = _("There are no active Lua session scripts present in this session.");
4076 MessageDialog am (msg);
4081 std::vector<std::string> reg = _session->registered_lua_functions ();
4082 SessionScriptManager sm ("Remove Lua Session Script", reg);
4083 switch (sm.run ()) {
4084 case Gtk::RESPONSE_ACCEPT:
4090 _session->unregister_lua_function (sm.name());
4091 } catch (luabridge::LuaException const& e) {
4092 string msg = string_compose (_("Session script '%1' removal failed: %2"), sm.name(), e.what ());
4093 MessageDialog am (msg);
4099 ARDOUR_UI::stop_video_server (bool ask_confirm)
4101 if (!video_server_process && ask_confirm) {
4102 warning << string_compose (_("Video-Server was not launched by %1. The request to stop it is ignored."), PROGRAM_NAME) << endmsg;
4104 if (video_server_process) {
4106 ArdourDialog confirm (_("Stop Video-Server"), true);
4107 Label m (_("Do you really want to stop the Video Server?"));
4108 confirm.get_vbox()->pack_start (m, true, true);
4109 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
4110 confirm.add_button (_("Yes, Stop It"), Gtk::RESPONSE_ACCEPT);
4111 confirm.show_all ();
4112 if (confirm.run() == RESPONSE_CANCEL) {
4116 delete video_server_process;
4117 video_server_process =0;
4122 ARDOUR_UI::start_video_server_menu (Gtk::Window* float_window)
4124 ARDOUR_UI::start_video_server( float_window, true);
4128 ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg)
4134 if (ARDOUR_UI::instance()->video_timeline->check_server()) {
4135 if (video_server_process) {
4136 popup_error(_("The Video Server is already started."));
4138 popup_error(_("An external Video Server is configured and can be reached. Not starting a new instance."));
4144 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4146 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4148 VideoServerDialog *video_server_dialog = new VideoServerDialog (_session);
4150 video_server_dialog->set_transient_for (*float_window);
4153 if (!Config->get_show_video_server_dialog() && firsttime < 2) {
4154 video_server_dialog->hide();
4156 ResponseType r = (ResponseType) video_server_dialog->run ();
4157 video_server_dialog->hide();
4158 if (r != RESPONSE_ACCEPT) { return false; }
4159 if (video_server_dialog->show_again()) {
4160 Config->set_show_video_server_dialog(false);
4164 std::string icsd_exec = video_server_dialog->get_exec_path();
4165 std::string icsd_docroot = video_server_dialog->get_docroot();
4166 if (icsd_docroot.empty()) {
4167 #ifndef PLATFORM_WINDOWS
4168 icsd_docroot = X_("/");
4170 icsd_docroot = X_("C:\\");
4175 if (g_lstat (icsd_docroot.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode)) {
4176 warning << _("Specified docroot is not an existing directory.") << endmsg;
4179 #ifndef PLATFORM_WINDOWS
4180 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4181 || (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0 ) {
4182 warning << _("Given Video Server is not an executable file.") << endmsg;
4186 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4187 || (sb.st_mode & (S_IXUSR)) == 0 ) {
4188 warning << _("Given Video Server is not an executable file.") << endmsg;
4194 argp=(char**) calloc(9,sizeof(char*));
4195 argp[0] = strdup(icsd_exec.c_str());
4196 argp[1] = strdup("-P");
4197 argp[2] = (char*) calloc(16,sizeof(char)); snprintf(argp[2], 16, "%s", video_server_dialog->get_listenaddr().c_str());
4198 argp[3] = strdup("-p");
4199 argp[4] = (char*) calloc(6,sizeof(char)); snprintf(argp[4], 6, "%i", video_server_dialog->get_listenport());
4200 argp[5] = strdup("-C");
4201 argp[6] = (char*) calloc(6,sizeof(char)); snprintf(argp[6], 6, "%i", video_server_dialog->get_cachesize());
4202 argp[7] = strdup(icsd_docroot.c_str());
4204 stop_video_server();
4206 if (icsd_docroot == X_("/") || icsd_docroot == X_("C:\\")) {
4207 Config->set_video_advanced_setup(false);
4209 std::ostringstream osstream;
4210 osstream << "http://127.0.0.1:" << video_server_dialog->get_listenport() << "/";
4211 Config->set_video_server_url(osstream.str());
4212 Config->set_video_server_docroot(icsd_docroot);
4213 Config->set_video_advanced_setup(true);
4216 if (video_server_process) {
4217 delete video_server_process;
4220 video_server_process = new ARDOUR::SystemExec(icsd_exec, argp);
4221 if (video_server_process->start()) {
4222 warning << _("Cannot launch the video-server") << endmsg;
4225 int timeout = 120; // 6 sec
4226 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4227 Glib::usleep (50000);
4229 if (--timeout <= 0 || !video_server_process->is_running()) break;
4232 warning << _("Video-server was started but does not respond to requests...") << endmsg;
4234 if (!ARDOUR_UI::instance()->video_timeline->check_server_docroot()) {
4235 delete video_server_process;
4236 video_server_process = 0;
4244 ARDOUR_UI::add_video (Gtk::Window* float_window)
4250 if (!start_video_server(float_window, false)) {
4251 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4256 add_video_dialog->set_transient_for (*float_window);
4259 if (add_video_dialog->is_visible()) {
4260 /* we're already doing this */
4264 ResponseType r = (ResponseType) add_video_dialog->run ();
4265 add_video_dialog->hide();
4266 if (r != RESPONSE_ACCEPT) { return; }
4268 bool local_file, orig_local_file;
4269 std::string path = add_video_dialog->file_name(local_file);
4271 std::string orig_path = path;
4272 orig_local_file = local_file;
4274 bool auto_set_session_fps = add_video_dialog->auto_set_session_fps();
4276 if (local_file && !Glib::file_test(path, Glib::FILE_TEST_EXISTS)) {
4277 warning << string_compose(_("could not open %1"), path) << endmsg;
4280 if (!local_file && path.length() == 0) {
4281 warning << _("no video-file selected") << endmsg;
4285 std::string audio_from_video;
4286 bool detect_ltc = false;
4288 switch (add_video_dialog->import_option()) {
4289 case VTL_IMPORT_TRANSCODE:
4291 TranscodeVideoDialog *transcode_video_dialog;
4292 transcode_video_dialog = new TranscodeVideoDialog (_session, path);
4293 ResponseType r = (ResponseType) transcode_video_dialog->run ();
4294 transcode_video_dialog->hide();
4295 if (r != RESPONSE_ACCEPT) {
4296 delete transcode_video_dialog;
4300 audio_from_video = transcode_video_dialog->get_audiofile();
4302 if (!audio_from_video.empty() && transcode_video_dialog->detect_ltc()) {
4305 else if (!audio_from_video.empty()) {
4306 editor->embed_audio_from_video(
4308 video_timeline->get_offset(),
4309 (transcode_video_dialog->import_option() != VTL_IMPORT_NO_VIDEO)
4312 switch (transcode_video_dialog->import_option()) {
4313 case VTL_IMPORT_TRANSCODED:
4314 path = transcode_video_dialog->get_filename();
4317 case VTL_IMPORT_REFERENCE:
4320 delete transcode_video_dialog;
4323 delete transcode_video_dialog;
4327 case VTL_IMPORT_NONE:
4331 /* strip _session->session_directory().video_path() from video file if possible */
4332 if (local_file && !path.compare(0, _session->session_directory().video_path().size(), _session->session_directory().video_path())) {
4333 path=path.substr(_session->session_directory().video_path().size());
4334 if (path.at(0) == G_DIR_SEPARATOR) {
4335 path=path.substr(1);
4339 video_timeline->set_update_session_fps(auto_set_session_fps);
4341 if (video_timeline->video_file_info(path, local_file)) {
4342 XMLNode* node = new XMLNode(X_("Videotimeline"));
4343 node->add_property (X_("Filename"), path);
4344 node->add_property (X_("AutoFPS"), auto_set_session_fps?X_("1"):X_("0"));
4345 node->add_property (X_("LocalFile"), local_file?X_("1"):X_("0"));
4346 if (orig_local_file) {
4347 node->add_property (X_("OriginalVideoFile"), orig_path);
4349 node->remove_property (X_("OriginalVideoFile"));
4351 _session->add_extra_xml (*node);
4352 _session->set_dirty ();
4354 if (!audio_from_video.empty() && detect_ltc) {
4355 std::vector<LTCFileReader::LTCMap> ltc_seq;
4358 /* TODO ask user about TV standard (LTC alignment if any) */
4359 LTCFileReader ltcr (audio_from_video, video_timeline->get_video_file_fps());
4360 /* TODO ASK user which channel: 0 .. ltcr->channels() - 1 */
4362 ltc_seq = ltcr.read_ltc (/*channel*/ 0, /*max LTC frames to decode*/ 15);
4364 /* TODO seek near end of file, and read LTC until end.
4365 * if it fails to find any LTC frames, scan complete file
4367 * calculate drift of LTC compared to video-duration,
4368 * ask user for reference (timecode from start/mid/end)
4371 // LTCFileReader will have written error messages
4374 ::g_unlink(audio_from_video.c_str());
4376 if (ltc_seq.size() == 0) {
4377 PBD::error << _("No LTC detected, video will not be aligned.") << endmsg;
4379 /* the very first TC in the file is somteimes not aligned properly */
4380 int i = ltc_seq.size() -1;
4381 ARDOUR::frameoffset_t video_start_offset =
4382 _session->nominal_frame_rate() * (ltc_seq[i].timecode_sec - ltc_seq[i].framepos_sec);
4383 PBD::info << string_compose (_("Align video-start to %1 [samples]"), video_start_offset) << endmsg;
4384 video_timeline->set_offset(video_start_offset);
4388 _session->maybe_update_session_range(
4389 std::max(video_timeline->get_offset(), (ARDOUR::frameoffset_t) 0),
4390 std::max(video_timeline->get_offset() + video_timeline->get_duration(), (ARDOUR::frameoffset_t) 0));
4393 if (add_video_dialog->launch_xjadeo() && local_file) {
4394 editor->set_xjadeo_sensitive(true);
4395 editor->toggle_xjadeo_proc(1);
4397 editor->toggle_xjadeo_proc(0);
4399 editor->toggle_ruler_video(true);
4404 ARDOUR_UI::remove_video ()
4406 video_timeline->close_session();
4407 editor->toggle_ruler_video(false);
4410 video_timeline->set_offset_locked(false);
4411 video_timeline->set_offset(0);
4413 /* delete session state */
4414 XMLNode* node = new XMLNode(X_("Videotimeline"));
4415 _session->add_extra_xml(*node);
4416 node = new XMLNode(X_("Videomonitor"));
4417 _session->add_extra_xml(*node);
4418 node = new XMLNode(X_("Videoexport"));
4419 _session->add_extra_xml(*node);
4420 stop_video_server();
4424 ARDOUR_UI::flush_videotimeline_cache (bool localcacheonly)
4426 if (localcacheonly) {
4427 video_timeline->vmon_update();
4429 video_timeline->flush_cache();
4431 editor->queue_visual_videotimeline_update();
4435 ARDOUR_UI::export_video (bool range)
4437 if (ARDOUR::Config->get_show_video_export_info()) {
4438 ExportVideoInfobox infobox (_session);
4439 Gtk::ResponseType rv = (Gtk::ResponseType) infobox.run();
4440 if (infobox.show_again()) {
4441 ARDOUR::Config->set_show_video_export_info(false);
4444 case GTK_RESPONSE_YES:
4445 PBD::open_uri (ARDOUR::Config->get_reference_manual_url() + "/video-timeline/operations/#export");
4451 export_video_dialog->set_session (_session);
4452 export_video_dialog->apply_state(editor->get_selection().time, range);
4453 export_video_dialog->run ();
4454 export_video_dialog->hide ();
4458 ARDOUR_UI::mixer_settings () const
4463 node = _session->instant_xml(X_("Mixer"));
4465 node = Config->instant_xml(X_("Mixer"));
4469 node = new XMLNode (X_("Mixer"));
4476 ARDOUR_UI::main_window_settings () const
4481 node = _session->instant_xml(X_("Main"));
4483 node = Config->instant_xml(X_("Main"));
4487 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4488 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4493 node = new XMLNode (X_("Main"));
4500 ARDOUR_UI::editor_settings () const
4505 node = _session->instant_xml(X_("Editor"));
4507 node = Config->instant_xml(X_("Editor"));
4511 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4512 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4517 node = new XMLNode (X_("Editor"));
4524 ARDOUR_UI::keyboard_settings () const
4528 node = Config->extra_xml(X_("Keyboard"));
4531 node = new XMLNode (X_("Keyboard"));
4538 ARDOUR_UI::create_xrun_marker (framepos_t where)
4541 Location *location = new Location (*_session, where, where, _("xrun"), Location::IsMark);
4542 _session->locations()->add (location);
4547 ARDOUR_UI::halt_on_xrun_message ()
4549 cerr << "HALT on xrun\n";
4550 MessageDialog msg (_main_window, _("Recording was stopped because your system could not keep up."));
4555 ARDOUR_UI::xrun_handler (framepos_t where)
4561 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
4563 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
4564 create_xrun_marker(where);
4567 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
4568 halt_on_xrun_message ();
4573 ARDOUR_UI::disk_overrun_handler ()
4575 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
4577 if (!have_disk_speed_dialog_displayed) {
4578 have_disk_speed_dialog_displayed = true;
4579 MessageDialog* msg = new MessageDialog (_main_window, string_compose (_("\
4580 The disk system on your computer\n\
4581 was not able to keep up with %1.\n\
4583 Specifically, it failed to write data to disk\n\
4584 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
4585 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4591 /* TODO: this is getting elaborate enough to warrant being split into a dedicated class */
4592 static MessageDialog *scan_dlg = NULL;
4593 static ProgressBar *scan_pbar = NULL;
4594 static HBox *scan_tbox = NULL;
4595 static Gtk::Button *scan_timeout_button;
4598 ARDOUR_UI::cancel_plugin_scan ()
4600 PluginManager::instance().cancel_plugin_scan();
4604 ARDOUR_UI::cancel_plugin_timeout ()
4606 PluginManager::instance().cancel_plugin_timeout();
4607 scan_timeout_button->set_sensitive (false);
4611 ARDOUR_UI::plugin_scan_timeout (int timeout)
4613 if (!scan_dlg || !scan_dlg->is_mapped() || !scan_pbar) {
4617 scan_pbar->set_sensitive (false);
4618 scan_timeout_button->set_sensitive (true);
4619 scan_pbar->set_fraction ((float) timeout / (float) Config->get_vst_scan_timeout());
4622 scan_pbar->set_sensitive (false);
4623 scan_timeout_button->set_sensitive (false);
4629 ARDOUR_UI::plugin_scan_dialog (std::string type, std::string plugin, bool can_cancel)
4631 if (type == X_("closeme") && !(scan_dlg && scan_dlg->is_mapped())) {
4635 const bool cancelled = PluginManager::instance().cancelled();
4636 if (type != X_("closeme") && (!UIConfiguration::instance().get_show_plugin_scan_window()) && !_initial_verbose_plugin_scan) {
4637 if (cancelled && scan_dlg->is_mapped()) {
4642 if (cancelled || !can_cancel) {
4647 static Gtk::Button *cancel_button;
4649 scan_dlg = new MessageDialog("", false, MESSAGE_INFO, BUTTONS_NONE); // TODO manage
4650 VBox* vbox = scan_dlg->get_vbox();
4651 vbox->set_size_request(400,-1);
4652 scan_dlg->set_title (_("Scanning for plugins"));
4654 cancel_button = manage(new Gtk::Button(_("Cancel plugin scan")));
4655 cancel_button->set_name ("EditorGTKButton");
4656 cancel_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_scan) );
4657 cancel_button->show();
4659 scan_dlg->get_vbox()->pack_start ( *cancel_button, PACK_SHRINK);
4661 scan_tbox = manage( new HBox() );
4663 scan_timeout_button = manage(new Gtk::Button(_("Stop Timeout")));
4664 scan_timeout_button->set_name ("EditorGTKButton");
4665 scan_timeout_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_timeout) );
4666 scan_timeout_button->show();
4668 scan_pbar = manage(new ProgressBar());
4669 scan_pbar->set_orientation(Gtk::PROGRESS_RIGHT_TO_LEFT);
4670 scan_pbar->set_text(_("Scan Timeout"));
4673 scan_tbox->pack_start (*scan_pbar, PACK_EXPAND_WIDGET, 4);
4674 scan_tbox->pack_start (*scan_timeout_button, PACK_SHRINK, 4);
4676 scan_dlg->get_vbox()->pack_start (*scan_tbox, PACK_SHRINK, 4);
4679 assert(scan_dlg && scan_tbox && cancel_button);
4681 if (type == X_("closeme")) {
4685 scan_dlg->set_message(type + ": " + Glib::path_get_basename(plugin));
4688 if (!can_cancel || !cancelled) {
4689 scan_timeout_button->set_sensitive(false);
4691 cancel_button->set_sensitive(can_cancel && !cancelled);
4697 ARDOUR_UI::gui_idle_handler ()
4700 /* due to idle calls, gtk_events_pending() may always return true */
4701 while (gtk_events_pending() && --timeout) {
4702 gtk_main_iteration ();
4707 ARDOUR_UI::disk_underrun_handler ()
4709 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
4711 if (!have_disk_speed_dialog_displayed) {
4712 have_disk_speed_dialog_displayed = true;
4713 MessageDialog* msg = new MessageDialog (
4714 _main_window, string_compose (_("The disk system on your computer\n\
4715 was not able to keep up with %1.\n\
4717 Specifically, it failed to read data from disk\n\
4718 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
4719 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4725 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
4727 have_disk_speed_dialog_displayed = false;
4732 ARDOUR_UI::session_dialog (std::string msg)
4734 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
4738 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
4745 ARDOUR_UI::pending_state_dialog ()
4747 HBox* hbox = manage (new HBox());
4748 Image* image = manage (new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG));
4749 ArdourDialog dialog (_("Crash Recovery"), true);
4750 Label message (string_compose (_("\
4751 This session appears to have been in the\n\
4752 middle of recording when %1 or\n\
4753 the computer was shutdown.\n\
4755 %1 can recover any captured audio for\n\
4756 you, or it can ignore it. Please decide\n\
4757 what you would like to do.\n"), PROGRAM_NAME));
4758 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4759 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4760 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4761 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4762 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
4763 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
4764 dialog.set_default_response (RESPONSE_ACCEPT);
4765 dialog.set_position (WIN_POS_CENTER);
4770 switch (dialog.run ()) {
4771 case RESPONSE_ACCEPT:
4779 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
4781 HBox* hbox = new HBox();
4782 Image* image = new Image (Stock::DIALOG_WARNING, ICON_SIZE_DIALOG);
4783 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
4784 Label message (string_compose (_("\
4785 This session was created with a sample rate of %1 Hz, but\n\
4786 %2 is currently running at %3 Hz. If you load this session,\n\
4787 audio may be played at the wrong sample rate.\n"), desired, PROGRAM_NAME, actual));
4789 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4790 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4791 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4792 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4793 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
4794 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
4795 dialog.set_default_response (RESPONSE_ACCEPT);
4796 dialog.set_position (WIN_POS_CENTER);
4801 switch (dialog.run()) {
4802 case RESPONSE_ACCEPT:
4812 ARDOUR_UI::use_config ()
4814 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
4816 set_transport_controllable_state (*node);
4821 ARDOUR_UI::update_transport_clocks (framepos_t pos)
4823 if (UIConfiguration::instance().get_primary_clock_delta_edit_cursor()) {
4824 primary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
4826 primary_clock->set (pos);
4829 if (UIConfiguration::instance().get_secondary_clock_delta_edit_cursor()) {
4830 secondary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
4832 secondary_clock->set (pos);
4835 if (big_clock_window) {
4836 big_clock->set (pos);
4838 ARDOUR_UI::instance()->video_timeline->manual_seek_video_monitor(pos);
4842 ARDOUR_UI::step_edit_status_change (bool yn)
4844 // XXX should really store pre-step edit status of things
4845 // we make insensitive
4848 rec_button.set_active_state (Gtkmm2ext::ImplicitActive);
4849 rec_button.set_sensitive (false);
4851 rec_button.unset_active_state ();;
4852 rec_button.set_sensitive (true);
4857 ARDOUR_UI::record_state_changed ()
4859 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
4861 if (!_session || !big_clock_window) {
4862 /* why bother - the clock isn't visible */
4866 if (_session->record_status () == Session::Recording && _session->have_rec_enabled_track ()) {
4867 big_clock->set_active (true);
4869 big_clock->set_active (false);
4874 ARDOUR_UI::first_idle ()
4877 _session->allow_auto_play (true);
4881 editor->first_idle();
4884 Keyboard::set_can_save_keybindings (true);
4889 ARDOUR_UI::store_clock_modes ()
4891 XMLNode* node = new XMLNode(X_("ClockModes"));
4893 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
4894 XMLNode* child = new XMLNode (X_("Clock"));
4896 child->add_property (X_("name"), (*x)->name());
4897 child->add_property (X_("mode"), enum_2_string ((*x)->mode()));
4898 child->add_property (X_("on"), ((*x)->off() ? X_("no") : X_("yes")));
4900 node->add_child_nocopy (*child);
4903 _session->add_extra_xml (*node);
4904 _session->set_dirty ();
4907 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
4908 : Controllable (name), ui (u), type(tp)
4914 ARDOUR_UI::TransportControllable::set_value (double val, PBD::Controllable::GroupControlDisposition /*group_override*/)
4917 /* do nothing: these are radio-style actions */
4921 const char *action = 0;
4925 action = X_("Roll");
4928 action = X_("Stop");
4931 action = X_("GotoStart");
4934 action = X_("GotoEnd");
4937 action = X_("Loop");
4940 action = X_("PlaySelection");
4943 action = X_("Record");
4953 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
4961 ARDOUR_UI::TransportControllable::get_value (void) const
4988 ARDOUR_UI::setup_profile ()
4990 if (gdk_screen_width() < 1200 || getenv ("ARDOUR_NARROW_SCREEN")) {
4991 Profile->set_small_screen ();
4994 if (g_getenv ("TRX")) {
4995 Profile->set_trx ();
4998 if (g_getenv ("MIXBUS")) {
4999 Profile->set_mixbus ();
5004 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
5006 MissingFileDialog dialog (s, str, type);
5011 int result = dialog.run ();
5018 return 1; // quit entire session load
5021 result = dialog.get_action ();
5027 ARDOUR_UI::ambiguous_file (std::string file, std::vector<std::string> hits)
5029 AmbiguousFileDialog dialog (file, hits);
5036 return dialog.get_which ();
5039 /** Allocate our thread-local buffers */
5041 ARDOUR_UI::get_process_buffers ()
5043 _process_thread->get_buffers ();
5046 /** Drop our thread-local buffers */
5048 ARDOUR_UI::drop_process_buffers ()
5050 _process_thread->drop_buffers ();
5054 ARDOUR_UI::feedback_detected ()
5056 _feedback_exists = true;
5060 ARDOUR_UI::successful_graph_sort ()
5062 _feedback_exists = false;
5066 ARDOUR_UI::midi_panic ()
5069 _session->midi_panic();
5074 ARDOUR_UI::session_format_mismatch (std::string xml_path, std::string backup_path)
5076 const char* start_big = "<span size=\"x-large\" weight=\"bold\">";
5077 const char* end_big = "</span>";
5078 const char* start_mono = "<tt>";
5079 const char* end_mono = "</tt>";
5081 MessageDialog msg (string_compose (_("%4This is a session from an older version of %3%5\n\n"
5082 "%3 has copied the old session file\n\n%6%1%7\n\nto\n\n%6%2%7\n\n"
5083 "From now on, use the -2000 version with older versions of %3"),
5084 xml_path, backup_path, PROGRAM_NAME,
5086 start_mono, end_mono), true);
5093 ARDOUR_UI::reset_peak_display ()
5095 if (!_session || !_session->master_out() || !editor_meter) return;
5096 editor_meter->clear_meters();
5097 editor_meter_max_peak = -INFINITY;
5098 editor_meter_peak_display.set_active_state ( Gtkmm2ext::Off );
5102 ARDOUR_UI::reset_group_peak_display (RouteGroup* group)
5104 if (!_session || !_session->master_out()) return;
5105 if (group == _session->master_out()->route_group()) {
5106 reset_peak_display ();
5111 ARDOUR_UI::reset_route_peak_display (Route* route)
5113 if (!_session || !_session->master_out()) return;
5114 if (_session->master_out().get() == route) {
5115 reset_peak_display ();
5120 ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate)
5122 audio_midi_setup->set_desired_sample_rate (desired_sample_rate);
5123 audio_midi_setup->set_position (WIN_POS_CENTER);
5128 response = audio_midi_setup->run();
5130 case Gtk::RESPONSE_OK:
5131 if (!AudioEngine::instance()->running()) {
5145 ARDOUR_UI::transport_numpad_timeout ()
5147 _numpad_locate_happening = false;
5148 if (_numpad_timeout_connection.connected() )
5149 _numpad_timeout_connection.disconnect();
5154 ARDOUR_UI::transport_numpad_decimal ()
5156 _numpad_timeout_connection.disconnect();
5158 if (_numpad_locate_happening) {
5159 if (editor) editor->goto_nth_marker(_pending_locate_num - 1);
5160 _numpad_locate_happening = false;
5162 _pending_locate_num = 0;
5163 _numpad_locate_happening = true;
5164 _numpad_timeout_connection = Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::transport_numpad_timeout), 2*1000);
5169 ARDOUR_UI::transport_numpad_event (int num)
5171 if ( _numpad_locate_happening ) {
5172 _pending_locate_num = _pending_locate_num*10 + num;
5175 case 0: toggle_roll(false, false); break;
5176 case 1: transport_rewind(1); break;
5177 case 2: transport_forward(1); break;
5178 case 3: transport_record(true); break;
5179 case 4: toggle_session_auto_loop(); break;
5180 case 5: transport_record(false); toggle_session_auto_loop(); break;
5181 case 6: toggle_punch(); break;
5182 case 7: toggle_click(); break;
5183 case 8: toggle_auto_return(); break;
5184 case 9: toggle_follow_edits(); break;
5190 ARDOUR_UI::set_flat_buttons ()
5192 CairoWidget::set_flat_buttons( UIConfiguration::instance().get_flat_buttons() );
5196 ARDOUR_UI::audioengine_became_silent ()
5198 MessageDialog msg (string_compose (_("This is a free/demo copy of %1. It has just switched to silent mode."), PROGRAM_NAME),
5200 Gtk::MESSAGE_WARNING,
5204 msg.set_title (string_compose (_("%1 is now silent"), PROGRAM_NAME));
5206 Gtk::Label pay_label (string_compose (_("Please consider paying for a copy of %1 - you can pay whatever you want."), PROGRAM_NAME));
5207 Gtk::Label subscribe_label (_("Better yet become a subscriber - subscriptions start at US$1 per month."));
5208 Gtk::Button pay_button (_("Pay for a copy (via the web)"));
5209 Gtk::Button subscribe_button (_("Become a subscriber (via the web)"));
5210 Gtk::HBox pay_button_box;
5211 Gtk::HBox subscribe_button_box;
5213 pay_button_box.pack_start (pay_button, true, false);
5214 subscribe_button_box.pack_start (subscribe_button, true, false);
5216 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 */
5218 pay_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://ardour.org/download")));
5219 subscribe_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://community.ardour.org/s/subscribe")));
5221 msg.get_vbox()->pack_start (pay_label);
5222 msg.get_vbox()->pack_start (pay_button_box);
5223 msg.get_vbox()->pack_start (subscribe_label);
5224 msg.get_vbox()->pack_start (subscribe_button_box);
5226 msg.get_vbox()->show_all ();
5228 msg.add_button (_("Remain silent"), Gtk::RESPONSE_CANCEL);
5229 msg.add_button (_("Save and quit"), Gtk::RESPONSE_NO);
5230 msg.add_button (_("Give me more time"), Gtk::RESPONSE_YES);
5235 case Gtk::RESPONSE_YES:
5236 AudioEngine::instance()->reset_silence_countdown ();
5239 case Gtk::RESPONSE_NO:
5241 save_state_canfail ("");
5245 case Gtk::RESPONSE_CANCEL:
5247 /* don't reset, save session and exit */
5253 ARDOUR_UI::hide_application ()
5255 Application::instance ()-> hide ();
5259 ARDOUR_UI::setup_toplevel_window (Gtk::Window& window, const string& name, void* owner)
5261 /* icons, titles, WM stuff */
5263 static list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
5265 if (window_icons.empty()) {
5266 Glib::RefPtr<Gdk::Pixbuf> icon;
5267 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
5268 window_icons.push_back (icon);
5270 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
5271 window_icons.push_back (icon);
5273 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
5274 window_icons.push_back (icon);
5276 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
5277 window_icons.push_back (icon);
5281 if (!window_icons.empty()) {
5282 window.set_default_icon_list (window_icons);
5285 Gtkmm2ext::WindowTitle title (Glib::get_application_name());
5287 if (!name.empty()) {
5291 window.set_title (title.get_string());
5292 window.set_wmclass (string_compose (X_("%1_%1"), downcase (PROGRAM_NAME), downcase (name)), PROGRAM_NAME);
5294 window.set_flags (CAN_FOCUS);
5295 window.add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
5297 /* This is a hack to ensure that GTK-accelerators continue to
5298 * work. Once we switch over to entirely native bindings, this will be
5299 * unnecessary and should be removed
5301 window.add_accel_group (ActionManager::ui_manager->get_accel_group());
5303 window.signal_configure_event().connect (sigc::mem_fun (*this, &ARDOUR_UI::configure_handler));
5304 window.signal_window_state_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::tabbed_window_state_event_handler), owner));
5305 window.signal_key_press_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5306 window.signal_key_release_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5310 ARDOUR_UI::key_event_handler (GdkEventKey* ev, Gtk::Window* event_window)
5312 Gtkmm2ext::Bindings* bindings = 0;
5313 Gtk::Window* window = 0;
5315 /* until we get ardour bindings working, we are not handling key
5319 if (ev->type != GDK_KEY_PRESS) {
5323 if (event_window == &_main_window) {
5325 window = event_window;
5327 /* find current tab contents */
5329 Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page());
5331 /* see if it uses the ardour binding system */
5334 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(w->get_data ("ardour-bindings"));
5337 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("main window key event, bindings = %1, global = %2\n", bindings, &global_bindings));
5341 window = event_window;
5343 /* see if window uses ardour binding system */
5345 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(window->get_data ("ardour-bindings"));
5348 /* An empty binding set is treated as if it doesn't exist */
5350 if (bindings && bindings->empty()) {
5354 return key_press_focus_accelerator_handler (*window, ev, bindings);
5357 static Gtkmm2ext::Bindings*
5358 get_bindings_from_widget_heirarchy (GtkWidget* w)
5363 if ((p = g_object_get_data (G_OBJECT(w), "ardour-bindings")) != 0) {
5366 w = gtk_widget_get_parent (w);
5369 return reinterpret_cast<Gtkmm2ext::Bindings*> (p);
5373 ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev, Gtkmm2ext::Bindings* bindings)
5375 GtkWindow* win = window.gobj();
5376 GtkWidget* focus = gtk_window_get_focus (win);
5377 bool special_handling_of_unmodified_accelerators = false;
5378 const guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK));
5382 /* some widget has keyboard focus */
5384 if (GTK_IS_ENTRY(focus) || Keyboard::some_magic_widget_has_focus()) {
5386 /* A particular kind of focusable widget currently has keyboard
5387 * focus. All unmodified key events should go to that widget
5388 * first and not be used as an accelerator by default
5391 special_handling_of_unmodified_accelerators = true;
5395 Gtkmm2ext::Bindings* focus_bindings = get_bindings_from_widget_heirarchy (focus);
5396 if (focus_bindings) {
5397 bindings = focus_bindings;
5398 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Switch bindings based on focus widget, now using %1\n", bindings->name()));
5403 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Win = %1 focus = %7 (%8) Key event: code = %2 state = %3 special handling ? %4 magic widget focus ? %5 focus widget %6 named %7 mods ? %8\n",
5406 show_gdk_event_state (ev->state),
5407 special_handling_of_unmodified_accelerators,
5408 Keyboard::some_magic_widget_has_focus(),
5410 (focus ? gtk_widget_get_name (focus) : "no focus widget"),
5411 ((ev->state & mask) ? "yes" : "no")));
5413 /* This exists to allow us to override the way GTK handles
5414 key events. The normal sequence is:
5416 a) event is delivered to a GtkWindow
5417 b) accelerators/mnemonics are activated
5418 c) if (b) didn't handle the event, propagate to
5419 the focus widget and/or focus chain
5421 The problem with this is that if the accelerators include
5422 keys without modifiers, such as the space bar or the
5423 letter "e", then pressing the key while typing into
5424 a text entry widget results in the accelerator being
5425 activated, instead of the desired letter appearing
5428 There is no good way of fixing this, but this
5429 represents a compromise. The idea is that
5430 key events involving modifiers (not Shift)
5431 get routed into the activation pathway first, then
5432 get propagated to the focus widget if necessary.
5434 If the key event doesn't involve modifiers,
5435 we deliver to the focus widget first, thus allowing
5436 it to get "normal text" without interference
5439 Of course, this can also be problematic: if there
5440 is a widget with focus, then it will swallow
5441 all "normal text" accelerators.
5445 if (!special_handling_of_unmodified_accelerators || (ev->state & mask)) {
5447 /* no special handling or there are modifiers in effect: accelerate first */
5449 DEBUG_TRACE (DEBUG::Accelerators, "\tactivate, then propagate\n");
5450 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tevent send-event:%1 time:%2 length:%3 name %7 string:%4 hardware_keycode:%5 group:%6\n",
5451 ev->send_event, ev->time, ev->length, ev->string, ev->hardware_keycode, ev->group, gdk_keyval_name (ev->keyval)));
5453 DEBUG_TRACE (DEBUG::Accelerators, "\tsending to window\n");
5454 KeyboardKey k (ev->state, ev->keyval);
5458 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tusing Ardour bindings %1 @ %2 for this event\n", bindings->name(), bindings));
5460 if (bindings->activate (k, Bindings::Press)) {
5461 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5466 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5468 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5469 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5473 DEBUG_TRACE (DEBUG::Accelerators, "\tnot accelerated, now propagate\n");
5475 if (gtk_window_propagate_key_event (win, ev)) {
5476 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate handled\n");
5482 /* no modifiers, propagate first */
5484 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate, then activate\n");
5486 if (gtk_window_propagate_key_event (win, ev)) {
5487 DEBUG_TRACE (DEBUG::Accelerators, "\thandled by propagate\n");
5491 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagation didn't handle, so activate\n");
5492 KeyboardKey k (ev->state, ev->keyval);
5496 DEBUG_TRACE (DEBUG::Accelerators, "\tusing Ardour bindings for this window\n");
5499 if (bindings->activate (k, Bindings::Press)) {
5500 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5506 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5508 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5509 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5514 DEBUG_TRACE (DEBUG::Accelerators, "\tnot handled\n");
5519 ARDOUR_UI::load_bindings ()
5521 if ((global_bindings = Bindings::get_bindings (X_("Global"), global_actions)) == 0) {
5522 error << _("Global keybindings are missing") << endmsg;
5527 ARDOUR_UI::cancel_solo ()
5530 if (_session->soloing()) {
5531 _session->set_solo (_session->get_routes(), false);
5532 } else if (_session->listening()) {
5533 _session->set_listen (_session->get_routes(), false);
5536 _session->clear_all_solo_state (_session->get_routes()); // safeguard, ideally this won't do anything, check the log-window