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 XMLProperty const * 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,
1802 Plugin::PresetRecord* pset)
1804 list<boost::shared_ptr<MidiTrack> > tracks;
1806 if (_session == 0) {
1807 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1812 tracks = _session->new_midi_track (input, output, instrument, ARDOUR::Normal, route_group, how_many, name_template, pset);
1814 if (tracks.size() != how_many) {
1815 error << string_compose(P_("could not create %1 new mixed track", "could not create %1 new mixed tracks", how_many), how_many) << endmsg;
1820 display_insufficient_ports_message ();
1825 for (list<boost::shared_ptr<MidiTrack> >::iterator i = tracks.begin(); i != tracks.end(); ++i) {
1826 (*i)->set_strict_io (true);
1832 ARDOUR_UI::session_add_midi_bus (
1833 RouteGroup* route_group,
1835 const string& name_template,
1837 PluginInfoPtr instrument,
1838 Plugin::PresetRecord* pset)
1842 if (_session == 0) {
1843 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1848 routes = _session->new_midi_route (route_group, how_many, name_template, instrument, pset);
1849 if (routes.size() != how_many) {
1850 error << string_compose(P_("could not create %1 new Midi Bus", "could not create %1 new Midi Busses", how_many), how_many) << endmsg;
1855 display_insufficient_ports_message ();
1860 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
1861 (*i)->set_strict_io (true);
1867 ARDOUR_UI::session_add_midi_route (
1869 RouteGroup* route_group,
1871 const string& name_template,
1873 PluginInfoPtr instrument,
1874 Plugin::PresetRecord* pset)
1876 ChanCount one_midi_channel;
1877 one_midi_channel.set (DataType::MIDI, 1);
1880 session_add_mixed_track (one_midi_channel, one_midi_channel, route_group, how_many, name_template, strict_io, instrument, pset);
1882 session_add_midi_bus (route_group, how_many, name_template, strict_io, instrument, pset);
1887 ARDOUR_UI::session_add_audio_route (
1889 int32_t input_channels,
1890 int32_t output_channels,
1891 ARDOUR::TrackMode mode,
1892 RouteGroup* route_group,
1894 string const & name_template,
1898 list<boost::shared_ptr<AudioTrack> > tracks;
1901 if (_session == 0) {
1902 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1908 tracks = _session->new_audio_track (input_channels, output_channels, mode, route_group, how_many, name_template);
1910 if (tracks.size() != how_many) {
1911 error << string_compose (P_("could not create %1 new audio track", "could not create %1 new audio tracks", how_many), how_many)
1917 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template);
1919 if (routes.size() != how_many) {
1920 error << string_compose (P_("could not create %1 new audio bus", "could not create %1 new audio busses", how_many), how_many)
1927 display_insufficient_ports_message ();
1932 for (list<boost::shared_ptr<AudioTrack> >::iterator i = tracks.begin(); i != tracks.end(); ++i) {
1933 (*i)->set_strict_io (true);
1935 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
1936 (*i)->set_strict_io (true);
1942 ARDOUR_UI::display_insufficient_ports_message ()
1944 MessageDialog msg (_main_window,
1945 string_compose (_("There are insufficient ports available\n\
1946 to create a new track or bus.\n\
1947 You should save %1, exit and\n\
1948 restart with more ports."), PROGRAM_NAME));
1949 pop_back_splash (msg);
1954 ARDOUR_UI::transport_goto_start ()
1957 _session->goto_start();
1959 /* force displayed area in editor to start no matter
1960 what "follow playhead" setting is.
1964 editor->center_screen (_session->current_start_frame ());
1970 ARDOUR_UI::transport_goto_zero ()
1973 _session->request_locate (0);
1975 /* force displayed area in editor to start no matter
1976 what "follow playhead" setting is.
1980 editor->reset_x_origin (0);
1986 ARDOUR_UI::transport_goto_wallclock ()
1988 if (_session && editor) {
1995 localtime_r (&now, &tmnow);
1997 framecnt_t frame_rate = _session->frame_rate();
1999 if (frame_rate == 0) {
2000 /* no frame rate available */
2004 frames = tmnow.tm_hour * (60 * 60 * frame_rate);
2005 frames += tmnow.tm_min * (60 * frame_rate);
2006 frames += tmnow.tm_sec * frame_rate;
2008 _session->request_locate (frames, _session->transport_rolling ());
2010 /* force displayed area in editor to start no matter
2011 what "follow playhead" setting is.
2015 editor->center_screen (frames);
2021 ARDOUR_UI::transport_goto_end ()
2024 framepos_t const frame = _session->current_end_frame();
2025 _session->request_locate (frame);
2027 /* force displayed area in editor to start no matter
2028 what "follow playhead" setting is.
2032 editor->center_screen (frame);
2038 ARDOUR_UI::transport_stop ()
2044 if (_session->is_auditioning()) {
2045 _session->cancel_audition ();
2049 _session->request_stop (false, true);
2052 /** Check if any tracks are record enabled. If none are, record enable all of them.
2053 * @return true if track record-enabled status was changed, false otherwise.
2056 ARDOUR_UI::trx_record_enable_all_tracks ()
2062 boost::shared_ptr<RouteList> rl = _session->get_tracks ();
2063 bool none_record_enabled = true;
2065 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
2066 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*r);
2069 if (t->record_enabled()) {
2070 none_record_enabled = false;
2075 if (none_record_enabled) {
2076 _session->set_record_enabled (rl, true, Session::rt_cleanup);
2079 return none_record_enabled;
2083 ARDOUR_UI::transport_record (bool roll)
2086 switch (_session->record_status()) {
2087 case Session::Disabled:
2088 if (_session->ntracks() == 0) {
2089 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."));
2093 if (Profile->get_trx()) {
2094 roll = trx_record_enable_all_tracks ();
2096 _session->maybe_enable_record ();
2101 case Session::Recording:
2103 _session->request_stop();
2105 _session->disable_record (false, true);
2109 case Session::Enabled:
2110 _session->disable_record (false, true);
2116 ARDOUR_UI::transport_roll ()
2122 if (_session->is_auditioning()) {
2127 if (_session->config.get_external_sync()) {
2128 switch (Config->get_sync_source()) {
2132 /* transport controlled by the master */
2138 bool rolling = _session->transport_rolling();
2140 if (_session->get_play_loop()) {
2142 /* If loop playback is not a mode, then we should cancel
2143 it when this action is requested. If it is a mode
2144 we just leave it in place.
2147 if (!Config->get_loop_is_mode()) {
2148 /* XXX it is not possible to just leave seamless loop and keep
2149 playing at present (nov 4th 2009)
2151 if (!Config->get_seamless_loop()) {
2152 /* stop loop playback and stop rolling */
2153 _session->request_play_loop (false, true);
2154 } else if (rolling) {
2155 /* stop loop playback but keep rolling */
2156 _session->request_play_loop (false, false);
2160 } else if (_session->get_play_range () ) {
2161 /* stop playing a range if we currently are */
2162 _session->request_play_range (0, true);
2166 _session->request_transport_speed (1.0f);
2171 ARDOUR_UI::get_smart_mode() const
2173 return ( editor->get_smart_mode() );
2178 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
2184 if (_session->is_auditioning()) {
2185 _session->cancel_audition ();
2189 if (_session->config.get_external_sync()) {
2190 switch (Config->get_sync_source()) {
2194 /* transport controlled by the master */
2199 bool rolling = _session->transport_rolling();
2200 bool affect_transport = true;
2202 if (rolling && roll_out_of_bounded_mode) {
2203 /* drop out of loop/range playback but leave transport rolling */
2204 if (_session->get_play_loop()) {
2205 if (_session->actively_recording()) {
2207 /* just stop using the loop, then actually stop
2210 _session->request_play_loop (false, affect_transport);
2213 if (Config->get_seamless_loop()) {
2214 /* the disk buffers contain copies of the loop - we can't
2215 just keep playing, so stop the transport. the user
2216 can restart as they wish.
2218 affect_transport = true;
2220 /* disk buffers are normal, so we can keep playing */
2221 affect_transport = false;
2223 _session->request_play_loop (false, affect_transport);
2225 } else if (_session->get_play_range ()) {
2226 affect_transport = false;
2227 _session->request_play_range (0, true);
2231 if (affect_transport) {
2233 _session->request_stop (with_abort, true);
2235 /* the only external sync condition we can be in here
2236 * would be Engine (JACK) sync, in which case we still
2240 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
2241 _session->request_play_range (&editor->get_selection().time, true);
2242 _session->set_requested_return_frame( editor->get_selection().time.front().start ); //force an auto-return here
2244 _session->request_transport_speed (1.0f);
2250 ARDOUR_UI::toggle_session_auto_loop ()
2256 Location * looploc = _session->locations()->auto_loop_location();
2262 if (_session->get_play_loop()) {
2264 /* looping enabled, our job is to disable it */
2266 _session->request_play_loop (false);
2270 /* looping not enabled, our job is to enable it.
2272 loop-is-NOT-mode: this action always starts the transport rolling.
2273 loop-IS-mode: this action simply sets the loop play mechanism, but
2274 does not start transport.
2276 if (Config->get_loop_is_mode()) {
2277 _session->request_play_loop (true, false);
2279 _session->request_play_loop (true, true);
2283 //show the loop markers
2284 looploc->set_hidden (false, this);
2288 ARDOUR_UI::transport_play_selection ()
2294 editor->play_selection ();
2298 ARDOUR_UI::transport_play_preroll ()
2303 editor->play_with_preroll ();
2307 ARDOUR_UI::transport_rewind (int option)
2309 float current_transport_speed;
2312 current_transport_speed = _session->transport_speed();
2314 if (current_transport_speed >= 0.0f) {
2317 _session->request_transport_speed (-1.0f);
2320 _session->request_transport_speed (-4.0f);
2323 _session->request_transport_speed (-0.5f);
2328 _session->request_transport_speed (current_transport_speed * 1.5f);
2334 ARDOUR_UI::transport_forward (int option)
2340 float current_transport_speed = _session->transport_speed();
2342 if (current_transport_speed <= 0.0f) {
2345 _session->request_transport_speed (1.0f);
2348 _session->request_transport_speed (4.0f);
2351 _session->request_transport_speed (0.5f);
2356 _session->request_transport_speed (current_transport_speed * 1.5f);
2361 ARDOUR_UI::toggle_record_enable (uint32_t rid)
2367 boost::shared_ptr<Route> r;
2369 if ((r = _session->route_by_remote_id (rid)) != 0) {
2371 boost::shared_ptr<Track> t;
2373 if ((t = boost::dynamic_pointer_cast<Track>(r)) != 0) {
2374 t->set_record_enabled (!t->record_enabled(), Controllable::UseGroup);
2380 ARDOUR_UI::map_transport_state ()
2383 auto_loop_button.unset_active_state ();
2384 play_selection_button.unset_active_state ();
2385 roll_button.unset_active_state ();
2386 stop_button.set_active_state (Gtkmm2ext::ExplicitActive);
2390 shuttle_box->map_transport_state ();
2392 float sp = _session->transport_speed();
2398 if (_session->get_play_range()) {
2400 play_selection_button.set_active_state (Gtkmm2ext::ExplicitActive);
2401 roll_button.unset_active_state ();
2402 auto_loop_button.unset_active_state ();
2404 } else if (_session->get_play_loop ()) {
2406 auto_loop_button.set_active (true);
2407 play_selection_button.set_active (false);
2408 if (Config->get_loop_is_mode()) {
2409 roll_button.set_active (true);
2411 roll_button.set_active (false);
2416 roll_button.set_active (true);
2417 play_selection_button.set_active (false);
2418 auto_loop_button.set_active (false);
2421 if (UIConfiguration::instance().get_follow_edits() && !_session->config.get_external_sync()) {
2422 /* light up both roll and play-selection if they are joined */
2423 roll_button.set_active (true);
2424 play_selection_button.set_active (true);
2427 stop_button.set_active (false);
2431 stop_button.set_active (true);
2432 roll_button.set_active (false);
2433 play_selection_button.set_active (false);
2434 if (Config->get_loop_is_mode ()) {
2435 auto_loop_button.set_active (_session->get_play_loop());
2437 auto_loop_button.set_active (false);
2439 update_disk_space ();
2444 ARDOUR_UI::blink_handler (bool blink_on)
2446 transport_rec_enable_blink (blink_on);
2447 solo_blink (blink_on);
2448 sync_blink (blink_on);
2449 audition_blink (blink_on);
2450 feedback_blink (blink_on);
2451 error_blink (blink_on);
2455 ARDOUR_UI::update_clocks ()
2457 if (!_session) return;
2459 if (editor && !editor->dragging_playhead()) {
2460 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD)); /* EMIT_SIGNAL */
2465 ARDOUR_UI::start_clocking ()
2467 if (UIConfiguration::instance().get_super_rapid_clock_update()) {
2468 clock_signal_connection = Timers::fps_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2470 clock_signal_connection = Timers::rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2475 ARDOUR_UI::stop_clocking ()
2477 clock_signal_connection.disconnect ();
2481 ARDOUR_UI::save_as_progress_update (float fraction, int64_t cnt, int64_t total, Gtk::Label* label, Gtk::ProgressBar* bar)
2485 snprintf (buf, sizeof (buf), _("Copied %" PRId64 " of %" PRId64), cnt, total);
2487 label->set_text (buf);
2488 bar->set_fraction (fraction);
2490 /* process events, redraws, etc. */
2492 while (gtk_events_pending()) {
2493 gtk_main_iteration ();
2496 return true; /* continue with save-as */
2500 ARDOUR_UI::save_session_as ()
2506 if (!save_as_dialog) {
2507 save_as_dialog = new SaveAsDialog;
2510 save_as_dialog->set_name (_session->name());
2512 int response = save_as_dialog->run ();
2514 save_as_dialog->hide ();
2517 case Gtk::RESPONSE_OK:
2526 sa.new_parent_folder = save_as_dialog->new_parent_folder ();
2527 sa.new_name = save_as_dialog->new_name ();
2528 sa.switch_to = save_as_dialog->switch_to();
2529 sa.copy_media = save_as_dialog->copy_media();
2530 sa.copy_external = save_as_dialog->copy_external();
2531 sa.include_media = save_as_dialog->include_media ();
2533 /* Only bother with a progress dialog if we're going to copy
2534 media into the save-as target. Without that choice, this
2535 will be very fast because we're only talking about a few kB's to
2536 perhaps a couple of MB's of data.
2539 ArdourDialog progress_dialog (_("Save As"), true);
2541 if (sa.include_media && sa.copy_media) {
2544 Gtk::ProgressBar progress_bar;
2546 progress_dialog.get_vbox()->pack_start (label);
2547 progress_dialog.get_vbox()->pack_start (progress_bar);
2549 progress_bar.show ();
2551 /* this signal will be emitted from within this, the calling thread,
2552 * after every file is copied. It provides information on percentage
2553 * complete (in terms of total data to copy), the number of files
2554 * copied so far, and the total number to copy.
2559 sa.Progress.connect_same_thread (c, boost::bind (&ARDOUR_UI::save_as_progress_update, this, _1, _2, _3, &label, &progress_bar));
2561 progress_dialog.show_all ();
2562 progress_dialog.present ();
2565 if (_session->save_as (sa)) {
2567 MessageDialog msg (string_compose (_("Save As failed: %1"), sa.failure_message));
2571 if (!sa.include_media) {
2572 unload_session (false);
2573 load_session (sa.final_session_folder_name, sa.new_name);
2578 ARDOUR_UI::quick_snapshot_session (bool switch_to_it)
2582 struct tm local_time;
2585 localtime_r (&n, &local_time);
2586 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2588 save_state (timebuf, switch_to_it);
2593 ARDOUR_UI::process_snapshot_session_prompter (ArdourPrompter& prompter, bool switch_to_it)
2597 prompter.get_result (snapname);
2599 bool do_save = (snapname.length() != 0);
2602 char illegal = Session::session_name_is_legal(snapname);
2604 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2605 "snapshot names may not contain a '%1' character"), illegal));
2611 vector<std::string> p;
2612 get_state_files_in_directory (_session->session_directory().root_path(), p);
2613 vector<string> n = get_file_names_no_extension (p);
2615 if (find (n.begin(), n.end(), snapname) != n.end()) {
2617 do_save = overwrite_file_dialog (prompter,
2618 _("Confirm Snapshot Overwrite"),
2619 _("A snapshot already exists with that name. Do you want to overwrite it?"));
2623 save_state (snapname, switch_to_it);
2633 /** Ask the user for the name of a new snapshot and then take it.
2637 ARDOUR_UI::snapshot_session (bool switch_to_it)
2639 ArdourPrompter prompter (true);
2641 prompter.set_name ("Prompter");
2642 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2644 prompter.set_title (_("Snapshot and switch"));
2645 prompter.set_prompt (_("New session name"));
2647 prompter.set_title (_("Take Snapshot"));
2648 prompter.set_prompt (_("Name of new snapshot"));
2652 prompter.set_initial_text (_session->snap_name());
2656 struct tm local_time;
2659 localtime_r (&n, &local_time);
2660 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2661 prompter.set_initial_text (timebuf);
2664 bool finished = false;
2666 switch (prompter.run()) {
2667 case RESPONSE_ACCEPT:
2669 finished = process_snapshot_session_prompter (prompter, switch_to_it);
2680 /** Ask the user for a new session name and then rename the session to it.
2684 ARDOUR_UI::rename_session ()
2690 ArdourPrompter prompter (true);
2693 prompter.set_name ("Prompter");
2694 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2695 prompter.set_title (_("Rename Session"));
2696 prompter.set_prompt (_("New session name"));
2699 switch (prompter.run()) {
2700 case RESPONSE_ACCEPT:
2702 prompter.get_result (name);
2704 bool do_rename = (name.length() != 0);
2707 char illegal = Session::session_name_is_legal (name);
2710 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2711 "session names may not contain a '%1' character"), illegal));
2716 switch (_session->rename (name)) {
2718 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
2719 msg.set_position (WIN_POS_MOUSE);
2727 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
2728 msg.set_position (WIN_POS_MOUSE);
2744 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2746 if (!_session || _session->deletion_in_progress()) {
2750 XMLNode* node = new XMLNode (X_("UI"));
2752 WM::Manager::instance().add_state (*node);
2754 node->add_child_nocopy (gui_object_state->get_state());
2756 _session->add_extra_xml (*node);
2758 if (export_video_dialog) {
2759 _session->add_extra_xml (export_video_dialog->get_state());
2762 save_state_canfail (name, switch_to_it);
2766 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2771 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2776 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2781 ARDOUR_UI::primary_clock_value_changed ()
2784 _session->request_locate (primary_clock->current_time ());
2789 ARDOUR_UI::big_clock_value_changed ()
2792 _session->request_locate (big_clock->current_time ());
2797 ARDOUR_UI::secondary_clock_value_changed ()
2800 _session->request_locate (secondary_clock->current_time ());
2805 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2807 if (_session == 0) {
2811 if (_session->step_editing()) {
2815 Session::RecordState const r = _session->record_status ();
2816 bool const h = _session->have_rec_enabled_track ();
2818 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2820 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2822 rec_button.set_active_state (Gtkmm2ext::Off);
2824 } else if (r == Session::Recording && h) {
2825 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2827 rec_button.unset_active_state ();
2832 ARDOUR_UI::process_save_template_prompter (ArdourPrompter& prompter)
2836 prompter.get_result (name);
2838 if (name.length()) {
2839 int failed = _session->save_template (name);
2841 if (failed == -2) { /* file already exists. */
2842 bool overwrite = overwrite_file_dialog (prompter,
2843 _("Confirm Template Overwrite"),
2844 _("A template already exists with that name. Do you want to overwrite it?"));
2847 _session->save_template (name, true);
2859 ARDOUR_UI::save_template ()
2861 ArdourPrompter prompter (true);
2863 if (!check_audioengine (_main_window)) {
2867 prompter.set_name (X_("Prompter"));
2868 prompter.set_title (_("Save Template"));
2869 prompter.set_prompt (_("Name for template:"));
2870 prompter.set_initial_text(_session->name() + _("-template"));
2871 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2873 bool finished = false;
2875 switch (prompter.run()) {
2876 case RESPONSE_ACCEPT:
2877 finished = process_save_template_prompter (prompter);
2888 ARDOUR_UI::edit_metadata ()
2890 SessionMetadataEditor dialog;
2891 dialog.set_session (_session);
2892 dialog.grab_focus ();
2897 ARDOUR_UI::import_metadata ()
2899 SessionMetadataImporter dialog;
2900 dialog.set_session (_session);
2905 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
2907 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2909 MessageDialog msg (str,
2911 Gtk::MESSAGE_WARNING,
2912 Gtk::BUTTONS_YES_NO,
2916 msg.set_name (X_("OpenExistingDialog"));
2917 msg.set_title (_("Open Existing Session"));
2918 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
2919 msg.set_position (Gtk::WIN_POS_CENTER);
2920 pop_back_splash (msg);
2922 switch (msg.run()) {
2931 ARDOUR_UI::build_session_from_dialog (SessionDialog& sd, const std::string& session_path, const std::string& session_name)
2933 BusProfile bus_profile;
2937 bus_profile.master_out_channels = 2;
2938 bus_profile.input_ac = AutoConnectPhysical;
2939 bus_profile.output_ac = AutoConnectMaster;
2940 bus_profile.requested_physical_in = 0; // use all available
2941 bus_profile.requested_physical_out = 0; // use all available
2945 /* get settings from advanced section of NSD */
2947 if (sd.create_master_bus()) {
2948 bus_profile.master_out_channels = (uint32_t) sd.master_channel_count();
2950 bus_profile.master_out_channels = 0;
2953 if (sd.connect_inputs()) {
2954 bus_profile.input_ac = AutoConnectPhysical;
2956 bus_profile.input_ac = AutoConnectOption (0);
2959 bus_profile.output_ac = AutoConnectOption (0);
2961 if (sd.connect_outputs ()) {
2962 if (sd.connect_outs_to_master()) {
2963 bus_profile.output_ac = AutoConnectMaster;
2964 } else if (sd.connect_outs_to_physical()) {
2965 bus_profile.output_ac = AutoConnectPhysical;
2969 bus_profile.requested_physical_in = (uint32_t) sd.input_limit_count();
2970 bus_profile.requested_physical_out = (uint32_t) sd.output_limit_count();
2973 if (build_session (session_path, session_name, bus_profile)) {
2981 ARDOUR_UI::load_from_application_api (const std::string& path)
2983 ARDOUR_COMMAND_LINE::session_name = path;
2984 /* Cancel SessionDialog if it's visible to make OSX delegates work.
2986 * ARDOUR_UI::starting connects app->ShouldLoad signal and then shows a SessionDialog
2988 * - ShouldLoad does not arrive in time, ARDOUR_COMMAND_LINE::session_name is empty:
2989 * -> ARDOUR_UI::get_session_parameters starts a SessionDialog.
2990 * - ShouldLoad signal arrives, this function is called and sets ARDOUR_COMMAND_LINE::session_name
2991 * -> SessionDialog is not displayed
2994 if (_session_dialog) {
2995 std::string session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
2996 std::string session_path = path;
2997 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_REGULAR)) {
2998 session_path = Glib::path_get_dirname (session_path);
3000 // signal the existing dialog in ARDOUR_UI::get_session_parameters()
3001 _session_dialog->set_provided_session (session_name, session_path);
3002 _session_dialog->response (RESPONSE_NONE);
3003 _session_dialog->hide();
3008 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
3009 /* /path/to/foo => /path/to/foo, foo */
3010 rv = load_session (path, basename_nosuffix (path));
3012 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
3013 rv =load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
3016 // if load_session fails -> pop up SessionDialog.
3018 ARDOUR_COMMAND_LINE::session_name = "";
3020 if (get_session_parameters (true, false)) {
3026 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
3028 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
3030 string session_name;
3031 string session_path;
3032 string template_name;
3034 bool likely_new = false;
3035 bool cancel_not_quit;
3037 /* deal with any existing DIRTY session now, rather than later. don't
3038 * treat a non-dirty session this way, so that it stays visible
3039 * as we bring up the new session dialog.
3042 if (_session && ARDOUR_UI::instance()->video_timeline) {
3043 ARDOUR_UI::instance()->video_timeline->sync_session_state();
3046 /* if there is already a session, relabel the button
3047 on the SessionDialog so that we don't Quit directly
3049 cancel_not_quit = (_session != 0);
3051 if (_session && _session->dirty()) {
3052 if (unload_session (false)) {
3053 /* unload cancelled by user */
3056 ARDOUR_COMMAND_LINE::session_name = "";
3059 if (!load_template.empty()) {
3060 should_be_new = true;
3061 template_name = load_template;
3064 session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3065 session_path = ARDOUR_COMMAND_LINE::session_name;
3067 if (!session_path.empty()) {
3068 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_EXISTS)) {
3069 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_IS_REGULAR)) {
3070 /* session/snapshot file, change path to be dir */
3071 session_path = Glib::path_get_dirname (session_path);
3076 SessionDialog session_dialog (should_be_new, session_name, session_path, load_template, cancel_not_quit);
3078 _session_dialog = &session_dialog;
3081 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
3083 /* if they named a specific statefile, use it, otherwise they are
3084 just giving a session folder, and we want to use it as is
3085 to find the session.
3088 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
3090 if (suffix != string::npos) {
3091 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
3092 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
3093 session_name = Glib::path_get_basename (session_name);
3095 session_path = ARDOUR_COMMAND_LINE::session_name;
3096 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
3101 session_dialog.clear_given ();
3104 if (should_be_new || session_name.empty()) {
3105 /* need the dialog to get info from user */
3107 cerr << "run dialog\n";
3109 switch (session_dialog.run()) {
3110 case RESPONSE_ACCEPT:
3113 /* this is used for async * app->ShouldLoad(). */
3114 continue; // while loop
3117 if (quit_on_cancel) {
3118 // JE - Currently (July 2014) this section can only get reached if the
3119 // user quits from the main 'Session Setup' dialog (i.e. reaching this
3120 // point does NOT indicate an abnormal termination). Therefore, let's
3121 // behave gracefully (i.e. let's do some cleanup) before we call exit()
3123 pthread_cancel_all ();
3131 session_dialog.hide ();
3134 /* if we run the startup dialog again, offer more than just "new session" */
3136 should_be_new = false;
3138 session_name = session_dialog.session_name (likely_new);
3139 session_path = session_dialog.session_folder ();
3145 string::size_type suffix = session_name.find (statefile_suffix);
3147 if (suffix != string::npos) {
3148 session_name = session_name.substr (0, suffix);
3151 /* this shouldn't happen, but we catch it just in case it does */
3153 if (session_name.empty()) {
3157 if (session_dialog.use_session_template()) {
3158 template_name = session_dialog.session_template_name();
3159 _session_is_new = true;
3162 if (session_name[0] == G_DIR_SEPARATOR ||
3163 #ifdef PLATFORM_WINDOWS
3164 (session_name.length() > 3 && session_name[1] == ':' && session_name[2] == G_DIR_SEPARATOR)
3166 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
3167 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)
3172 /* absolute path or cwd-relative path specified for session name: infer session folder
3173 from what was given.
3176 session_path = Glib::path_get_dirname (session_name);
3177 session_name = Glib::path_get_basename (session_name);
3181 session_path = session_dialog.session_folder();
3183 char illegal = Session::session_name_is_legal (session_name);
3186 MessageDialog msg (session_dialog,
3187 string_compose (_("To ensure compatibility with various systems\n"
3188 "session names may not contain a '%1' character"),
3191 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3196 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
3199 if (likely_new && !nsm) {
3201 std::string existing = Glib::build_filename (session_path, session_name);
3203 if (!ask_about_loading_existing_session (existing)) {
3204 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3209 _session_is_new = false;
3214 pop_back_splash (session_dialog);
3215 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
3217 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3221 char illegal = Session::session_name_is_legal(session_name);
3224 pop_back_splash (session_dialog);
3225 MessageDialog msg (session_dialog, string_compose(_("To ensure compatibility with various systems\n"
3226 "session names may not contain a '%1' character"), illegal));
3228 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3232 _session_is_new = true;
3235 if (likely_new && template_name.empty()) {
3237 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3241 ret = load_session (session_path, session_name, template_name);
3244 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
3248 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
3249 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
3253 /* clear this to avoid endless attempts to load the
3257 ARDOUR_COMMAND_LINE::session_name = "";
3261 _session_dialog = NULL;
3267 ARDOUR_UI::close_session()
3269 if (!check_audioengine (_main_window)) {
3273 if (unload_session (true)) {
3277 ARDOUR_COMMAND_LINE::session_name = "";
3279 if (get_session_parameters (true, false)) {
3282 if (splash && splash->is_visible()) {
3283 // in 1 second, hide the splash screen
3284 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
3288 /** @param snap_name Snapshot name (without .ardour suffix).
3289 * @return -2 if the load failed because we are not connected to the AudioEngine.
3292 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
3294 Session *new_session;
3299 unload_status = unload_session ();
3301 if (unload_status < 0) {
3303 } else if (unload_status > 0) {
3309 session_loaded = false;
3311 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
3314 new_session = new Session (*AudioEngine::instance(), path, snap_name, 0, mix_template);
3317 /* this one is special */
3319 catch (AudioEngine::PortRegistrationFailure& err) {
3321 MessageDialog msg (err.what(),
3324 Gtk::BUTTONS_CLOSE);
3326 msg.set_title (_("Port Registration Error"));
3327 msg.set_secondary_text (_("Click the Close button to try again."));
3328 msg.set_position (Gtk::WIN_POS_CENTER);
3329 pop_back_splash (msg);
3332 int response = msg.run ();
3337 case RESPONSE_CANCEL:
3344 catch (SessionException e) {
3345 MessageDialog msg (string_compose(
3346 _("Session \"%1 (snapshot %2)\" did not load successfully: %3"),
3347 path, snap_name, e.what()),
3352 msg.set_title (_("Loading Error"));
3353 msg.set_position (Gtk::WIN_POS_CENTER);
3354 pop_back_splash (msg);
3366 MessageDialog msg (string_compose(
3367 _("Session \"%1 (snapshot %2)\" did not load successfully"),
3373 msg.set_title (_("Loading Error"));
3374 msg.set_position (Gtk::WIN_POS_CENTER);
3375 pop_back_splash (msg);
3387 list<string> const u = new_session->unknown_processors ();
3389 MissingPluginDialog d (_session, u);
3394 if (!new_session->writable()) {
3395 MessageDialog msg (_("This session has been opened in read-only mode.\n\nYou will not be able to record or save."),
3400 msg.set_title (_("Read-only Session"));
3401 msg.set_position (Gtk::WIN_POS_CENTER);
3402 pop_back_splash (msg);
3409 /* Now the session been created, add the transport controls */
3410 new_session->add_controllable(roll_controllable);
3411 new_session->add_controllable(stop_controllable);
3412 new_session->add_controllable(goto_start_controllable);
3413 new_session->add_controllable(goto_end_controllable);
3414 new_session->add_controllable(auto_loop_controllable);
3415 new_session->add_controllable(play_selection_controllable);
3416 new_session->add_controllable(rec_controllable);
3418 set_session (new_session);
3420 session_loaded = true;
3423 _session->set_clean ();
3426 #ifdef WINDOWS_VST_SUPPORT
3427 fst_stop_threading();
3431 Timers::TimerSuspender t;
3435 #ifdef WINDOWS_VST_SUPPORT
3436 fst_start_threading();
3445 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
3447 Session *new_session;
3450 session_loaded = false;
3451 x = unload_session ();
3459 _session_is_new = true;
3462 new_session = new Session (*AudioEngine::instance(), path, snap_name, &bus_profile);
3465 catch (SessionException e) {
3467 MessageDialog msg (string_compose(_("Could not create session in \"%1\": %2"), path, e.what()));
3468 msg.set_title (_("Loading Error"));
3469 msg.set_position (Gtk::WIN_POS_CENTER);
3470 pop_back_splash (msg);
3476 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
3477 msg.set_title (_("Loading Error"));
3478 msg.set_position (Gtk::WIN_POS_CENTER);
3479 pop_back_splash (msg);
3484 /* Give the new session the default GUI state, if such things exist */
3487 n = Config->instant_xml (X_("Editor"));
3489 n->remove_nodes_and_delete ("Selection"); // no not apply selection to new sessions.
3490 new_session->add_instant_xml (*n, false);
3492 n = Config->instant_xml (X_("Mixer"));
3494 new_session->add_instant_xml (*n, false);
3497 /* Put the playhead at 0 and scroll fully left */
3498 n = new_session->instant_xml (X_("Editor"));
3500 n->add_property (X_("playhead"), X_("0"));
3501 n->add_property (X_("left-frame"), X_("0"));
3504 set_session (new_session);
3506 session_loaded = true;
3508 new_session->save_state(new_session->name());
3514 ARDOUR_UI::launch_chat ()
3516 MessageDialog dialog(_("<b>Just ask and wait for an answer.\nIt may take from minutes to hours.</b>"), true);
3518 dialog.set_title (_("About the Chat"));
3519 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."));
3521 switch (dialog.run()) {
3524 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
3525 #elif defined PLATFORM_WINDOWS
3526 open_uri("http://webchat.freenode.net/?channels=ardour-windows");
3528 open_uri("http://webchat.freenode.net/?channels=ardour");
3537 ARDOUR_UI::launch_manual ()
3539 PBD::open_uri (Config->get_tutorial_manual_url());
3543 ARDOUR_UI::launch_reference ()
3545 PBD::open_uri (Config->get_reference_manual_url());
3549 ARDOUR_UI::launch_tracker ()
3551 PBD::open_uri ("http://tracker.ardour.org");
3555 ARDOUR_UI::launch_subscribe ()
3557 PBD::open_uri ("https://community.ardour.org/s/subscribe");
3561 ARDOUR_UI::launch_cheat_sheet ()
3564 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheat_sheet_osx.pdf");
3566 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheatsheet.pdf");
3571 ARDOUR_UI::launch_website ()
3573 PBD::open_uri ("http://ardour.org");
3577 ARDOUR_UI::launch_website_dev ()
3579 PBD::open_uri ("http://ardour.org/development.html");
3583 ARDOUR_UI::launch_forums ()
3585 PBD::open_uri ("https://community.ardour.org/forums");
3589 ARDOUR_UI::launch_howto_report ()
3591 PBD::open_uri ("http://ardour.org/reporting_bugs");
3595 ARDOUR_UI::loading_message (const std::string& msg)
3597 if (ARDOUR_COMMAND_LINE::no_splash) {
3605 splash->message (msg);
3609 ARDOUR_UI::show_splash ()
3613 splash = new Splash;
3623 ARDOUR_UI::hide_splash ()
3630 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title, const bool msg_delete)
3634 removed = rep.paths.size();
3637 MessageDialog msgd (_main_window,
3638 _("No files were ready for clean-up"),
3642 msgd.set_title (_("Clean-up"));
3643 msgd.set_secondary_text (_("If this seems suprising, \n\
3644 check for any existing snapshots.\n\
3645 These may still include regions that\n\
3646 require some unused files to continue to exist."));
3652 ArdourDialog results (_("Clean-up"), true, false);
3654 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
3655 CleanupResultsModelColumns() {
3659 Gtk::TreeModelColumn<std::string> visible_name;
3660 Gtk::TreeModelColumn<std::string> fullpath;
3664 CleanupResultsModelColumns results_columns;
3665 Glib::RefPtr<Gtk::ListStore> results_model;
3666 Gtk::TreeView results_display;
3668 results_model = ListStore::create (results_columns);
3669 results_display.set_model (results_model);
3670 results_display.append_column (list_title, results_columns.visible_name);
3672 results_display.set_name ("CleanupResultsList");
3673 results_display.set_headers_visible (true);
3674 results_display.set_headers_clickable (false);
3675 results_display.set_reorderable (false);
3677 Gtk::ScrolledWindow list_scroller;
3680 Gtk::HBox dhbox; // the hbox for the image and text
3681 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
3682 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
3684 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
3686 const string dead_directory = _session->session_directory().dead_path();
3689 %1 - number of files removed
3690 %2 - location of "dead"
3691 %3 - size of files affected
3692 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
3695 const char* bprefix;
3696 double space_adjusted = 0;
3698 if (rep.space < 1000) {
3700 space_adjusted = rep.space;
3701 } else if (rep.space < 1000000) {
3702 bprefix = _("kilo");
3703 space_adjusted = floorf((float)rep.space / 1000.0);
3704 } else if (rep.space < 1000000 * 1000) {
3705 bprefix = _("mega");
3706 space_adjusted = floorf((float)rep.space / (1000.0 * 1000.0));
3708 bprefix = _("giga");
3709 space_adjusted = floorf((float)rep.space / (1000.0 * 1000 * 1000.0));
3713 txt.set_markup (string_compose (P_("\
3714 The following file was deleted from %2,\n\
3715 releasing %3 %4bytes of disk space", "\
3716 The following %1 files were deleted from %2,\n\
3717 releasing %3 %4bytes of disk space", removed),
3718 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3720 txt.set_markup (string_compose (P_("\
3721 The following file was not in use and \n\
3722 has been moved to: %2\n\n\
3723 After a restart of %5\n\n\
3724 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3725 will release an additional %3 %4bytes of disk space.\n", "\
3726 The following %1 files were not in use and \n\
3727 have been moved to: %2\n\n\
3728 After a restart of %5\n\n\
3729 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3730 will release an additional %3 %4bytes of disk space.\n", removed),
3731 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3734 dhbox.pack_start (*dimage, true, false, 5);
3735 dhbox.pack_start (txt, true, false, 5);
3737 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
3738 TreeModel::Row row = *(results_model->append());
3739 row[results_columns.visible_name] = *i;
3740 row[results_columns.fullpath] = *i;
3743 list_scroller.add (results_display);
3744 list_scroller.set_size_request (-1, 150);
3745 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
3747 dvbox.pack_start (dhbox, true, false, 5);
3748 dvbox.pack_start (list_scroller, true, false, 5);
3749 ddhbox.pack_start (dvbox, true, false, 5);
3751 results.get_vbox()->pack_start (ddhbox, true, false, 5);
3752 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
3753 results.set_default_response (RESPONSE_CLOSE);
3754 results.set_position (Gtk::WIN_POS_MOUSE);
3756 results_display.show();
3757 list_scroller.show();
3764 //results.get_vbox()->show();
3765 results.set_resizable (false);
3772 ARDOUR_UI::cleanup ()
3774 if (_session == 0) {
3775 /* shouldn't happen: menu item is insensitive */
3780 MessageDialog checker (_("Are you sure you want to clean-up?"),
3782 Gtk::MESSAGE_QUESTION,
3785 checker.set_title (_("Clean-up"));
3787 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
3788 ALL undo/redo information will be lost if you clean-up.\n\
3789 Clean-up will move all unused files to a \"dead\" location."));
3791 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3792 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
3793 checker.set_default_response (RESPONSE_CANCEL);
3795 checker.set_name (_("CleanupDialog"));
3796 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3797 checker.set_position (Gtk::WIN_POS_MOUSE);
3799 switch (checker.run()) {
3800 case RESPONSE_ACCEPT:
3806 ARDOUR::CleanupReport rep;
3808 editor->prepare_for_cleanup ();
3810 /* do not allow flush until a session is reloaded */
3812 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3814 act->set_sensitive (false);
3817 if (_session->cleanup_sources (rep)) {
3818 editor->finish_cleanup ();
3822 editor->finish_cleanup ();
3825 display_cleanup_results (rep, _("Cleaned Files"), false);
3829 ARDOUR_UI::flush_trash ()
3831 if (_session == 0) {
3832 /* shouldn't happen: menu item is insensitive */
3836 ARDOUR::CleanupReport rep;
3838 if (_session->cleanup_trash_sources (rep)) {
3842 display_cleanup_results (rep, _("deleted file"), true);
3846 ARDOUR_UI::cleanup_peakfiles ()
3848 if (_session == 0) {
3849 /* shouldn't happen: menu item is insensitive */
3853 if (! _session->can_cleanup_peakfiles ()) {
3857 // get all region-views in this session
3859 TrackViewList empty;
3861 editor->get_regions_after(rs, (framepos_t) 0, empty);
3862 std::list<RegionView*> views = rs.by_layer();
3864 // remove displayed audio-region-views waveforms
3865 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
3866 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
3867 if (!arv) { continue ; }
3868 arv->delete_waves();
3871 // cleanup peak files:
3872 // - stop pending peakfile threads
3873 // - close peakfiles if any
3874 // - remove peak dir in session
3875 // - setup peakfiles (background thread)
3876 _session->cleanup_peakfiles ();
3878 // re-add waves to ARV
3879 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
3880 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
3881 if (!arv) { continue ; }
3882 arv->create_waves();
3887 ARDOUR_UI::setup_order_hint (AddRouteDialog::InsertAt place)
3889 uint32_t order_hint = UINT32_MAX;
3891 if (editor->get_selection().tracks.empty()) {
3896 we want the new routes to have their order keys set starting from
3897 the highest order key in the selection + 1 (if available).
3900 if (place == AddRouteDialog::AfterSelection) {
3901 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.back());
3903 order_hint = rtav->route()->order_key();
3906 } else if (place == AddRouteDialog::BeforeSelection) {
3907 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.front());
3909 order_hint = rtav->route()->order_key();
3911 } else if (place == AddRouteDialog::First) {
3914 /* leave order_hint at UINT32_MAX */
3917 if (order_hint == UINT32_MAX) {
3918 /** AddRouteDialog::Last or selection with first/last not a RouteTimeAxisView
3919 * not setting an order hint will place new routes last.
3924 _session->set_order_hint (order_hint);
3926 /* create a gap in the existing route order keys to accomodate new routes.*/
3927 boost::shared_ptr <RouteList> rd = _session->get_routes();
3928 for (RouteList::iterator ri = rd->begin(); ri != rd->end(); ++ri) {
3929 boost::shared_ptr<Route> rt (*ri);
3931 if (rt->is_monitor()) {
3935 if (rt->order_key () >= order_hint) {
3936 rt->set_order_key (rt->order_key () + add_route_dialog->count());
3942 ARDOUR_UI::start_duplicate_routes ()
3944 if (!duplicate_routes_dialog) {
3945 duplicate_routes_dialog = new DuplicateRouteDialog;
3948 if (duplicate_routes_dialog->restart (_session)) {
3952 duplicate_routes_dialog->present ();
3956 ARDOUR_UI::add_route ()
3964 if (add_route_dialog->is_visible()) {
3965 /* we're already doing this */
3969 ResponseType r = (ResponseType) add_route_dialog->run ();
3971 add_route_dialog->hide();
3974 case RESPONSE_ACCEPT:
3981 if ((count = add_route_dialog->count()) <= 0) {
3985 setup_order_hint(add_route_dialog->insert_at());
3986 string template_path = add_route_dialog->track_template();
3987 DisplaySuspender ds;
3989 if (!template_path.empty()) {
3990 if (add_route_dialog->name_template_is_default()) {
3991 _session->new_route_from_template (count, template_path, string());
3993 _session->new_route_from_template (count, template_path, add_route_dialog->name_template());
3998 ChanCount input_chan= add_route_dialog->channels ();
3999 ChanCount output_chan;
4000 string name_template = add_route_dialog->name_template ();
4001 PluginInfoPtr instrument = add_route_dialog->requested_instrument ();
4002 RouteGroup* route_group = add_route_dialog->route_group ();
4003 AutoConnectOption oac = Config->get_output_auto_connect();
4004 bool strict_io = add_route_dialog->use_strict_io ();
4006 if (oac & AutoConnectMaster) {
4007 output_chan.set (DataType::AUDIO, (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan.n_audio()));
4008 output_chan.set (DataType::MIDI, 0);
4010 output_chan = input_chan;
4013 /* XXX do something with name template */
4015 switch (add_route_dialog->type_wanted()) {
4016 case AddRouteDialog::AudioTrack:
4017 session_add_audio_track (input_chan.n_audio(), output_chan.n_audio(), add_route_dialog->mode(), route_group, count, name_template, strict_io);
4019 case AddRouteDialog::MidiTrack:
4020 session_add_midi_track (route_group, count, name_template, strict_io, instrument);
4022 case AddRouteDialog::MixedTrack:
4023 session_add_mixed_track (input_chan, output_chan, route_group, count, name_template, strict_io, instrument, 0);
4025 case AddRouteDialog::AudioBus:
4026 session_add_audio_bus (input_chan.n_audio(), output_chan.n_audio(), route_group, count, name_template, strict_io);
4028 case AddRouteDialog::MidiBus:
4029 session_add_midi_bus (route_group, count, name_template, strict_io, instrument, 0);
4035 ARDOUR_UI::add_lua_script ()
4041 LuaScriptInfoPtr spi;
4042 ScriptSelector ss ("Add Lua Session Script", LuaScriptInfo::Session);
4043 switch (ss.run ()) {
4044 case Gtk::RESPONSE_ACCEPT:
4052 std::string script = "";
4055 script = Glib::file_get_contents (spi->path);
4056 } catch (Glib::FileError e) {
4057 string msg = string_compose (_("Cannot read session script '%1': %2"), spi->path, e.what());
4058 MessageDialog am (msg);
4063 LuaScriptParamList lsp = LuaScriptParams::script_params (spi, "sess_params");
4064 std::vector<std::string> reg = _session->registered_lua_functions ();
4066 ScriptParameterDialog spd (_("Set Script Parameters"), spi, reg, lsp);
4067 switch (spd.run ()) {
4068 case Gtk::RESPONSE_ACCEPT:
4075 _session->register_lua_function (spd.name(), script, lsp);
4076 } catch (luabridge::LuaException const& e) {
4077 string msg = string_compose (_("Session script '%1' instantiation failed: %2"), spd.name(), e.what ());
4078 MessageDialog am (msg);
4080 } catch (SessionException e) {
4081 string msg = string_compose (_("Loading Session script '%1' failed: %2"), spd.name(), e.what ());
4082 MessageDialog am (msg);
4088 ARDOUR_UI::remove_lua_script ()
4093 if (_session->registered_lua_function_count () == 0) {
4094 string msg = _("There are no active Lua session scripts present in this session.");
4095 MessageDialog am (msg);
4100 std::vector<std::string> reg = _session->registered_lua_functions ();
4101 SessionScriptManager sm ("Remove Lua Session Script", reg);
4102 switch (sm.run ()) {
4103 case Gtk::RESPONSE_ACCEPT:
4109 _session->unregister_lua_function (sm.name());
4110 } catch (luabridge::LuaException const& e) {
4111 string msg = string_compose (_("Session script '%1' removal failed: %2"), sm.name(), e.what ());
4112 MessageDialog am (msg);
4118 ARDOUR_UI::stop_video_server (bool ask_confirm)
4120 if (!video_server_process && ask_confirm) {
4121 warning << string_compose (_("Video-Server was not launched by %1. The request to stop it is ignored."), PROGRAM_NAME) << endmsg;
4123 if (video_server_process) {
4125 ArdourDialog confirm (_("Stop Video-Server"), true);
4126 Label m (_("Do you really want to stop the Video Server?"));
4127 confirm.get_vbox()->pack_start (m, true, true);
4128 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
4129 confirm.add_button (_("Yes, Stop It"), Gtk::RESPONSE_ACCEPT);
4130 confirm.show_all ();
4131 if (confirm.run() == RESPONSE_CANCEL) {
4135 delete video_server_process;
4136 video_server_process =0;
4141 ARDOUR_UI::start_video_server_menu (Gtk::Window* float_window)
4143 ARDOUR_UI::start_video_server( float_window, true);
4147 ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg)
4153 if (ARDOUR_UI::instance()->video_timeline->check_server()) {
4154 if (video_server_process) {
4155 popup_error(_("The Video Server is already started."));
4157 popup_error(_("An external Video Server is configured and can be reached. Not starting a new instance."));
4163 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4165 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4167 VideoServerDialog *video_server_dialog = new VideoServerDialog (_session);
4169 video_server_dialog->set_transient_for (*float_window);
4172 if (!Config->get_show_video_server_dialog() && firsttime < 2) {
4173 video_server_dialog->hide();
4175 ResponseType r = (ResponseType) video_server_dialog->run ();
4176 video_server_dialog->hide();
4177 if (r != RESPONSE_ACCEPT) { return false; }
4178 if (video_server_dialog->show_again()) {
4179 Config->set_show_video_server_dialog(false);
4183 std::string icsd_exec = video_server_dialog->get_exec_path();
4184 std::string icsd_docroot = video_server_dialog->get_docroot();
4185 if (icsd_docroot.empty()) {
4186 #ifndef PLATFORM_WINDOWS
4187 icsd_docroot = X_("/");
4189 icsd_docroot = X_("C:\\");
4194 if (g_lstat (icsd_docroot.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode)) {
4195 warning << _("Specified docroot is not an existing directory.") << endmsg;
4198 #ifndef PLATFORM_WINDOWS
4199 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4200 || (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0 ) {
4201 warning << _("Given Video Server is not an executable file.") << endmsg;
4205 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4206 || (sb.st_mode & (S_IXUSR)) == 0 ) {
4207 warning << _("Given Video Server is not an executable file.") << endmsg;
4213 argp=(char**) calloc(9,sizeof(char*));
4214 argp[0] = strdup(icsd_exec.c_str());
4215 argp[1] = strdup("-P");
4216 argp[2] = (char*) calloc(16,sizeof(char)); snprintf(argp[2], 16, "%s", video_server_dialog->get_listenaddr().c_str());
4217 argp[3] = strdup("-p");
4218 argp[4] = (char*) calloc(6,sizeof(char)); snprintf(argp[4], 6, "%i", video_server_dialog->get_listenport());
4219 argp[5] = strdup("-C");
4220 argp[6] = (char*) calloc(6,sizeof(char)); snprintf(argp[6], 6, "%i", video_server_dialog->get_cachesize());
4221 argp[7] = strdup(icsd_docroot.c_str());
4223 stop_video_server();
4225 if (icsd_docroot == X_("/") || icsd_docroot == X_("C:\\")) {
4226 Config->set_video_advanced_setup(false);
4228 std::ostringstream osstream;
4229 osstream << "http://127.0.0.1:" << video_server_dialog->get_listenport() << "/";
4230 Config->set_video_server_url(osstream.str());
4231 Config->set_video_server_docroot(icsd_docroot);
4232 Config->set_video_advanced_setup(true);
4235 if (video_server_process) {
4236 delete video_server_process;
4239 video_server_process = new ARDOUR::SystemExec(icsd_exec, argp);
4240 if (video_server_process->start()) {
4241 warning << _("Cannot launch the video-server") << endmsg;
4244 int timeout = 120; // 6 sec
4245 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4246 Glib::usleep (50000);
4248 if (--timeout <= 0 || !video_server_process->is_running()) break;
4251 warning << _("Video-server was started but does not respond to requests...") << endmsg;
4253 if (!ARDOUR_UI::instance()->video_timeline->check_server_docroot()) {
4254 delete video_server_process;
4255 video_server_process = 0;
4263 ARDOUR_UI::add_video (Gtk::Window* float_window)
4269 if (!start_video_server(float_window, false)) {
4270 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4275 add_video_dialog->set_transient_for (*float_window);
4278 if (add_video_dialog->is_visible()) {
4279 /* we're already doing this */
4283 ResponseType r = (ResponseType) add_video_dialog->run ();
4284 add_video_dialog->hide();
4285 if (r != RESPONSE_ACCEPT) { return; }
4287 bool local_file, orig_local_file;
4288 std::string path = add_video_dialog->file_name(local_file);
4290 std::string orig_path = path;
4291 orig_local_file = local_file;
4293 bool auto_set_session_fps = add_video_dialog->auto_set_session_fps();
4295 if (local_file && !Glib::file_test(path, Glib::FILE_TEST_EXISTS)) {
4296 warning << string_compose(_("could not open %1"), path) << endmsg;
4299 if (!local_file && path.length() == 0) {
4300 warning << _("no video-file selected") << endmsg;
4304 std::string audio_from_video;
4305 bool detect_ltc = false;
4307 switch (add_video_dialog->import_option()) {
4308 case VTL_IMPORT_TRANSCODE:
4310 TranscodeVideoDialog *transcode_video_dialog;
4311 transcode_video_dialog = new TranscodeVideoDialog (_session, path);
4312 ResponseType r = (ResponseType) transcode_video_dialog->run ();
4313 transcode_video_dialog->hide();
4314 if (r != RESPONSE_ACCEPT) {
4315 delete transcode_video_dialog;
4319 audio_from_video = transcode_video_dialog->get_audiofile();
4321 if (!audio_from_video.empty() && transcode_video_dialog->detect_ltc()) {
4324 else if (!audio_from_video.empty()) {
4325 editor->embed_audio_from_video(
4327 video_timeline->get_offset(),
4328 (transcode_video_dialog->import_option() != VTL_IMPORT_NO_VIDEO)
4331 switch (transcode_video_dialog->import_option()) {
4332 case VTL_IMPORT_TRANSCODED:
4333 path = transcode_video_dialog->get_filename();
4336 case VTL_IMPORT_REFERENCE:
4339 delete transcode_video_dialog;
4342 delete transcode_video_dialog;
4346 case VTL_IMPORT_NONE:
4350 /* strip _session->session_directory().video_path() from video file if possible */
4351 if (local_file && !path.compare(0, _session->session_directory().video_path().size(), _session->session_directory().video_path())) {
4352 path=path.substr(_session->session_directory().video_path().size());
4353 if (path.at(0) == G_DIR_SEPARATOR) {
4354 path=path.substr(1);
4358 video_timeline->set_update_session_fps(auto_set_session_fps);
4360 if (video_timeline->video_file_info(path, local_file)) {
4361 XMLNode* node = new XMLNode(X_("Videotimeline"));
4362 node->add_property (X_("Filename"), path);
4363 node->add_property (X_("AutoFPS"), auto_set_session_fps?X_("1"):X_("0"));
4364 node->add_property (X_("LocalFile"), local_file?X_("1"):X_("0"));
4365 if (orig_local_file) {
4366 node->add_property (X_("OriginalVideoFile"), orig_path);
4368 node->remove_property (X_("OriginalVideoFile"));
4370 _session->add_extra_xml (*node);
4371 _session->set_dirty ();
4373 if (!audio_from_video.empty() && detect_ltc) {
4374 std::vector<LTCFileReader::LTCMap> ltc_seq;
4377 /* TODO ask user about TV standard (LTC alignment if any) */
4378 LTCFileReader ltcr (audio_from_video, video_timeline->get_video_file_fps());
4379 /* TODO ASK user which channel: 0 .. ltcr->channels() - 1 */
4381 ltc_seq = ltcr.read_ltc (/*channel*/ 0, /*max LTC frames to decode*/ 15);
4383 /* TODO seek near end of file, and read LTC until end.
4384 * if it fails to find any LTC frames, scan complete file
4386 * calculate drift of LTC compared to video-duration,
4387 * ask user for reference (timecode from start/mid/end)
4390 // LTCFileReader will have written error messages
4393 ::g_unlink(audio_from_video.c_str());
4395 if (ltc_seq.size() == 0) {
4396 PBD::error << _("No LTC detected, video will not be aligned.") << endmsg;
4398 /* the very first TC in the file is somteimes not aligned properly */
4399 int i = ltc_seq.size() -1;
4400 ARDOUR::frameoffset_t video_start_offset =
4401 _session->nominal_frame_rate() * (ltc_seq[i].timecode_sec - ltc_seq[i].framepos_sec);
4402 PBD::info << string_compose (_("Align video-start to %1 [samples]"), video_start_offset) << endmsg;
4403 video_timeline->set_offset(video_start_offset);
4407 _session->maybe_update_session_range(
4408 std::max(video_timeline->get_offset(), (ARDOUR::frameoffset_t) 0),
4409 std::max(video_timeline->get_offset() + video_timeline->get_duration(), (ARDOUR::frameoffset_t) 0));
4412 if (add_video_dialog->launch_xjadeo() && local_file) {
4413 editor->set_xjadeo_sensitive(true);
4414 editor->toggle_xjadeo_proc(1);
4416 editor->toggle_xjadeo_proc(0);
4418 editor->toggle_ruler_video(true);
4423 ARDOUR_UI::remove_video ()
4425 video_timeline->close_session();
4426 editor->toggle_ruler_video(false);
4429 video_timeline->set_offset_locked(false);
4430 video_timeline->set_offset(0);
4432 /* delete session state */
4433 XMLNode* node = new XMLNode(X_("Videotimeline"));
4434 _session->add_extra_xml(*node);
4435 node = new XMLNode(X_("Videomonitor"));
4436 _session->add_extra_xml(*node);
4437 node = new XMLNode(X_("Videoexport"));
4438 _session->add_extra_xml(*node);
4439 stop_video_server();
4443 ARDOUR_UI::flush_videotimeline_cache (bool localcacheonly)
4445 if (localcacheonly) {
4446 video_timeline->vmon_update();
4448 video_timeline->flush_cache();
4450 editor->queue_visual_videotimeline_update();
4454 ARDOUR_UI::export_video (bool range)
4456 if (ARDOUR::Config->get_show_video_export_info()) {
4457 ExportVideoInfobox infobox (_session);
4458 Gtk::ResponseType rv = (Gtk::ResponseType) infobox.run();
4459 if (infobox.show_again()) {
4460 ARDOUR::Config->set_show_video_export_info(false);
4463 case GTK_RESPONSE_YES:
4464 PBD::open_uri (ARDOUR::Config->get_reference_manual_url() + "/video-timeline/operations/#export");
4470 export_video_dialog->set_session (_session);
4471 export_video_dialog->apply_state(editor->get_selection().time, range);
4472 export_video_dialog->run ();
4473 export_video_dialog->hide ();
4477 ARDOUR_UI::mixer_settings () const
4482 node = _session->instant_xml(X_("Mixer"));
4484 node = Config->instant_xml(X_("Mixer"));
4488 node = new XMLNode (X_("Mixer"));
4495 ARDOUR_UI::main_window_settings () const
4500 node = _session->instant_xml(X_("Main"));
4502 node = Config->instant_xml(X_("Main"));
4506 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4507 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4512 node = new XMLNode (X_("Main"));
4519 ARDOUR_UI::editor_settings () const
4524 node = _session->instant_xml(X_("Editor"));
4526 node = Config->instant_xml(X_("Editor"));
4530 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4531 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4536 node = new XMLNode (X_("Editor"));
4543 ARDOUR_UI::keyboard_settings () const
4547 node = Config->extra_xml(X_("Keyboard"));
4550 node = new XMLNode (X_("Keyboard"));
4557 ARDOUR_UI::create_xrun_marker (framepos_t where)
4560 Location *location = new Location (*_session, where, where, _("xrun"), Location::IsMark);
4561 _session->locations()->add (location);
4566 ARDOUR_UI::halt_on_xrun_message ()
4568 cerr << "HALT on xrun\n";
4569 MessageDialog msg (_main_window, _("Recording was stopped because your system could not keep up."));
4574 ARDOUR_UI::xrun_handler (framepos_t where)
4580 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
4582 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
4583 create_xrun_marker(where);
4586 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
4587 halt_on_xrun_message ();
4592 ARDOUR_UI::disk_overrun_handler ()
4594 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
4596 if (!have_disk_speed_dialog_displayed) {
4597 have_disk_speed_dialog_displayed = true;
4598 MessageDialog* msg = new MessageDialog (_main_window, string_compose (_("\
4599 The disk system on your computer\n\
4600 was not able to keep up with %1.\n\
4602 Specifically, it failed to write data to disk\n\
4603 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
4604 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4610 /* TODO: this is getting elaborate enough to warrant being split into a dedicated class */
4611 static MessageDialog *scan_dlg = NULL;
4612 static ProgressBar *scan_pbar = NULL;
4613 static HBox *scan_tbox = NULL;
4614 static Gtk::Button *scan_timeout_button;
4617 ARDOUR_UI::cancel_plugin_scan ()
4619 PluginManager::instance().cancel_plugin_scan();
4623 ARDOUR_UI::cancel_plugin_timeout ()
4625 PluginManager::instance().cancel_plugin_timeout();
4626 scan_timeout_button->set_sensitive (false);
4630 ARDOUR_UI::plugin_scan_timeout (int timeout)
4632 if (!scan_dlg || !scan_dlg->is_mapped() || !scan_pbar) {
4636 scan_pbar->set_sensitive (false);
4637 scan_timeout_button->set_sensitive (true);
4638 scan_pbar->set_fraction ((float) timeout / (float) Config->get_vst_scan_timeout());
4641 scan_pbar->set_sensitive (false);
4642 scan_timeout_button->set_sensitive (false);
4648 ARDOUR_UI::plugin_scan_dialog (std::string type, std::string plugin, bool can_cancel)
4650 if (type == X_("closeme") && !(scan_dlg && scan_dlg->is_mapped())) {
4654 const bool cancelled = PluginManager::instance().cancelled();
4655 if (type != X_("closeme") && (!UIConfiguration::instance().get_show_plugin_scan_window()) && !_initial_verbose_plugin_scan) {
4656 if (cancelled && scan_dlg->is_mapped()) {
4661 if (cancelled || !can_cancel) {
4666 static Gtk::Button *cancel_button;
4668 scan_dlg = new MessageDialog("", false, MESSAGE_INFO, BUTTONS_NONE); // TODO manage
4669 VBox* vbox = scan_dlg->get_vbox();
4670 vbox->set_size_request(400,-1);
4671 scan_dlg->set_title (_("Scanning for plugins"));
4673 cancel_button = manage(new Gtk::Button(_("Cancel plugin scan")));
4674 cancel_button->set_name ("EditorGTKButton");
4675 cancel_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_scan) );
4676 cancel_button->show();
4678 scan_dlg->get_vbox()->pack_start ( *cancel_button, PACK_SHRINK);
4680 scan_tbox = manage( new HBox() );
4682 scan_timeout_button = manage(new Gtk::Button(_("Stop Timeout")));
4683 scan_timeout_button->set_name ("EditorGTKButton");
4684 scan_timeout_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_timeout) );
4685 scan_timeout_button->show();
4687 scan_pbar = manage(new ProgressBar());
4688 scan_pbar->set_orientation(Gtk::PROGRESS_RIGHT_TO_LEFT);
4689 scan_pbar->set_text(_("Scan Timeout"));
4692 scan_tbox->pack_start (*scan_pbar, PACK_EXPAND_WIDGET, 4);
4693 scan_tbox->pack_start (*scan_timeout_button, PACK_SHRINK, 4);
4695 scan_dlg->get_vbox()->pack_start (*scan_tbox, PACK_SHRINK, 4);
4698 assert(scan_dlg && scan_tbox && cancel_button);
4700 if (type == X_("closeme")) {
4704 scan_dlg->set_message(type + ": " + Glib::path_get_basename(plugin));
4707 if (!can_cancel || !cancelled) {
4708 scan_timeout_button->set_sensitive(false);
4710 cancel_button->set_sensitive(can_cancel && !cancelled);
4716 ARDOUR_UI::gui_idle_handler ()
4719 /* due to idle calls, gtk_events_pending() may always return true */
4720 while (gtk_events_pending() && --timeout) {
4721 gtk_main_iteration ();
4726 ARDOUR_UI::disk_underrun_handler ()
4728 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
4730 if (!have_disk_speed_dialog_displayed) {
4731 have_disk_speed_dialog_displayed = true;
4732 MessageDialog* msg = new MessageDialog (
4733 _main_window, string_compose (_("The disk system on your computer\n\
4734 was not able to keep up with %1.\n\
4736 Specifically, it failed to read data from disk\n\
4737 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
4738 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4744 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
4746 have_disk_speed_dialog_displayed = false;
4751 ARDOUR_UI::session_dialog (std::string msg)
4753 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
4757 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
4764 ARDOUR_UI::pending_state_dialog ()
4766 HBox* hbox = manage (new HBox());
4767 Image* image = manage (new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG));
4768 ArdourDialog dialog (_("Crash Recovery"), true);
4769 Label message (string_compose (_("\
4770 This session appears to have been in the\n\
4771 middle of recording when %1 or\n\
4772 the computer was shutdown.\n\
4774 %1 can recover any captured audio for\n\
4775 you, or it can ignore it. Please decide\n\
4776 what you would like to do.\n"), PROGRAM_NAME));
4777 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4778 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4779 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4780 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4781 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
4782 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
4783 dialog.set_default_response (RESPONSE_ACCEPT);
4784 dialog.set_position (WIN_POS_CENTER);
4789 switch (dialog.run ()) {
4790 case RESPONSE_ACCEPT:
4798 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
4800 HBox* hbox = new HBox();
4801 Image* image = new Image (Stock::DIALOG_WARNING, ICON_SIZE_DIALOG);
4802 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
4803 Label message (string_compose (_("\
4804 This session was created with a sample rate of %1 Hz, but\n\
4805 %2 is currently running at %3 Hz. If you load this session,\n\
4806 audio may be played at the wrong sample rate.\n"), desired, PROGRAM_NAME, actual));
4808 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4809 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4810 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4811 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4812 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
4813 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
4814 dialog.set_default_response (RESPONSE_ACCEPT);
4815 dialog.set_position (WIN_POS_CENTER);
4820 switch (dialog.run()) {
4821 case RESPONSE_ACCEPT:
4831 ARDOUR_UI::sr_mismatch_message (framecnt_t desired, framecnt_t actual)
4833 MessageDialog msg (string_compose (_("\
4834 This session was created with a sample rate of %1 Hz, but\n\
4835 %2 is currently running at %3 Hz.\n\
4836 Audio will be recorded and played at the wrong sample rate.\n\
4837 Re-Configure the Audio Engine in\n\
4838 Menu > Window > Audio/Midi Setup"),
4839 desired, PROGRAM_NAME, actual),
4841 Gtk::MESSAGE_WARNING);
4846 ARDOUR_UI::use_config ()
4848 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
4850 set_transport_controllable_state (*node);
4855 ARDOUR_UI::update_transport_clocks (framepos_t pos)
4857 if (UIConfiguration::instance().get_primary_clock_delta_edit_cursor()) {
4858 primary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
4860 primary_clock->set (pos);
4863 if (UIConfiguration::instance().get_secondary_clock_delta_edit_cursor()) {
4864 secondary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
4866 secondary_clock->set (pos);
4869 if (big_clock_window) {
4870 big_clock->set (pos);
4872 ARDOUR_UI::instance()->video_timeline->manual_seek_video_monitor(pos);
4876 ARDOUR_UI::step_edit_status_change (bool yn)
4878 // XXX should really store pre-step edit status of things
4879 // we make insensitive
4882 rec_button.set_active_state (Gtkmm2ext::ImplicitActive);
4883 rec_button.set_sensitive (false);
4885 rec_button.unset_active_state ();;
4886 rec_button.set_sensitive (true);
4891 ARDOUR_UI::record_state_changed ()
4893 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
4895 if (!_session || !big_clock_window) {
4896 /* why bother - the clock isn't visible */
4900 if (_session->record_status () == Session::Recording && _session->have_rec_enabled_track ()) {
4901 big_clock->set_active (true);
4903 big_clock->set_active (false);
4908 ARDOUR_UI::first_idle ()
4911 _session->allow_auto_play (true);
4915 editor->first_idle();
4918 Keyboard::set_can_save_keybindings (true);
4923 ARDOUR_UI::store_clock_modes ()
4925 XMLNode* node = new XMLNode(X_("ClockModes"));
4927 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
4928 XMLNode* child = new XMLNode (X_("Clock"));
4930 child->add_property (X_("name"), (*x)->name());
4931 child->add_property (X_("mode"), enum_2_string ((*x)->mode()));
4932 child->add_property (X_("on"), ((*x)->off() ? X_("no") : X_("yes")));
4934 node->add_child_nocopy (*child);
4937 _session->add_extra_xml (*node);
4938 _session->set_dirty ();
4941 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
4942 : Controllable (name), ui (u), type(tp)
4948 ARDOUR_UI::TransportControllable::set_value (double val, PBD::Controllable::GroupControlDisposition /*group_override*/)
4951 /* do nothing: these are radio-style actions */
4955 const char *action = 0;
4959 action = X_("Roll");
4962 action = X_("Stop");
4965 action = X_("GotoStart");
4968 action = X_("GotoEnd");
4971 action = X_("Loop");
4974 action = X_("PlaySelection");
4977 action = X_("Record");
4987 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
4995 ARDOUR_UI::TransportControllable::get_value (void) const
5022 ARDOUR_UI::setup_profile ()
5024 if (gdk_screen_width() < 1200 || getenv ("ARDOUR_NARROW_SCREEN")) {
5025 Profile->set_small_screen ();
5028 if (g_getenv ("TRX")) {
5029 Profile->set_trx ();
5032 if (g_getenv ("MIXBUS")) {
5033 Profile->set_mixbus ();
5038 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
5040 MissingFileDialog dialog (s, str, type);
5045 int result = dialog.run ();
5052 return 1; // quit entire session load
5055 result = dialog.get_action ();
5061 ARDOUR_UI::ambiguous_file (std::string file, std::vector<std::string> hits)
5063 AmbiguousFileDialog dialog (file, hits);
5070 return dialog.get_which ();
5073 /** Allocate our thread-local buffers */
5075 ARDOUR_UI::get_process_buffers ()
5077 _process_thread->get_buffers ();
5080 /** Drop our thread-local buffers */
5082 ARDOUR_UI::drop_process_buffers ()
5084 _process_thread->drop_buffers ();
5088 ARDOUR_UI::feedback_detected ()
5090 _feedback_exists = true;
5094 ARDOUR_UI::successful_graph_sort ()
5096 _feedback_exists = false;
5100 ARDOUR_UI::midi_panic ()
5103 _session->midi_panic();
5108 ARDOUR_UI::session_format_mismatch (std::string xml_path, std::string backup_path)
5110 const char* start_big = "<span size=\"x-large\" weight=\"bold\">";
5111 const char* end_big = "</span>";
5112 const char* start_mono = "<tt>";
5113 const char* end_mono = "</tt>";
5115 MessageDialog msg (string_compose (_("%4This is a session from an older version of %3%5\n\n"
5116 "%3 has copied the old session file\n\n%6%1%7\n\nto\n\n%6%2%7\n\n"
5117 "From now on, use the -2000 version with older versions of %3"),
5118 xml_path, backup_path, PROGRAM_NAME,
5120 start_mono, end_mono), true);
5127 ARDOUR_UI::reset_peak_display ()
5129 if (!_session || !_session->master_out() || !editor_meter) return;
5130 editor_meter->clear_meters();
5131 editor_meter_max_peak = -INFINITY;
5132 editor_meter_peak_display.set_active_state ( Gtkmm2ext::Off );
5136 ARDOUR_UI::reset_group_peak_display (RouteGroup* group)
5138 if (!_session || !_session->master_out()) return;
5139 if (group == _session->master_out()->route_group()) {
5140 reset_peak_display ();
5145 ARDOUR_UI::reset_route_peak_display (Route* route)
5147 if (!_session || !_session->master_out()) return;
5148 if (_session->master_out().get() == route) {
5149 reset_peak_display ();
5154 ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate)
5156 audio_midi_setup->set_desired_sample_rate (desired_sample_rate);
5157 audio_midi_setup->set_position (WIN_POS_CENTER);
5159 if (Config->get_try_autostart_engine () || getenv ("TRY_AUTOSTART_ENGINE")) {
5160 audio_midi_setup->try_autostart ();
5161 if (ARDOUR::AudioEngine::instance()->running()) {
5167 int response = audio_midi_setup->run();
5169 case Gtk::RESPONSE_OK:
5170 if (!AudioEngine::instance()->running()) {
5184 ARDOUR_UI::transport_numpad_timeout ()
5186 _numpad_locate_happening = false;
5187 if (_numpad_timeout_connection.connected() )
5188 _numpad_timeout_connection.disconnect();
5193 ARDOUR_UI::transport_numpad_decimal ()
5195 _numpad_timeout_connection.disconnect();
5197 if (_numpad_locate_happening) {
5198 if (editor) editor->goto_nth_marker(_pending_locate_num - 1);
5199 _numpad_locate_happening = false;
5201 _pending_locate_num = 0;
5202 _numpad_locate_happening = true;
5203 _numpad_timeout_connection = Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::transport_numpad_timeout), 2*1000);
5208 ARDOUR_UI::transport_numpad_event (int num)
5210 if ( _numpad_locate_happening ) {
5211 _pending_locate_num = _pending_locate_num*10 + num;
5214 case 0: toggle_roll(false, false); break;
5215 case 1: transport_rewind(1); break;
5216 case 2: transport_forward(1); break;
5217 case 3: transport_record(true); break;
5218 case 4: toggle_session_auto_loop(); break;
5219 case 5: transport_record(false); toggle_session_auto_loop(); break;
5220 case 6: toggle_punch(); break;
5221 case 7: toggle_click(); break;
5222 case 8: toggle_auto_return(); break;
5223 case 9: toggle_follow_edits(); break;
5229 ARDOUR_UI::set_flat_buttons ()
5231 CairoWidget::set_flat_buttons( UIConfiguration::instance().get_flat_buttons() );
5235 ARDOUR_UI::audioengine_became_silent ()
5237 MessageDialog msg (string_compose (_("This is a free/demo copy of %1. It has just switched to silent mode."), PROGRAM_NAME),
5239 Gtk::MESSAGE_WARNING,
5243 msg.set_title (string_compose (_("%1 is now silent"), PROGRAM_NAME));
5245 Gtk::Label pay_label (string_compose (_("Please consider paying for a copy of %1 - you can pay whatever you want."), PROGRAM_NAME));
5246 Gtk::Label subscribe_label (_("Better yet become a subscriber - subscriptions start at US$1 per month."));
5247 Gtk::Button pay_button (_("Pay for a copy (via the web)"));
5248 Gtk::Button subscribe_button (_("Become a subscriber (via the web)"));
5249 Gtk::HBox pay_button_box;
5250 Gtk::HBox subscribe_button_box;
5252 pay_button_box.pack_start (pay_button, true, false);
5253 subscribe_button_box.pack_start (subscribe_button, true, false);
5255 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 */
5257 pay_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://ardour.org/download")));
5258 subscribe_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://community.ardour.org/s/subscribe")));
5260 msg.get_vbox()->pack_start (pay_label);
5261 msg.get_vbox()->pack_start (pay_button_box);
5262 msg.get_vbox()->pack_start (subscribe_label);
5263 msg.get_vbox()->pack_start (subscribe_button_box);
5265 msg.get_vbox()->show_all ();
5267 msg.add_button (_("Remain silent"), Gtk::RESPONSE_CANCEL);
5268 msg.add_button (_("Save and quit"), Gtk::RESPONSE_NO);
5269 msg.add_button (_("Give me more time"), Gtk::RESPONSE_YES);
5274 case Gtk::RESPONSE_YES:
5275 AudioEngine::instance()->reset_silence_countdown ();
5278 case Gtk::RESPONSE_NO:
5280 save_state_canfail ("");
5284 case Gtk::RESPONSE_CANCEL:
5286 /* don't reset, save session and exit */
5292 ARDOUR_UI::hide_application ()
5294 Application::instance ()-> hide ();
5298 ARDOUR_UI::setup_toplevel_window (Gtk::Window& window, const string& name, void* owner)
5300 /* icons, titles, WM stuff */
5302 static list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
5304 if (window_icons.empty()) {
5305 Glib::RefPtr<Gdk::Pixbuf> icon;
5306 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
5307 window_icons.push_back (icon);
5309 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
5310 window_icons.push_back (icon);
5312 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
5313 window_icons.push_back (icon);
5315 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
5316 window_icons.push_back (icon);
5320 if (!window_icons.empty()) {
5321 window.set_default_icon_list (window_icons);
5324 Gtkmm2ext::WindowTitle title (Glib::get_application_name());
5326 if (!name.empty()) {
5330 window.set_title (title.get_string());
5331 window.set_wmclass (string_compose (X_("%1_%1"), downcase (PROGRAM_NAME), downcase (name)), PROGRAM_NAME);
5333 window.set_flags (CAN_FOCUS);
5334 window.add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
5336 /* This is a hack to ensure that GTK-accelerators continue to
5337 * work. Once we switch over to entirely native bindings, this will be
5338 * unnecessary and should be removed
5340 window.add_accel_group (ActionManager::ui_manager->get_accel_group());
5342 window.signal_configure_event().connect (sigc::mem_fun (*this, &ARDOUR_UI::configure_handler));
5343 window.signal_window_state_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::tabbed_window_state_event_handler), owner));
5344 window.signal_key_press_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5345 window.signal_key_release_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5349 ARDOUR_UI::key_event_handler (GdkEventKey* ev, Gtk::Window* event_window)
5351 Gtkmm2ext::Bindings* bindings = 0;
5352 Gtk::Window* window = 0;
5354 /* until we get ardour bindings working, we are not handling key
5358 if (ev->type != GDK_KEY_PRESS) {
5362 if (event_window == &_main_window) {
5364 window = event_window;
5366 /* find current tab contents */
5368 Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page());
5370 /* see if it uses the ardour binding system */
5373 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(w->get_data ("ardour-bindings"));
5376 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("main window key event, bindings = %1, global = %2\n", bindings, &global_bindings));
5380 window = event_window;
5382 /* see if window uses ardour binding system */
5384 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(window->get_data ("ardour-bindings"));
5387 /* An empty binding set is treated as if it doesn't exist */
5389 if (bindings && bindings->empty()) {
5393 return key_press_focus_accelerator_handler (*window, ev, bindings);
5396 static Gtkmm2ext::Bindings*
5397 get_bindings_from_widget_heirarchy (GtkWidget* w)
5402 if ((p = g_object_get_data (G_OBJECT(w), "ardour-bindings")) != 0) {
5405 w = gtk_widget_get_parent (w);
5408 return reinterpret_cast<Gtkmm2ext::Bindings*> (p);
5412 ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev, Gtkmm2ext::Bindings* bindings)
5414 GtkWindow* win = window.gobj();
5415 GtkWidget* focus = gtk_window_get_focus (win);
5416 bool special_handling_of_unmodified_accelerators = false;
5417 const guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK));
5421 /* some widget has keyboard focus */
5423 if (GTK_IS_ENTRY(focus) || Keyboard::some_magic_widget_has_focus()) {
5425 /* A particular kind of focusable widget currently has keyboard
5426 * focus. All unmodified key events should go to that widget
5427 * first and not be used as an accelerator by default
5430 special_handling_of_unmodified_accelerators = true;
5434 Gtkmm2ext::Bindings* focus_bindings = get_bindings_from_widget_heirarchy (focus);
5435 if (focus_bindings) {
5436 bindings = focus_bindings;
5437 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Switch bindings based on focus widget, now using %1\n", bindings->name()));
5442 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",
5445 show_gdk_event_state (ev->state),
5446 special_handling_of_unmodified_accelerators,
5447 Keyboard::some_magic_widget_has_focus(),
5449 (focus ? gtk_widget_get_name (focus) : "no focus widget"),
5450 ((ev->state & mask) ? "yes" : "no"),
5451 window.get_title()));
5453 /* This exists to allow us to override the way GTK handles
5454 key events. The normal sequence is:
5456 a) event is delivered to a GtkWindow
5457 b) accelerators/mnemonics are activated
5458 c) if (b) didn't handle the event, propagate to
5459 the focus widget and/or focus chain
5461 The problem with this is that if the accelerators include
5462 keys without modifiers, such as the space bar or the
5463 letter "e", then pressing the key while typing into
5464 a text entry widget results in the accelerator being
5465 activated, instead of the desired letter appearing
5468 There is no good way of fixing this, but this
5469 represents a compromise. The idea is that
5470 key events involving modifiers (not Shift)
5471 get routed into the activation pathway first, then
5472 get propagated to the focus widget if necessary.
5474 If the key event doesn't involve modifiers,
5475 we deliver to the focus widget first, thus allowing
5476 it to get "normal text" without interference
5479 Of course, this can also be problematic: if there
5480 is a widget with focus, then it will swallow
5481 all "normal text" accelerators.
5485 if (!special_handling_of_unmodified_accelerators || (ev->state & mask)) {
5487 /* no special handling or there are modifiers in effect: accelerate first */
5489 DEBUG_TRACE (DEBUG::Accelerators, "\tactivate, then propagate\n");
5490 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tevent send-event:%1 time:%2 length:%3 name %7 string:%4 hardware_keycode:%5 group:%6\n",
5491 ev->send_event, ev->time, ev->length, ev->string, ev->hardware_keycode, ev->group, gdk_keyval_name (ev->keyval)));
5493 DEBUG_TRACE (DEBUG::Accelerators, "\tsending to window\n");
5494 KeyboardKey k (ev->state, ev->keyval);
5498 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tusing Ardour bindings %1 @ %2 for this event\n", bindings->name(), bindings));
5500 if (bindings->activate (k, Bindings::Press)) {
5501 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5506 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5508 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5509 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5513 DEBUG_TRACE (DEBUG::Accelerators, "\tnot accelerated, now propagate\n");
5515 if (gtk_window_propagate_key_event (win, ev)) {
5516 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate handled\n");
5522 /* no modifiers, propagate first */
5524 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate, then activate\n");
5526 if (gtk_window_propagate_key_event (win, ev)) {
5527 DEBUG_TRACE (DEBUG::Accelerators, "\thandled by propagate\n");
5531 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagation didn't handle, so activate\n");
5532 KeyboardKey k (ev->state, ev->keyval);
5536 DEBUG_TRACE (DEBUG::Accelerators, "\tusing Ardour bindings for this window\n");
5539 if (bindings->activate (k, Bindings::Press)) {
5540 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5546 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5548 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5549 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5554 DEBUG_TRACE (DEBUG::Accelerators, "\tnot handled\n");
5559 ARDOUR_UI::load_bindings ()
5561 if ((global_bindings = Bindings::get_bindings (X_("Global"), global_actions)) == 0) {
5562 error << _("Global keybindings are missing") << endmsg;
5567 ARDOUR_UI::cancel_solo ()
5570 if (_session->soloing()) {
5571 _session->set_solo (_session->get_routes(), false);
5572 } else if (_session->listening()) {
5573 _session->set_listen (_session->get_routes(), false);
5576 _session->clear_all_solo_state (_session->get_routes()); // safeguard, ideally this won't do anything, check the log-window