2 Copyright (C) 1999-2013 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include "gtk2ardour-config.h"
22 #include "gtk2ardour-version.h"
32 #ifndef PLATFORM_WINDOWS
33 #include <sys/resource.h>
43 #include "pbd/gstdio_compat.h"
45 #include <gtkmm/messagedialog.h>
46 #include <gtkmm/accelmap.h>
48 #include "pbd/error.h"
49 #include "pbd/basename.h"
50 #include "pbd/compose.h"
51 #include "pbd/convert.h"
52 #include "pbd/failed_constructor.h"
53 #include "pbd/enumwriter.h"
54 #include "pbd/memento_command.h"
55 #include "pbd/openuri.h"
56 #include "pbd/stl_delete.h"
57 #include "pbd/file_utils.h"
58 #include "pbd/localtime_r.h"
59 #include "pbd/pthread_utils.h"
60 #include "pbd/replace_all.h"
61 #include "pbd/xml++.h"
63 #include "gtkmm2ext/application.h"
64 #include "gtkmm2ext/bindings.h"
65 #include "gtkmm2ext/gtk_ui.h"
66 #include "gtkmm2ext/utils.h"
67 #include "gtkmm2ext/click_box.h"
68 #include "gtkmm2ext/fastmeter.h"
69 #include "gtkmm2ext/popup.h"
70 #include "gtkmm2ext/window_title.h"
72 #include "ardour/ardour.h"
73 #include "ardour/audio_backend.h"
74 #include "ardour/audio_track.h"
75 #include "ardour/audioengine.h"
76 #include "ardour/audiofilesource.h"
77 #include "ardour/automation_watch.h"
78 #include "ardour/diskstream.h"
79 #include "ardour/filename_extensions.h"
80 #include "ardour/filesystem_paths.h"
81 #include "ardour/ltc_file_reader.h"
82 #include "ardour/midi_track.h"
83 #include "ardour/port.h"
84 #include "ardour/plugin_manager.h"
85 #include "ardour/process_thread.h"
86 #include "ardour/profile.h"
87 #include "ardour/recent_sessions.h"
88 #include "ardour/session_directory.h"
89 #include "ardour/session_route.h"
90 #include "ardour/session_state_utils.h"
91 #include "ardour/session_utils.h"
92 #include "ardour/source_factory.h"
93 #include "ardour/slave.h"
94 #include "ardour/system_exec.h"
96 #include "LuaBridge/LuaBridge.h"
98 #ifdef WINDOWS_VST_SUPPORT
101 #ifdef AUDIOUNIT_SUPPORT
102 #include "ardour/audio_unit.h"
105 // fix for OSX (nsm.h has a check function, AU/Apple defines check)
110 #include "timecode/time.h"
112 typedef uint64_t microseconds_t;
117 #include "add_route_dialog.h"
118 #include "ambiguous_file_dialog.h"
119 #include "ardour_ui.h"
120 #include "audio_clock.h"
121 #include "audio_region_view.h"
122 #include "big_clock_window.h"
123 #include "bundle_manager.h"
124 #include "duplicate_routes_dialog.h"
126 #include "engine_dialog.h"
127 #include "export_video_dialog.h"
128 #include "export_video_infobox.h"
129 #include "gain_meter.h"
130 #include "global_port_matrix.h"
131 #include "gui_object.h"
132 #include "gui_thread.h"
133 #include "keyboard.h"
134 #include "keyeditor.h"
135 #include "location_ui.h"
136 #include "lua_script_manager.h"
137 #include "luawindow.h"
138 #include "main_clock.h"
139 #include "missing_file_dialog.h"
140 #include "missing_plugin_dialog.h"
141 #include "mixer_ui.h"
142 #include "meterbridge.h"
143 #include "mouse_cursors.h"
146 #include "pingback.h"
147 #include "processor_box.h"
148 #include "prompter.h"
149 #include "public_editor.h"
150 #include "rc_option_editor.h"
151 #include "route_time_axis.h"
152 #include "route_params_ui.h"
153 #include "save_as_dialog.h"
154 #include "script_selector.h"
155 #include "session_dialog.h"
156 #include "session_metadata_dialog.h"
157 #include "session_option_editor.h"
158 #include "shuttle_control.h"
159 #include "speaker_dialog.h"
162 #include "theme_manager.h"
163 #include "time_axis_view_item.h"
166 #include "video_server_dialog.h"
167 #include "add_video_dialog.h"
168 #include "transcode_video_dialog.h"
172 using namespace ARDOUR;
173 using namespace ARDOUR_UI_UTILS;
175 using namespace Gtkmm2ext;
178 using namespace Editing;
180 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
182 sigc::signal<void, framepos_t, bool, framepos_t> ARDOUR_UI::Clock;
183 sigc::signal<void> ARDOUR_UI::CloseAllDialogs;
186 ask_about_configuration_copy (string const & old_dir, string const & new_dir, int version)
188 MessageDialog msg (string_compose (_("%1 %2.x has discovered configuration files from %1 %3.x.\n\n"
189 "Would you like these files to be copied and used for %1 %2.x?\n\n"
190 "(This will require you to restart %1.)"),
191 PROGRAM_NAME, PROGRAM_VERSION, version),
192 false, /* no markup */
195 true /* modal, though it hardly matters since it is the only window */
198 msg.set_default_response (Gtk::RESPONSE_YES);
201 return (msg.run() == Gtk::RESPONSE_YES);
205 libxml_generic_error_func (void* /* parsing_context*/,
213 vsnprintf (buf, sizeof (buf), msg, ap);
214 error << buf << endmsg;
219 libxml_structured_error_func (void* /* parsing_context*/,
227 replace_all (msg, "\n", "");
230 if (err->file && err->line) {
231 error << X_("XML error: ") << msg << " in " << err->file << " at line " << err->line;
234 error << ':' << err->int2;
239 error << X_("XML error: ") << msg << endmsg;
245 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
246 : Gtkmm2ext::UI (PROGRAM_NAME, X_("gui"), argcp, argvp)
247 , session_loaded (false)
248 , gui_object_state (new GUIObjectState)
249 , primary_clock (new MainClock (X_("primary"), X_("transport"), true ))
250 , secondary_clock (new MainClock (X_("secondary"), X_("secondary"), false))
251 , big_clock (new AudioClock (X_("bigclock"), false, "big", true, true, false, false))
253 , global_actions (X_("global"))
254 , ignore_dual_punch (false)
259 , _mixer_on_top (false)
260 , _initial_verbose_plugin_scan (false)
261 , first_time_engine_run (true)
262 , roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll))
263 , stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop))
264 , goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart))
265 , goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd))
266 , auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop))
267 , play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection))
268 , rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable))
269 , auto_return_button (ArdourButton::led_default_elements)
270 , follow_edits_button (ArdourButton::led_default_elements)
271 , auto_input_button (ArdourButton::led_default_elements)
272 , auditioning_alert_button (_("Audition"))
273 , solo_alert_button (_("Solo"))
274 , feedback_alert_button (_("Feedback"))
275 , error_alert_button ( ArdourButton::just_led_default_elements )
277 , editor_meter_peak_display()
278 , _numpad_locate_happening (false)
279 , _session_is_new (false)
280 , last_key_press_time (0)
284 , rc_option_editor (0)
285 , speaker_config_window (X_("speaker-config"), _("Speaker Configuration"))
286 , add_route_dialog (X_("add-routes"), _("Add Tracks/Busses"))
287 , about (X_("about"), _("About"))
288 , location_ui (X_("locations"), _("Locations"))
289 , route_params (X_("inspector"), _("Tracks and Busses"))
290 , audio_midi_setup (X_("audio-midi-setup"), _("Audio/MIDI Setup"))
291 , export_video_dialog (X_("video-export"), _("Video Export Dialog"))
292 , lua_script_window (X_("script-manager"), _("Script Manager"))
293 , session_option_editor (X_("session-options-editor"), _("Properties"), boost::bind (&ARDOUR_UI::create_session_option_editor, this))
294 , add_video_dialog (X_("add-video"), _("Add Video"), boost::bind (&ARDOUR_UI::create_add_video_dialog, this))
295 , bundle_manager (X_("bundle-manager"), _("Bundle Manager"), boost::bind (&ARDOUR_UI::create_bundle_manager, this))
296 , big_clock_window (X_("big-clock"), _("Big Clock"), boost::bind (&ARDOUR_UI::create_big_clock_window, this))
297 , audio_port_matrix (X_("audio-connection-manager"), _("Audio Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::AUDIO))
298 , midi_port_matrix (X_("midi-connection-manager"), _("MIDI Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::MIDI))
299 , key_editor (X_("key-editor"), _("Bindings Editor"), boost::bind (&ARDOUR_UI::create_key_editor, this))
300 , video_server_process (0)
302 , have_configure_timeout (false)
303 , last_configure_time (0)
305 , have_disk_speed_dialog_displayed (false)
306 , _status_bar_visibility (X_("status-bar"))
307 , _feedback_exists (false)
308 , _log_not_acknowledged (LogLevelNone)
309 , duplicate_routes_dialog (0)
310 , editor_visibility_button (S_("Window|Editor"))
311 , mixer_visibility_button (S_("Window|Mixer"))
312 , prefs_visibility_button (S_("Window|Preferences"))
314 Gtkmm2ext::init (localedir);
316 UIConfiguration::instance().post_gui_init ();
318 if (ARDOUR::handle_old_configuration_files (boost::bind (ask_about_configuration_copy, _1, _2, _3))) {
319 MessageDialog msg (string_compose (_("Your configuration files were copied. You can now restart %1."), PROGRAM_NAME), true);
321 /* configuration was modified, exit immediately */
325 if (theArdourUI == 0) {
329 /* stop libxml from spewing to stdout/stderr */
331 xmlSetGenericErrorFunc (this, libxml_generic_error_func);
332 xmlSetStructuredErrorFunc (this, libxml_structured_error_func);
334 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::parameter_changed));
335 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
336 UIConfiguration::instance().map_parameters (pc);
338 roll_button.set_controllable (roll_controllable);
339 stop_button.set_controllable (stop_controllable);
340 goto_start_button.set_controllable (goto_start_controllable);
341 goto_end_button.set_controllable (goto_end_controllable);
342 auto_loop_button.set_controllable (auto_loop_controllable);
343 play_selection_button.set_controllable (play_selection_controllable);
344 rec_button.set_controllable (rec_controllable);
346 roll_button.set_name ("transport button");
347 stop_button.set_name ("transport button");
348 goto_start_button.set_name ("transport button");
349 goto_end_button.set_name ("transport button");
350 auto_loop_button.set_name ("transport button");
351 play_selection_button.set_name ("transport button");
352 rec_button.set_name ("transport recenable button");
353 midi_panic_button.set_name ("transport button");
355 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
356 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
358 ARDOUR::Session::VersionMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_format_mismatch, this, _1, _2), gui_context());
360 /* handle dialog requests */
362 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
364 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
366 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
368 /* handle Audio/MIDI setup when session requires it */
370 ARDOUR::Session::AudioEngineSetupRequired.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::do_audio_midi_setup, this, _1));
372 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
374 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
376 /* handle sr mismatch with a dialog - cross-thread from engine */
377 ARDOUR::Session::NotifyAboutSampleRateMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::sr_mismatch_message, this, _1, _2), gui_context ());
379 /* handle requests to quit (coming from JACK session) */
381 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::finish, this), gui_context ());
383 /* tell the user about feedback */
385 ARDOUR::Session::FeedbackDetected.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::feedback_detected, this), gui_context ());
386 ARDOUR::Session::SuccessfulGraphSort.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::successful_graph_sort, this), gui_context ());
388 /* handle requests to deal with missing files */
390 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
392 /* and ambiguous files */
394 ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2));
396 /* also plugin scan messages */
397 ARDOUR::PluginScanMessage.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_dialog, this, _1, _2, _3), gui_context());
398 ARDOUR::PluginScanTimeout.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_timeout, this, _1), gui_context());
400 ARDOUR::GUIIdle.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::gui_idle_handler, this), gui_context());
402 Config->ParameterChanged.connect ( forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::set_flat_buttons, this), gui_context() );
405 /* lets get this party started */
407 setup_gtk_ardour_enums ();
410 SessionEvent::create_per_thread_pool ("GUI", 4096);
412 /* we like keyboards */
414 keyboard = new ArdourKeyboard(*this);
416 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
418 keyboard->set_state (*node, Stateful::loading_state_version);
421 UIConfiguration::instance().reset_dpi ();
423 TimeAxisViewItem::set_constant_heights ();
425 /* Set this up so that our window proxies can register actions */
427 ActionManager::init ();
429 /* The following must happen after ARDOUR::init() so that Config is set up */
431 const XMLNode* ui_xml = Config->extra_xml (X_("UI"));
434 key_editor.set_state (*ui_xml, 0);
435 session_option_editor.set_state (*ui_xml, 0);
436 speaker_config_window.set_state (*ui_xml, 0);
437 about.set_state (*ui_xml, 0);
438 add_route_dialog.set_state (*ui_xml, 0);
439 add_video_dialog.set_state (*ui_xml, 0);
440 route_params.set_state (*ui_xml, 0);
441 bundle_manager.set_state (*ui_xml, 0);
442 location_ui.set_state (*ui_xml, 0);
443 big_clock_window.set_state (*ui_xml, 0);
444 audio_port_matrix.set_state (*ui_xml, 0);
445 midi_port_matrix.set_state (*ui_xml, 0);
446 export_video_dialog.set_state (*ui_xml, 0);
447 lua_script_window.set_state (*ui_xml, 0);
450 /* Separate windows */
452 WM::Manager::instance().register_window (&key_editor);
453 WM::Manager::instance().register_window (&session_option_editor);
454 WM::Manager::instance().register_window (&speaker_config_window);
455 WM::Manager::instance().register_window (&about);
456 WM::Manager::instance().register_window (&add_route_dialog);
457 WM::Manager::instance().register_window (&add_video_dialog);
458 WM::Manager::instance().register_window (&route_params);
459 WM::Manager::instance().register_window (&audio_midi_setup);
460 WM::Manager::instance().register_window (&export_video_dialog);
461 WM::Manager::instance().register_window (&lua_script_window);
462 WM::Manager::instance().register_window (&bundle_manager);
463 WM::Manager::instance().register_window (&location_ui);
464 WM::Manager::instance().register_window (&big_clock_window);
465 WM::Manager::instance().register_window (&audio_port_matrix);
466 WM::Manager::instance().register_window (&midi_port_matrix);
468 /* Trigger setting up the color scheme and loading the GTK RC file */
470 UIConfiguration::instance().load_rc_file (false);
472 _process_thread = new ProcessThread ();
473 _process_thread->init ();
475 UIConfiguration::instance().DPIReset.connect (sigc::mem_fun (*this, &ARDOUR_UI::resize_text_widgets));
480 GlobalPortMatrixWindow*
481 ARDOUR_UI::create_global_port_matrix (ARDOUR::DataType type)
486 return new GlobalPortMatrixWindow (_session, type);
490 ARDOUR_UI::attach_to_engine ()
492 AudioEngine::instance()->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
493 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
497 ARDOUR_UI::engine_stopped ()
499 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
500 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
501 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
502 update_sample_rate (0);
507 ARDOUR_UI::engine_running ()
509 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
510 if (first_time_engine_run) {
512 first_time_engine_run = false;
516 _session->reset_xrun_count ();
518 update_disk_space ();
520 update_xrun_count ();
521 update_sample_rate (AudioEngine::instance()->sample_rate());
522 update_timecode_format ();
523 update_peak_thread_work ();
524 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, true);
525 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, false);
529 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
531 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
532 /* we can't rely on the original string continuing to exist when we are called
533 again in the GUI thread, so make a copy and note that we need to
536 char *copy = strdup (reason);
537 Gtkmm2ext::UI::instance()->call_slot (MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
541 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
542 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
544 update_sample_rate (0);
548 /* if the reason is a non-empty string, it means that the backend was shutdown
549 rather than just Ardour.
552 if (strlen (reason)) {
553 msgstr = string_compose (_("The audio backend was shutdown because:\n\n%1"), reason);
555 msgstr = string_compose (_("\
556 The audio backend has either been shutdown or it\n\
557 disconnected %1 because %1\n\
558 was not fast enough. Try to restart\n\
559 the audio backend and save the session."), PROGRAM_NAME);
562 MessageDialog msg (_main_window, msgstr);
563 pop_back_splash (msg);
567 free (const_cast<char*> (reason));
572 ARDOUR_UI::post_engine ()
574 /* Things to be done once (and once ONLY) after we have a backend running in the AudioEngine
576 #ifdef AUDIOUNIT_SUPPORT
578 if (AUPluginInfo::au_get_crashlog(au_msg)) {
579 popup_error(_("Audio Unit Plugin Scan Failed. Automatic AU scanning has been disabled. Please see the log window for further details."));
580 error << _("Audio Unit Plugin Scan Failed:") << endmsg;
581 info << au_msg << endmsg;
585 ARDOUR::init_post_engine ();
587 /* connect to important signals */
589 AudioEngine::instance()->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
590 AudioEngine::instance()->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
591 AudioEngine::instance()->BufferSizeChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
592 AudioEngine::instance()->Halted.connect_same_thread (halt_connection, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
593 AudioEngine::instance()->BecameSilent.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::audioengine_became_silent, this), gui_context());
595 if (setup_windows ()) {
596 throw failed_constructor ();
599 /* Do this after setup_windows (), as that's when the _status_bar_visibility is created */
600 XMLNode* n = Config->extra_xml (X_("UI"));
602 _status_bar_visibility.set_state (*n);
605 check_memory_locking();
607 /* this is the first point at which all the possible actions are
608 * available, because some of the available actions are dependent on
609 * aspects of the engine/backend.
612 if (ARDOUR_COMMAND_LINE::show_key_actions) {
615 vector<string> paths;
616 vector<string> labels;
617 vector<string> tooltips;
619 vector<Glib::RefPtr<Gtk::Action> > actions;
621 Gtkmm2ext::ActionMap::get_all_actions (paths, labels, tooltips, keys, actions);
623 vector<string>::iterator k;
624 vector<string>::iterator p;
626 for (p = paths.begin(), k = keys.begin(); p != paths.end(); ++k, ++p) {
631 cout << *p << " => " << *k << endl;
635 halt_connection.disconnect ();
636 AudioEngine::instance()->stop ();
640 /* this being a GUI and all, we want peakfiles */
642 AudioFileSource::set_build_peakfiles (true);
643 AudioFileSource::set_build_missing_peakfiles (true);
645 /* set default clock modes */
647 primary_clock->set_mode (AudioClock::Timecode);
648 secondary_clock->set_mode (AudioClock::BBT);
650 /* start the time-of-day-clock */
653 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
654 update_wall_clock ();
655 Glib::signal_timeout().connect_seconds (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 1);
660 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
661 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
662 Config->map_parameters (pc);
664 UIConfiguration::instance().map_parameters (pc);
668 ARDOUR_UI::~ARDOUR_UI ()
670 UIConfiguration::instance().save_state();
674 if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
675 // don't bother at 'real' exit. the OS cleans up for us.
676 delete big_clock; big_clock = 0;
677 delete primary_clock; primary_clock = 0;
678 delete secondary_clock; secondary_clock = 0;
679 delete _process_thread; _process_thread = 0;
680 delete meterbridge; meterbridge = 0;
681 delete luawindow; luawindow = 0;
682 delete editor; editor = 0;
683 delete mixer; mixer = 0;
685 delete gui_object_state; gui_object_state = 0;
686 FastMeter::flush_pattern_cache ();
687 PixFader::flush_pattern_cache ();
691 /* Small trick to flush main-thread event pool.
692 * Other thread-pools are destroyed at pthread_exit(),
693 * but tmain thread termination is too late to trigger Pool::~Pool()
695 SessionEvent* ev = new SessionEvent (SessionEvent::SetTransportSpeed, SessionEvent::Clear, SessionEvent::Immediate, 0, 0); // get the pool reference, values don't matter since the event is never queued.
696 delete ev->event_pool();
701 ARDOUR_UI::pop_back_splash (Gtk::Window& win)
703 if (Splash::instance()) {
704 Splash::instance()->pop_back_for (win);
709 ARDOUR_UI::configure_timeout ()
711 if (last_configure_time == 0) {
712 /* no configure events yet */
716 /* force a gap of 0.5 seconds since the last configure event
719 if (get_microseconds() - last_configure_time < 500000) {
722 have_configure_timeout = false;
723 save_ardour_state ();
729 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
731 if (have_configure_timeout) {
732 last_configure_time = get_microseconds();
734 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
735 have_configure_timeout = true;
742 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
744 const XMLProperty* prop;
746 if ((prop = node.property ("roll")) != 0) {
747 roll_controllable->set_id (prop->value());
749 if ((prop = node.property ("stop")) != 0) {
750 stop_controllable->set_id (prop->value());
752 if ((prop = node.property ("goto-start")) != 0) {
753 goto_start_controllable->set_id (prop->value());
755 if ((prop = node.property ("goto-end")) != 0) {
756 goto_end_controllable->set_id (prop->value());
758 if ((prop = node.property ("auto-loop")) != 0) {
759 auto_loop_controllable->set_id (prop->value());
761 if ((prop = node.property ("play-selection")) != 0) {
762 play_selection_controllable->set_id (prop->value());
764 if ((prop = node.property ("rec")) != 0) {
765 rec_controllable->set_id (prop->value());
767 if ((prop = node.property ("shuttle")) != 0) {
768 shuttle_box->controllable()->set_id (prop->value());
773 ARDOUR_UI::get_transport_controllable_state ()
775 XMLNode* node = new XMLNode(X_("TransportControllables"));
778 roll_controllable->id().print (buf, sizeof (buf));
779 node->add_property (X_("roll"), buf);
780 stop_controllable->id().print (buf, sizeof (buf));
781 node->add_property (X_("stop"), buf);
782 goto_start_controllable->id().print (buf, sizeof (buf));
783 node->add_property (X_("goto_start"), buf);
784 goto_end_controllable->id().print (buf, sizeof (buf));
785 node->add_property (X_("goto_end"), buf);
786 auto_loop_controllable->id().print (buf, sizeof (buf));
787 node->add_property (X_("auto_loop"), buf);
788 play_selection_controllable->id().print (buf, sizeof (buf));
789 node->add_property (X_("play_selection"), buf);
790 rec_controllable->id().print (buf, sizeof (buf));
791 node->add_property (X_("rec"), buf);
792 shuttle_box->controllable()->id().print (buf, sizeof (buf));
793 node->add_property (X_("shuttle"), buf);
799 ARDOUR_UI::save_session_at_its_request (std::string snapshot_name)
802 _session->save_state (snapshot_name);
807 ARDOUR_UI::autosave_session ()
809 if (g_main_depth() > 1) {
810 /* inside a recursive main loop,
811 give up because we may not be able to
817 if (!Config->get_periodic_safety_backups()) {
822 _session->maybe_write_autosave();
829 ARDOUR_UI::session_dirty_changed ()
836 ARDOUR_UI::update_autosave ()
838 if (_session && _session->dirty()) {
839 if (_autosave_connection.connected()) {
840 _autosave_connection.disconnect();
843 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
844 Config->get_periodic_safety_backup_interval() * 1000);
847 if (_autosave_connection.connected()) {
848 _autosave_connection.disconnect();
854 ARDOUR_UI::check_announcements ()
857 string _annc_filename;
860 _annc_filename = PROGRAM_NAME "_announcements_osx_";
861 #elif defined PLATFORM_WINDOWS
862 _annc_filename = PROGRAM_NAME "_announcements_windows_";
864 _annc_filename = PROGRAM_NAME "_announcements_linux_";
866 _annc_filename.append (VERSIONSTRING);
868 _announce_string = "";
870 std::string path = Glib::build_filename (user_config_directory(), _annc_filename);
871 FILE* fin = g_fopen (path.c_str(), "rb");
873 while (!feof (fin)) {
876 if ((len = fread (tmp, sizeof(char), 1024, fin)) == 0 || ferror (fin)) {
879 _announce_string.append (tmp, len);
884 pingback (VERSIONSTRING, path);
889 _hide_splash (gpointer arg)
891 ((ARDOUR_UI*)arg)->hide_splash();
896 ARDOUR_UI::starting ()
898 Application* app = Application::instance ();
900 bool brand_new_user = ArdourStartup::required ();
902 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
903 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::load_from_application_api));
905 if (ARDOUR_COMMAND_LINE::check_announcements) {
906 check_announcements ();
911 /* we need to create this early because it may need to set the
912 * audio backend end up.
916 audio_midi_setup.get (true);
918 std::cerr << "audio-midi engine setup failed."<< std::endl;
922 if ((nsm_url = g_getenv ("NSM_URL")) != 0) {
923 nsm = new NSM_Client;
924 if (!nsm->init (nsm_url)) {
925 /* the ardour executable may have different names:
927 * waf's obj.target for distro versions: eg ardour4, ardourvst4
928 * Ardour4, Mixbus3 for bundled versions + full path on OSX & windows
929 * argv[0] does not apply since we need the wrapper-script (not the binary itself)
931 * The wrapper startup script should set the environment variable 'ARDOUR_SELF'
933 const char *process_name = g_getenv ("ARDOUR_SELF");
934 nsm->announce (PROGRAM_NAME, ":dirty:", process_name ? process_name : "ardour4");
937 // wait for announce reply from nsm server
938 for ( i = 0; i < 5000; ++i) {
942 if (nsm->is_active()) {
947 error << _("NSM server did not announce itself") << endmsg;
950 // wait for open command from nsm server
951 for ( i = 0; i < 5000; ++i) {
954 if (nsm->client_id ()) {
960 error << _("NSM: no client ID provided") << endmsg;
964 if (_session && nsm) {
965 _session->set_nsm_state( nsm->is_active() );
967 error << _("NSM: no session created") << endmsg;
971 // nsm requires these actions disabled
972 vector<string> action_names;
973 action_names.push_back("SaveAs");
974 action_names.push_back("Rename");
975 action_names.push_back("New");
976 action_names.push_back("Open");
977 action_names.push_back("Recent");
978 action_names.push_back("Close");
980 for (vector<string>::const_iterator n = action_names.begin(); n != action_names.end(); ++n) {
981 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), (*n).c_str());
983 act->set_sensitive (false);
990 error << _("NSM: initialization failed") << endmsg;
996 if (brand_new_user) {
997 _initial_verbose_plugin_scan = true;
1002 _initial_verbose_plugin_scan = false;
1003 switch (s.response ()) {
1004 case Gtk::RESPONSE_OK:
1011 #ifdef NO_PLUGIN_STATE
1013 ARDOUR::RecentSessions rs;
1014 ARDOUR::read_recent_sessions (rs);
1016 string path = Glib::build_filename (user_config_directory(), ".iknowaboutfreeversion");
1018 if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS) && !rs.empty()) {
1020 /* already used Ardour, have sessions ... warn about plugin state */
1022 ArdourDialog d (_("Free/Demo Version Warning"), true);
1024 Button b (string_compose (_("Subscribe and support development of %1"), PROGRAM_NAME));
1025 CheckButton c (_("Don't warn me about this again"));
1027 l.set_markup (string_compose (_("<span weight=\"bold\" size=\"large\">%1</span>\n\n<b>%2</b>\n\n<i>%3</i>\n\n%4"),
1028 string_compose (_("This is a free/demo version of %1"), PROGRAM_NAME),
1029 _("It will not restore OR save any plugin settings"),
1030 _("If you load an existing session with plugin settings\n"
1031 "they will not be used and will be lost."),
1032 _("To get full access to updates without this limitation\n"
1033 "consider becoming a subscriber for a low cost every month.")));
1034 l.set_justify (JUSTIFY_CENTER);
1036 b.signal_clicked().connect (mem_fun(*this, &ARDOUR_UI::launch_subscribe));
1038 d.get_vbox()->pack_start (l, true, true);
1039 d.get_vbox()->pack_start (b, false, false, 12);
1040 d.get_vbox()->pack_start (c, false, false, 12);
1042 d.add_button (_("Quit now"), RESPONSE_CANCEL);
1043 d.add_button (string_compose (_("Continue using %1"), PROGRAM_NAME), RESPONSE_OK);
1047 c.signal_toggled().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (toggle_file_existence), path)));
1049 if (d.run () != RESPONSE_OK) {
1055 /* go get a session */
1057 const bool new_session_required = (ARDOUR_COMMAND_LINE::new_session || brand_new_user);
1059 if (get_session_parameters (false, new_session_required, ARDOUR_COMMAND_LINE::load_template)) {
1060 std::cerr << "Cannot get session parameters."<< std::endl;
1067 WM::Manager::instance().show_visible ();
1069 /* We have to do this here since goto_editor_window() ends up calling show_all() on the
1070 * editor window, and we may want stuff to be hidden.
1072 _status_bar_visibility.update ();
1074 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
1076 if (splash && splash->is_visible()) {
1077 // in 1 second, hide the splash screen
1078 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
1081 /* all other dialogs are created conditionally */
1087 ARDOUR_UI::check_memory_locking ()
1089 #if defined(__APPLE__) || defined(PLATFORM_WINDOWS)
1090 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
1094 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
1096 if (AudioEngine::instance()->is_realtime() && memory_warning_node == 0) {
1098 struct rlimit limits;
1100 long pages, page_size;
1102 size_t pages_len=sizeof(pages);
1103 if ((page_size = getpagesize()) < 0 ||
1104 sysctlbyname("hw.availpages", &pages, &pages_len, NULL, 0))
1106 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0)
1111 ram = (int64_t) pages * (int64_t) page_size;
1114 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
1118 if (limits.rlim_cur != RLIM_INFINITY) {
1120 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
1124 _("WARNING: Your system has a limit for maximum amount of locked memory. "
1125 "This might cause %1 to run out of memory before your system "
1126 "runs out of memory. \n\n"
1127 "You can view the memory limit with 'ulimit -l', "
1128 "and it is normally controlled by %2"),
1131 X_("/etc/login.conf")
1133 X_(" /etc/security/limits.conf")
1137 msg.set_default_response (RESPONSE_OK);
1139 VBox* vbox = msg.get_vbox();
1141 CheckButton cb (_("Do not show this window again"));
1142 hbox.pack_start (cb, true, false);
1143 vbox->pack_start (hbox);
1148 pop_back_splash (msg);
1152 if (cb.get_active()) {
1153 XMLNode node (X_("no-memory-warning"));
1154 Config->add_instant_xml (node);
1159 #endif // !__APPLE__
1164 ARDOUR_UI::queue_finish ()
1166 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
1170 ARDOUR_UI::idle_finish ()
1173 return false; /* do not call again */
1180 ARDOUR_UI::instance()->video_timeline->sync_session_state();
1182 if (_session->dirty()) {
1183 vector<string> actions;
1184 actions.push_back (_("Don't quit"));
1185 actions.push_back (_("Just quit"));
1186 actions.push_back (_("Save and quit"));
1187 switch (ask_about_saving_session(actions)) {
1192 /* use the default name */
1193 if (save_state_canfail ("")) {
1194 /* failed - don't quit */
1195 MessageDialog msg (_main_window,
1196 string_compose (_("\
1197 %1 was unable to save your session.\n\n\
1198 If you still wish to quit, please use the\n\n\
1199 \"Just quit\" option."), PROGRAM_NAME));
1200 pop_back_splash(msg);
1210 second_connection.disconnect ();
1211 point_one_second_connection.disconnect ();
1212 point_zero_something_second_connection.disconnect();
1213 fps_connection.disconnect();
1216 delete ARDOUR_UI::instance()->video_timeline;
1217 ARDOUR_UI::instance()->video_timeline = NULL;
1218 stop_video_server();
1220 /* Save state before deleting the session, as that causes some
1221 windows to be destroyed before their visible state can be
1224 save_ardour_state ();
1226 close_all_dialogs ();
1229 _session->set_clean ();
1230 _session->remove_pending_capture_state ();
1235 halt_connection.disconnect ();
1236 AudioEngine::instance()->stop ();
1237 #ifdef WINDOWS_VST_SUPPORT
1238 fst_stop_threading();
1244 ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
1246 ArdourDialog window (_("Unsaved Session"));
1247 Gtk::HBox dhbox; // the hbox for the image and text
1248 Gtk::Label prompt_label;
1249 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
1253 assert (actions.size() >= 3);
1255 window.add_button (actions[0], RESPONSE_REJECT);
1256 window.add_button (actions[1], RESPONSE_APPLY);
1257 window.add_button (actions[2], RESPONSE_ACCEPT);
1259 window.set_default_response (RESPONSE_ACCEPT);
1261 Gtk::Button noquit_button (msg);
1262 noquit_button.set_name ("EditorGTKButton");
1266 if (_session->snap_name() == _session->name()) {
1267 prompt = string_compose(_("The session \"%1\"\nhas not been saved.\n\nAny changes made this time\nwill be lost unless you save it.\n\nWhat do you want to do?"),
1268 _session->snap_name());
1270 prompt = string_compose(_("The snapshot \"%1\"\nhas not been saved.\n\nAny changes made this time\nwill be lost unless you save it.\n\nWhat do you want to do?"),
1271 _session->snap_name());
1274 prompt_label.set_text (prompt);
1275 prompt_label.set_name (X_("PrompterLabel"));
1276 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
1278 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
1279 dhbox.set_homogeneous (false);
1280 dhbox.pack_start (*dimage, false, false, 5);
1281 dhbox.pack_start (prompt_label, true, false, 5);
1282 window.get_vbox()->pack_start (dhbox);
1284 window.set_name (_("Prompter"));
1285 window.set_modal (true);
1286 window.set_resizable (false);
1289 prompt_label.show();
1294 ResponseType r = (ResponseType) window.run();
1299 case RESPONSE_ACCEPT: // save and get out of here
1301 case RESPONSE_APPLY: // get out of here
1312 ARDOUR_UI::every_second ()
1315 update_xrun_count ();
1316 update_buffer_load ();
1317 update_disk_space ();
1318 update_timecode_format ();
1319 update_peak_thread_work ();
1321 if (nsm && nsm->is_active ()) {
1324 if (!_was_dirty && _session->dirty ()) {
1328 else if (_was_dirty && !_session->dirty ()){
1336 ARDOUR_UI::every_point_one_seconds ()
1338 // TODO get rid of this..
1339 // ShuttleControl is updated directly via TransportStateChange signal
1343 ARDOUR_UI::every_point_zero_something_seconds ()
1345 // august 2007: actual update frequency: 25Hz (40ms), not 100Hz
1347 if (editor_meter && UIConfiguration::instance().get_show_editor_meter()) {
1348 float mpeak = editor_meter->update_meters();
1349 if (mpeak > editor_meter_max_peak) {
1350 if (mpeak >= UIConfiguration::instance().get_meter_peak()) {
1351 editor_meter_peak_display.set_active_state ( Gtkmm2ext::ExplicitActive );
1358 ARDOUR_UI::set_fps_timeout_connection ()
1360 unsigned int interval = 40;
1361 if (!_session) return;
1362 if (_session->timecode_frames_per_second() != 0) {
1363 /* ideally we'll use a select() to sleep and not accumulate
1364 * idle time to provide a regular periodic signal.
1365 * See linux_vst_gui_support.cc 'elapsed_time_ms'.
1366 * However, that'll require a dedicated thread and cross-thread
1367 * signals to the GUI Thread..
1369 interval = floor(500. /* update twice per FPS, since Glib::signal_timeout is very irregular */
1370 * _session->frame_rate() / _session->nominal_frame_rate()
1371 / _session->timecode_frames_per_second()
1373 #ifdef PLATFORM_WINDOWS
1374 // the smallest windows scheduler time-slice is ~15ms.
1375 // periodic GUI timeouts shorter than that will cause
1376 // WaitForSingleObject to spinlock (100% of one CPU Core)
1377 // and gtk never enters idle mode.
1378 // also changing timeBeginPeriod(1) does not affect that in
1379 // any beneficial way, so we just limit the max rate for now.
1380 interval = std::max(30u, interval); // at most ~33Hz.
1382 interval = std::max(8u, interval); // at most 120Hz.
1385 fps_connection.disconnect();
1386 Timers::set_fps_interval (interval);
1390 ARDOUR_UI::update_sample_rate (framecnt_t)
1394 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
1396 if (!AudioEngine::instance()->connected()) {
1398 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1402 framecnt_t rate = AudioEngine::instance()->sample_rate();
1405 /* no sample rate available */
1406 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1409 if (fmod (rate, 1000.0) != 0.0) {
1410 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
1411 (float) rate / 1000.0f,
1412 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1414 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
1416 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1420 sample_rate_label.set_markup (buf);
1424 ARDOUR_UI::update_format ()
1427 format_label.set_text ("");
1432 s << _("File:") << X_(" <span foreground=\"green\">");
1434 switch (_session->config.get_native_file_header_format ()) {
1466 switch (_session->config.get_native_file_data_format ()) {
1480 format_label.set_markup (s.str ());
1484 ARDOUR_UI::update_xrun_count ()
1488 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1489 should also be changed.
1493 const unsigned int x = _session->get_xrun_count ();
1495 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">>10K</span>"), X_("red"));
1497 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">%u</span>"), x > 0 ? X_("red") : X_("green"), x);
1500 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">?</span>"), X_("yellow"));
1502 xrun_label.set_markup (buf);
1503 set_tip (xrun_label, _("Audio dropouts. Shift+click to reset"));
1507 ARDOUR_UI::update_cpu_load ()
1511 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1512 should also be changed.
1515 double const c = AudioEngine::instance()->get_dsp_load ();
1516 snprintf (buf, sizeof (buf), _("DSP: <span foreground=\"%s\">%5.1f%%</span>"), c >= 90 ? X_("red") : X_("green"), c);
1517 cpu_load_label.set_markup (buf);
1521 ARDOUR_UI::update_peak_thread_work ()
1524 const int c = SourceFactory::peak_work_queue_length ();
1526 snprintf (buf, sizeof (buf), _("PkBld: <span foreground=\"%s\">%d</span>"), c >= 2 ? X_("red") : X_("green"), c);
1527 peak_thread_work_label.set_markup (buf);
1529 peak_thread_work_label.set_markup (X_(""));
1534 ARDOUR_UI::update_buffer_load ()
1538 uint32_t const playback = _session ? _session->playback_load () : 100;
1539 uint32_t const capture = _session ? _session->capture_load () : 100;
1541 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1542 should also be changed.
1548 _("Buffers: <span foreground=\"green\">p:</span><span foreground=\"%s\">%" PRIu32 "%%</span> "
1549 "<span foreground=\"green\">c:</span><span foreground=\"%s\">%" PRIu32 "%%</span>"),
1550 playback <= 5 ? X_("red") : X_("green"),
1552 capture <= 5 ? X_("red") : X_("green"),
1556 buffer_load_label.set_markup (buf);
1558 buffer_load_label.set_text ("");
1563 ARDOUR_UI::count_recenabled_streams (Route& route)
1565 Track* track = dynamic_cast<Track*>(&route);
1566 if (track && track->record_enabled()) {
1567 rec_enabled_streams += track->n_inputs().n_total();
1572 ARDOUR_UI::update_disk_space()
1574 if (_session == 0) {
1578 boost::optional<framecnt_t> opt_frames = _session->available_capture_duration();
1580 framecnt_t fr = _session->frame_rate();
1583 /* skip update - no SR available */
1588 /* Available space is unknown */
1589 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">Unknown</span>"));
1590 } else if (opt_frames.get_value_or (0) == max_framecnt) {
1591 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">24hrs+</span>"));
1593 rec_enabled_streams = 0;
1594 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams, false);
1596 framecnt_t frames = opt_frames.get_value_or (0);
1598 if (rec_enabled_streams) {
1599 frames /= rec_enabled_streams;
1606 hrs = frames / (fr * 3600);
1609 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">>24 hrs</span>"));
1611 frames -= hrs * fr * 3600;
1612 mins = frames / (fr * 60);
1613 frames -= mins * fr * 60;
1616 bool const low = (hrs == 0 && mins <= 30);
1620 _("Disk: <span foreground=\"%s\">%02dh:%02dm:%02ds</span>"),
1621 low ? X_("red") : X_("green"),
1627 disk_space_label.set_markup (buf);
1631 ARDOUR_UI::update_timecode_format ()
1637 TimecodeSlave* tcslave;
1638 SyncSource sync_src = Config->get_sync_source();
1640 if ((sync_src == LTC || sync_src == MTC) && (tcslave = dynamic_cast<TimecodeSlave*>(_session->slave())) != 0) {
1641 matching = (tcslave->apparent_timecode_format() == _session->config.get_timecode_format());
1646 snprintf (buf, sizeof (buf), S_("Timecode|TC: <span foreground=\"%s\">%s</span>"),
1647 matching ? X_("green") : X_("red"),
1648 Timecode::timecode_format_name (_session->config.get_timecode_format()).c_str());
1650 snprintf (buf, sizeof (buf), "TC: n/a");
1653 timecode_format_label.set_markup (buf);
1657 ARDOUR_UI::update_wall_clock ()
1661 static int last_min = -1;
1664 tm_now = localtime (&now);
1665 if (last_min != tm_now->tm_min) {
1667 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1668 wall_clock_label.set_text (buf);
1669 last_min = tm_now->tm_min;
1676 ARDOUR_UI::open_recent_session ()
1678 bool can_return = (_session != 0);
1680 SessionDialog recent_session_dialog;
1684 ResponseType r = (ResponseType) recent_session_dialog.run ();
1687 case RESPONSE_ACCEPT:
1691 recent_session_dialog.hide();
1698 recent_session_dialog.hide();
1702 std::string path = recent_session_dialog.session_folder();
1703 std::string state = recent_session_dialog.session_name (should_be_new);
1705 if (should_be_new == true) {
1709 _session_is_new = false;
1711 if (load_session (path, state) == 0) {
1717 if (splash && splash->is_visible()) {
1718 // in 1 second, hide the splash screen
1719 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
1724 ARDOUR_UI::check_audioengine (Gtk::Window& parent)
1726 if (!AudioEngine::instance()->connected()) {
1727 MessageDialog msg (parent, string_compose (
1728 _("%1 is not connected to any audio backend.\n"
1729 "You cannot open or close sessions in this condition"),
1731 pop_back_splash (msg);
1739 ARDOUR_UI::open_session ()
1741 if (!check_audioengine (_main_window)) {
1745 /* ardour sessions are folders */
1746 Gtk::FileChooserDialog open_session_selector(_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1747 open_session_selector.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1748 open_session_selector.add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1749 open_session_selector.set_default_response(Gtk::RESPONSE_ACCEPT);
1752 string session_parent_dir = Glib::path_get_dirname(_session->path());
1753 open_session_selector.set_current_folder(session_parent_dir);
1755 open_session_selector.set_current_folder(Config->get_default_session_parent_dir());
1758 Gtkmm2ext::add_volume_shortcuts (open_session_selector);
1760 /* add_shortcut_folder throws an exception if the folder being added already has a shortcut */
1761 string default_session_folder = Config->get_default_session_parent_dir();
1762 open_session_selector.add_shortcut_folder (default_session_folder);
1764 catch (Glib::Error & e) {
1765 std::cerr << "open_session_selector.add_shortcut_folder() threw Glib::Error " << e.what() << std::endl;
1768 FileFilter session_filter;
1769 session_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::statefile_suffix));
1770 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1771 open_session_selector.add_filter (session_filter);
1772 open_session_selector.set_filter (session_filter);
1774 int response = open_session_selector.run();
1775 open_session_selector.hide ();
1777 if (response == Gtk::RESPONSE_CANCEL) {
1781 string session_path = open_session_selector.get_filename();
1785 if (session_path.length() > 0) {
1786 if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1787 _session_is_new = isnew;
1788 load_session (path, name);
1794 ARDOUR_UI::session_add_mixed_track (
1795 const ChanCount& input,
1796 const ChanCount& output,
1797 RouteGroup* route_group,
1799 const string& name_template,
1801 PluginInfoPtr instrument)
1803 list<boost::shared_ptr<MidiTrack> > tracks;
1805 if (_session == 0) {
1806 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1811 tracks = _session->new_midi_track (input, output, instrument, ARDOUR::Normal, route_group, how_many, name_template);
1813 if (tracks.size() != how_many) {
1814 error << string_compose(P_("could not create %1 new mixed track", "could not create %1 new mixed tracks", how_many), how_many) << endmsg;
1819 display_insufficient_ports_message ();
1824 for (list<boost::shared_ptr<MidiTrack> >::iterator i = tracks.begin(); i != tracks.end(); ++i) {
1825 (*i)->set_strict_io (true);
1831 ARDOUR_UI::session_add_midi_bus (
1832 RouteGroup* route_group,
1834 const string& name_template,
1836 PluginInfoPtr instrument)
1840 if (_session == 0) {
1841 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1846 routes = _session->new_midi_route (route_group, how_many, name_template, instrument);
1847 if (routes.size() != how_many) {
1848 error << string_compose(P_("could not create %1 new Midi Bus", "could not create %1 new Midi Busses", how_many), how_many) << endmsg;
1853 display_insufficient_ports_message ();
1858 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
1859 (*i)->set_strict_io (true);
1865 ARDOUR_UI::session_add_midi_route (
1867 RouteGroup* route_group,
1869 const string& name_template,
1871 PluginInfoPtr instrument)
1873 ChanCount one_midi_channel;
1874 one_midi_channel.set (DataType::MIDI, 1);
1877 session_add_mixed_track (one_midi_channel, one_midi_channel, route_group, how_many, name_template, strict_io, instrument);
1879 session_add_midi_bus (route_group, how_many, name_template, strict_io, instrument);
1884 ARDOUR_UI::session_add_audio_route (
1886 int32_t input_channels,
1887 int32_t output_channels,
1888 ARDOUR::TrackMode mode,
1889 RouteGroup* route_group,
1891 string const & name_template,
1895 list<boost::shared_ptr<AudioTrack> > tracks;
1898 if (_session == 0) {
1899 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1905 tracks = _session->new_audio_track (input_channels, output_channels, mode, route_group, how_many, name_template);
1907 if (tracks.size() != how_many) {
1908 error << string_compose (P_("could not create %1 new audio track", "could not create %1 new audio tracks", how_many), how_many)
1914 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template);
1916 if (routes.size() != how_many) {
1917 error << string_compose (P_("could not create %1 new audio bus", "could not create %1 new audio busses", how_many), how_many)
1924 display_insufficient_ports_message ();
1929 for (list<boost::shared_ptr<AudioTrack> >::iterator i = tracks.begin(); i != tracks.end(); ++i) {
1930 (*i)->set_strict_io (true);
1932 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
1933 (*i)->set_strict_io (true);
1939 ARDOUR_UI::display_insufficient_ports_message ()
1941 MessageDialog msg (_main_window,
1942 string_compose (_("There are insufficient ports available\n\
1943 to create a new track or bus.\n\
1944 You should save %1, exit and\n\
1945 restart with more ports."), PROGRAM_NAME));
1946 pop_back_splash (msg);
1951 ARDOUR_UI::transport_goto_start ()
1954 _session->goto_start();
1956 /* force displayed area in editor to start no matter
1957 what "follow playhead" setting is.
1961 editor->center_screen (_session->current_start_frame ());
1967 ARDOUR_UI::transport_goto_zero ()
1970 _session->request_locate (0);
1972 /* force displayed area in editor to start no matter
1973 what "follow playhead" setting is.
1977 editor->reset_x_origin (0);
1983 ARDOUR_UI::transport_goto_wallclock ()
1985 if (_session && editor) {
1992 localtime_r (&now, &tmnow);
1994 framecnt_t frame_rate = _session->frame_rate();
1996 if (frame_rate == 0) {
1997 /* no frame rate available */
2001 frames = tmnow.tm_hour * (60 * 60 * frame_rate);
2002 frames += tmnow.tm_min * (60 * frame_rate);
2003 frames += tmnow.tm_sec * frame_rate;
2005 _session->request_locate (frames, _session->transport_rolling ());
2007 /* force displayed area in editor to start no matter
2008 what "follow playhead" setting is.
2012 editor->center_screen (frames);
2018 ARDOUR_UI::transport_goto_end ()
2021 framepos_t const frame = _session->current_end_frame();
2022 _session->request_locate (frame);
2024 /* force displayed area in editor to start no matter
2025 what "follow playhead" setting is.
2029 editor->center_screen (frame);
2035 ARDOUR_UI::transport_stop ()
2041 if (_session->is_auditioning()) {
2042 _session->cancel_audition ();
2046 _session->request_stop (false, true);
2049 /** Check if any tracks are record enabled. If none are, record enable all of them.
2050 * @return true if track record-enabled status was changed, false otherwise.
2053 ARDOUR_UI::trx_record_enable_all_tracks ()
2059 boost::shared_ptr<RouteList> rl = _session->get_tracks ();
2060 bool none_record_enabled = true;
2062 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
2063 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*r);
2066 if (t->record_enabled()) {
2067 none_record_enabled = false;
2072 if (none_record_enabled) {
2073 _session->set_record_enabled (rl, true, Session::rt_cleanup);
2076 return none_record_enabled;
2080 ARDOUR_UI::transport_record (bool roll)
2083 switch (_session->record_status()) {
2084 case Session::Disabled:
2085 if (_session->ntracks() == 0) {
2086 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."));
2090 if (Profile->get_trx()) {
2091 roll = trx_record_enable_all_tracks ();
2093 _session->maybe_enable_record ();
2098 case Session::Recording:
2100 _session->request_stop();
2102 _session->disable_record (false, true);
2106 case Session::Enabled:
2107 _session->disable_record (false, true);
2113 ARDOUR_UI::transport_roll ()
2119 if (_session->is_auditioning()) {
2124 if (_session->config.get_external_sync()) {
2125 switch (Config->get_sync_source()) {
2129 /* transport controlled by the master */
2135 bool rolling = _session->transport_rolling();
2137 if (_session->get_play_loop()) {
2139 /* If loop playback is not a mode, then we should cancel
2140 it when this action is requested. If it is a mode
2141 we just leave it in place.
2144 if (!Config->get_loop_is_mode()) {
2145 /* XXX it is not possible to just leave seamless loop and keep
2146 playing at present (nov 4th 2009)
2148 if (!Config->get_seamless_loop()) {
2149 /* stop loop playback and stop rolling */
2150 _session->request_play_loop (false, true);
2151 } else if (rolling) {
2152 /* stop loop playback but keep rolling */
2153 _session->request_play_loop (false, false);
2157 } else if (_session->get_play_range () ) {
2158 /* stop playing a range if we currently are */
2159 _session->request_play_range (0, true);
2163 _session->request_transport_speed (1.0f);
2168 ARDOUR_UI::get_smart_mode() const
2170 return ( editor->get_smart_mode() );
2175 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
2181 if (_session->is_auditioning()) {
2182 _session->cancel_audition ();
2186 if (_session->config.get_external_sync()) {
2187 switch (Config->get_sync_source()) {
2191 /* transport controlled by the master */
2196 bool rolling = _session->transport_rolling();
2197 bool affect_transport = true;
2199 if (rolling && roll_out_of_bounded_mode) {
2200 /* drop out of loop/range playback but leave transport rolling */
2201 if (_session->get_play_loop()) {
2202 if (_session->actively_recording()) {
2204 /* just stop using the loop, then actually stop
2207 _session->request_play_loop (false, affect_transport);
2210 if (Config->get_seamless_loop()) {
2211 /* the disk buffers contain copies of the loop - we can't
2212 just keep playing, so stop the transport. the user
2213 can restart as they wish.
2215 affect_transport = true;
2217 /* disk buffers are normal, so we can keep playing */
2218 affect_transport = false;
2220 _session->request_play_loop (false, affect_transport);
2222 } else if (_session->get_play_range ()) {
2223 affect_transport = false;
2224 _session->request_play_range (0, true);
2228 if (affect_transport) {
2230 _session->request_stop (with_abort, true);
2232 /* the only external sync condition we can be in here
2233 * would be Engine (JACK) sync, in which case we still
2237 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
2238 _session->request_play_range (&editor->get_selection().time, true);
2239 _session->set_requested_return_frame( editor->get_selection().time.front().start ); //force an auto-return here
2241 _session->request_transport_speed (1.0f);
2247 ARDOUR_UI::toggle_session_auto_loop ()
2253 Location * looploc = _session->locations()->auto_loop_location();
2259 if (_session->get_play_loop()) {
2261 /* looping enabled, our job is to disable it */
2263 _session->request_play_loop (false);
2267 /* looping not enabled, our job is to enable it.
2269 loop-is-NOT-mode: this action always starts the transport rolling.
2270 loop-IS-mode: this action simply sets the loop play mechanism, but
2271 does not start transport.
2273 if (Config->get_loop_is_mode()) {
2274 _session->request_play_loop (true, false);
2276 _session->request_play_loop (true, true);
2280 //show the loop markers
2281 looploc->set_hidden (false, this);
2285 ARDOUR_UI::transport_play_selection ()
2291 editor->play_selection ();
2295 ARDOUR_UI::transport_play_preroll ()
2300 editor->play_with_preroll ();
2304 ARDOUR_UI::transport_rewind (int option)
2306 float current_transport_speed;
2309 current_transport_speed = _session->transport_speed();
2311 if (current_transport_speed >= 0.0f) {
2314 _session->request_transport_speed (-1.0f);
2317 _session->request_transport_speed (-4.0f);
2320 _session->request_transport_speed (-0.5f);
2325 _session->request_transport_speed (current_transport_speed * 1.5f);
2331 ARDOUR_UI::transport_forward (int option)
2337 float current_transport_speed = _session->transport_speed();
2339 if (current_transport_speed <= 0.0f) {
2342 _session->request_transport_speed (1.0f);
2345 _session->request_transport_speed (4.0f);
2348 _session->request_transport_speed (0.5f);
2353 _session->request_transport_speed (current_transport_speed * 1.5f);
2358 ARDOUR_UI::toggle_record_enable (uint32_t rid)
2364 boost::shared_ptr<Route> r;
2366 if ((r = _session->route_by_remote_id (rid)) != 0) {
2368 boost::shared_ptr<Track> t;
2370 if ((t = boost::dynamic_pointer_cast<Track>(r)) != 0) {
2371 t->set_record_enabled (!t->record_enabled(), Controllable::UseGroup);
2377 ARDOUR_UI::map_transport_state ()
2380 auto_loop_button.unset_active_state ();
2381 play_selection_button.unset_active_state ();
2382 roll_button.unset_active_state ();
2383 stop_button.set_active_state (Gtkmm2ext::ExplicitActive);
2387 shuttle_box->map_transport_state ();
2389 float sp = _session->transport_speed();
2395 if (_session->get_play_range()) {
2397 play_selection_button.set_active_state (Gtkmm2ext::ExplicitActive);
2398 roll_button.unset_active_state ();
2399 auto_loop_button.unset_active_state ();
2401 } else if (_session->get_play_loop ()) {
2403 auto_loop_button.set_active (true);
2404 play_selection_button.set_active (false);
2405 if (Config->get_loop_is_mode()) {
2406 roll_button.set_active (true);
2408 roll_button.set_active (false);
2413 roll_button.set_active (true);
2414 play_selection_button.set_active (false);
2415 auto_loop_button.set_active (false);
2418 if (UIConfiguration::instance().get_follow_edits() && !_session->config.get_external_sync()) {
2419 /* light up both roll and play-selection if they are joined */
2420 roll_button.set_active (true);
2421 play_selection_button.set_active (true);
2424 stop_button.set_active (false);
2428 stop_button.set_active (true);
2429 roll_button.set_active (false);
2430 play_selection_button.set_active (false);
2431 if (Config->get_loop_is_mode ()) {
2432 auto_loop_button.set_active (_session->get_play_loop());
2434 auto_loop_button.set_active (false);
2436 update_disk_space ();
2441 ARDOUR_UI::blink_handler (bool blink_on)
2443 transport_rec_enable_blink (blink_on);
2444 solo_blink (blink_on);
2445 sync_blink (blink_on);
2446 audition_blink (blink_on);
2447 feedback_blink (blink_on);
2448 error_blink (blink_on);
2452 ARDOUR_UI::update_clocks ()
2454 if (!_session) return;
2456 if (editor && !editor->dragging_playhead()) {
2457 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD)); /* EMIT_SIGNAL */
2462 ARDOUR_UI::start_clocking ()
2464 if (UIConfiguration::instance().get_super_rapid_clock_update()) {
2465 clock_signal_connection = Timers::fps_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2467 clock_signal_connection = Timers::rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2472 ARDOUR_UI::stop_clocking ()
2474 clock_signal_connection.disconnect ();
2478 ARDOUR_UI::save_as_progress_update (float fraction, int64_t cnt, int64_t total, Gtk::Label* label, Gtk::ProgressBar* bar)
2482 snprintf (buf, sizeof (buf), _("Copied %" PRId64 " of %" PRId64), cnt, total);
2484 label->set_text (buf);
2485 bar->set_fraction (fraction);
2487 /* process events, redraws, etc. */
2489 while (gtk_events_pending()) {
2490 gtk_main_iteration ();
2493 return true; /* continue with save-as */
2497 ARDOUR_UI::save_session_as ()
2503 if (!save_as_dialog) {
2504 save_as_dialog = new SaveAsDialog;
2507 save_as_dialog->set_name (_session->name());
2509 int response = save_as_dialog->run ();
2511 save_as_dialog->hide ();
2514 case Gtk::RESPONSE_OK:
2523 sa.new_parent_folder = save_as_dialog->new_parent_folder ();
2524 sa.new_name = save_as_dialog->new_name ();
2525 sa.switch_to = save_as_dialog->switch_to();
2526 sa.copy_media = save_as_dialog->copy_media();
2527 sa.copy_external = save_as_dialog->copy_external();
2528 sa.include_media = save_as_dialog->include_media ();
2530 /* Only bother with a progress dialog if we're going to copy
2531 media into the save-as target. Without that choice, this
2532 will be very fast because we're only talking about a few kB's to
2533 perhaps a couple of MB's of data.
2536 ArdourDialog progress_dialog (_("Save As"), true);
2538 if (sa.include_media && sa.copy_media) {
2541 Gtk::ProgressBar progress_bar;
2543 progress_dialog.get_vbox()->pack_start (label);
2544 progress_dialog.get_vbox()->pack_start (progress_bar);
2546 progress_bar.show ();
2548 /* this signal will be emitted from within this, the calling thread,
2549 * after every file is copied. It provides information on percentage
2550 * complete (in terms of total data to copy), the number of files
2551 * copied so far, and the total number to copy.
2556 sa.Progress.connect_same_thread (c, boost::bind (&ARDOUR_UI::save_as_progress_update, this, _1, _2, _3, &label, &progress_bar));
2558 progress_dialog.show_all ();
2559 progress_dialog.present ();
2562 if (_session->save_as (sa)) {
2564 MessageDialog msg (string_compose (_("Save As failed: %1"), sa.failure_message));
2568 if (!sa.include_media) {
2569 unload_session (false);
2570 load_session (sa.final_session_folder_name, sa.new_name);
2575 ARDOUR_UI::quick_snapshot_session (bool switch_to_it)
2579 struct tm local_time;
2582 localtime_r (&n, &local_time);
2583 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2585 save_state (timebuf, switch_to_it);
2590 ARDOUR_UI::process_snapshot_session_prompter (ArdourPrompter& prompter, bool switch_to_it)
2594 prompter.get_result (snapname);
2596 bool do_save = (snapname.length() != 0);
2599 char illegal = Session::session_name_is_legal(snapname);
2601 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2602 "snapshot names may not contain a '%1' character"), illegal));
2608 vector<std::string> p;
2609 get_state_files_in_directory (_session->session_directory().root_path(), p);
2610 vector<string> n = get_file_names_no_extension (p);
2612 if (find (n.begin(), n.end(), snapname) != n.end()) {
2614 do_save = overwrite_file_dialog (prompter,
2615 _("Confirm Snapshot Overwrite"),
2616 _("A snapshot already exists with that name. Do you want to overwrite it?"));
2620 save_state (snapname, switch_to_it);
2630 /** Ask the user for the name of a new snapshot and then take it.
2634 ARDOUR_UI::snapshot_session (bool switch_to_it)
2636 ArdourPrompter prompter (true);
2638 prompter.set_name ("Prompter");
2639 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2641 prompter.set_title (_("Snapshot and switch"));
2642 prompter.set_prompt (_("New session name"));
2644 prompter.set_title (_("Take Snapshot"));
2645 prompter.set_prompt (_("Name of new snapshot"));
2649 prompter.set_initial_text (_session->snap_name());
2653 struct tm local_time;
2656 localtime_r (&n, &local_time);
2657 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2658 prompter.set_initial_text (timebuf);
2661 bool finished = false;
2663 switch (prompter.run()) {
2664 case RESPONSE_ACCEPT:
2666 finished = process_snapshot_session_prompter (prompter, switch_to_it);
2677 /** Ask the user for a new session name and then rename the session to it.
2681 ARDOUR_UI::rename_session ()
2687 ArdourPrompter prompter (true);
2690 prompter.set_name ("Prompter");
2691 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2692 prompter.set_title (_("Rename Session"));
2693 prompter.set_prompt (_("New session name"));
2696 switch (prompter.run()) {
2697 case RESPONSE_ACCEPT:
2699 prompter.get_result (name);
2701 bool do_rename = (name.length() != 0);
2704 char illegal = Session::session_name_is_legal (name);
2707 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2708 "session names may not contain a '%1' character"), illegal));
2713 switch (_session->rename (name)) {
2715 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
2716 msg.set_position (WIN_POS_MOUSE);
2724 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
2725 msg.set_position (WIN_POS_MOUSE);
2741 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2743 if (!_session || _session->deletion_in_progress()) {
2747 XMLNode* node = new XMLNode (X_("UI"));
2749 WM::Manager::instance().add_state (*node);
2751 node->add_child_nocopy (gui_object_state->get_state());
2753 _session->add_extra_xml (*node);
2755 if (export_video_dialog) {
2756 _session->add_extra_xml (export_video_dialog->get_state());
2759 save_state_canfail (name, switch_to_it);
2763 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2768 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2773 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2778 ARDOUR_UI::primary_clock_value_changed ()
2781 _session->request_locate (primary_clock->current_time ());
2786 ARDOUR_UI::big_clock_value_changed ()
2789 _session->request_locate (big_clock->current_time ());
2794 ARDOUR_UI::secondary_clock_value_changed ()
2797 _session->request_locate (secondary_clock->current_time ());
2802 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2804 if (_session == 0) {
2808 if (_session->step_editing()) {
2812 Session::RecordState const r = _session->record_status ();
2813 bool const h = _session->have_rec_enabled_track ();
2815 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2817 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2819 rec_button.set_active_state (Gtkmm2ext::Off);
2821 } else if (r == Session::Recording && h) {
2822 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2824 rec_button.unset_active_state ();
2829 ARDOUR_UI::process_save_template_prompter (ArdourPrompter& prompter)
2833 prompter.get_result (name);
2835 if (name.length()) {
2836 int failed = _session->save_template (name);
2838 if (failed == -2) { /* file already exists. */
2839 bool overwrite = overwrite_file_dialog (prompter,
2840 _("Confirm Template Overwrite"),
2841 _("A template already exists with that name. Do you want to overwrite it?"));
2844 _session->save_template (name, true);
2856 ARDOUR_UI::save_template ()
2858 ArdourPrompter prompter (true);
2860 if (!check_audioengine (_main_window)) {
2864 prompter.set_name (X_("Prompter"));
2865 prompter.set_title (_("Save Template"));
2866 prompter.set_prompt (_("Name for template:"));
2867 prompter.set_initial_text(_session->name() + _("-template"));
2868 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2870 bool finished = false;
2872 switch (prompter.run()) {
2873 case RESPONSE_ACCEPT:
2874 finished = process_save_template_prompter (prompter);
2885 ARDOUR_UI::edit_metadata ()
2887 SessionMetadataEditor dialog;
2888 dialog.set_session (_session);
2889 dialog.grab_focus ();
2894 ARDOUR_UI::import_metadata ()
2896 SessionMetadataImporter dialog;
2897 dialog.set_session (_session);
2902 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
2904 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2906 MessageDialog msg (str,
2908 Gtk::MESSAGE_WARNING,
2909 Gtk::BUTTONS_YES_NO,
2913 msg.set_name (X_("OpenExistingDialog"));
2914 msg.set_title (_("Open Existing Session"));
2915 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
2916 msg.set_position (Gtk::WIN_POS_CENTER);
2917 pop_back_splash (msg);
2919 switch (msg.run()) {
2928 ARDOUR_UI::build_session_from_dialog (SessionDialog& sd, const std::string& session_path, const std::string& session_name)
2930 BusProfile bus_profile;
2934 bus_profile.master_out_channels = 2;
2935 bus_profile.input_ac = AutoConnectPhysical;
2936 bus_profile.output_ac = AutoConnectMaster;
2937 bus_profile.requested_physical_in = 0; // use all available
2938 bus_profile.requested_physical_out = 0; // use all available
2942 /* get settings from advanced section of NSD */
2944 if (sd.create_master_bus()) {
2945 bus_profile.master_out_channels = (uint32_t) sd.master_channel_count();
2947 bus_profile.master_out_channels = 0;
2950 if (sd.connect_inputs()) {
2951 bus_profile.input_ac = AutoConnectPhysical;
2953 bus_profile.input_ac = AutoConnectOption (0);
2956 bus_profile.output_ac = AutoConnectOption (0);
2958 if (sd.connect_outputs ()) {
2959 if (sd.connect_outs_to_master()) {
2960 bus_profile.output_ac = AutoConnectMaster;
2961 } else if (sd.connect_outs_to_physical()) {
2962 bus_profile.output_ac = AutoConnectPhysical;
2966 bus_profile.requested_physical_in = (uint32_t) sd.input_limit_count();
2967 bus_profile.requested_physical_out = (uint32_t) sd.output_limit_count();
2970 if (build_session (session_path, session_name, bus_profile)) {
2978 ARDOUR_UI::load_from_application_api (const std::string& path)
2980 ARDOUR_COMMAND_LINE::session_name = path;
2981 /* Cancel SessionDialog if it's visible to make OSX delegates work.
2983 * ARDOUR_UI::starting connects app->ShouldLoad signal and then shows a SessionDialog
2985 * - ShouldLoad does not arrive in time, ARDOUR_COMMAND_LINE::session_name is empty:
2986 * -> ARDOUR_UI::get_session_parameters starts a SessionDialog.
2987 * - ShouldLoad signal arrives, this function is called and sets ARDOUR_COMMAND_LINE::session_name
2988 * -> SessionDialog is not displayed
2991 if (_session_dialog) {
2992 std::string session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
2993 std::string session_path = path;
2994 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_REGULAR)) {
2995 session_path = Glib::path_get_dirname (session_path);
2997 // signal the existing dialog in ARDOUR_UI::get_session_parameters()
2998 _session_dialog->set_provided_session (session_name, session_path);
2999 _session_dialog->response (RESPONSE_NONE);
3000 _session_dialog->hide();
3005 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
3006 /* /path/to/foo => /path/to/foo, foo */
3007 rv = load_session (path, basename_nosuffix (path));
3009 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
3010 rv =load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
3013 // if load_session fails -> pop up SessionDialog.
3015 ARDOUR_COMMAND_LINE::session_name = "";
3017 if (get_session_parameters (true, false)) {
3023 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
3025 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
3027 string session_name;
3028 string session_path;
3029 string template_name;
3031 bool likely_new = false;
3032 bool cancel_not_quit;
3034 /* deal with any existing DIRTY session now, rather than later. don't
3035 * treat a non-dirty session this way, so that it stays visible
3036 * as we bring up the new session dialog.
3039 if (_session && ARDOUR_UI::instance()->video_timeline) {
3040 ARDOUR_UI::instance()->video_timeline->sync_session_state();
3043 /* if there is already a session, relabel the button
3044 on the SessionDialog so that we don't Quit directly
3046 cancel_not_quit = (_session != 0);
3048 if (_session && _session->dirty()) {
3049 if (unload_session (false)) {
3050 /* unload cancelled by user */
3053 ARDOUR_COMMAND_LINE::session_name = "";
3056 if (!load_template.empty()) {
3057 should_be_new = true;
3058 template_name = load_template;
3061 session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3062 session_path = ARDOUR_COMMAND_LINE::session_name;
3064 if (!session_path.empty()) {
3065 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_EXISTS)) {
3066 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_IS_REGULAR)) {
3067 /* session/snapshot file, change path to be dir */
3068 session_path = Glib::path_get_dirname (session_path);
3073 SessionDialog session_dialog (should_be_new, session_name, session_path, load_template, cancel_not_quit);
3075 _session_dialog = &session_dialog;
3078 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
3080 /* if they named a specific statefile, use it, otherwise they are
3081 just giving a session folder, and we want to use it as is
3082 to find the session.
3085 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
3087 if (suffix != string::npos) {
3088 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
3089 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
3090 session_name = Glib::path_get_basename (session_name);
3092 session_path = ARDOUR_COMMAND_LINE::session_name;
3093 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
3098 session_dialog.clear_given ();
3101 if (should_be_new || session_name.empty()) {
3102 /* need the dialog to get info from user */
3104 cerr << "run dialog\n";
3106 switch (session_dialog.run()) {
3107 case RESPONSE_ACCEPT:
3110 /* this is used for async * app->ShouldLoad(). */
3111 continue; // while loop
3114 if (quit_on_cancel) {
3115 // JE - Currently (July 2014) this section can only get reached if the
3116 // user quits from the main 'Session Setup' dialog (i.e. reaching this
3117 // point does NOT indicate an abnormal termination). Therefore, let's
3118 // behave gracefully (i.e. let's do some cleanup) before we call exit()
3120 pthread_cancel_all ();
3128 session_dialog.hide ();
3131 /* if we run the startup dialog again, offer more than just "new session" */
3133 should_be_new = false;
3135 session_name = session_dialog.session_name (likely_new);
3136 session_path = session_dialog.session_folder ();
3142 string::size_type suffix = session_name.find (statefile_suffix);
3144 if (suffix != string::npos) {
3145 session_name = session_name.substr (0, suffix);
3148 /* this shouldn't happen, but we catch it just in case it does */
3150 if (session_name.empty()) {
3154 if (session_dialog.use_session_template()) {
3155 template_name = session_dialog.session_template_name();
3156 _session_is_new = true;
3159 if (session_name[0] == G_DIR_SEPARATOR ||
3160 #ifdef PLATFORM_WINDOWS
3161 (session_name.length() > 3 && session_name[1] == ':' && session_name[2] == G_DIR_SEPARATOR)
3163 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
3164 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)
3169 /* absolute path or cwd-relative path specified for session name: infer session folder
3170 from what was given.
3173 session_path = Glib::path_get_dirname (session_name);
3174 session_name = Glib::path_get_basename (session_name);
3178 session_path = session_dialog.session_folder();
3180 char illegal = Session::session_name_is_legal (session_name);
3183 MessageDialog msg (session_dialog,
3184 string_compose (_("To ensure compatibility with various systems\n"
3185 "session names may not contain a '%1' character"),
3188 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3193 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
3196 if (likely_new && !nsm) {
3198 std::string existing = Glib::build_filename (session_path, session_name);
3200 if (!ask_about_loading_existing_session (existing)) {
3201 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3206 _session_is_new = false;
3211 pop_back_splash (session_dialog);
3212 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
3214 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3218 char illegal = Session::session_name_is_legal(session_name);
3221 pop_back_splash (session_dialog);
3222 MessageDialog msg (session_dialog, string_compose(_("To ensure compatibility with various systems\n"
3223 "session names may not contain a '%1' character"), illegal));
3225 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3229 _session_is_new = true;
3232 if (likely_new && template_name.empty()) {
3234 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3238 ret = load_session (session_path, session_name, template_name);
3241 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
3245 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
3246 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
3250 /* clear this to avoid endless attempts to load the
3254 ARDOUR_COMMAND_LINE::session_name = "";
3258 _session_dialog = NULL;
3264 ARDOUR_UI::close_session()
3266 if (!check_audioengine (_main_window)) {
3270 if (unload_session (true)) {
3274 ARDOUR_COMMAND_LINE::session_name = "";
3276 if (get_session_parameters (true, false)) {
3279 if (splash && splash->is_visible()) {
3280 // in 1 second, hide the splash screen
3281 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
3285 /** @param snap_name Snapshot name (without .ardour suffix).
3286 * @return -2 if the load failed because we are not connected to the AudioEngine.
3289 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
3291 Session *new_session;
3296 unload_status = unload_session ();
3298 if (unload_status < 0) {
3300 } else if (unload_status > 0) {
3306 session_loaded = false;
3308 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
3311 new_session = new Session (*AudioEngine::instance(), path, snap_name, 0, mix_template);
3314 /* this one is special */
3316 catch (AudioEngine::PortRegistrationFailure& err) {
3318 MessageDialog msg (err.what(),
3321 Gtk::BUTTONS_CLOSE);
3323 msg.set_title (_("Port Registration Error"));
3324 msg.set_secondary_text (_("Click the Close button to try again."));
3325 msg.set_position (Gtk::WIN_POS_CENTER);
3326 pop_back_splash (msg);
3329 int response = msg.run ();
3334 case RESPONSE_CANCEL:
3341 catch (SessionException e) {
3342 MessageDialog msg (string_compose(
3343 _("Session \"%1 (snapshot %2)\" did not load successfully: %3"),
3344 path, snap_name, e.what()),
3349 msg.set_title (_("Loading Error"));
3350 msg.set_position (Gtk::WIN_POS_CENTER);
3351 pop_back_splash (msg);
3363 MessageDialog msg (string_compose(
3364 _("Session \"%1 (snapshot %2)\" did not load successfully"),
3370 msg.set_title (_("Loading Error"));
3371 msg.set_position (Gtk::WIN_POS_CENTER);
3372 pop_back_splash (msg);
3384 list<string> const u = new_session->unknown_processors ();
3386 MissingPluginDialog d (_session, u);
3391 if (!new_session->writable()) {
3392 MessageDialog msg (_("This session has been opened in read-only mode.\n\nYou will not be able to record or save."),
3397 msg.set_title (_("Read-only Session"));
3398 msg.set_position (Gtk::WIN_POS_CENTER);
3399 pop_back_splash (msg);
3406 /* Now the session been created, add the transport controls */
3407 new_session->add_controllable(roll_controllable);
3408 new_session->add_controllable(stop_controllable);
3409 new_session->add_controllable(goto_start_controllable);
3410 new_session->add_controllable(goto_end_controllable);
3411 new_session->add_controllable(auto_loop_controllable);
3412 new_session->add_controllable(play_selection_controllable);
3413 new_session->add_controllable(rec_controllable);
3415 set_session (new_session);
3417 session_loaded = true;
3420 _session->set_clean ();
3423 #ifdef WINDOWS_VST_SUPPORT
3424 fst_stop_threading();
3428 Timers::TimerSuspender t;
3432 #ifdef WINDOWS_VST_SUPPORT
3433 fst_start_threading();
3442 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
3444 Session *new_session;
3447 session_loaded = false;
3448 x = unload_session ();
3456 _session_is_new = true;
3459 new_session = new Session (*AudioEngine::instance(), path, snap_name, &bus_profile);
3462 catch (SessionException e) {
3464 MessageDialog msg (string_compose(_("Could not create session in \"%1\": %2"), path, e.what()));
3465 msg.set_title (_("Loading Error"));
3466 msg.set_position (Gtk::WIN_POS_CENTER);
3467 pop_back_splash (msg);
3473 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
3474 msg.set_title (_("Loading Error"));
3475 msg.set_position (Gtk::WIN_POS_CENTER);
3476 pop_back_splash (msg);
3481 /* Give the new session the default GUI state, if such things exist */
3484 n = Config->instant_xml (X_("Editor"));
3486 n->remove_nodes_and_delete ("Selection"); // no not apply selection to new sessions.
3487 new_session->add_instant_xml (*n, false);
3489 n = Config->instant_xml (X_("Mixer"));
3491 new_session->add_instant_xml (*n, false);
3494 /* Put the playhead at 0 and scroll fully left */
3495 n = new_session->instant_xml (X_("Editor"));
3497 n->add_property (X_("playhead"), X_("0"));
3498 n->add_property (X_("left-frame"), X_("0"));
3501 set_session (new_session);
3503 session_loaded = true;
3505 new_session->save_state(new_session->name());
3511 ARDOUR_UI::launch_chat ()
3513 MessageDialog dialog(_("<b>Just ask and wait for an answer.\nIt may take from minutes to hours.</b>"), true);
3515 dialog.set_title (_("About the Chat"));
3516 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."));
3518 switch (dialog.run()) {
3521 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
3522 #elif defined PLATFORM_WINDOWS
3523 open_uri("http://webchat.freenode.net/?channels=ardour-windows");
3525 open_uri("http://webchat.freenode.net/?channels=ardour");
3534 ARDOUR_UI::launch_manual ()
3536 PBD::open_uri (Config->get_tutorial_manual_url());
3540 ARDOUR_UI::launch_reference ()
3542 PBD::open_uri (Config->get_reference_manual_url());
3546 ARDOUR_UI::launch_tracker ()
3548 PBD::open_uri ("http://tracker.ardour.org");
3552 ARDOUR_UI::launch_subscribe ()
3554 PBD::open_uri ("https://community.ardour.org/s/subscribe");
3558 ARDOUR_UI::launch_cheat_sheet ()
3561 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheat_sheet_osx.pdf");
3563 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheatsheet.pdf");
3568 ARDOUR_UI::launch_website ()
3570 PBD::open_uri ("http://ardour.org");
3574 ARDOUR_UI::launch_website_dev ()
3576 PBD::open_uri ("http://ardour.org/development.html");
3580 ARDOUR_UI::launch_forums ()
3582 PBD::open_uri ("https://community.ardour.org/forums");
3586 ARDOUR_UI::launch_howto_report ()
3588 PBD::open_uri ("http://ardour.org/reporting_bugs");
3592 ARDOUR_UI::loading_message (const std::string& msg)
3594 if (ARDOUR_COMMAND_LINE::no_splash) {
3602 splash->message (msg);
3606 ARDOUR_UI::show_splash ()
3610 splash = new Splash;
3620 ARDOUR_UI::hide_splash ()
3627 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title, const bool msg_delete)
3631 removed = rep.paths.size();
3634 MessageDialog msgd (_main_window,
3635 _("No files were ready for clean-up"),
3639 msgd.set_title (_("Clean-up"));
3640 msgd.set_secondary_text (_("If this seems suprising, \n\
3641 check for any existing snapshots.\n\
3642 These may still include regions that\n\
3643 require some unused files to continue to exist."));
3649 ArdourDialog results (_("Clean-up"), true, false);
3651 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
3652 CleanupResultsModelColumns() {
3656 Gtk::TreeModelColumn<std::string> visible_name;
3657 Gtk::TreeModelColumn<std::string> fullpath;
3661 CleanupResultsModelColumns results_columns;
3662 Glib::RefPtr<Gtk::ListStore> results_model;
3663 Gtk::TreeView results_display;
3665 results_model = ListStore::create (results_columns);
3666 results_display.set_model (results_model);
3667 results_display.append_column (list_title, results_columns.visible_name);
3669 results_display.set_name ("CleanupResultsList");
3670 results_display.set_headers_visible (true);
3671 results_display.set_headers_clickable (false);
3672 results_display.set_reorderable (false);
3674 Gtk::ScrolledWindow list_scroller;
3677 Gtk::HBox dhbox; // the hbox for the image and text
3678 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
3679 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
3681 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
3683 const string dead_directory = _session->session_directory().dead_path();
3686 %1 - number of files removed
3687 %2 - location of "dead"
3688 %3 - size of files affected
3689 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
3692 const char* bprefix;
3693 double space_adjusted = 0;
3695 if (rep.space < 1000) {
3697 space_adjusted = rep.space;
3698 } else if (rep.space < 1000000) {
3699 bprefix = _("kilo");
3700 space_adjusted = floorf((float)rep.space / 1000.0);
3701 } else if (rep.space < 1000000 * 1000) {
3702 bprefix = _("mega");
3703 space_adjusted = floorf((float)rep.space / (1000.0 * 1000.0));
3705 bprefix = _("giga");
3706 space_adjusted = floorf((float)rep.space / (1000.0 * 1000 * 1000.0));
3710 txt.set_markup (string_compose (P_("\
3711 The following file was deleted from %2,\n\
3712 releasing %3 %4bytes of disk space", "\
3713 The following %1 files were deleted from %2,\n\
3714 releasing %3 %4bytes of disk space", removed),
3715 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3717 txt.set_markup (string_compose (P_("\
3718 The following file was not in use and \n\
3719 has been moved to: %2\n\n\
3720 After a restart of %5\n\n\
3721 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3722 will release an additional %3 %4bytes of disk space.\n", "\
3723 The following %1 files were not in use and \n\
3724 have been moved to: %2\n\n\
3725 After a restart of %5\n\n\
3726 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3727 will release an additional %3 %4bytes of disk space.\n", removed),
3728 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3731 dhbox.pack_start (*dimage, true, false, 5);
3732 dhbox.pack_start (txt, true, false, 5);
3734 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
3735 TreeModel::Row row = *(results_model->append());
3736 row[results_columns.visible_name] = *i;
3737 row[results_columns.fullpath] = *i;
3740 list_scroller.add (results_display);
3741 list_scroller.set_size_request (-1, 150);
3742 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
3744 dvbox.pack_start (dhbox, true, false, 5);
3745 dvbox.pack_start (list_scroller, true, false, 5);
3746 ddhbox.pack_start (dvbox, true, false, 5);
3748 results.get_vbox()->pack_start (ddhbox, true, false, 5);
3749 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
3750 results.set_default_response (RESPONSE_CLOSE);
3751 results.set_position (Gtk::WIN_POS_MOUSE);
3753 results_display.show();
3754 list_scroller.show();
3761 //results.get_vbox()->show();
3762 results.set_resizable (false);
3769 ARDOUR_UI::cleanup ()
3771 if (_session == 0) {
3772 /* shouldn't happen: menu item is insensitive */
3777 MessageDialog checker (_("Are you sure you want to clean-up?"),
3779 Gtk::MESSAGE_QUESTION,
3782 checker.set_title (_("Clean-up"));
3784 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
3785 ALL undo/redo information will be lost if you clean-up.\n\
3786 Clean-up will move all unused files to a \"dead\" location."));
3788 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3789 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
3790 checker.set_default_response (RESPONSE_CANCEL);
3792 checker.set_name (_("CleanupDialog"));
3793 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3794 checker.set_position (Gtk::WIN_POS_MOUSE);
3796 switch (checker.run()) {
3797 case RESPONSE_ACCEPT:
3803 ARDOUR::CleanupReport rep;
3805 editor->prepare_for_cleanup ();
3807 /* do not allow flush until a session is reloaded */
3809 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3811 act->set_sensitive (false);
3814 if (_session->cleanup_sources (rep)) {
3815 editor->finish_cleanup ();
3819 editor->finish_cleanup ();
3822 display_cleanup_results (rep, _("Cleaned Files"), false);
3826 ARDOUR_UI::flush_trash ()
3828 if (_session == 0) {
3829 /* shouldn't happen: menu item is insensitive */
3833 ARDOUR::CleanupReport rep;
3835 if (_session->cleanup_trash_sources (rep)) {
3839 display_cleanup_results (rep, _("deleted file"), true);
3843 ARDOUR_UI::cleanup_peakfiles ()
3845 if (_session == 0) {
3846 /* shouldn't happen: menu item is insensitive */
3850 if (! _session->can_cleanup_peakfiles ()) {
3854 // get all region-views in this session
3856 TrackViewList empty;
3858 editor->get_regions_after(rs, (framepos_t) 0, empty);
3859 std::list<RegionView*> views = rs.by_layer();
3861 // remove displayed audio-region-views waveforms
3862 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
3863 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
3864 if (!arv) { continue ; }
3865 arv->delete_waves();
3868 // cleanup peak files:
3869 // - stop pending peakfile threads
3870 // - close peakfiles if any
3871 // - remove peak dir in session
3872 // - setup peakfiles (background thread)
3873 _session->cleanup_peakfiles ();
3875 // re-add waves to ARV
3876 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
3877 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
3878 if (!arv) { continue ; }
3879 arv->create_waves();
3884 ARDOUR_UI::setup_order_hint (AddRouteDialog::InsertAt place)
3886 uint32_t order_hint = UINT32_MAX;
3888 if (editor->get_selection().tracks.empty()) {
3893 we want the new routes to have their order keys set starting from
3894 the highest order key in the selection + 1 (if available).
3897 if (place == AddRouteDialog::AfterSelection) {
3898 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.back());
3900 order_hint = rtav->route()->order_key();
3903 } else if (place == AddRouteDialog::BeforeSelection) {
3904 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.front());
3906 order_hint = rtav->route()->order_key();
3908 } else if (place == AddRouteDialog::First) {
3911 /* leave order_hint at UINT32_MAX */
3914 if (order_hint == UINT32_MAX) {
3915 /** AddRouteDialog::Last or selection with first/last not a RouteTimeAxisView
3916 * not setting an order hint will place new routes last.
3921 _session->set_order_hint (order_hint);
3923 /* create a gap in the existing route order keys to accomodate new routes.*/
3924 boost::shared_ptr <RouteList> rd = _session->get_routes();
3925 for (RouteList::iterator ri = rd->begin(); ri != rd->end(); ++ri) {
3926 boost::shared_ptr<Route> rt (*ri);
3928 if (rt->is_monitor()) {
3932 if (rt->order_key () >= order_hint) {
3933 rt->set_order_key (rt->order_key () + add_route_dialog->count());
3939 ARDOUR_UI::start_duplicate_routes ()
3941 if (!duplicate_routes_dialog) {
3942 duplicate_routes_dialog = new DuplicateRouteDialog;
3945 if (duplicate_routes_dialog->restart (_session)) {
3949 duplicate_routes_dialog->present ();
3953 ARDOUR_UI::add_route (Gtk::Window* /* ignored */)
3961 if (add_route_dialog->is_visible()) {
3962 /* we're already doing this */
3966 ResponseType r = (ResponseType) add_route_dialog->run ();
3968 add_route_dialog->hide();
3971 case RESPONSE_ACCEPT:
3978 if ((count = add_route_dialog->count()) <= 0) {
3982 setup_order_hint(add_route_dialog->insert_at());
3983 string template_path = add_route_dialog->track_template();
3984 DisplaySuspender ds;
3986 if (!template_path.empty()) {
3987 if (add_route_dialog->name_template_is_default()) {
3988 _session->new_route_from_template (count, template_path, string());
3990 _session->new_route_from_template (count, template_path, add_route_dialog->name_template());
3995 ChanCount input_chan= add_route_dialog->channels ();
3996 ChanCount output_chan;
3997 string name_template = add_route_dialog->name_template ();
3998 PluginInfoPtr instrument = add_route_dialog->requested_instrument ();
3999 RouteGroup* route_group = add_route_dialog->route_group ();
4000 AutoConnectOption oac = Config->get_output_auto_connect();
4001 bool strict_io = add_route_dialog->use_strict_io ();
4003 if (oac & AutoConnectMaster) {
4004 output_chan.set (DataType::AUDIO, (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan.n_audio()));
4005 output_chan.set (DataType::MIDI, 0);
4007 output_chan = input_chan;
4010 /* XXX do something with name template */
4012 switch (add_route_dialog->type_wanted()) {
4013 case AddRouteDialog::AudioTrack:
4014 session_add_audio_track (input_chan.n_audio(), output_chan.n_audio(), add_route_dialog->mode(), route_group, count, name_template, strict_io);
4016 case AddRouteDialog::MidiTrack:
4017 session_add_midi_track (route_group, count, name_template, strict_io, instrument);
4019 case AddRouteDialog::MixedTrack:
4020 session_add_mixed_track (input_chan, output_chan, route_group, count, name_template, strict_io, instrument);
4022 case AddRouteDialog::AudioBus:
4023 session_add_audio_bus (input_chan.n_audio(), output_chan.n_audio(), route_group, count, name_template, strict_io);
4025 case AddRouteDialog::MidiBus:
4026 session_add_midi_bus (route_group, count, name_template, strict_io, instrument);
4032 ARDOUR_UI::add_lua_script ()
4038 LuaScriptInfoPtr spi;
4039 ScriptSelector ss ("Add Lua Session Script", LuaScriptInfo::Session);
4040 switch (ss.run ()) {
4041 case Gtk::RESPONSE_ACCEPT:
4049 std::string script = "";
4052 script = Glib::file_get_contents (spi->path);
4053 } catch (Glib::FileError e) {
4054 string msg = string_compose (_("Cannot read session script '%1': %2"), spi->path, e.what());
4055 MessageDialog am (msg);
4060 LuaScriptParamList lsp = LuaScriptParams::script_params (spi, "sess_params");
4061 std::vector<std::string> reg = _session->registered_lua_functions ();
4063 ScriptParameterDialog spd (_("Set Script Parameters"), spi, reg, lsp);
4064 switch (spd.run ()) {
4065 case Gtk::RESPONSE_ACCEPT:
4072 _session->register_lua_function (spd.name(), script, lsp);
4073 } catch (luabridge::LuaException const& e) {
4074 string msg = string_compose (_("Session script '%1' instantiation failed: %2"), spd.name(), e.what ());
4075 MessageDialog am (msg);
4077 } catch (SessionException e) {
4078 string msg = string_compose (_("Loading Session script '%1' failed: %2"), spd.name(), e.what ());
4079 MessageDialog am (msg);
4085 ARDOUR_UI::remove_lua_script ()
4090 if (_session->registered_lua_function_count () == 0) {
4091 string msg = _("There are no active Lua session scripts present in this session.");
4092 MessageDialog am (msg);
4097 std::vector<std::string> reg = _session->registered_lua_functions ();
4098 SessionScriptManager sm ("Remove Lua Session Script", reg);
4099 switch (sm.run ()) {
4100 case Gtk::RESPONSE_ACCEPT:
4106 _session->unregister_lua_function (sm.name());
4107 } catch (luabridge::LuaException const& e) {
4108 string msg = string_compose (_("Session script '%1' removal failed: %2"), sm.name(), e.what ());
4109 MessageDialog am (msg);
4115 ARDOUR_UI::stop_video_server (bool ask_confirm)
4117 if (!video_server_process && ask_confirm) {
4118 warning << string_compose (_("Video-Server was not launched by %1. The request to stop it is ignored."), PROGRAM_NAME) << endmsg;
4120 if (video_server_process) {
4122 ArdourDialog confirm (_("Stop Video-Server"), true);
4123 Label m (_("Do you really want to stop the Video Server?"));
4124 confirm.get_vbox()->pack_start (m, true, true);
4125 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
4126 confirm.add_button (_("Yes, Stop It"), Gtk::RESPONSE_ACCEPT);
4127 confirm.show_all ();
4128 if (confirm.run() == RESPONSE_CANCEL) {
4132 delete video_server_process;
4133 video_server_process =0;
4138 ARDOUR_UI::start_video_server_menu (Gtk::Window* float_window)
4140 ARDOUR_UI::start_video_server( float_window, true);
4144 ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg)
4150 if (ARDOUR_UI::instance()->video_timeline->check_server()) {
4151 if (video_server_process) {
4152 popup_error(_("The Video Server is already started."));
4154 popup_error(_("An external Video Server is configured and can be reached. Not starting a new instance."));
4160 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4162 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4164 VideoServerDialog *video_server_dialog = new VideoServerDialog (_session);
4166 video_server_dialog->set_transient_for (*float_window);
4169 if (!Config->get_show_video_server_dialog() && firsttime < 2) {
4170 video_server_dialog->hide();
4172 ResponseType r = (ResponseType) video_server_dialog->run ();
4173 video_server_dialog->hide();
4174 if (r != RESPONSE_ACCEPT) { return false; }
4175 if (video_server_dialog->show_again()) {
4176 Config->set_show_video_server_dialog(false);
4180 std::string icsd_exec = video_server_dialog->get_exec_path();
4181 std::string icsd_docroot = video_server_dialog->get_docroot();
4182 if (icsd_docroot.empty()) {
4183 #ifndef PLATFORM_WINDOWS
4184 icsd_docroot = X_("/");
4186 icsd_docroot = X_("C:\\");
4191 if (g_lstat (icsd_docroot.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode)) {
4192 warning << _("Specified docroot is not an existing directory.") << endmsg;
4195 #ifndef PLATFORM_WINDOWS
4196 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4197 || (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0 ) {
4198 warning << _("Given Video Server is not an executable file.") << endmsg;
4202 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4203 || (sb.st_mode & (S_IXUSR)) == 0 ) {
4204 warning << _("Given Video Server is not an executable file.") << endmsg;
4210 argp=(char**) calloc(9,sizeof(char*));
4211 argp[0] = strdup(icsd_exec.c_str());
4212 argp[1] = strdup("-P");
4213 argp[2] = (char*) calloc(16,sizeof(char)); snprintf(argp[2], 16, "%s", video_server_dialog->get_listenaddr().c_str());
4214 argp[3] = strdup("-p");
4215 argp[4] = (char*) calloc(6,sizeof(char)); snprintf(argp[4], 6, "%i", video_server_dialog->get_listenport());
4216 argp[5] = strdup("-C");
4217 argp[6] = (char*) calloc(6,sizeof(char)); snprintf(argp[6], 6, "%i", video_server_dialog->get_cachesize());
4218 argp[7] = strdup(icsd_docroot.c_str());
4220 stop_video_server();
4222 if (icsd_docroot == X_("/") || icsd_docroot == X_("C:\\")) {
4223 Config->set_video_advanced_setup(false);
4225 std::ostringstream osstream;
4226 osstream << "http://127.0.0.1:" << video_server_dialog->get_listenport() << "/";
4227 Config->set_video_server_url(osstream.str());
4228 Config->set_video_server_docroot(icsd_docroot);
4229 Config->set_video_advanced_setup(true);
4232 if (video_server_process) {
4233 delete video_server_process;
4236 video_server_process = new ARDOUR::SystemExec(icsd_exec, argp);
4237 if (video_server_process->start()) {
4238 warning << _("Cannot launch the video-server") << endmsg;
4241 int timeout = 120; // 6 sec
4242 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4243 Glib::usleep (50000);
4245 if (--timeout <= 0 || !video_server_process->is_running()) break;
4248 warning << _("Video-server was started but does not respond to requests...") << endmsg;
4250 if (!ARDOUR_UI::instance()->video_timeline->check_server_docroot()) {
4251 delete video_server_process;
4252 video_server_process = 0;
4260 ARDOUR_UI::add_video (Gtk::Window* float_window)
4266 if (!start_video_server(float_window, false)) {
4267 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4272 add_video_dialog->set_transient_for (*float_window);
4275 if (add_video_dialog->is_visible()) {
4276 /* we're already doing this */
4280 ResponseType r = (ResponseType) add_video_dialog->run ();
4281 add_video_dialog->hide();
4282 if (r != RESPONSE_ACCEPT) { return; }
4284 bool local_file, orig_local_file;
4285 std::string path = add_video_dialog->file_name(local_file);
4287 std::string orig_path = path;
4288 orig_local_file = local_file;
4290 bool auto_set_session_fps = add_video_dialog->auto_set_session_fps();
4292 if (local_file && !Glib::file_test(path, Glib::FILE_TEST_EXISTS)) {
4293 warning << string_compose(_("could not open %1"), path) << endmsg;
4296 if (!local_file && path.length() == 0) {
4297 warning << _("no video-file selected") << endmsg;
4301 std::string audio_from_video;
4302 bool detect_ltc = false;
4304 switch (add_video_dialog->import_option()) {
4305 case VTL_IMPORT_TRANSCODE:
4307 TranscodeVideoDialog *transcode_video_dialog;
4308 transcode_video_dialog = new TranscodeVideoDialog (_session, path);
4309 ResponseType r = (ResponseType) transcode_video_dialog->run ();
4310 transcode_video_dialog->hide();
4311 if (r != RESPONSE_ACCEPT) {
4312 delete transcode_video_dialog;
4316 audio_from_video = transcode_video_dialog->get_audiofile();
4318 if (!audio_from_video.empty() && transcode_video_dialog->detect_ltc()) {
4321 else if (!audio_from_video.empty()) {
4322 editor->embed_audio_from_video(
4324 video_timeline->get_offset(),
4325 (transcode_video_dialog->import_option() != VTL_IMPORT_NO_VIDEO)
4328 switch (transcode_video_dialog->import_option()) {
4329 case VTL_IMPORT_TRANSCODED:
4330 path = transcode_video_dialog->get_filename();
4333 case VTL_IMPORT_REFERENCE:
4336 delete transcode_video_dialog;
4339 delete transcode_video_dialog;
4343 case VTL_IMPORT_NONE:
4347 /* strip _session->session_directory().video_path() from video file if possible */
4348 if (local_file && !path.compare(0, _session->session_directory().video_path().size(), _session->session_directory().video_path())) {
4349 path=path.substr(_session->session_directory().video_path().size());
4350 if (path.at(0) == G_DIR_SEPARATOR) {
4351 path=path.substr(1);
4355 video_timeline->set_update_session_fps(auto_set_session_fps);
4357 if (video_timeline->video_file_info(path, local_file)) {
4358 XMLNode* node = new XMLNode(X_("Videotimeline"));
4359 node->add_property (X_("Filename"), path);
4360 node->add_property (X_("AutoFPS"), auto_set_session_fps?X_("1"):X_("0"));
4361 node->add_property (X_("LocalFile"), local_file?X_("1"):X_("0"));
4362 if (orig_local_file) {
4363 node->add_property (X_("OriginalVideoFile"), orig_path);
4365 node->remove_property (X_("OriginalVideoFile"));
4367 _session->add_extra_xml (*node);
4368 _session->set_dirty ();
4370 if (!audio_from_video.empty() && detect_ltc) {
4371 std::vector<LTCFileReader::LTCMap> ltc_seq;
4374 /* TODO ask user about TV standard (LTC alignment if any) */
4375 LTCFileReader ltcr (audio_from_video, video_timeline->get_video_file_fps());
4376 /* TODO ASK user which channel: 0 .. ltcr->channels() - 1 */
4378 ltc_seq = ltcr.read_ltc (/*channel*/ 0, /*max LTC frames to decode*/ 15);
4380 /* TODO seek near end of file, and read LTC until end.
4381 * if it fails to find any LTC frames, scan complete file
4383 * calculate drift of LTC compared to video-duration,
4384 * ask user for reference (timecode from start/mid/end)
4387 // LTCFileReader will have written error messages
4390 ::g_unlink(audio_from_video.c_str());
4392 if (ltc_seq.size() == 0) {
4393 PBD::error << _("No LTC detected, video will not be aligned.") << endmsg;
4395 /* the very first TC in the file is somteimes not aligned properly */
4396 int i = ltc_seq.size() -1;
4397 ARDOUR::frameoffset_t video_start_offset =
4398 _session->nominal_frame_rate() * (ltc_seq[i].timecode_sec - ltc_seq[i].framepos_sec);
4399 PBD::info << string_compose (_("Align video-start to %1 [samples]"), video_start_offset) << endmsg;
4400 video_timeline->set_offset(video_start_offset);
4404 _session->maybe_update_session_range(
4405 std::max(video_timeline->get_offset(), (ARDOUR::frameoffset_t) 0),
4406 std::max(video_timeline->get_offset() + video_timeline->get_duration(), (ARDOUR::frameoffset_t) 0));
4409 if (add_video_dialog->launch_xjadeo() && local_file) {
4410 editor->set_xjadeo_sensitive(true);
4411 editor->toggle_xjadeo_proc(1);
4413 editor->toggle_xjadeo_proc(0);
4415 editor->toggle_ruler_video(true);
4420 ARDOUR_UI::remove_video ()
4422 video_timeline->close_session();
4423 editor->toggle_ruler_video(false);
4426 video_timeline->set_offset_locked(false);
4427 video_timeline->set_offset(0);
4429 /* delete session state */
4430 XMLNode* node = new XMLNode(X_("Videotimeline"));
4431 _session->add_extra_xml(*node);
4432 node = new XMLNode(X_("Videomonitor"));
4433 _session->add_extra_xml(*node);
4434 node = new XMLNode(X_("Videoexport"));
4435 _session->add_extra_xml(*node);
4436 stop_video_server();
4440 ARDOUR_UI::flush_videotimeline_cache (bool localcacheonly)
4442 if (localcacheonly) {
4443 video_timeline->vmon_update();
4445 video_timeline->flush_cache();
4447 editor->queue_visual_videotimeline_update();
4451 ARDOUR_UI::export_video (bool range)
4453 if (ARDOUR::Config->get_show_video_export_info()) {
4454 ExportVideoInfobox infobox (_session);
4455 Gtk::ResponseType rv = (Gtk::ResponseType) infobox.run();
4456 if (infobox.show_again()) {
4457 ARDOUR::Config->set_show_video_export_info(false);
4460 case GTK_RESPONSE_YES:
4461 PBD::open_uri (ARDOUR::Config->get_reference_manual_url() + "/video-timeline/operations/#export");
4467 export_video_dialog->set_session (_session);
4468 export_video_dialog->apply_state(editor->get_selection().time, range);
4469 export_video_dialog->run ();
4470 export_video_dialog->hide ();
4474 ARDOUR_UI::mixer_settings () const
4479 node = _session->instant_xml(X_("Mixer"));
4481 node = Config->instant_xml(X_("Mixer"));
4485 node = new XMLNode (X_("Mixer"));
4492 ARDOUR_UI::main_window_settings () const
4497 node = _session->instant_xml(X_("Main"));
4499 node = Config->instant_xml(X_("Main"));
4503 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4504 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4509 node = new XMLNode (X_("Main"));
4516 ARDOUR_UI::editor_settings () const
4521 node = _session->instant_xml(X_("Editor"));
4523 node = Config->instant_xml(X_("Editor"));
4527 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4528 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4533 node = new XMLNode (X_("Editor"));
4540 ARDOUR_UI::keyboard_settings () const
4544 node = Config->extra_xml(X_("Keyboard"));
4547 node = new XMLNode (X_("Keyboard"));
4554 ARDOUR_UI::create_xrun_marker (framepos_t where)
4557 Location *location = new Location (*_session, where, where, _("xrun"), Location::IsMark);
4558 _session->locations()->add (location);
4563 ARDOUR_UI::halt_on_xrun_message ()
4565 cerr << "HALT on xrun\n";
4566 MessageDialog msg (_main_window, _("Recording was stopped because your system could not keep up."));
4571 ARDOUR_UI::xrun_handler (framepos_t where)
4577 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
4579 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
4580 create_xrun_marker(where);
4583 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
4584 halt_on_xrun_message ();
4589 ARDOUR_UI::disk_overrun_handler ()
4591 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
4593 if (!have_disk_speed_dialog_displayed) {
4594 have_disk_speed_dialog_displayed = true;
4595 MessageDialog* msg = new MessageDialog (_main_window, string_compose (_("\
4596 The disk system on your computer\n\
4597 was not able to keep up with %1.\n\
4599 Specifically, it failed to write data to disk\n\
4600 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
4601 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4607 /* TODO: this is getting elaborate enough to warrant being split into a dedicated class */
4608 static MessageDialog *scan_dlg = NULL;
4609 static ProgressBar *scan_pbar = NULL;
4610 static HBox *scan_tbox = NULL;
4611 static Gtk::Button *scan_timeout_button;
4614 ARDOUR_UI::cancel_plugin_scan ()
4616 PluginManager::instance().cancel_plugin_scan();
4620 ARDOUR_UI::cancel_plugin_timeout ()
4622 PluginManager::instance().cancel_plugin_timeout();
4623 scan_timeout_button->set_sensitive (false);
4627 ARDOUR_UI::plugin_scan_timeout (int timeout)
4629 if (!scan_dlg || !scan_dlg->is_mapped() || !scan_pbar) {
4633 scan_pbar->set_sensitive (false);
4634 scan_timeout_button->set_sensitive (true);
4635 scan_pbar->set_fraction ((float) timeout / (float) Config->get_vst_scan_timeout());
4638 scan_pbar->set_sensitive (false);
4639 scan_timeout_button->set_sensitive (false);
4645 ARDOUR_UI::plugin_scan_dialog (std::string type, std::string plugin, bool can_cancel)
4647 if (type == X_("closeme") && !(scan_dlg && scan_dlg->is_mapped())) {
4651 const bool cancelled = PluginManager::instance().cancelled();
4652 if (type != X_("closeme") && (!UIConfiguration::instance().get_show_plugin_scan_window()) && !_initial_verbose_plugin_scan) {
4653 if (cancelled && scan_dlg->is_mapped()) {
4658 if (cancelled || !can_cancel) {
4663 static Gtk::Button *cancel_button;
4665 scan_dlg = new MessageDialog("", false, MESSAGE_INFO, BUTTONS_NONE); // TODO manage
4666 VBox* vbox = scan_dlg->get_vbox();
4667 vbox->set_size_request(400,-1);
4668 scan_dlg->set_title (_("Scanning for plugins"));
4670 cancel_button = manage(new Gtk::Button(_("Cancel plugin scan")));
4671 cancel_button->set_name ("EditorGTKButton");
4672 cancel_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_scan) );
4673 cancel_button->show();
4675 scan_dlg->get_vbox()->pack_start ( *cancel_button, PACK_SHRINK);
4677 scan_tbox = manage( new HBox() );
4679 scan_timeout_button = manage(new Gtk::Button(_("Stop Timeout")));
4680 scan_timeout_button->set_name ("EditorGTKButton");
4681 scan_timeout_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_timeout) );
4682 scan_timeout_button->show();
4684 scan_pbar = manage(new ProgressBar());
4685 scan_pbar->set_orientation(Gtk::PROGRESS_RIGHT_TO_LEFT);
4686 scan_pbar->set_text(_("Scan Timeout"));
4689 scan_tbox->pack_start (*scan_pbar, PACK_EXPAND_WIDGET, 4);
4690 scan_tbox->pack_start (*scan_timeout_button, PACK_SHRINK, 4);
4692 scan_dlg->get_vbox()->pack_start (*scan_tbox, PACK_SHRINK, 4);
4695 assert(scan_dlg && scan_tbox && cancel_button);
4697 if (type == X_("closeme")) {
4701 scan_dlg->set_message(type + ": " + Glib::path_get_basename(plugin));
4704 if (!can_cancel || !cancelled) {
4705 scan_timeout_button->set_sensitive(false);
4707 cancel_button->set_sensitive(can_cancel && !cancelled);
4713 ARDOUR_UI::gui_idle_handler ()
4716 /* due to idle calls, gtk_events_pending() may always return true */
4717 while (gtk_events_pending() && --timeout) {
4718 gtk_main_iteration ();
4723 ARDOUR_UI::disk_underrun_handler ()
4725 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
4727 if (!have_disk_speed_dialog_displayed) {
4728 have_disk_speed_dialog_displayed = true;
4729 MessageDialog* msg = new MessageDialog (
4730 _main_window, string_compose (_("The disk system on your computer\n\
4731 was not able to keep up with %1.\n\
4733 Specifically, it failed to read data from disk\n\
4734 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
4735 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4741 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
4743 have_disk_speed_dialog_displayed = false;
4748 ARDOUR_UI::session_dialog (std::string msg)
4750 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
4754 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
4761 ARDOUR_UI::pending_state_dialog ()
4763 HBox* hbox = manage (new HBox());
4764 Image* image = manage (new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG));
4765 ArdourDialog dialog (_("Crash Recovery"), true);
4766 Label message (string_compose (_("\
4767 This session appears to have been in the\n\
4768 middle of recording when %1 or\n\
4769 the computer was shutdown.\n\
4771 %1 can recover any captured audio for\n\
4772 you, or it can ignore it. Please decide\n\
4773 what you would like to do.\n"), PROGRAM_NAME));
4774 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4775 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4776 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4777 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4778 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
4779 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
4780 dialog.set_default_response (RESPONSE_ACCEPT);
4781 dialog.set_position (WIN_POS_CENTER);
4786 switch (dialog.run ()) {
4787 case RESPONSE_ACCEPT:
4795 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
4797 HBox* hbox = new HBox();
4798 Image* image = new Image (Stock::DIALOG_WARNING, ICON_SIZE_DIALOG);
4799 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
4800 Label message (string_compose (_("\
4801 This session was created with a sample rate of %1 Hz, but\n\
4802 %2 is currently running at %3 Hz. If you load this session,\n\
4803 audio may be played at the wrong sample rate.\n"), desired, PROGRAM_NAME, actual));
4805 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4806 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4807 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4808 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4809 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
4810 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
4811 dialog.set_default_response (RESPONSE_ACCEPT);
4812 dialog.set_position (WIN_POS_CENTER);
4817 switch (dialog.run()) {
4818 case RESPONSE_ACCEPT:
4828 ARDOUR_UI::sr_mismatch_message (framecnt_t desired, framecnt_t actual)
4830 MessageDialog msg (string_compose (_("\
4831 This session was created with a sample rate of %1 Hz, but\n\
4832 %2 is currently running at %3 Hz.\n\
4833 Audio will be recorded and played at the wrong sample rate.\n\
4834 Re-Configure the Audio Engine in\n\
4835 Menu > Window > Audio/Midi Setup"),
4836 desired, PROGRAM_NAME, actual),
4838 Gtk::MESSAGE_WARNING);
4843 ARDOUR_UI::use_config ()
4845 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
4847 set_transport_controllable_state (*node);
4852 ARDOUR_UI::update_transport_clocks (framepos_t pos)
4854 if (UIConfiguration::instance().get_primary_clock_delta_edit_cursor()) {
4855 primary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
4857 primary_clock->set (pos);
4860 if (UIConfiguration::instance().get_secondary_clock_delta_edit_cursor()) {
4861 secondary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
4863 secondary_clock->set (pos);
4866 if (big_clock_window) {
4867 big_clock->set (pos);
4869 ARDOUR_UI::instance()->video_timeline->manual_seek_video_monitor(pos);
4873 ARDOUR_UI::step_edit_status_change (bool yn)
4875 // XXX should really store pre-step edit status of things
4876 // we make insensitive
4879 rec_button.set_active_state (Gtkmm2ext::ImplicitActive);
4880 rec_button.set_sensitive (false);
4882 rec_button.unset_active_state ();;
4883 rec_button.set_sensitive (true);
4888 ARDOUR_UI::record_state_changed ()
4890 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
4892 if (!_session || !big_clock_window) {
4893 /* why bother - the clock isn't visible */
4897 if (_session->record_status () == Session::Recording && _session->have_rec_enabled_track ()) {
4898 big_clock->set_active (true);
4900 big_clock->set_active (false);
4905 ARDOUR_UI::first_idle ()
4908 _session->allow_auto_play (true);
4912 editor->first_idle();
4915 Keyboard::set_can_save_keybindings (true);
4920 ARDOUR_UI::store_clock_modes ()
4922 XMLNode* node = new XMLNode(X_("ClockModes"));
4924 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
4925 XMLNode* child = new XMLNode (X_("Clock"));
4927 child->add_property (X_("name"), (*x)->name());
4928 child->add_property (X_("mode"), enum_2_string ((*x)->mode()));
4929 child->add_property (X_("on"), ((*x)->off() ? X_("no") : X_("yes")));
4931 node->add_child_nocopy (*child);
4934 _session->add_extra_xml (*node);
4935 _session->set_dirty ();
4938 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
4939 : Controllable (name), ui (u), type(tp)
4945 ARDOUR_UI::TransportControllable::set_value (double val, PBD::Controllable::GroupControlDisposition /*group_override*/)
4948 /* do nothing: these are radio-style actions */
4952 const char *action = 0;
4956 action = X_("Roll");
4959 action = X_("Stop");
4962 action = X_("GotoStart");
4965 action = X_("GotoEnd");
4968 action = X_("Loop");
4971 action = X_("PlaySelection");
4974 action = X_("Record");
4984 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
4992 ARDOUR_UI::TransportControllable::get_value (void) const
5019 ARDOUR_UI::setup_profile ()
5021 if (gdk_screen_width() < 1200 || getenv ("ARDOUR_NARROW_SCREEN")) {
5022 Profile->set_small_screen ();
5025 if (g_getenv ("TRX")) {
5026 Profile->set_trx ();
5029 if (g_getenv ("MIXBUS")) {
5030 Profile->set_mixbus ();
5035 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
5037 MissingFileDialog dialog (s, str, type);
5042 int result = dialog.run ();
5049 return 1; // quit entire session load
5052 result = dialog.get_action ();
5058 ARDOUR_UI::ambiguous_file (std::string file, std::vector<std::string> hits)
5060 AmbiguousFileDialog dialog (file, hits);
5067 return dialog.get_which ();
5070 /** Allocate our thread-local buffers */
5072 ARDOUR_UI::get_process_buffers ()
5074 _process_thread->get_buffers ();
5077 /** Drop our thread-local buffers */
5079 ARDOUR_UI::drop_process_buffers ()
5081 _process_thread->drop_buffers ();
5085 ARDOUR_UI::feedback_detected ()
5087 _feedback_exists = true;
5091 ARDOUR_UI::successful_graph_sort ()
5093 _feedback_exists = false;
5097 ARDOUR_UI::midi_panic ()
5100 _session->midi_panic();
5105 ARDOUR_UI::session_format_mismatch (std::string xml_path, std::string backup_path)
5107 const char* start_big = "<span size=\"x-large\" weight=\"bold\">";
5108 const char* end_big = "</span>";
5109 const char* start_mono = "<tt>";
5110 const char* end_mono = "</tt>";
5112 MessageDialog msg (string_compose (_("%4This is a session from an older version of %3%5\n\n"
5113 "%3 has copied the old session file\n\n%6%1%7\n\nto\n\n%6%2%7\n\n"
5114 "From now on, use the -2000 version with older versions of %3"),
5115 xml_path, backup_path, PROGRAM_NAME,
5117 start_mono, end_mono), true);
5124 ARDOUR_UI::reset_peak_display ()
5126 if (!_session || !_session->master_out() || !editor_meter) return;
5127 editor_meter->clear_meters();
5128 editor_meter_max_peak = -INFINITY;
5129 editor_meter_peak_display.set_active_state ( Gtkmm2ext::Off );
5133 ARDOUR_UI::reset_group_peak_display (RouteGroup* group)
5135 if (!_session || !_session->master_out()) return;
5136 if (group == _session->master_out()->route_group()) {
5137 reset_peak_display ();
5142 ARDOUR_UI::reset_route_peak_display (Route* route)
5144 if (!_session || !_session->master_out()) return;
5145 if (_session->master_out().get() == route) {
5146 reset_peak_display ();
5151 ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate)
5153 audio_midi_setup->set_desired_sample_rate (desired_sample_rate);
5154 audio_midi_setup->set_position (WIN_POS_CENTER);
5156 if (Config->get_try_autostart_engine () || getenv ("TRY_AUTOSTART_ENGINE")) {
5157 audio_midi_setup->try_autostart ();
5158 if (ARDOUR::AudioEngine::instance()->running()) {
5164 int response = audio_midi_setup->run();
5166 case Gtk::RESPONSE_OK:
5167 if (!AudioEngine::instance()->running()) {
5181 ARDOUR_UI::transport_numpad_timeout ()
5183 _numpad_locate_happening = false;
5184 if (_numpad_timeout_connection.connected() )
5185 _numpad_timeout_connection.disconnect();
5190 ARDOUR_UI::transport_numpad_decimal ()
5192 _numpad_timeout_connection.disconnect();
5194 if (_numpad_locate_happening) {
5195 if (editor) editor->goto_nth_marker(_pending_locate_num - 1);
5196 _numpad_locate_happening = false;
5198 _pending_locate_num = 0;
5199 _numpad_locate_happening = true;
5200 _numpad_timeout_connection = Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::transport_numpad_timeout), 2*1000);
5205 ARDOUR_UI::transport_numpad_event (int num)
5207 if ( _numpad_locate_happening ) {
5208 _pending_locate_num = _pending_locate_num*10 + num;
5211 case 0: toggle_roll(false, false); break;
5212 case 1: transport_rewind(1); break;
5213 case 2: transport_forward(1); break;
5214 case 3: transport_record(true); break;
5215 case 4: toggle_session_auto_loop(); break;
5216 case 5: transport_record(false); toggle_session_auto_loop(); break;
5217 case 6: toggle_punch(); break;
5218 case 7: toggle_click(); break;
5219 case 8: toggle_auto_return(); break;
5220 case 9: toggle_follow_edits(); break;
5226 ARDOUR_UI::set_flat_buttons ()
5228 CairoWidget::set_flat_buttons( UIConfiguration::instance().get_flat_buttons() );
5232 ARDOUR_UI::audioengine_became_silent ()
5234 MessageDialog msg (string_compose (_("This is a free/demo copy of %1. It has just switched to silent mode."), PROGRAM_NAME),
5236 Gtk::MESSAGE_WARNING,
5240 msg.set_title (string_compose (_("%1 is now silent"), PROGRAM_NAME));
5242 Gtk::Label pay_label (string_compose (_("Please consider paying for a copy of %1 - you can pay whatever you want."), PROGRAM_NAME));
5243 Gtk::Label subscribe_label (_("Better yet become a subscriber - subscriptions start at US$1 per month."));
5244 Gtk::Button pay_button (_("Pay for a copy (via the web)"));
5245 Gtk::Button subscribe_button (_("Become a subscriber (via the web)"));
5246 Gtk::HBox pay_button_box;
5247 Gtk::HBox subscribe_button_box;
5249 pay_button_box.pack_start (pay_button, true, false);
5250 subscribe_button_box.pack_start (subscribe_button, true, false);
5252 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 */
5254 pay_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://ardour.org/download")));
5255 subscribe_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://community.ardour.org/s/subscribe")));
5257 msg.get_vbox()->pack_start (pay_label);
5258 msg.get_vbox()->pack_start (pay_button_box);
5259 msg.get_vbox()->pack_start (subscribe_label);
5260 msg.get_vbox()->pack_start (subscribe_button_box);
5262 msg.get_vbox()->show_all ();
5264 msg.add_button (_("Remain silent"), Gtk::RESPONSE_CANCEL);
5265 msg.add_button (_("Save and quit"), Gtk::RESPONSE_NO);
5266 msg.add_button (_("Give me more time"), Gtk::RESPONSE_YES);
5271 case Gtk::RESPONSE_YES:
5272 AudioEngine::instance()->reset_silence_countdown ();
5275 case Gtk::RESPONSE_NO:
5277 save_state_canfail ("");
5281 case Gtk::RESPONSE_CANCEL:
5283 /* don't reset, save session and exit */
5289 ARDOUR_UI::hide_application ()
5291 Application::instance ()-> hide ();
5295 ARDOUR_UI::setup_toplevel_window (Gtk::Window& window, const string& name, void* owner)
5297 /* icons, titles, WM stuff */
5299 static list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
5301 if (window_icons.empty()) {
5302 Glib::RefPtr<Gdk::Pixbuf> icon;
5303 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
5304 window_icons.push_back (icon);
5306 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
5307 window_icons.push_back (icon);
5309 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
5310 window_icons.push_back (icon);
5312 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
5313 window_icons.push_back (icon);
5317 if (!window_icons.empty()) {
5318 window.set_default_icon_list (window_icons);
5321 Gtkmm2ext::WindowTitle title (Glib::get_application_name());
5323 if (!name.empty()) {
5327 window.set_title (title.get_string());
5328 window.set_wmclass (string_compose (X_("%1_%1"), downcase (PROGRAM_NAME), downcase (name)), PROGRAM_NAME);
5330 window.set_flags (CAN_FOCUS);
5331 window.add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
5333 /* This is a hack to ensure that GTK-accelerators continue to
5334 * work. Once we switch over to entirely native bindings, this will be
5335 * unnecessary and should be removed
5337 window.add_accel_group (ActionManager::ui_manager->get_accel_group());
5339 window.signal_configure_event().connect (sigc::mem_fun (*this, &ARDOUR_UI::configure_handler));
5340 window.signal_window_state_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::tabbed_window_state_event_handler), owner));
5341 window.signal_key_press_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5342 window.signal_key_release_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5346 ARDOUR_UI::key_event_handler (GdkEventKey* ev, Gtk::Window* event_window)
5348 Gtkmm2ext::Bindings* bindings = 0;
5349 Gtk::Window* window = 0;
5351 /* until we get ardour bindings working, we are not handling key
5355 if (ev->type != GDK_KEY_PRESS) {
5359 if (event_window == &_main_window) {
5361 window = event_window;
5363 /* find current tab contents */
5365 Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page());
5367 /* see if it uses the ardour binding system */
5370 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(w->get_data ("ardour-bindings"));
5373 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("main window key event, bindings = %1, global = %2\n", bindings, &global_bindings));
5377 window = event_window;
5379 /* see if window uses ardour binding system */
5381 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(window->get_data ("ardour-bindings"));
5384 /* An empty binding set is treated as if it doesn't exist */
5386 if (bindings && bindings->empty()) {
5390 return key_press_focus_accelerator_handler (*window, ev, bindings);
5393 static Gtkmm2ext::Bindings*
5394 get_bindings_from_widget_heirarchy (GtkWidget* w)
5399 if ((p = g_object_get_data (G_OBJECT(w), "ardour-bindings")) != 0) {
5402 w = gtk_widget_get_parent (w);
5405 return reinterpret_cast<Gtkmm2ext::Bindings*> (p);
5409 ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev, Gtkmm2ext::Bindings* bindings)
5411 GtkWindow* win = window.gobj();
5412 GtkWidget* focus = gtk_window_get_focus (win);
5413 bool special_handling_of_unmodified_accelerators = false;
5414 const guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK));
5418 /* some widget has keyboard focus */
5420 if (GTK_IS_ENTRY(focus) || Keyboard::some_magic_widget_has_focus()) {
5422 /* A particular kind of focusable widget currently has keyboard
5423 * focus. All unmodified key events should go to that widget
5424 * first and not be used as an accelerator by default
5427 special_handling_of_unmodified_accelerators = true;
5431 Gtkmm2ext::Bindings* focus_bindings = get_bindings_from_widget_heirarchy (focus);
5432 if (focus_bindings) {
5433 bindings = focus_bindings;
5434 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Switch bindings based on focus widget, now using %1\n", bindings->name()));
5439 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Win = %1 [title = %9] focus = %7 (%8) Key event: code = %2 state = %3 special handling ? %4 magic widget focus ? %5 focus widget %6 named %7 mods ? %8\n",
5442 show_gdk_event_state (ev->state),
5443 special_handling_of_unmodified_accelerators,
5444 Keyboard::some_magic_widget_has_focus(),
5446 (focus ? gtk_widget_get_name (focus) : "no focus widget"),
5447 ((ev->state & mask) ? "yes" : "no"),
5448 window.get_title()));
5450 /* This exists to allow us to override the way GTK handles
5451 key events. The normal sequence is:
5453 a) event is delivered to a GtkWindow
5454 b) accelerators/mnemonics are activated
5455 c) if (b) didn't handle the event, propagate to
5456 the focus widget and/or focus chain
5458 The problem with this is that if the accelerators include
5459 keys without modifiers, such as the space bar or the
5460 letter "e", then pressing the key while typing into
5461 a text entry widget results in the accelerator being
5462 activated, instead of the desired letter appearing
5465 There is no good way of fixing this, but this
5466 represents a compromise. The idea is that
5467 key events involving modifiers (not Shift)
5468 get routed into the activation pathway first, then
5469 get propagated to the focus widget if necessary.
5471 If the key event doesn't involve modifiers,
5472 we deliver to the focus widget first, thus allowing
5473 it to get "normal text" without interference
5476 Of course, this can also be problematic: if there
5477 is a widget with focus, then it will swallow
5478 all "normal text" accelerators.
5482 if (!special_handling_of_unmodified_accelerators || (ev->state & mask)) {
5484 /* no special handling or there are modifiers in effect: accelerate first */
5486 DEBUG_TRACE (DEBUG::Accelerators, "\tactivate, then propagate\n");
5487 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tevent send-event:%1 time:%2 length:%3 name %7 string:%4 hardware_keycode:%5 group:%6\n",
5488 ev->send_event, ev->time, ev->length, ev->string, ev->hardware_keycode, ev->group, gdk_keyval_name (ev->keyval)));
5490 DEBUG_TRACE (DEBUG::Accelerators, "\tsending to window\n");
5491 KeyboardKey k (ev->state, ev->keyval);
5495 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tusing Ardour bindings %1 @ %2 for this event\n", bindings->name(), bindings));
5497 if (bindings->activate (k, Bindings::Press)) {
5498 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5503 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5505 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5506 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5510 DEBUG_TRACE (DEBUG::Accelerators, "\tnot accelerated, now propagate\n");
5512 if (gtk_window_propagate_key_event (win, ev)) {
5513 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate handled\n");
5519 /* no modifiers, propagate first */
5521 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate, then activate\n");
5523 if (gtk_window_propagate_key_event (win, ev)) {
5524 DEBUG_TRACE (DEBUG::Accelerators, "\thandled by propagate\n");
5528 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagation didn't handle, so activate\n");
5529 KeyboardKey k (ev->state, ev->keyval);
5533 DEBUG_TRACE (DEBUG::Accelerators, "\tusing Ardour bindings for this window\n");
5536 if (bindings->activate (k, Bindings::Press)) {
5537 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5543 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5545 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5546 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5551 DEBUG_TRACE (DEBUG::Accelerators, "\tnot handled\n");
5556 ARDOUR_UI::load_bindings ()
5558 if ((global_bindings = Bindings::get_bindings (X_("Global"), global_actions)) == 0) {
5559 error << _("Global keybindings are missing") << endmsg;
5564 ARDOUR_UI::cancel_solo ()
5567 if (_session->soloing()) {
5568 _session->set_solo (_session->get_routes(), false);
5569 } else if (_session->listening()) {
5570 _session->set_listen (_session->get_routes(), false);
5573 _session->clear_all_solo_state (_session->get_routes()); // safeguard, ideally this won't do anything, check the log-window