2 Copyright (C) 1999-2013 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include "gtk2ardour-config.h"
22 #include "gtk2ardour-version.h"
32 #ifndef PLATFORM_WINDOWS
33 #include <sys/resource.h>
43 #include "pbd/gstdio_compat.h"
45 #include <gtkmm/messagedialog.h>
46 #include <gtkmm/accelmap.h>
48 #include "pbd/error.h"
49 #include "pbd/basename.h"
50 #include "pbd/compose.h"
51 #include "pbd/convert.h"
52 #include "pbd/failed_constructor.h"
53 #include "pbd/enumwriter.h"
54 #include "pbd/memento_command.h"
55 #include "pbd/openuri.h"
56 #include "pbd/stl_delete.h"
57 #include "pbd/file_utils.h"
58 #include "pbd/localtime_r.h"
59 #include "pbd/pthread_utils.h"
60 #include "pbd/replace_all.h"
61 #include "pbd/xml++.h"
63 #include "gtkmm2ext/application.h"
64 #include "gtkmm2ext/bindings.h"
65 #include "gtkmm2ext/gtk_ui.h"
66 #include "gtkmm2ext/utils.h"
67 #include "gtkmm2ext/click_box.h"
68 #include "gtkmm2ext/fastmeter.h"
69 #include "gtkmm2ext/popup.h"
70 #include "gtkmm2ext/window_title.h"
72 #include "ardour/ardour.h"
73 #include "ardour/audio_backend.h"
74 #include "ardour/audio_track.h"
75 #include "ardour/audioengine.h"
76 #include "ardour/audiofilesource.h"
77 #include "ardour/automation_watch.h"
78 #include "ardour/diskstream.h"
79 #include "ardour/filename_extensions.h"
80 #include "ardour/filesystem_paths.h"
81 #include "ardour/ltc_file_reader.h"
82 #include "ardour/midi_track.h"
83 #include "ardour/port.h"
84 #include "ardour/plugin_manager.h"
85 #include "ardour/process_thread.h"
86 #include "ardour/profile.h"
87 #include "ardour/recent_sessions.h"
88 #include "ardour/session_directory.h"
89 #include "ardour/session_route.h"
90 #include "ardour/session_state_utils.h"
91 #include "ardour/session_utils.h"
92 #include "ardour/source_factory.h"
93 #include "ardour/slave.h"
94 #include "ardour/system_exec.h"
96 #include "LuaBridge/LuaBridge.h"
98 #ifdef WINDOWS_VST_SUPPORT
101 #ifdef AUDIOUNIT_SUPPORT
102 #include "ardour/audio_unit.h"
105 // fix for OSX (nsm.h has a check function, AU/Apple defines check)
110 #include "timecode/time.h"
112 typedef uint64_t microseconds_t;
117 #include "add_route_dialog.h"
118 #include "ambiguous_file_dialog.h"
119 #include "ardour_ui.h"
120 #include "audio_clock.h"
121 #include "audio_region_view.h"
122 #include "big_clock_window.h"
123 #include "bundle_manager.h"
124 #include "duplicate_routes_dialog.h"
126 #include "engine_dialog.h"
127 #include "export_video_dialog.h"
128 #include "export_video_infobox.h"
129 #include "gain_meter.h"
130 #include "global_port_matrix.h"
131 #include "gui_object.h"
132 #include "gui_thread.h"
133 #include "keyboard.h"
134 #include "keyeditor.h"
135 #include "location_ui.h"
136 #include "lua_script_manager.h"
137 #include "luawindow.h"
138 #include "main_clock.h"
139 #include "missing_file_dialog.h"
140 #include "missing_plugin_dialog.h"
141 #include "mixer_ui.h"
142 #include "meterbridge.h"
143 #include "mouse_cursors.h"
146 #include "pingback.h"
147 #include "processor_box.h"
148 #include "prompter.h"
149 #include "public_editor.h"
150 #include "rc_option_editor.h"
151 #include "route_time_axis.h"
152 #include "route_params_ui.h"
153 #include "save_as_dialog.h"
154 #include "script_selector.h"
155 #include "session_dialog.h"
156 #include "session_metadata_dialog.h"
157 #include "session_option_editor.h"
158 #include "shuttle_control.h"
159 #include "speaker_dialog.h"
162 #include "theme_manager.h"
163 #include "time_axis_view_item.h"
166 #include "video_server_dialog.h"
167 #include "add_video_dialog.h"
168 #include "transcode_video_dialog.h"
172 using namespace ARDOUR;
173 using namespace ARDOUR_UI_UTILS;
175 using namespace Gtkmm2ext;
178 using namespace Editing;
180 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
182 sigc::signal<void, framepos_t, bool, framepos_t> ARDOUR_UI::Clock;
183 sigc::signal<void> ARDOUR_UI::CloseAllDialogs;
186 ask_about_configuration_copy (string const & old_dir, string const & new_dir, int version)
188 MessageDialog msg (string_compose (_("%1 %2.x has discovered configuration files from %1 %3.x.\n\n"
189 "Would you like these files to be copied and used for %1 %2.x?\n\n"
190 "(This will require you to restart %1.)"),
191 PROGRAM_NAME, PROGRAM_VERSION, version),
192 false, /* no markup */
195 true /* modal, though it hardly matters since it is the only window */
198 msg.set_default_response (Gtk::RESPONSE_YES);
201 return (msg.run() == Gtk::RESPONSE_YES);
205 libxml_generic_error_func (void* /* parsing_context*/,
213 vsnprintf (buf, sizeof (buf), msg, ap);
214 error << buf << endmsg;
219 libxml_structured_error_func (void* /* parsing_context*/,
227 replace_all (msg, "\n", "");
229 if (err->file && err->line) {
230 error << X_("XML error: ") << msg << " in " << err->file << " at line " << err->line;
233 error << ':' << err->int2;
240 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
241 : Gtkmm2ext::UI (PROGRAM_NAME, X_("gui"), argcp, argvp)
242 , session_loaded (false)
243 , gui_object_state (new GUIObjectState)
244 , primary_clock (new MainClock (X_("primary"), X_("transport"), true ))
245 , secondary_clock (new MainClock (X_("secondary"), X_("secondary"), false))
246 , big_clock (new AudioClock (X_("bigclock"), false, "big", true, true, false, false))
248 , global_actions (X_("global"))
249 , ignore_dual_punch (false)
254 , _mixer_on_top (false)
255 , _initial_verbose_plugin_scan (false)
256 , first_time_engine_run (true)
257 , roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll))
258 , stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop))
259 , goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart))
260 , goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd))
261 , auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop))
262 , play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection))
263 , rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable))
264 , auto_return_button (ArdourButton::led_default_elements)
265 , follow_edits_button (ArdourButton::led_default_elements)
266 , auto_input_button (ArdourButton::led_default_elements)
267 , auditioning_alert_button (_("Audition"))
268 , solo_alert_button (_("Solo"))
269 , feedback_alert_button (_("Feedback"))
270 , error_alert_button ( ArdourButton::just_led_default_elements )
272 , editor_meter_peak_display()
273 , _numpad_locate_happening (false)
274 , _session_is_new (false)
275 , last_key_press_time (0)
279 , rc_option_editor (0)
280 , speaker_config_window (X_("speaker-config"), _("Speaker Configuration"))
281 , add_route_dialog (X_("add-routes"), _("Add Tracks/Busses"))
282 , about (X_("about"), _("About"))
283 , location_ui (X_("locations"), _("Locations"))
284 , route_params (X_("inspector"), _("Tracks and Busses"))
285 , audio_midi_setup (X_("audio-midi-setup"), _("Audio/MIDI Setup"))
286 , export_video_dialog (X_("video-export"), _("Video Export Dialog"))
287 , lua_script_window (X_("script-manager"), _("Script Manager"))
288 , session_option_editor (X_("session-options-editor"), _("Properties"), boost::bind (&ARDOUR_UI::create_session_option_editor, this))
289 , add_video_dialog (X_("add-video"), _("Add Video"), boost::bind (&ARDOUR_UI::create_add_video_dialog, this))
290 , bundle_manager (X_("bundle-manager"), _("Bundle Manager"), boost::bind (&ARDOUR_UI::create_bundle_manager, this))
291 , big_clock_window (X_("big-clock"), _("Big Clock"), boost::bind (&ARDOUR_UI::create_big_clock_window, this))
292 , audio_port_matrix (X_("audio-connection-manager"), _("Audio Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::AUDIO))
293 , midi_port_matrix (X_("midi-connection-manager"), _("MIDI Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::MIDI))
294 , key_editor (X_("key-editor"), _("Bindings Editor"), boost::bind (&ARDOUR_UI::create_key_editor, this))
295 , video_server_process (0)
297 , have_configure_timeout (false)
298 , last_configure_time (0)
300 , have_disk_speed_dialog_displayed (false)
301 , _status_bar_visibility (X_("status-bar"))
302 , _feedback_exists (false)
303 , _log_not_acknowledged (LogLevelNone)
304 , duplicate_routes_dialog (0)
305 , editor_visibility_button (S_("Window|Editor"))
306 , mixer_visibility_button (S_("Window|Mixer"))
307 , prefs_visibility_button (S_("Window|Preferences"))
309 Gtkmm2ext::init (localedir);
311 UIConfiguration::instance().post_gui_init ();
313 if (ARDOUR::handle_old_configuration_files (boost::bind (ask_about_configuration_copy, _1, _2, _3))) {
314 MessageDialog msg (string_compose (_("Your configuration files were copied. You can now restart %1."), PROGRAM_NAME), true);
316 /* configuration was modified, exit immediately */
320 if (theArdourUI == 0) {
324 /* stop libxml from spewing to stdout/stderr */
326 xmlSetGenericErrorFunc (this, libxml_generic_error_func);
327 xmlSetStructuredErrorFunc (this, libxml_structured_error_func);
329 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::parameter_changed));
330 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
331 UIConfiguration::instance().map_parameters (pc);
333 roll_button.set_controllable (roll_controllable);
334 stop_button.set_controllable (stop_controllable);
335 goto_start_button.set_controllable (goto_start_controllable);
336 goto_end_button.set_controllable (goto_end_controllable);
337 auto_loop_button.set_controllable (auto_loop_controllable);
338 play_selection_button.set_controllable (play_selection_controllable);
339 rec_button.set_controllable (rec_controllable);
341 roll_button.set_name ("transport button");
342 stop_button.set_name ("transport button");
343 goto_start_button.set_name ("transport button");
344 goto_end_button.set_name ("transport button");
345 auto_loop_button.set_name ("transport button");
346 play_selection_button.set_name ("transport button");
347 rec_button.set_name ("transport recenable button");
348 midi_panic_button.set_name ("transport button");
350 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
351 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
353 ARDOUR::Session::VersionMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_format_mismatch, this, _1, _2), gui_context());
355 /* handle dialog requests */
357 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
359 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
361 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
363 /* handle Audio/MIDI setup when session requires it */
365 ARDOUR::Session::AudioEngineSetupRequired.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::do_audio_midi_setup, this, _1));
367 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
369 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
371 /* handle sr mismatch with a dialog - cross-thread from engine */
372 ARDOUR::Session::NotifyAboutSampleRateMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::sr_mismatch_message, this, _1, _2), gui_context ());
374 /* handle requests to quit (coming from JACK session) */
376 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::finish, this), gui_context ());
378 /* tell the user about feedback */
380 ARDOUR::Session::FeedbackDetected.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::feedback_detected, this), gui_context ());
381 ARDOUR::Session::SuccessfulGraphSort.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::successful_graph_sort, this), gui_context ());
383 /* handle requests to deal with missing files */
385 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
387 /* and ambiguous files */
389 ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2));
391 /* also plugin scan messages */
392 ARDOUR::PluginScanMessage.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_dialog, this, _1, _2, _3), gui_context());
393 ARDOUR::PluginScanTimeout.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_timeout, this, _1), gui_context());
395 ARDOUR::GUIIdle.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::gui_idle_handler, this), gui_context());
397 Config->ParameterChanged.connect ( forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::set_flat_buttons, this), gui_context() );
400 /* lets get this party started */
402 setup_gtk_ardour_enums ();
405 SessionEvent::create_per_thread_pool ("GUI", 4096);
407 /* we like keyboards */
409 keyboard = new ArdourKeyboard(*this);
411 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
413 keyboard->set_state (*node, Stateful::loading_state_version);
416 UIConfiguration::instance().reset_dpi ();
418 TimeAxisViewItem::set_constant_heights ();
420 /* Set this up so that our window proxies can register actions */
422 ActionManager::init ();
424 /* The following must happen after ARDOUR::init() so that Config is set up */
426 const XMLNode* ui_xml = Config->extra_xml (X_("UI"));
429 key_editor.set_state (*ui_xml, 0);
430 session_option_editor.set_state (*ui_xml, 0);
431 speaker_config_window.set_state (*ui_xml, 0);
432 about.set_state (*ui_xml, 0);
433 add_route_dialog.set_state (*ui_xml, 0);
434 add_video_dialog.set_state (*ui_xml, 0);
435 route_params.set_state (*ui_xml, 0);
436 bundle_manager.set_state (*ui_xml, 0);
437 location_ui.set_state (*ui_xml, 0);
438 big_clock_window.set_state (*ui_xml, 0);
439 audio_port_matrix.set_state (*ui_xml, 0);
440 midi_port_matrix.set_state (*ui_xml, 0);
441 export_video_dialog.set_state (*ui_xml, 0);
442 lua_script_window.set_state (*ui_xml, 0);
445 /* Separate windows */
447 WM::Manager::instance().register_window (&key_editor);
448 WM::Manager::instance().register_window (&session_option_editor);
449 WM::Manager::instance().register_window (&speaker_config_window);
450 WM::Manager::instance().register_window (&about);
451 WM::Manager::instance().register_window (&add_route_dialog);
452 WM::Manager::instance().register_window (&add_video_dialog);
453 WM::Manager::instance().register_window (&route_params);
454 WM::Manager::instance().register_window (&audio_midi_setup);
455 WM::Manager::instance().register_window (&export_video_dialog);
456 WM::Manager::instance().register_window (&lua_script_window);
457 WM::Manager::instance().register_window (&bundle_manager);
458 WM::Manager::instance().register_window (&location_ui);
459 WM::Manager::instance().register_window (&big_clock_window);
460 WM::Manager::instance().register_window (&audio_port_matrix);
461 WM::Manager::instance().register_window (&midi_port_matrix);
463 /* Trigger setting up the color scheme and loading the GTK RC file */
465 UIConfiguration::instance().load_rc_file (false);
467 _process_thread = new ProcessThread ();
468 _process_thread->init ();
470 UIConfiguration::instance().DPIReset.connect (sigc::mem_fun (*this, &ARDOUR_UI::resize_text_widgets));
475 GlobalPortMatrixWindow*
476 ARDOUR_UI::create_global_port_matrix (ARDOUR::DataType type)
481 return new GlobalPortMatrixWindow (_session, type);
485 ARDOUR_UI::attach_to_engine ()
487 AudioEngine::instance()->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
488 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
492 ARDOUR_UI::engine_stopped ()
494 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
495 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
496 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
497 update_sample_rate (0);
502 ARDOUR_UI::engine_running ()
504 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
505 if (first_time_engine_run) {
507 first_time_engine_run = false;
511 _session->reset_xrun_count ();
513 update_disk_space ();
515 update_xrun_count ();
516 update_sample_rate (AudioEngine::instance()->sample_rate());
517 update_timecode_format ();
518 update_peak_thread_work ();
519 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, true);
520 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, false);
524 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
526 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
527 /* we can't rely on the original string continuing to exist when we are called
528 again in the GUI thread, so make a copy and note that we need to
531 char *copy = strdup (reason);
532 Gtkmm2ext::UI::instance()->call_slot (MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
536 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
537 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
539 update_sample_rate (0);
543 /* if the reason is a non-empty string, it means that the backend was shutdown
544 rather than just Ardour.
547 if (strlen (reason)) {
548 msgstr = string_compose (_("The audio backend was shutdown because:\n\n%1"), reason);
550 msgstr = string_compose (_("\
551 The audio backend has either been shutdown or it\n\
552 disconnected %1 because %1\n\
553 was not fast enough. Try to restart\n\
554 the audio backend and save the session."), PROGRAM_NAME);
557 MessageDialog msg (_main_window, msgstr);
558 pop_back_splash (msg);
562 free (const_cast<char*> (reason));
567 ARDOUR_UI::post_engine ()
569 /* Things to be done once (and once ONLY) after we have a backend running in the AudioEngine
571 #ifdef AUDIOUNIT_SUPPORT
573 if (AUPluginInfo::au_get_crashlog(au_msg)) {
574 popup_error(_("Audio Unit Plugin Scan Failed. Automatic AU scanning has been disabled. Please see the log window for further details."));
575 error << _("Audio Unit Plugin Scan Failed:") << endmsg;
576 info << au_msg << endmsg;
580 ARDOUR::init_post_engine ();
582 /* connect to important signals */
584 AudioEngine::instance()->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
585 AudioEngine::instance()->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
586 AudioEngine::instance()->BufferSizeChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
587 AudioEngine::instance()->Halted.connect_same_thread (halt_connection, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
588 AudioEngine::instance()->BecameSilent.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::audioengine_became_silent, this), gui_context());
590 if (setup_windows ()) {
591 throw failed_constructor ();
594 /* Do this after setup_windows (), as that's when the _status_bar_visibility is created */
595 XMLNode* n = Config->extra_xml (X_("UI"));
597 _status_bar_visibility.set_state (*n);
600 check_memory_locking();
602 /* this is the first point at which all the possible actions are
603 * available, because some of the available actions are dependent on
604 * aspects of the engine/backend.
607 if (ARDOUR_COMMAND_LINE::show_key_actions) {
610 vector<string> paths;
611 vector<string> labels;
612 vector<string> tooltips;
614 vector<Glib::RefPtr<Gtk::Action> > actions;
616 Gtkmm2ext::ActionMap::get_all_actions (paths, labels, tooltips, keys, actions);
618 vector<string>::iterator k;
619 vector<string>::iterator p;
621 for (p = paths.begin(), k = keys.begin(); p != paths.end(); ++k, ++p) {
626 cout << *p << " => " << *k << endl;
630 halt_connection.disconnect ();
631 AudioEngine::instance()->stop ();
635 /* this being a GUI and all, we want peakfiles */
637 AudioFileSource::set_build_peakfiles (true);
638 AudioFileSource::set_build_missing_peakfiles (true);
640 /* set default clock modes */
642 primary_clock->set_mode (AudioClock::Timecode);
643 secondary_clock->set_mode (AudioClock::BBT);
645 /* start the time-of-day-clock */
648 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
649 update_wall_clock ();
650 Glib::signal_timeout().connect_seconds (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 1);
655 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
656 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
657 Config->map_parameters (pc);
659 UIConfiguration::instance().map_parameters (pc);
663 ARDOUR_UI::~ARDOUR_UI ()
665 UIConfiguration::instance().save_state();
669 if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
670 // don't bother at 'real' exit. the OS cleans up for us.
671 delete big_clock; big_clock = 0;
672 delete primary_clock; primary_clock = 0;
673 delete secondary_clock; secondary_clock = 0;
674 delete _process_thread; _process_thread = 0;
675 delete meterbridge; meterbridge = 0;
676 delete luawindow; luawindow = 0;
677 delete editor; editor = 0;
678 delete mixer; mixer = 0;
680 delete gui_object_state; gui_object_state = 0;
681 FastMeter::flush_pattern_cache ();
682 PixFader::flush_pattern_cache ();
686 /* Small trick to flush main-thread event pool.
687 * Other thread-pools are destroyed at pthread_exit(),
688 * but tmain thread termination is too late to trigger Pool::~Pool()
690 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.
691 delete ev->event_pool();
696 ARDOUR_UI::pop_back_splash (Gtk::Window& win)
698 if (Splash::instance()) {
699 Splash::instance()->pop_back_for (win);
704 ARDOUR_UI::configure_timeout ()
706 if (last_configure_time == 0) {
707 /* no configure events yet */
711 /* force a gap of 0.5 seconds since the last configure event
714 if (get_microseconds() - last_configure_time < 500000) {
717 have_configure_timeout = false;
718 save_ardour_state ();
724 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
726 if (have_configure_timeout) {
727 last_configure_time = get_microseconds();
729 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
730 have_configure_timeout = true;
737 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
739 const XMLProperty* prop;
741 if ((prop = node.property ("roll")) != 0) {
742 roll_controllable->set_id (prop->value());
744 if ((prop = node.property ("stop")) != 0) {
745 stop_controllable->set_id (prop->value());
747 if ((prop = node.property ("goto-start")) != 0) {
748 goto_start_controllable->set_id (prop->value());
750 if ((prop = node.property ("goto-end")) != 0) {
751 goto_end_controllable->set_id (prop->value());
753 if ((prop = node.property ("auto-loop")) != 0) {
754 auto_loop_controllable->set_id (prop->value());
756 if ((prop = node.property ("play-selection")) != 0) {
757 play_selection_controllable->set_id (prop->value());
759 if ((prop = node.property ("rec")) != 0) {
760 rec_controllable->set_id (prop->value());
762 if ((prop = node.property ("shuttle")) != 0) {
763 shuttle_box->controllable()->set_id (prop->value());
768 ARDOUR_UI::get_transport_controllable_state ()
770 XMLNode* node = new XMLNode(X_("TransportControllables"));
773 roll_controllable->id().print (buf, sizeof (buf));
774 node->add_property (X_("roll"), buf);
775 stop_controllable->id().print (buf, sizeof (buf));
776 node->add_property (X_("stop"), buf);
777 goto_start_controllable->id().print (buf, sizeof (buf));
778 node->add_property (X_("goto_start"), buf);
779 goto_end_controllable->id().print (buf, sizeof (buf));
780 node->add_property (X_("goto_end"), buf);
781 auto_loop_controllable->id().print (buf, sizeof (buf));
782 node->add_property (X_("auto_loop"), buf);
783 play_selection_controllable->id().print (buf, sizeof (buf));
784 node->add_property (X_("play_selection"), buf);
785 rec_controllable->id().print (buf, sizeof (buf));
786 node->add_property (X_("rec"), buf);
787 shuttle_box->controllable()->id().print (buf, sizeof (buf));
788 node->add_property (X_("shuttle"), buf);
794 ARDOUR_UI::save_session_at_its_request (std::string snapshot_name)
797 _session->save_state (snapshot_name);
802 ARDOUR_UI::autosave_session ()
804 if (g_main_depth() > 1) {
805 /* inside a recursive main loop,
806 give up because we may not be able to
812 if (!Config->get_periodic_safety_backups()) {
817 _session->maybe_write_autosave();
824 ARDOUR_UI::session_dirty_changed ()
831 ARDOUR_UI::update_autosave ()
833 if (_session && _session->dirty()) {
834 if (_autosave_connection.connected()) {
835 _autosave_connection.disconnect();
838 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
839 Config->get_periodic_safety_backup_interval() * 1000);
842 if (_autosave_connection.connected()) {
843 _autosave_connection.disconnect();
849 ARDOUR_UI::check_announcements ()
852 string _annc_filename;
855 _annc_filename = PROGRAM_NAME "_announcements_osx_";
856 #elif defined PLATFORM_WINDOWS
857 _annc_filename = PROGRAM_NAME "_announcements_windows_";
859 _annc_filename = PROGRAM_NAME "_announcements_linux_";
861 _annc_filename.append (VERSIONSTRING);
863 _announce_string = "";
865 std::string path = Glib::build_filename (user_config_directory(), _annc_filename);
866 FILE* fin = g_fopen (path.c_str(), "rb");
868 while (!feof (fin)) {
871 if ((len = fread (tmp, sizeof(char), 1024, fin)) == 0 || ferror (fin)) {
874 _announce_string.append (tmp, len);
879 pingback (VERSIONSTRING, path);
884 _hide_splash (gpointer arg)
886 ((ARDOUR_UI*)arg)->hide_splash();
891 ARDOUR_UI::starting ()
893 Application* app = Application::instance ();
895 bool brand_new_user = ArdourStartup::required ();
897 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
898 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::load_from_application_api));
900 if (ARDOUR_COMMAND_LINE::check_announcements) {
901 check_announcements ();
906 /* we need to create this early because it may need to set the
907 * audio backend end up.
911 audio_midi_setup.get (true);
913 std::cerr << "audio-midi engine setup failed."<< std::endl;
917 if ((nsm_url = g_getenv ("NSM_URL")) != 0) {
918 nsm = new NSM_Client;
919 if (!nsm->init (nsm_url)) {
920 /* the ardour executable may have different names:
922 * waf's obj.target for distro versions: eg ardour4, ardourvst4
923 * Ardour4, Mixbus3 for bundled versions + full path on OSX & windows
924 * argv[0] does not apply since we need the wrapper-script (not the binary itself)
926 * The wrapper startup script should set the environment variable 'ARDOUR_SELF'
928 const char *process_name = g_getenv ("ARDOUR_SELF");
929 nsm->announce (PROGRAM_NAME, ":dirty:", process_name ? process_name : "ardour4");
932 // wait for announce reply from nsm server
933 for ( i = 0; i < 5000; ++i) {
937 if (nsm->is_active()) {
942 error << _("NSM server did not announce itself") << endmsg;
945 // wait for open command from nsm server
946 for ( i = 0; i < 5000; ++i) {
949 if (nsm->client_id ()) {
955 error << _("NSM: no client ID provided") << endmsg;
959 if (_session && nsm) {
960 _session->set_nsm_state( nsm->is_active() );
962 error << _("NSM: no session created") << endmsg;
966 // nsm requires these actions disabled
967 vector<string> action_names;
968 action_names.push_back("SaveAs");
969 action_names.push_back("Rename");
970 action_names.push_back("New");
971 action_names.push_back("Open");
972 action_names.push_back("Recent");
973 action_names.push_back("Close");
975 for (vector<string>::const_iterator n = action_names.begin(); n != action_names.end(); ++n) {
976 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), (*n).c_str());
978 act->set_sensitive (false);
985 error << _("NSM: initialization failed") << endmsg;
991 if (brand_new_user) {
992 _initial_verbose_plugin_scan = true;
997 _initial_verbose_plugin_scan = false;
998 switch (s.response ()) {
999 case Gtk::RESPONSE_OK:
1006 #ifdef NO_PLUGIN_STATE
1008 ARDOUR::RecentSessions rs;
1009 ARDOUR::read_recent_sessions (rs);
1011 string path = Glib::build_filename (user_config_directory(), ".iknowaboutfreeversion");
1013 if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS) && !rs.empty()) {
1015 /* already used Ardour, have sessions ... warn about plugin state */
1017 ArdourDialog d (_("Free/Demo Version Warning"), true);
1019 Button b (string_compose (_("Subscribe and support development of %1"), PROGRAM_NAME));
1020 CheckButton c (_("Don't warn me about this again"));
1022 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"),
1023 string_compose (_("This is a free/demo version of %1"), PROGRAM_NAME),
1024 _("It will not restore OR save any plugin settings"),
1025 _("If you load an existing session with plugin settings\n"
1026 "they will not be used and will be lost."),
1027 _("To get full access to updates without this limitation\n"
1028 "consider becoming a subscriber for a low cost every month.")));
1029 l.set_justify (JUSTIFY_CENTER);
1031 b.signal_clicked().connect (mem_fun(*this, &ARDOUR_UI::launch_subscribe));
1033 d.get_vbox()->pack_start (l, true, true);
1034 d.get_vbox()->pack_start (b, false, false, 12);
1035 d.get_vbox()->pack_start (c, false, false, 12);
1037 d.add_button (_("Quit now"), RESPONSE_CANCEL);
1038 d.add_button (string_compose (_("Continue using %1"), PROGRAM_NAME), RESPONSE_OK);
1042 c.signal_toggled().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (toggle_file_existence), path)));
1044 if (d.run () != RESPONSE_OK) {
1050 /* go get a session */
1052 const bool new_session_required = (ARDOUR_COMMAND_LINE::new_session || brand_new_user);
1054 if (get_session_parameters (false, new_session_required, ARDOUR_COMMAND_LINE::load_template)) {
1055 std::cerr << "Cannot get session parameters."<< std::endl;
1062 WM::Manager::instance().show_visible ();
1064 /* We have to do this here since goto_editor_window() ends up calling show_all() on the
1065 * editor window, and we may want stuff to be hidden.
1067 _status_bar_visibility.update ();
1069 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
1071 if (splash && splash->is_visible()) {
1072 // in 1 second, hide the splash screen
1073 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
1076 /* all other dialogs are created conditionally */
1082 ARDOUR_UI::check_memory_locking ()
1084 #if defined(__APPLE__) || defined(PLATFORM_WINDOWS)
1085 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
1089 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
1091 if (AudioEngine::instance()->is_realtime() && memory_warning_node == 0) {
1093 struct rlimit limits;
1095 long pages, page_size;
1097 size_t pages_len=sizeof(pages);
1098 if ((page_size = getpagesize()) < 0 ||
1099 sysctlbyname("hw.availpages", &pages, &pages_len, NULL, 0))
1101 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0)
1106 ram = (int64_t) pages * (int64_t) page_size;
1109 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
1113 if (limits.rlim_cur != RLIM_INFINITY) {
1115 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
1119 _("WARNING: Your system has a limit for maximum amount of locked memory. "
1120 "This might cause %1 to run out of memory before your system "
1121 "runs out of memory. \n\n"
1122 "You can view the memory limit with 'ulimit -l', "
1123 "and it is normally controlled by %2"),
1126 X_("/etc/login.conf")
1128 X_(" /etc/security/limits.conf")
1132 msg.set_default_response (RESPONSE_OK);
1134 VBox* vbox = msg.get_vbox();
1136 CheckButton cb (_("Do not show this window again"));
1137 hbox.pack_start (cb, true, false);
1138 vbox->pack_start (hbox);
1143 pop_back_splash (msg);
1147 if (cb.get_active()) {
1148 XMLNode node (X_("no-memory-warning"));
1149 Config->add_instant_xml (node);
1154 #endif // !__APPLE__
1159 ARDOUR_UI::queue_finish ()
1161 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
1165 ARDOUR_UI::idle_finish ()
1168 return false; /* do not call again */
1175 ARDOUR_UI::instance()->video_timeline->sync_session_state();
1177 if (_session->dirty()) {
1178 vector<string> actions;
1179 actions.push_back (_("Don't quit"));
1180 actions.push_back (_("Just quit"));
1181 actions.push_back (_("Save and quit"));
1182 switch (ask_about_saving_session(actions)) {
1187 /* use the default name */
1188 if (save_state_canfail ("")) {
1189 /* failed - don't quit */
1190 MessageDialog msg (_main_window,
1191 string_compose (_("\
1192 %1 was unable to save your session.\n\n\
1193 If you still wish to quit, please use the\n\n\
1194 \"Just quit\" option."), PROGRAM_NAME));
1195 pop_back_splash(msg);
1205 second_connection.disconnect ();
1206 point_one_second_connection.disconnect ();
1207 point_zero_something_second_connection.disconnect();
1208 fps_connection.disconnect();
1211 delete ARDOUR_UI::instance()->video_timeline;
1212 ARDOUR_UI::instance()->video_timeline = NULL;
1213 stop_video_server();
1215 /* Save state before deleting the session, as that causes some
1216 windows to be destroyed before their visible state can be
1219 save_ardour_state ();
1221 close_all_dialogs ();
1224 _session->set_clean ();
1225 _session->remove_pending_capture_state ();
1230 halt_connection.disconnect ();
1231 AudioEngine::instance()->stop ();
1232 #ifdef WINDOWS_VST_SUPPORT
1233 fst_stop_threading();
1239 ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
1241 ArdourDialog window (_("Unsaved Session"));
1242 Gtk::HBox dhbox; // the hbox for the image and text
1243 Gtk::Label prompt_label;
1244 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
1248 assert (actions.size() >= 3);
1250 window.add_button (actions[0], RESPONSE_REJECT);
1251 window.add_button (actions[1], RESPONSE_APPLY);
1252 window.add_button (actions[2], RESPONSE_ACCEPT);
1254 window.set_default_response (RESPONSE_ACCEPT);
1256 Gtk::Button noquit_button (msg);
1257 noquit_button.set_name ("EditorGTKButton");
1261 if (_session->snap_name() == _session->name()) {
1262 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?"),
1263 _session->snap_name());
1265 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?"),
1266 _session->snap_name());
1269 prompt_label.set_text (prompt);
1270 prompt_label.set_name (X_("PrompterLabel"));
1271 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
1273 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
1274 dhbox.set_homogeneous (false);
1275 dhbox.pack_start (*dimage, false, false, 5);
1276 dhbox.pack_start (prompt_label, true, false, 5);
1277 window.get_vbox()->pack_start (dhbox);
1279 window.set_name (_("Prompter"));
1280 window.set_modal (true);
1281 window.set_resizable (false);
1284 prompt_label.show();
1289 ResponseType r = (ResponseType) window.run();
1294 case RESPONSE_ACCEPT: // save and get out of here
1296 case RESPONSE_APPLY: // get out of here
1307 ARDOUR_UI::every_second ()
1310 update_xrun_count ();
1311 update_buffer_load ();
1312 update_disk_space ();
1313 update_timecode_format ();
1314 update_peak_thread_work ();
1316 if (nsm && nsm->is_active ()) {
1319 if (!_was_dirty && _session->dirty ()) {
1323 else if (_was_dirty && !_session->dirty ()){
1331 ARDOUR_UI::every_point_one_seconds ()
1333 // TODO get rid of this..
1334 // ShuttleControl is updated directly via TransportStateChange signal
1338 ARDOUR_UI::every_point_zero_something_seconds ()
1340 // august 2007: actual update frequency: 25Hz (40ms), not 100Hz
1342 if (editor_meter && UIConfiguration::instance().get_show_editor_meter()) {
1343 float mpeak = editor_meter->update_meters();
1344 if (mpeak > editor_meter_max_peak) {
1345 if (mpeak >= UIConfiguration::instance().get_meter_peak()) {
1346 editor_meter_peak_display.set_active_state ( Gtkmm2ext::ExplicitActive );
1353 ARDOUR_UI::set_fps_timeout_connection ()
1355 unsigned int interval = 40;
1356 if (!_session) return;
1357 if (_session->timecode_frames_per_second() != 0) {
1358 /* ideally we'll use a select() to sleep and not accumulate
1359 * idle time to provide a regular periodic signal.
1360 * See linux_vst_gui_support.cc 'elapsed_time_ms'.
1361 * However, that'll require a dedicated thread and cross-thread
1362 * signals to the GUI Thread..
1364 interval = floor(500. /* update twice per FPS, since Glib::signal_timeout is very irregular */
1365 * _session->frame_rate() / _session->nominal_frame_rate()
1366 / _session->timecode_frames_per_second()
1368 #ifdef PLATFORM_WINDOWS
1369 // the smallest windows scheduler time-slice is ~15ms.
1370 // periodic GUI timeouts shorter than that will cause
1371 // WaitForSingleObject to spinlock (100% of one CPU Core)
1372 // and gtk never enters idle mode.
1373 // also changing timeBeginPeriod(1) does not affect that in
1374 // any beneficial way, so we just limit the max rate for now.
1375 interval = std::max(30u, interval); // at most ~33Hz.
1377 interval = std::max(8u, interval); // at most 120Hz.
1380 fps_connection.disconnect();
1381 Timers::set_fps_interval (interval);
1385 ARDOUR_UI::update_sample_rate (framecnt_t)
1389 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
1391 if (!AudioEngine::instance()->connected()) {
1393 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1397 framecnt_t rate = AudioEngine::instance()->sample_rate();
1400 /* no sample rate available */
1401 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1404 if (fmod (rate, 1000.0) != 0.0) {
1405 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
1406 (float) rate / 1000.0f,
1407 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1409 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
1411 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1415 sample_rate_label.set_markup (buf);
1419 ARDOUR_UI::update_format ()
1422 format_label.set_text ("");
1427 s << _("File:") << X_(" <span foreground=\"green\">");
1429 switch (_session->config.get_native_file_header_format ()) {
1461 switch (_session->config.get_native_file_data_format ()) {
1475 format_label.set_markup (s.str ());
1479 ARDOUR_UI::update_xrun_count ()
1483 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1484 should also be changed.
1488 const unsigned int x = _session->get_xrun_count ();
1490 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">>10K</span>"), X_("red"));
1492 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">%u</span>"), x > 0 ? X_("red") : X_("green"), x);
1495 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">?</span>"), X_("yellow"));
1497 xrun_label.set_markup (buf);
1498 set_tip (xrun_label, _("Audio dropouts. Shift+click to reset"));
1502 ARDOUR_UI::update_cpu_load ()
1506 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1507 should also be changed.
1510 double const c = AudioEngine::instance()->get_dsp_load ();
1511 snprintf (buf, sizeof (buf), _("DSP: <span foreground=\"%s\">%5.1f%%</span>"), c >= 90 ? X_("red") : X_("green"), c);
1512 cpu_load_label.set_markup (buf);
1516 ARDOUR_UI::update_peak_thread_work ()
1519 const int c = SourceFactory::peak_work_queue_length ();
1521 snprintf (buf, sizeof (buf), _("PkBld: <span foreground=\"%s\">%d</span>"), c >= 2 ? X_("red") : X_("green"), c);
1522 peak_thread_work_label.set_markup (buf);
1524 peak_thread_work_label.set_markup (X_(""));
1529 ARDOUR_UI::update_buffer_load ()
1533 uint32_t const playback = _session ? _session->playback_load () : 100;
1534 uint32_t const capture = _session ? _session->capture_load () : 100;
1536 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1537 should also be changed.
1543 _("Buffers: <span foreground=\"green\">p:</span><span foreground=\"%s\">%" PRIu32 "%%</span> "
1544 "<span foreground=\"green\">c:</span><span foreground=\"%s\">%" PRIu32 "%%</span>"),
1545 playback <= 5 ? X_("red") : X_("green"),
1547 capture <= 5 ? X_("red") : X_("green"),
1551 buffer_load_label.set_markup (buf);
1553 buffer_load_label.set_text ("");
1558 ARDOUR_UI::count_recenabled_streams (Route& route)
1560 Track* track = dynamic_cast<Track*>(&route);
1561 if (track && track->record_enabled()) {
1562 rec_enabled_streams += track->n_inputs().n_total();
1567 ARDOUR_UI::update_disk_space()
1569 if (_session == 0) {
1573 boost::optional<framecnt_t> opt_frames = _session->available_capture_duration();
1575 framecnt_t fr = _session->frame_rate();
1578 /* skip update - no SR available */
1583 /* Available space is unknown */
1584 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">Unknown</span>"));
1585 } else if (opt_frames.get_value_or (0) == max_framecnt) {
1586 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">24hrs+</span>"));
1588 rec_enabled_streams = 0;
1589 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams, false);
1591 framecnt_t frames = opt_frames.get_value_or (0);
1593 if (rec_enabled_streams) {
1594 frames /= rec_enabled_streams;
1601 hrs = frames / (fr * 3600);
1604 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">>24 hrs</span>"));
1606 frames -= hrs * fr * 3600;
1607 mins = frames / (fr * 60);
1608 frames -= mins * fr * 60;
1611 bool const low = (hrs == 0 && mins <= 30);
1615 _("Disk: <span foreground=\"%s\">%02dh:%02dm:%02ds</span>"),
1616 low ? X_("red") : X_("green"),
1622 disk_space_label.set_markup (buf);
1626 ARDOUR_UI::update_timecode_format ()
1632 TimecodeSlave* tcslave;
1633 SyncSource sync_src = Config->get_sync_source();
1635 if ((sync_src == LTC || sync_src == MTC) && (tcslave = dynamic_cast<TimecodeSlave*>(_session->slave())) != 0) {
1636 matching = (tcslave->apparent_timecode_format() == _session->config.get_timecode_format());
1641 snprintf (buf, sizeof (buf), S_("Timecode|TC: <span foreground=\"%s\">%s</span>"),
1642 matching ? X_("green") : X_("red"),
1643 Timecode::timecode_format_name (_session->config.get_timecode_format()).c_str());
1645 snprintf (buf, sizeof (buf), "TC: n/a");
1648 timecode_format_label.set_markup (buf);
1652 ARDOUR_UI::update_wall_clock ()
1656 static int last_min = -1;
1659 tm_now = localtime (&now);
1660 if (last_min != tm_now->tm_min) {
1662 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1663 wall_clock_label.set_text (buf);
1664 last_min = tm_now->tm_min;
1671 ARDOUR_UI::open_recent_session ()
1673 bool can_return = (_session != 0);
1675 SessionDialog recent_session_dialog;
1679 ResponseType r = (ResponseType) recent_session_dialog.run ();
1682 case RESPONSE_ACCEPT:
1686 recent_session_dialog.hide();
1693 recent_session_dialog.hide();
1697 std::string path = recent_session_dialog.session_folder();
1698 std::string state = recent_session_dialog.session_name (should_be_new);
1700 if (should_be_new == true) {
1704 _session_is_new = false;
1706 if (load_session (path, state) == 0) {
1715 ARDOUR_UI::check_audioengine (Gtk::Window& parent)
1717 if (!AudioEngine::instance()->connected()) {
1718 MessageDialog msg (parent, string_compose (
1719 _("%1 is not connected to any audio backend.\n"
1720 "You cannot open or close sessions in this condition"),
1722 pop_back_splash (msg);
1730 ARDOUR_UI::open_session ()
1732 if (!check_audioengine (_main_window)) {
1736 /* ardour sessions are folders */
1737 Gtk::FileChooserDialog open_session_selector(_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1738 open_session_selector.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1739 open_session_selector.add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1740 open_session_selector.set_default_response(Gtk::RESPONSE_ACCEPT);
1743 string session_parent_dir = Glib::path_get_dirname(_session->path());
1744 open_session_selector.set_current_folder(session_parent_dir);
1746 open_session_selector.set_current_folder(Config->get_default_session_parent_dir());
1749 Gtkmm2ext::add_volume_shortcuts (open_session_selector);
1751 /* add_shortcut_folder throws an exception if the folder being added already has a shortcut */
1752 string default_session_folder = Config->get_default_session_parent_dir();
1753 open_session_selector.add_shortcut_folder (default_session_folder);
1755 catch (Glib::Error & e) {
1756 std::cerr << "open_session_selector.add_shortcut_folder() threw Glib::Error " << e.what() << std::endl;
1759 FileFilter session_filter;
1760 session_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::statefile_suffix));
1761 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1762 open_session_selector.add_filter (session_filter);
1763 open_session_selector.set_filter (session_filter);
1765 int response = open_session_selector.run();
1766 open_session_selector.hide ();
1768 if (response == Gtk::RESPONSE_CANCEL) {
1772 string session_path = open_session_selector.get_filename();
1776 if (session_path.length() > 0) {
1777 if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1778 _session_is_new = isnew;
1779 load_session (path, name);
1785 ARDOUR_UI::session_add_mixed_track (
1786 const ChanCount& input,
1787 const ChanCount& output,
1788 RouteGroup* route_group,
1790 const string& name_template,
1792 PluginInfoPtr instrument)
1794 list<boost::shared_ptr<MidiTrack> > tracks;
1796 if (_session == 0) {
1797 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1802 tracks = _session->new_midi_track (input, output, instrument, ARDOUR::Normal, route_group, how_many, name_template);
1804 if (tracks.size() != how_many) {
1805 error << string_compose(P_("could not create %1 new mixed track", "could not create %1 new mixed tracks", how_many), how_many) << endmsg;
1810 display_insufficient_ports_message ();
1815 for (list<boost::shared_ptr<MidiTrack> >::iterator i = tracks.begin(); i != tracks.end(); ++i) {
1816 (*i)->set_strict_io (true);
1822 ARDOUR_UI::session_add_midi_bus (
1823 RouteGroup* route_group,
1825 const string& name_template,
1827 PluginInfoPtr instrument)
1831 if (_session == 0) {
1832 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1837 routes = _session->new_midi_route (route_group, how_many, name_template, instrument);
1838 if (routes.size() != how_many) {
1839 error << string_compose(P_("could not create %1 new Midi Bus", "could not create %1 new Midi Busses", how_many), how_many) << endmsg;
1844 display_insufficient_ports_message ();
1849 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
1850 (*i)->set_strict_io (true);
1856 ARDOUR_UI::session_add_midi_route (
1858 RouteGroup* route_group,
1860 const string& name_template,
1862 PluginInfoPtr instrument)
1864 ChanCount one_midi_channel;
1865 one_midi_channel.set (DataType::MIDI, 1);
1868 session_add_mixed_track (one_midi_channel, one_midi_channel, route_group, how_many, name_template, strict_io, instrument);
1870 session_add_midi_bus (route_group, how_many, name_template, strict_io, instrument);
1875 ARDOUR_UI::session_add_audio_route (
1877 int32_t input_channels,
1878 int32_t output_channels,
1879 ARDOUR::TrackMode mode,
1880 RouteGroup* route_group,
1882 string const & name_template,
1886 list<boost::shared_ptr<AudioTrack> > tracks;
1889 if (_session == 0) {
1890 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1896 tracks = _session->new_audio_track (input_channels, output_channels, mode, route_group, how_many, name_template);
1898 if (tracks.size() != how_many) {
1899 error << string_compose (P_("could not create %1 new audio track", "could not create %1 new audio tracks", how_many), how_many)
1905 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template);
1907 if (routes.size() != how_many) {
1908 error << string_compose (P_("could not create %1 new audio bus", "could not create %1 new audio busses", how_many), how_many)
1915 display_insufficient_ports_message ();
1920 for (list<boost::shared_ptr<AudioTrack> >::iterator i = tracks.begin(); i != tracks.end(); ++i) {
1921 (*i)->set_strict_io (true);
1923 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
1924 (*i)->set_strict_io (true);
1930 ARDOUR_UI::display_insufficient_ports_message ()
1932 MessageDialog msg (_main_window,
1933 string_compose (_("There are insufficient ports available\n\
1934 to create a new track or bus.\n\
1935 You should save %1, exit and\n\
1936 restart with more ports."), PROGRAM_NAME));
1937 pop_back_splash (msg);
1942 ARDOUR_UI::transport_goto_start ()
1945 _session->goto_start();
1947 /* force displayed area in editor to start no matter
1948 what "follow playhead" setting is.
1952 editor->center_screen (_session->current_start_frame ());
1958 ARDOUR_UI::transport_goto_zero ()
1961 _session->request_locate (0);
1963 /* force displayed area in editor to start no matter
1964 what "follow playhead" setting is.
1968 editor->reset_x_origin (0);
1974 ARDOUR_UI::transport_goto_wallclock ()
1976 if (_session && editor) {
1983 localtime_r (&now, &tmnow);
1985 framecnt_t frame_rate = _session->frame_rate();
1987 if (frame_rate == 0) {
1988 /* no frame rate available */
1992 frames = tmnow.tm_hour * (60 * 60 * frame_rate);
1993 frames += tmnow.tm_min * (60 * frame_rate);
1994 frames += tmnow.tm_sec * frame_rate;
1996 _session->request_locate (frames, _session->transport_rolling ());
1998 /* force displayed area in editor to start no matter
1999 what "follow playhead" setting is.
2003 editor->center_screen (frames);
2009 ARDOUR_UI::transport_goto_end ()
2012 framepos_t const frame = _session->current_end_frame();
2013 _session->request_locate (frame);
2015 /* force displayed area in editor to start no matter
2016 what "follow playhead" setting is.
2020 editor->center_screen (frame);
2026 ARDOUR_UI::transport_stop ()
2032 if (_session->is_auditioning()) {
2033 _session->cancel_audition ();
2037 _session->request_stop (false, true);
2040 /** Check if any tracks are record enabled. If none are, record enable all of them.
2041 * @return true if track record-enabled status was changed, false otherwise.
2044 ARDOUR_UI::trx_record_enable_all_tracks ()
2050 boost::shared_ptr<RouteList> rl = _session->get_tracks ();
2051 bool none_record_enabled = true;
2053 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
2054 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*r);
2057 if (t->record_enabled()) {
2058 none_record_enabled = false;
2063 if (none_record_enabled) {
2064 _session->set_record_enabled (rl, true, Session::rt_cleanup);
2067 return none_record_enabled;
2071 ARDOUR_UI::transport_record (bool roll)
2074 switch (_session->record_status()) {
2075 case Session::Disabled:
2076 if (_session->ntracks() == 0) {
2077 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."));
2081 if (Profile->get_trx()) {
2082 roll = trx_record_enable_all_tracks ();
2084 _session->maybe_enable_record ();
2089 case Session::Recording:
2091 _session->request_stop();
2093 _session->disable_record (false, true);
2097 case Session::Enabled:
2098 _session->disable_record (false, true);
2104 ARDOUR_UI::transport_roll ()
2110 if (_session->is_auditioning()) {
2115 if (_session->config.get_external_sync()) {
2116 switch (Config->get_sync_source()) {
2120 /* transport controlled by the master */
2126 bool rolling = _session->transport_rolling();
2128 if (_session->get_play_loop()) {
2130 /* If loop playback is not a mode, then we should cancel
2131 it when this action is requested. If it is a mode
2132 we just leave it in place.
2135 if (!Config->get_loop_is_mode()) {
2136 /* XXX it is not possible to just leave seamless loop and keep
2137 playing at present (nov 4th 2009)
2139 if (!Config->get_seamless_loop()) {
2140 /* stop loop playback and stop rolling */
2141 _session->request_play_loop (false, true);
2142 } else if (rolling) {
2143 /* stop loop playback but keep rolling */
2144 _session->request_play_loop (false, false);
2148 } else if (_session->get_play_range () ) {
2149 /* stop playing a range if we currently are */
2150 _session->request_play_range (0, true);
2154 _session->request_transport_speed (1.0f);
2159 ARDOUR_UI::get_smart_mode() const
2161 return ( editor->get_smart_mode() );
2166 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
2172 if (_session->is_auditioning()) {
2173 _session->cancel_audition ();
2177 if (_session->config.get_external_sync()) {
2178 switch (Config->get_sync_source()) {
2182 /* transport controlled by the master */
2187 bool rolling = _session->transport_rolling();
2188 bool affect_transport = true;
2190 if (rolling && roll_out_of_bounded_mode) {
2191 /* drop out of loop/range playback but leave transport rolling */
2192 if (_session->get_play_loop()) {
2193 if (_session->actively_recording()) {
2195 /* just stop using the loop, then actually stop
2198 _session->request_play_loop (false, affect_transport);
2201 if (Config->get_seamless_loop()) {
2202 /* the disk buffers contain copies of the loop - we can't
2203 just keep playing, so stop the transport. the user
2204 can restart as they wish.
2206 affect_transport = true;
2208 /* disk buffers are normal, so we can keep playing */
2209 affect_transport = false;
2211 _session->request_play_loop (false, affect_transport);
2213 } else if (_session->get_play_range ()) {
2214 affect_transport = false;
2215 _session->request_play_range (0, true);
2219 if (affect_transport) {
2221 _session->request_stop (with_abort, true);
2223 /* the only external sync condition we can be in here
2224 * would be Engine (JACK) sync, in which case we still
2228 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
2229 _session->request_play_range (&editor->get_selection().time, true);
2230 _session->set_requested_return_frame( editor->get_selection().time.front().start ); //force an auto-return here
2232 _session->request_transport_speed (1.0f);
2238 ARDOUR_UI::toggle_session_auto_loop ()
2244 Location * looploc = _session->locations()->auto_loop_location();
2250 if (_session->get_play_loop()) {
2252 /* looping enabled, our job is to disable it */
2254 _session->request_play_loop (false);
2258 /* looping not enabled, our job is to enable it.
2260 loop-is-NOT-mode: this action always starts the transport rolling.
2261 loop-IS-mode: this action simply sets the loop play mechanism, but
2262 does not start transport.
2264 if (Config->get_loop_is_mode()) {
2265 _session->request_play_loop (true, false);
2267 _session->request_play_loop (true, true);
2271 //show the loop markers
2272 looploc->set_hidden (false, this);
2276 ARDOUR_UI::transport_play_selection ()
2282 editor->play_selection ();
2286 ARDOUR_UI::transport_play_preroll ()
2291 editor->play_with_preroll ();
2295 ARDOUR_UI::transport_rewind (int option)
2297 float current_transport_speed;
2300 current_transport_speed = _session->transport_speed();
2302 if (current_transport_speed >= 0.0f) {
2305 _session->request_transport_speed (-1.0f);
2308 _session->request_transport_speed (-4.0f);
2311 _session->request_transport_speed (-0.5f);
2316 _session->request_transport_speed (current_transport_speed * 1.5f);
2322 ARDOUR_UI::transport_forward (int option)
2328 float current_transport_speed = _session->transport_speed();
2330 if (current_transport_speed <= 0.0f) {
2333 _session->request_transport_speed (1.0f);
2336 _session->request_transport_speed (4.0f);
2339 _session->request_transport_speed (0.5f);
2344 _session->request_transport_speed (current_transport_speed * 1.5f);
2349 ARDOUR_UI::toggle_record_enable (uint32_t rid)
2355 boost::shared_ptr<Route> r;
2357 if ((r = _session->route_by_remote_id (rid)) != 0) {
2359 boost::shared_ptr<Track> t;
2361 if ((t = boost::dynamic_pointer_cast<Track>(r)) != 0) {
2362 t->set_record_enabled (!t->record_enabled(), Controllable::UseGroup);
2368 ARDOUR_UI::map_transport_state ()
2371 auto_loop_button.unset_active_state ();
2372 play_selection_button.unset_active_state ();
2373 roll_button.unset_active_state ();
2374 stop_button.set_active_state (Gtkmm2ext::ExplicitActive);
2378 shuttle_box->map_transport_state ();
2380 float sp = _session->transport_speed();
2386 if (_session->get_play_range()) {
2388 play_selection_button.set_active_state (Gtkmm2ext::ExplicitActive);
2389 roll_button.unset_active_state ();
2390 auto_loop_button.unset_active_state ();
2392 } else if (_session->get_play_loop ()) {
2394 auto_loop_button.set_active (true);
2395 play_selection_button.set_active (false);
2396 if (Config->get_loop_is_mode()) {
2397 roll_button.set_active (true);
2399 roll_button.set_active (false);
2404 roll_button.set_active (true);
2405 play_selection_button.set_active (false);
2406 auto_loop_button.set_active (false);
2409 if (UIConfiguration::instance().get_follow_edits() && !_session->config.get_external_sync()) {
2410 /* light up both roll and play-selection if they are joined */
2411 roll_button.set_active (true);
2412 play_selection_button.set_active (true);
2415 stop_button.set_active (false);
2419 stop_button.set_active (true);
2420 roll_button.set_active (false);
2421 play_selection_button.set_active (false);
2422 if (Config->get_loop_is_mode ()) {
2423 auto_loop_button.set_active (_session->get_play_loop());
2425 auto_loop_button.set_active (false);
2427 update_disk_space ();
2432 ARDOUR_UI::blink_handler (bool blink_on)
2434 transport_rec_enable_blink (blink_on);
2435 solo_blink (blink_on);
2436 sync_blink (blink_on);
2437 audition_blink (blink_on);
2438 feedback_blink (blink_on);
2439 error_blink (blink_on);
2443 ARDOUR_UI::update_clocks ()
2445 if (!_session) return;
2447 if (editor && !editor->dragging_playhead()) {
2448 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD)); /* EMIT_SIGNAL */
2453 ARDOUR_UI::start_clocking ()
2455 if (UIConfiguration::instance().get_super_rapid_clock_update()) {
2456 clock_signal_connection = Timers::fps_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2458 clock_signal_connection = Timers::rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2463 ARDOUR_UI::stop_clocking ()
2465 clock_signal_connection.disconnect ();
2469 ARDOUR_UI::save_as_progress_update (float fraction, int64_t cnt, int64_t total, Gtk::Label* label, Gtk::ProgressBar* bar)
2473 snprintf (buf, sizeof (buf), _("Copied %" PRId64 " of %" PRId64), cnt, total);
2475 label->set_text (buf);
2476 bar->set_fraction (fraction);
2478 /* process events, redraws, etc. */
2480 while (gtk_events_pending()) {
2481 gtk_main_iteration ();
2484 return true; /* continue with save-as */
2488 ARDOUR_UI::save_session_as ()
2494 if (!save_as_dialog) {
2495 save_as_dialog = new SaveAsDialog;
2498 save_as_dialog->set_name (_session->name());
2500 int response = save_as_dialog->run ();
2502 save_as_dialog->hide ();
2505 case Gtk::RESPONSE_OK:
2514 sa.new_parent_folder = save_as_dialog->new_parent_folder ();
2515 sa.new_name = save_as_dialog->new_name ();
2516 sa.switch_to = save_as_dialog->switch_to();
2517 sa.copy_media = save_as_dialog->copy_media();
2518 sa.copy_external = save_as_dialog->copy_external();
2519 sa.include_media = save_as_dialog->include_media ();
2521 /* Only bother with a progress dialog if we're going to copy
2522 media into the save-as target. Without that choice, this
2523 will be very fast because we're only talking about a few kB's to
2524 perhaps a couple of MB's of data.
2527 ArdourDialog progress_dialog (_("Save As"), true);
2529 if (sa.include_media && sa.copy_media) {
2532 Gtk::ProgressBar progress_bar;
2534 progress_dialog.get_vbox()->pack_start (label);
2535 progress_dialog.get_vbox()->pack_start (progress_bar);
2537 progress_bar.show ();
2539 /* this signal will be emitted from within this, the calling thread,
2540 * after every file is copied. It provides information on percentage
2541 * complete (in terms of total data to copy), the number of files
2542 * copied so far, and the total number to copy.
2547 sa.Progress.connect_same_thread (c, boost::bind (&ARDOUR_UI::save_as_progress_update, this, _1, _2, _3, &label, &progress_bar));
2549 progress_dialog.show_all ();
2550 progress_dialog.present ();
2553 if (_session->save_as (sa)) {
2555 MessageDialog msg (string_compose (_("Save As failed: %1"), sa.failure_message));
2559 if (!sa.include_media) {
2560 unload_session (false);
2561 load_session (sa.final_session_folder_name, sa.new_name);
2566 ARDOUR_UI::quick_snapshot_session (bool switch_to_it)
2570 struct tm local_time;
2573 localtime_r (&n, &local_time);
2574 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2576 save_state (timebuf, switch_to_it);
2581 ARDOUR_UI::process_snapshot_session_prompter (ArdourPrompter& prompter, bool switch_to_it)
2585 prompter.get_result (snapname);
2587 bool do_save = (snapname.length() != 0);
2590 char illegal = Session::session_name_is_legal(snapname);
2592 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2593 "snapshot names may not contain a '%1' character"), illegal));
2599 vector<std::string> p;
2600 get_state_files_in_directory (_session->session_directory().root_path(), p);
2601 vector<string> n = get_file_names_no_extension (p);
2603 if (find (n.begin(), n.end(), snapname) != n.end()) {
2605 do_save = overwrite_file_dialog (prompter,
2606 _("Confirm Snapshot Overwrite"),
2607 _("A snapshot already exists with that name. Do you want to overwrite it?"));
2611 save_state (snapname, switch_to_it);
2621 /** Ask the user for the name of a new snapshot and then take it.
2625 ARDOUR_UI::snapshot_session (bool switch_to_it)
2627 ArdourPrompter prompter (true);
2629 prompter.set_name ("Prompter");
2630 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2632 prompter.set_title (_("Save as..."));
2633 prompter.set_prompt (_("New session name"));
2635 prompter.set_title (_("Take Snapshot"));
2636 prompter.set_prompt (_("Name of new snapshot"));
2640 prompter.set_initial_text (_session->snap_name());
2644 struct tm local_time;
2647 localtime_r (&n, &local_time);
2648 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2649 prompter.set_initial_text (timebuf);
2652 bool finished = false;
2654 switch (prompter.run()) {
2655 case RESPONSE_ACCEPT:
2657 finished = process_snapshot_session_prompter (prompter, switch_to_it);
2668 /** Ask the user for a new session name and then rename the session to it.
2672 ARDOUR_UI::rename_session ()
2678 ArdourPrompter prompter (true);
2681 prompter.set_name ("Prompter");
2682 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2683 prompter.set_title (_("Rename Session"));
2684 prompter.set_prompt (_("New session name"));
2687 switch (prompter.run()) {
2688 case RESPONSE_ACCEPT:
2690 prompter.get_result (name);
2692 bool do_rename = (name.length() != 0);
2695 char illegal = Session::session_name_is_legal (name);
2698 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2699 "session names may not contain a '%1' character"), illegal));
2704 switch (_session->rename (name)) {
2706 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
2707 msg.set_position (WIN_POS_MOUSE);
2715 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
2716 msg.set_position (WIN_POS_MOUSE);
2732 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2734 if (!_session || _session->deletion_in_progress()) {
2738 XMLNode* node = new XMLNode (X_("UI"));
2740 WM::Manager::instance().add_state (*node);
2742 node->add_child_nocopy (gui_object_state->get_state());
2744 _session->add_extra_xml (*node);
2746 if (export_video_dialog) {
2747 _session->add_extra_xml (export_video_dialog->get_state());
2750 save_state_canfail (name, switch_to_it);
2754 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2759 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2764 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2769 ARDOUR_UI::primary_clock_value_changed ()
2772 _session->request_locate (primary_clock->current_time ());
2777 ARDOUR_UI::big_clock_value_changed ()
2780 _session->request_locate (big_clock->current_time ());
2785 ARDOUR_UI::secondary_clock_value_changed ()
2788 _session->request_locate (secondary_clock->current_time ());
2793 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2795 if (_session == 0) {
2799 if (_session->step_editing()) {
2803 Session::RecordState const r = _session->record_status ();
2804 bool const h = _session->have_rec_enabled_track ();
2806 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2808 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2810 rec_button.set_active_state (Gtkmm2ext::Off);
2812 } else if (r == Session::Recording && h) {
2813 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2815 rec_button.unset_active_state ();
2820 ARDOUR_UI::process_save_template_prompter (ArdourPrompter& prompter)
2824 prompter.get_result (name);
2826 if (name.length()) {
2827 int failed = _session->save_template (name);
2829 if (failed == -2) { /* file already exists. */
2830 bool overwrite = overwrite_file_dialog (prompter,
2831 _("Confirm Template Overwrite"),
2832 _("A template already exists with that name. Do you want to overwrite it?"));
2835 _session->save_template (name, true);
2847 ARDOUR_UI::save_template ()
2849 ArdourPrompter prompter (true);
2851 if (!check_audioengine (_main_window)) {
2855 prompter.set_name (X_("Prompter"));
2856 prompter.set_title (_("Save Template"));
2857 prompter.set_prompt (_("Name for template:"));
2858 prompter.set_initial_text(_session->name() + _("-template"));
2859 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2861 bool finished = false;
2863 switch (prompter.run()) {
2864 case RESPONSE_ACCEPT:
2865 finished = process_save_template_prompter (prompter);
2876 ARDOUR_UI::edit_metadata ()
2878 SessionMetadataEditor dialog;
2879 dialog.set_session (_session);
2880 dialog.grab_focus ();
2885 ARDOUR_UI::import_metadata ()
2887 SessionMetadataImporter dialog;
2888 dialog.set_session (_session);
2893 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
2895 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2897 MessageDialog msg (str,
2899 Gtk::MESSAGE_WARNING,
2900 Gtk::BUTTONS_YES_NO,
2904 msg.set_name (X_("OpenExistingDialog"));
2905 msg.set_title (_("Open Existing Session"));
2906 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
2907 msg.set_position (Gtk::WIN_POS_CENTER);
2908 pop_back_splash (msg);
2910 switch (msg.run()) {
2919 ARDOUR_UI::build_session_from_dialog (SessionDialog& sd, const std::string& session_path, const std::string& session_name)
2921 BusProfile bus_profile;
2925 bus_profile.master_out_channels = 2;
2926 bus_profile.input_ac = AutoConnectPhysical;
2927 bus_profile.output_ac = AutoConnectMaster;
2928 bus_profile.requested_physical_in = 0; // use all available
2929 bus_profile.requested_physical_out = 0; // use all available
2933 /* get settings from advanced section of NSD */
2935 if (sd.create_master_bus()) {
2936 bus_profile.master_out_channels = (uint32_t) sd.master_channel_count();
2938 bus_profile.master_out_channels = 0;
2941 if (sd.connect_inputs()) {
2942 bus_profile.input_ac = AutoConnectPhysical;
2944 bus_profile.input_ac = AutoConnectOption (0);
2947 bus_profile.output_ac = AutoConnectOption (0);
2949 if (sd.connect_outputs ()) {
2950 if (sd.connect_outs_to_master()) {
2951 bus_profile.output_ac = AutoConnectMaster;
2952 } else if (sd.connect_outs_to_physical()) {
2953 bus_profile.output_ac = AutoConnectPhysical;
2957 bus_profile.requested_physical_in = (uint32_t) sd.input_limit_count();
2958 bus_profile.requested_physical_out = (uint32_t) sd.output_limit_count();
2961 if (build_session (session_path, session_name, bus_profile)) {
2969 ARDOUR_UI::load_from_application_api (const std::string& path)
2971 ARDOUR_COMMAND_LINE::session_name = path;
2972 /* Cancel SessionDialog if it's visible to make OSX delegates work.
2974 * ARDOUR_UI::starting connects app->ShouldLoad signal and then shows a SessionDialog
2976 * - ShouldLoad does not arrive in time, ARDOUR_COMMAND_LINE::session_name is empty:
2977 * -> ARDOUR_UI::get_session_parameters starts a SessionDialog.
2978 * - ShouldLoad signal arrives, this function is called and sets ARDOUR_COMMAND_LINE::session_name
2979 * -> SessionDialog is not displayed
2982 if (_session_dialog) {
2983 std::string session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
2984 std::string session_path = path;
2985 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_REGULAR)) {
2986 session_path = Glib::path_get_dirname (session_path);
2988 // signal the existing dialog in ARDOUR_UI::get_session_parameters()
2989 _session_dialog->set_provided_session (session_name, session_path);
2990 _session_dialog->response (RESPONSE_NONE);
2991 _session_dialog->hide();
2996 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2997 /* /path/to/foo => /path/to/foo, foo */
2998 rv = load_session (path, basename_nosuffix (path));
3000 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
3001 rv =load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
3004 // if load_session fails -> pop up SessionDialog.
3006 ARDOUR_COMMAND_LINE::session_name = "";
3008 if (get_session_parameters (true, false)) {
3014 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
3016 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
3018 string session_name;
3019 string session_path;
3020 string template_name;
3022 bool likely_new = false;
3023 bool cancel_not_quit;
3025 /* deal with any existing DIRTY session now, rather than later. don't
3026 * treat a non-dirty session this way, so that it stays visible
3027 * as we bring up the new session dialog.
3030 if (_session && ARDOUR_UI::instance()->video_timeline) {
3031 ARDOUR_UI::instance()->video_timeline->sync_session_state();
3034 /* if there is already a session, relabel the button
3035 on the SessionDialog so that we don't Quit directly
3037 cancel_not_quit = (_session != 0);
3039 if (_session && _session->dirty()) {
3040 if (unload_session (false)) {
3041 /* unload cancelled by user */
3044 ARDOUR_COMMAND_LINE::session_name = "";
3047 if (!load_template.empty()) {
3048 should_be_new = true;
3049 template_name = load_template;
3052 session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3053 session_path = ARDOUR_COMMAND_LINE::session_name;
3055 if (!session_path.empty()) {
3056 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_EXISTS)) {
3057 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_IS_REGULAR)) {
3058 /* session/snapshot file, change path to be dir */
3059 session_path = Glib::path_get_dirname (session_path);
3064 SessionDialog session_dialog (should_be_new, session_name, session_path, load_template, cancel_not_quit);
3066 _session_dialog = &session_dialog;
3069 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
3071 /* if they named a specific statefile, use it, otherwise they are
3072 just giving a session folder, and we want to use it as is
3073 to find the session.
3076 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
3078 if (suffix != string::npos) {
3079 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
3080 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
3081 session_name = Glib::path_get_basename (session_name);
3083 session_path = ARDOUR_COMMAND_LINE::session_name;
3084 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
3089 session_dialog.clear_given ();
3092 if (should_be_new || session_name.empty()) {
3093 /* need the dialog to get info from user */
3095 cerr << "run dialog\n";
3097 switch (session_dialog.run()) {
3098 case RESPONSE_ACCEPT:
3101 /* this is used for async * app->ShouldLoad(). */
3102 continue; // while loop
3105 if (quit_on_cancel) {
3106 // JE - Currently (July 2014) this section can only get reached if the
3107 // user quits from the main 'Session Setup' dialog (i.e. reaching this
3108 // point does NOT indicate an abnormal termination). Therefore, let's
3109 // behave gracefully (i.e. let's do some cleanup) before we call exit()
3111 pthread_cancel_all ();
3119 session_dialog.hide ();
3122 /* if we run the startup dialog again, offer more than just "new session" */
3124 should_be_new = false;
3126 session_name = session_dialog.session_name (likely_new);
3127 session_path = session_dialog.session_folder ();
3133 string::size_type suffix = session_name.find (statefile_suffix);
3135 if (suffix != string::npos) {
3136 session_name = session_name.substr (0, suffix);
3139 /* this shouldn't happen, but we catch it just in case it does */
3141 if (session_name.empty()) {
3145 if (session_dialog.use_session_template()) {
3146 template_name = session_dialog.session_template_name();
3147 _session_is_new = true;
3150 if (session_name[0] == G_DIR_SEPARATOR ||
3151 #ifdef PLATFORM_WINDOWS
3152 (session_name.length() > 3 && session_name[1] == ':' && session_name[2] == G_DIR_SEPARATOR)
3154 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
3155 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)
3160 /* absolute path or cwd-relative path specified for session name: infer session folder
3161 from what was given.
3164 session_path = Glib::path_get_dirname (session_name);
3165 session_name = Glib::path_get_basename (session_name);
3169 session_path = session_dialog.session_folder();
3171 char illegal = Session::session_name_is_legal (session_name);
3174 MessageDialog msg (session_dialog,
3175 string_compose (_("To ensure compatibility with various systems\n"
3176 "session names may not contain a '%1' character"),
3179 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3184 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
3187 if (likely_new && !nsm) {
3189 std::string existing = Glib::build_filename (session_path, session_name);
3191 if (!ask_about_loading_existing_session (existing)) {
3192 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3197 _session_is_new = false;
3202 pop_back_splash (session_dialog);
3203 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
3205 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3209 char illegal = Session::session_name_is_legal(session_name);
3212 pop_back_splash (session_dialog);
3213 MessageDialog msg (session_dialog, string_compose(_("To ensure compatibility with various systems\n"
3214 "session names may not contain a '%1' character"), illegal));
3216 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3220 _session_is_new = true;
3223 if (likely_new && template_name.empty()) {
3225 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3229 ret = load_session (session_path, session_name, template_name);
3232 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
3236 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
3237 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
3241 /* clear this to avoid endless attempts to load the
3245 ARDOUR_COMMAND_LINE::session_name = "";
3249 _session_dialog = NULL;
3255 ARDOUR_UI::close_session()
3257 if (!check_audioengine (_main_window)) {
3261 if (unload_session (true)) {
3265 ARDOUR_COMMAND_LINE::session_name = "";
3267 if (get_session_parameters (true, false)) {
3272 /** @param snap_name Snapshot name (without .ardour suffix).
3273 * @return -2 if the load failed because we are not connected to the AudioEngine.
3276 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
3278 Session *new_session;
3283 unload_status = unload_session ();
3285 if (unload_status < 0) {
3287 } else if (unload_status > 0) {
3293 session_loaded = false;
3295 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
3298 new_session = new Session (*AudioEngine::instance(), path, snap_name, 0, mix_template);
3301 /* this one is special */
3303 catch (AudioEngine::PortRegistrationFailure& err) {
3305 MessageDialog msg (err.what(),
3308 Gtk::BUTTONS_CLOSE);
3310 msg.set_title (_("Port Registration Error"));
3311 msg.set_secondary_text (_("Click the Close button to try again."));
3312 msg.set_position (Gtk::WIN_POS_CENTER);
3313 pop_back_splash (msg);
3316 int response = msg.run ();
3321 case RESPONSE_CANCEL:
3328 catch (SessionException e) {
3329 MessageDialog msg (string_compose(
3330 _("Session \"%1 (snapshot %2)\" did not load successfully: %3"),
3331 path, snap_name, e.what()),
3336 msg.set_title (_("Loading Error"));
3337 msg.set_position (Gtk::WIN_POS_CENTER);
3338 pop_back_splash (msg);
3350 MessageDialog msg (string_compose(
3351 _("Session \"%1 (snapshot %2)\" did not load successfully"),
3357 msg.set_title (_("Loading Error"));
3358 msg.set_position (Gtk::WIN_POS_CENTER);
3359 pop_back_splash (msg);
3371 list<string> const u = new_session->unknown_processors ();
3373 MissingPluginDialog d (_session, u);
3378 if (!new_session->writable()) {
3379 MessageDialog msg (_("This session has been opened in read-only mode.\n\nYou will not be able to record or save."),
3384 msg.set_title (_("Read-only Session"));
3385 msg.set_position (Gtk::WIN_POS_CENTER);
3386 pop_back_splash (msg);
3393 /* Now the session been created, add the transport controls */
3394 new_session->add_controllable(roll_controllable);
3395 new_session->add_controllable(stop_controllable);
3396 new_session->add_controllable(goto_start_controllable);
3397 new_session->add_controllable(goto_end_controllable);
3398 new_session->add_controllable(auto_loop_controllable);
3399 new_session->add_controllable(play_selection_controllable);
3400 new_session->add_controllable(rec_controllable);
3402 set_session (new_session);
3404 session_loaded = true;
3407 _session->set_clean ();
3410 #ifdef WINDOWS_VST_SUPPORT
3411 fst_stop_threading();
3415 Timers::TimerSuspender t;
3419 #ifdef WINDOWS_VST_SUPPORT
3420 fst_start_threading();
3429 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
3431 Session *new_session;
3434 session_loaded = false;
3435 x = unload_session ();
3443 _session_is_new = true;
3446 new_session = new Session (*AudioEngine::instance(), path, snap_name, &bus_profile);
3449 catch (SessionException e) {
3451 MessageDialog msg (string_compose(_("Could not create session in \"%1\": %2"), path, e.what()));
3452 msg.set_title (_("Loading Error"));
3453 msg.set_position (Gtk::WIN_POS_CENTER);
3454 pop_back_splash (msg);
3460 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
3461 msg.set_title (_("Loading Error"));
3462 msg.set_position (Gtk::WIN_POS_CENTER);
3463 pop_back_splash (msg);
3468 /* Give the new session the default GUI state, if such things exist */
3471 n = Config->instant_xml (X_("Editor"));
3473 n->remove_nodes_and_delete ("Selection"); // no not apply selection to new sessions.
3474 new_session->add_instant_xml (*n, false);
3476 n = Config->instant_xml (X_("Mixer"));
3478 new_session->add_instant_xml (*n, false);
3481 /* Put the playhead at 0 and scroll fully left */
3482 n = new_session->instant_xml (X_("Editor"));
3484 n->add_property (X_("playhead"), X_("0"));
3485 n->add_property (X_("left-frame"), X_("0"));
3488 set_session (new_session);
3490 session_loaded = true;
3492 new_session->save_state(new_session->name());
3498 ARDOUR_UI::launch_chat ()
3500 MessageDialog dialog(_("<b>Just ask and wait for an answer.\nIt may take from minutes to hours.</b>"), true);
3502 dialog.set_title (_("About the Chat"));
3503 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."));
3505 switch (dialog.run()) {
3508 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
3509 #elif defined PLATFORM_WINDOWS
3510 open_uri("http://webchat.freenode.net/?channels=ardour-windows");
3512 open_uri("http://webchat.freenode.net/?channels=ardour");
3521 ARDOUR_UI::launch_manual ()
3523 PBD::open_uri (Config->get_tutorial_manual_url());
3527 ARDOUR_UI::launch_reference ()
3529 PBD::open_uri (Config->get_reference_manual_url());
3533 ARDOUR_UI::launch_tracker ()
3535 PBD::open_uri ("http://tracker.ardour.org");
3539 ARDOUR_UI::launch_subscribe ()
3541 PBD::open_uri ("https://community.ardour.org/s/subscribe");
3545 ARDOUR_UI::launch_cheat_sheet ()
3548 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheat_sheet_osx.pdf");
3550 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheatsheet.pdf");
3555 ARDOUR_UI::launch_website ()
3557 PBD::open_uri ("http://ardour.org");
3561 ARDOUR_UI::launch_website_dev ()
3563 PBD::open_uri ("http://ardour.org/development.html");
3567 ARDOUR_UI::launch_forums ()
3569 PBD::open_uri ("https://community.ardour.org/forums");
3573 ARDOUR_UI::launch_howto_report ()
3575 PBD::open_uri ("http://ardour.org/reporting_bugs");
3579 ARDOUR_UI::loading_message (const std::string& msg)
3581 if (ARDOUR_COMMAND_LINE::no_splash) {
3589 splash->message (msg);
3593 ARDOUR_UI::show_splash ()
3597 splash = new Splash;
3607 ARDOUR_UI::hide_splash ()
3614 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title, const bool msg_delete)
3618 removed = rep.paths.size();
3621 MessageDialog msgd (_main_window,
3622 _("No files were ready for clean-up"),
3626 msgd.set_title (_("Clean-up"));
3627 msgd.set_secondary_text (_("If this seems suprising, \n\
3628 check for any existing snapshots.\n\
3629 These may still include regions that\n\
3630 require some unused files to continue to exist."));
3636 ArdourDialog results (_("Clean-up"), true, false);
3638 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
3639 CleanupResultsModelColumns() {
3643 Gtk::TreeModelColumn<std::string> visible_name;
3644 Gtk::TreeModelColumn<std::string> fullpath;
3648 CleanupResultsModelColumns results_columns;
3649 Glib::RefPtr<Gtk::ListStore> results_model;
3650 Gtk::TreeView results_display;
3652 results_model = ListStore::create (results_columns);
3653 results_display.set_model (results_model);
3654 results_display.append_column (list_title, results_columns.visible_name);
3656 results_display.set_name ("CleanupResultsList");
3657 results_display.set_headers_visible (true);
3658 results_display.set_headers_clickable (false);
3659 results_display.set_reorderable (false);
3661 Gtk::ScrolledWindow list_scroller;
3664 Gtk::HBox dhbox; // the hbox for the image and text
3665 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
3666 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
3668 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
3670 const string dead_directory = _session->session_directory().dead_path();
3673 %1 - number of files removed
3674 %2 - location of "dead"
3675 %3 - size of files affected
3676 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
3679 const char* bprefix;
3680 double space_adjusted = 0;
3682 if (rep.space < 1000) {
3684 space_adjusted = rep.space;
3685 } else if (rep.space < 1000000) {
3686 bprefix = _("kilo");
3687 space_adjusted = floorf((float)rep.space / 1000.0);
3688 } else if (rep.space < 1000000 * 1000) {
3689 bprefix = _("mega");
3690 space_adjusted = floorf((float)rep.space / (1000.0 * 1000.0));
3692 bprefix = _("giga");
3693 space_adjusted = floorf((float)rep.space / (1000.0 * 1000 * 1000.0));
3697 txt.set_markup (string_compose (P_("\
3698 The following file was deleted from %2,\n\
3699 releasing %3 %4bytes of disk space", "\
3700 The following %1 files were deleted from %2,\n\
3701 releasing %3 %4bytes of disk space", removed),
3702 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3704 txt.set_markup (string_compose (P_("\
3705 The following file was not in use and \n\
3706 has been moved to: %2\n\n\
3707 After a restart of %5\n\n\
3708 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3709 will release an additional %3 %4bytes of disk space.\n", "\
3710 The following %1 files were not in use and \n\
3711 have been moved to: %2\n\n\
3712 After a restart of %5\n\n\
3713 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3714 will release an additional %3 %4bytes of disk space.\n", removed),
3715 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3718 dhbox.pack_start (*dimage, true, false, 5);
3719 dhbox.pack_start (txt, true, false, 5);
3721 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
3722 TreeModel::Row row = *(results_model->append());
3723 row[results_columns.visible_name] = *i;
3724 row[results_columns.fullpath] = *i;
3727 list_scroller.add (results_display);
3728 list_scroller.set_size_request (-1, 150);
3729 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
3731 dvbox.pack_start (dhbox, true, false, 5);
3732 dvbox.pack_start (list_scroller, true, false, 5);
3733 ddhbox.pack_start (dvbox, true, false, 5);
3735 results.get_vbox()->pack_start (ddhbox, true, false, 5);
3736 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
3737 results.set_default_response (RESPONSE_CLOSE);
3738 results.set_position (Gtk::WIN_POS_MOUSE);
3740 results_display.show();
3741 list_scroller.show();
3748 //results.get_vbox()->show();
3749 results.set_resizable (false);
3756 ARDOUR_UI::cleanup ()
3758 if (_session == 0) {
3759 /* shouldn't happen: menu item is insensitive */
3764 MessageDialog checker (_("Are you sure you want to clean-up?"),
3766 Gtk::MESSAGE_QUESTION,
3769 checker.set_title (_("Clean-up"));
3771 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
3772 ALL undo/redo information will be lost if you clean-up.\n\
3773 Clean-up will move all unused files to a \"dead\" location."));
3775 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3776 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
3777 checker.set_default_response (RESPONSE_CANCEL);
3779 checker.set_name (_("CleanupDialog"));
3780 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3781 checker.set_position (Gtk::WIN_POS_MOUSE);
3783 switch (checker.run()) {
3784 case RESPONSE_ACCEPT:
3790 ARDOUR::CleanupReport rep;
3792 editor->prepare_for_cleanup ();
3794 /* do not allow flush until a session is reloaded */
3796 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3798 act->set_sensitive (false);
3801 if (_session->cleanup_sources (rep)) {
3802 editor->finish_cleanup ();
3806 editor->finish_cleanup ();
3809 display_cleanup_results (rep, _("Cleaned Files"), false);
3813 ARDOUR_UI::flush_trash ()
3815 if (_session == 0) {
3816 /* shouldn't happen: menu item is insensitive */
3820 ARDOUR::CleanupReport rep;
3822 if (_session->cleanup_trash_sources (rep)) {
3826 display_cleanup_results (rep, _("deleted file"), true);
3830 ARDOUR_UI::cleanup_peakfiles ()
3832 if (_session == 0) {
3833 /* shouldn't happen: menu item is insensitive */
3837 if (! _session->can_cleanup_peakfiles ()) {
3841 // get all region-views in this session
3843 TrackViewList empty;
3845 editor->get_regions_after(rs, (framepos_t) 0, empty);
3846 std::list<RegionView*> views = rs.by_layer();
3848 // remove displayed audio-region-views waveforms
3849 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
3850 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
3851 if (!arv) { continue ; }
3852 arv->delete_waves();
3855 // cleanup peak files:
3856 // - stop pending peakfile threads
3857 // - close peakfiles if any
3858 // - remove peak dir in session
3859 // - setup peakfiles (background thread)
3860 _session->cleanup_peakfiles ();
3862 // re-add waves to ARV
3863 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
3864 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
3865 if (!arv) { continue ; }
3866 arv->create_waves();
3871 ARDOUR_UI::setup_order_hint (AddRouteDialog::InsertAt place)
3873 uint32_t order_hint = UINT32_MAX;
3875 if (editor->get_selection().tracks.empty()) {
3880 we want the new routes to have their order keys set starting from
3881 the highest order key in the selection + 1 (if available).
3884 if (place == AddRouteDialog::AfterSelection) {
3885 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.back());
3887 order_hint = rtav->route()->order_key();
3890 } else if (place == AddRouteDialog::BeforeSelection) {
3891 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.front());
3893 order_hint = rtav->route()->order_key();
3895 } else if (place == AddRouteDialog::First) {
3898 /* leave order_hint at UINT32_MAX */
3901 if (order_hint == UINT32_MAX) {
3902 /** AddRouteDialog::Last or selection with first/last not a RouteTimeAxisView
3903 * not setting an order hint will place new routes last.
3908 _session->set_order_hint (order_hint);
3910 /* create a gap in the existing route order keys to accomodate new routes.*/
3911 boost::shared_ptr <RouteList> rd = _session->get_routes();
3912 for (RouteList::iterator ri = rd->begin(); ri != rd->end(); ++ri) {
3913 boost::shared_ptr<Route> rt (*ri);
3915 if (rt->is_monitor()) {
3919 if (rt->order_key () >= order_hint) {
3920 rt->set_order_key (rt->order_key () + add_route_dialog->count());
3926 ARDOUR_UI::start_duplicate_routes ()
3928 if (!duplicate_routes_dialog) {
3929 duplicate_routes_dialog = new DuplicateRouteDialog;
3932 if (duplicate_routes_dialog->restart (_session)) {
3936 duplicate_routes_dialog->present ();
3940 ARDOUR_UI::add_route (Gtk::Window* /* ignored */)
3948 if (add_route_dialog->is_visible()) {
3949 /* we're already doing this */
3953 ResponseType r = (ResponseType) add_route_dialog->run ();
3955 add_route_dialog->hide();
3958 case RESPONSE_ACCEPT:
3965 if ((count = add_route_dialog->count()) <= 0) {
3969 setup_order_hint(add_route_dialog->insert_at());
3970 string template_path = add_route_dialog->track_template();
3971 DisplaySuspender ds;
3973 if (!template_path.empty()) {
3974 if (add_route_dialog->name_template_is_default()) {
3975 _session->new_route_from_template (count, template_path, string());
3977 _session->new_route_from_template (count, template_path, add_route_dialog->name_template());
3982 ChanCount input_chan= add_route_dialog->channels ();
3983 ChanCount output_chan;
3984 string name_template = add_route_dialog->name_template ();
3985 PluginInfoPtr instrument = add_route_dialog->requested_instrument ();
3986 RouteGroup* route_group = add_route_dialog->route_group ();
3987 AutoConnectOption oac = Config->get_output_auto_connect();
3988 bool strict_io = add_route_dialog->use_strict_io ();
3990 if (oac & AutoConnectMaster) {
3991 output_chan.set (DataType::AUDIO, (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan.n_audio()));
3992 output_chan.set (DataType::MIDI, 0);
3994 output_chan = input_chan;
3997 /* XXX do something with name template */
3999 switch (add_route_dialog->type_wanted()) {
4000 case AddRouteDialog::AudioTrack:
4001 session_add_audio_track (input_chan.n_audio(), output_chan.n_audio(), add_route_dialog->mode(), route_group, count, name_template, strict_io);
4003 case AddRouteDialog::MidiTrack:
4004 session_add_midi_track (route_group, count, name_template, strict_io, instrument);
4006 case AddRouteDialog::MixedTrack:
4007 session_add_mixed_track (input_chan, output_chan, route_group, count, name_template, strict_io, instrument);
4009 case AddRouteDialog::AudioBus:
4010 session_add_audio_bus (input_chan.n_audio(), output_chan.n_audio(), route_group, count, name_template, strict_io);
4012 case AddRouteDialog::MidiBus:
4013 session_add_midi_bus (route_group, count, name_template, strict_io, instrument);
4019 ARDOUR_UI::add_lua_script ()
4025 LuaScriptInfoPtr spi;
4026 ScriptSelector ss ("Add Lua Session Script", LuaScriptInfo::Session);
4027 switch (ss.run ()) {
4028 case Gtk::RESPONSE_ACCEPT:
4036 std::string script = "";
4039 script = Glib::file_get_contents (spi->path);
4040 } catch (Glib::FileError e) {
4041 string msg = string_compose (_("Cannot read session script '%1': %2"), spi->path, e.what());
4042 MessageDialog am (msg);
4047 LuaScriptParamList lsp = LuaScriptParams::script_params (spi, "sess_params");
4048 std::vector<std::string> reg = _session->registered_lua_functions ();
4050 ScriptParameterDialog spd (_("Set Script Parameters"), spi, reg, lsp);
4051 switch (spd.run ()) {
4052 case Gtk::RESPONSE_ACCEPT:
4059 _session->register_lua_function (spd.name(), script, lsp);
4060 } catch (luabridge::LuaException const& e) {
4061 string msg = string_compose (_("Session script '%1' instantiation failed: %2"), spd.name(), e.what ());
4062 MessageDialog am (msg);
4064 } catch (SessionException e) {
4065 string msg = string_compose (_("Loading Session script '%1' failed: %2"), spd.name(), e.what ());
4066 MessageDialog am (msg);
4072 ARDOUR_UI::remove_lua_script ()
4077 if (_session->registered_lua_function_count () == 0) {
4078 string msg = _("There are no active Lua session scripts present in this session.");
4079 MessageDialog am (msg);
4084 std::vector<std::string> reg = _session->registered_lua_functions ();
4085 SessionScriptManager sm ("Remove Lua Session Script", reg);
4086 switch (sm.run ()) {
4087 case Gtk::RESPONSE_ACCEPT:
4093 _session->unregister_lua_function (sm.name());
4094 } catch (luabridge::LuaException const& e) {
4095 string msg = string_compose (_("Session script '%1' removal failed: %2"), sm.name(), e.what ());
4096 MessageDialog am (msg);
4102 ARDOUR_UI::stop_video_server (bool ask_confirm)
4104 if (!video_server_process && ask_confirm) {
4105 warning << string_compose (_("Video-Server was not launched by %1. The request to stop it is ignored."), PROGRAM_NAME) << endmsg;
4107 if (video_server_process) {
4109 ArdourDialog confirm (_("Stop Video-Server"), true);
4110 Label m (_("Do you really want to stop the Video Server?"));
4111 confirm.get_vbox()->pack_start (m, true, true);
4112 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
4113 confirm.add_button (_("Yes, Stop It"), Gtk::RESPONSE_ACCEPT);
4114 confirm.show_all ();
4115 if (confirm.run() == RESPONSE_CANCEL) {
4119 delete video_server_process;
4120 video_server_process =0;
4125 ARDOUR_UI::start_video_server_menu (Gtk::Window* float_window)
4127 ARDOUR_UI::start_video_server( float_window, true);
4131 ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg)
4137 if (ARDOUR_UI::instance()->video_timeline->check_server()) {
4138 if (video_server_process) {
4139 popup_error(_("The Video Server is already started."));
4141 popup_error(_("An external Video Server is configured and can be reached. Not starting a new instance."));
4147 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4149 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4151 VideoServerDialog *video_server_dialog = new VideoServerDialog (_session);
4153 video_server_dialog->set_transient_for (*float_window);
4156 if (!Config->get_show_video_server_dialog() && firsttime < 2) {
4157 video_server_dialog->hide();
4159 ResponseType r = (ResponseType) video_server_dialog->run ();
4160 video_server_dialog->hide();
4161 if (r != RESPONSE_ACCEPT) { return false; }
4162 if (video_server_dialog->show_again()) {
4163 Config->set_show_video_server_dialog(false);
4167 std::string icsd_exec = video_server_dialog->get_exec_path();
4168 std::string icsd_docroot = video_server_dialog->get_docroot();
4169 if (icsd_docroot.empty()) {
4170 #ifndef PLATFORM_WINDOWS
4171 icsd_docroot = X_("/");
4173 icsd_docroot = X_("C:\\");
4178 if (g_lstat (icsd_docroot.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode)) {
4179 warning << _("Specified docroot is not an existing directory.") << endmsg;
4182 #ifndef PLATFORM_WINDOWS
4183 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4184 || (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0 ) {
4185 warning << _("Given Video Server is not an executable file.") << endmsg;
4189 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4190 || (sb.st_mode & (S_IXUSR)) == 0 ) {
4191 warning << _("Given Video Server is not an executable file.") << endmsg;
4197 argp=(char**) calloc(9,sizeof(char*));
4198 argp[0] = strdup(icsd_exec.c_str());
4199 argp[1] = strdup("-P");
4200 argp[2] = (char*) calloc(16,sizeof(char)); snprintf(argp[2], 16, "%s", video_server_dialog->get_listenaddr().c_str());
4201 argp[3] = strdup("-p");
4202 argp[4] = (char*) calloc(6,sizeof(char)); snprintf(argp[4], 6, "%i", video_server_dialog->get_listenport());
4203 argp[5] = strdup("-C");
4204 argp[6] = (char*) calloc(6,sizeof(char)); snprintf(argp[6], 6, "%i", video_server_dialog->get_cachesize());
4205 argp[7] = strdup(icsd_docroot.c_str());
4207 stop_video_server();
4209 if (icsd_docroot == X_("/") || icsd_docroot == X_("C:\\")) {
4210 Config->set_video_advanced_setup(false);
4212 std::ostringstream osstream;
4213 osstream << "http://127.0.0.1:" << video_server_dialog->get_listenport() << "/";
4214 Config->set_video_server_url(osstream.str());
4215 Config->set_video_server_docroot(icsd_docroot);
4216 Config->set_video_advanced_setup(true);
4219 if (video_server_process) {
4220 delete video_server_process;
4223 video_server_process = new ARDOUR::SystemExec(icsd_exec, argp);
4224 if (video_server_process->start()) {
4225 warning << _("Cannot launch the video-server") << endmsg;
4228 int timeout = 120; // 6 sec
4229 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4230 Glib::usleep (50000);
4232 if (--timeout <= 0 || !video_server_process->is_running()) break;
4235 warning << _("Video-server was started but does not respond to requests...") << endmsg;
4237 if (!ARDOUR_UI::instance()->video_timeline->check_server_docroot()) {
4238 delete video_server_process;
4239 video_server_process = 0;
4247 ARDOUR_UI::add_video (Gtk::Window* float_window)
4253 if (!start_video_server(float_window, false)) {
4254 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4259 add_video_dialog->set_transient_for (*float_window);
4262 if (add_video_dialog->is_visible()) {
4263 /* we're already doing this */
4267 ResponseType r = (ResponseType) add_video_dialog->run ();
4268 add_video_dialog->hide();
4269 if (r != RESPONSE_ACCEPT) { return; }
4271 bool local_file, orig_local_file;
4272 std::string path = add_video_dialog->file_name(local_file);
4274 std::string orig_path = path;
4275 orig_local_file = local_file;
4277 bool auto_set_session_fps = add_video_dialog->auto_set_session_fps();
4279 if (local_file && !Glib::file_test(path, Glib::FILE_TEST_EXISTS)) {
4280 warning << string_compose(_("could not open %1"), path) << endmsg;
4283 if (!local_file && path.length() == 0) {
4284 warning << _("no video-file selected") << endmsg;
4288 std::string audio_from_video;
4289 bool detect_ltc = false;
4291 switch (add_video_dialog->import_option()) {
4292 case VTL_IMPORT_TRANSCODE:
4294 TranscodeVideoDialog *transcode_video_dialog;
4295 transcode_video_dialog = new TranscodeVideoDialog (_session, path);
4296 ResponseType r = (ResponseType) transcode_video_dialog->run ();
4297 transcode_video_dialog->hide();
4298 if (r != RESPONSE_ACCEPT) {
4299 delete transcode_video_dialog;
4303 audio_from_video = transcode_video_dialog->get_audiofile();
4305 if (!audio_from_video.empty() && transcode_video_dialog->detect_ltc()) {
4308 else if (!audio_from_video.empty()) {
4309 editor->embed_audio_from_video(
4311 video_timeline->get_offset(),
4312 (transcode_video_dialog->import_option() != VTL_IMPORT_NO_VIDEO)
4315 switch (transcode_video_dialog->import_option()) {
4316 case VTL_IMPORT_TRANSCODED:
4317 path = transcode_video_dialog->get_filename();
4320 case VTL_IMPORT_REFERENCE:
4323 delete transcode_video_dialog;
4326 delete transcode_video_dialog;
4330 case VTL_IMPORT_NONE:
4334 /* strip _session->session_directory().video_path() from video file if possible */
4335 if (local_file && !path.compare(0, _session->session_directory().video_path().size(), _session->session_directory().video_path())) {
4336 path=path.substr(_session->session_directory().video_path().size());
4337 if (path.at(0) == G_DIR_SEPARATOR) {
4338 path=path.substr(1);
4342 video_timeline->set_update_session_fps(auto_set_session_fps);
4344 if (video_timeline->video_file_info(path, local_file)) {
4345 XMLNode* node = new XMLNode(X_("Videotimeline"));
4346 node->add_property (X_("Filename"), path);
4347 node->add_property (X_("AutoFPS"), auto_set_session_fps?X_("1"):X_("0"));
4348 node->add_property (X_("LocalFile"), local_file?X_("1"):X_("0"));
4349 if (orig_local_file) {
4350 node->add_property (X_("OriginalVideoFile"), orig_path);
4352 node->remove_property (X_("OriginalVideoFile"));
4354 _session->add_extra_xml (*node);
4355 _session->set_dirty ();
4357 if (!audio_from_video.empty() && detect_ltc) {
4358 std::vector<LTCFileReader::LTCMap> ltc_seq;
4361 /* TODO ask user about TV standard (LTC alignment if any) */
4362 LTCFileReader ltcr (audio_from_video, video_timeline->get_video_file_fps());
4363 /* TODO ASK user which channel: 0 .. ltcr->channels() - 1 */
4365 ltc_seq = ltcr.read_ltc (/*channel*/ 0, /*max LTC frames to decode*/ 15);
4367 /* TODO seek near end of file, and read LTC until end.
4368 * if it fails to find any LTC frames, scan complete file
4370 * calculate drift of LTC compared to video-duration,
4371 * ask user for reference (timecode from start/mid/end)
4374 // LTCFileReader will have written error messages
4377 ::g_unlink(audio_from_video.c_str());
4379 if (ltc_seq.size() == 0) {
4380 PBD::error << _("No LTC detected, video will not be aligned.") << endmsg;
4382 /* the very first TC in the file is somteimes not aligned properly */
4383 int i = ltc_seq.size() -1;
4384 ARDOUR::frameoffset_t video_start_offset =
4385 _session->nominal_frame_rate() * (ltc_seq[i].timecode_sec - ltc_seq[i].framepos_sec);
4386 PBD::info << string_compose (_("Align video-start to %1 [samples]"), video_start_offset) << endmsg;
4387 video_timeline->set_offset(video_start_offset);
4391 _session->maybe_update_session_range(
4392 std::max(video_timeline->get_offset(), (ARDOUR::frameoffset_t) 0),
4393 std::max(video_timeline->get_offset() + video_timeline->get_duration(), (ARDOUR::frameoffset_t) 0));
4396 if (add_video_dialog->launch_xjadeo() && local_file) {
4397 editor->set_xjadeo_sensitive(true);
4398 editor->toggle_xjadeo_proc(1);
4400 editor->toggle_xjadeo_proc(0);
4402 editor->toggle_ruler_video(true);
4407 ARDOUR_UI::remove_video ()
4409 video_timeline->close_session();
4410 editor->toggle_ruler_video(false);
4413 video_timeline->set_offset_locked(false);
4414 video_timeline->set_offset(0);
4416 /* delete session state */
4417 XMLNode* node = new XMLNode(X_("Videotimeline"));
4418 _session->add_extra_xml(*node);
4419 node = new XMLNode(X_("Videomonitor"));
4420 _session->add_extra_xml(*node);
4421 node = new XMLNode(X_("Videoexport"));
4422 _session->add_extra_xml(*node);
4423 stop_video_server();
4427 ARDOUR_UI::flush_videotimeline_cache (bool localcacheonly)
4429 if (localcacheonly) {
4430 video_timeline->vmon_update();
4432 video_timeline->flush_cache();
4434 editor->queue_visual_videotimeline_update();
4438 ARDOUR_UI::export_video (bool range)
4440 if (ARDOUR::Config->get_show_video_export_info()) {
4441 ExportVideoInfobox infobox (_session);
4442 Gtk::ResponseType rv = (Gtk::ResponseType) infobox.run();
4443 if (infobox.show_again()) {
4444 ARDOUR::Config->set_show_video_export_info(false);
4447 case GTK_RESPONSE_YES:
4448 PBD::open_uri (ARDOUR::Config->get_reference_manual_url() + "/video-timeline/operations/#export");
4454 export_video_dialog->set_session (_session);
4455 export_video_dialog->apply_state(editor->get_selection().time, range);
4456 export_video_dialog->run ();
4457 export_video_dialog->hide ();
4461 ARDOUR_UI::mixer_settings () const
4466 node = _session->instant_xml(X_("Mixer"));
4468 node = Config->instant_xml(X_("Mixer"));
4472 node = new XMLNode (X_("Mixer"));
4479 ARDOUR_UI::main_window_settings () const
4484 node = _session->instant_xml(X_("Main"));
4486 node = Config->instant_xml(X_("Main"));
4490 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4491 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4496 node = new XMLNode (X_("Main"));
4503 ARDOUR_UI::editor_settings () const
4508 node = _session->instant_xml(X_("Editor"));
4510 node = Config->instant_xml(X_("Editor"));
4514 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4515 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4520 node = new XMLNode (X_("Editor"));
4527 ARDOUR_UI::keyboard_settings () const
4531 node = Config->extra_xml(X_("Keyboard"));
4534 node = new XMLNode (X_("Keyboard"));
4541 ARDOUR_UI::create_xrun_marker (framepos_t where)
4544 Location *location = new Location (*_session, where, where, _("xrun"), Location::IsMark);
4545 _session->locations()->add (location);
4550 ARDOUR_UI::halt_on_xrun_message ()
4552 cerr << "HALT on xrun\n";
4553 MessageDialog msg (_main_window, _("Recording was stopped because your system could not keep up."));
4558 ARDOUR_UI::xrun_handler (framepos_t where)
4564 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
4566 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
4567 create_xrun_marker(where);
4570 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
4571 halt_on_xrun_message ();
4576 ARDOUR_UI::disk_overrun_handler ()
4578 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
4580 if (!have_disk_speed_dialog_displayed) {
4581 have_disk_speed_dialog_displayed = true;
4582 MessageDialog* msg = new MessageDialog (_main_window, string_compose (_("\
4583 The disk system on your computer\n\
4584 was not able to keep up with %1.\n\
4586 Specifically, it failed to write data to disk\n\
4587 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
4588 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4594 /* TODO: this is getting elaborate enough to warrant being split into a dedicated class */
4595 static MessageDialog *scan_dlg = NULL;
4596 static ProgressBar *scan_pbar = NULL;
4597 static HBox *scan_tbox = NULL;
4598 static Gtk::Button *scan_timeout_button;
4601 ARDOUR_UI::cancel_plugin_scan ()
4603 PluginManager::instance().cancel_plugin_scan();
4607 ARDOUR_UI::cancel_plugin_timeout ()
4609 PluginManager::instance().cancel_plugin_timeout();
4610 scan_timeout_button->set_sensitive (false);
4614 ARDOUR_UI::plugin_scan_timeout (int timeout)
4616 if (!scan_dlg || !scan_dlg->is_mapped() || !scan_pbar) {
4620 scan_pbar->set_sensitive (false);
4621 scan_timeout_button->set_sensitive (true);
4622 scan_pbar->set_fraction ((float) timeout / (float) Config->get_vst_scan_timeout());
4625 scan_pbar->set_sensitive (false);
4626 scan_timeout_button->set_sensitive (false);
4632 ARDOUR_UI::plugin_scan_dialog (std::string type, std::string plugin, bool can_cancel)
4634 if (type == X_("closeme") && !(scan_dlg && scan_dlg->is_mapped())) {
4638 const bool cancelled = PluginManager::instance().cancelled();
4639 if (type != X_("closeme") && (!UIConfiguration::instance().get_show_plugin_scan_window()) && !_initial_verbose_plugin_scan) {
4640 if (cancelled && scan_dlg->is_mapped()) {
4645 if (cancelled || !can_cancel) {
4650 static Gtk::Button *cancel_button;
4652 scan_dlg = new MessageDialog("", false, MESSAGE_INFO, BUTTONS_NONE); // TODO manage
4653 VBox* vbox = scan_dlg->get_vbox();
4654 vbox->set_size_request(400,-1);
4655 scan_dlg->set_title (_("Scanning for plugins"));
4657 cancel_button = manage(new Gtk::Button(_("Cancel plugin scan")));
4658 cancel_button->set_name ("EditorGTKButton");
4659 cancel_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_scan) );
4660 cancel_button->show();
4662 scan_dlg->get_vbox()->pack_start ( *cancel_button, PACK_SHRINK);
4664 scan_tbox = manage( new HBox() );
4666 scan_timeout_button = manage(new Gtk::Button(_("Stop Timeout")));
4667 scan_timeout_button->set_name ("EditorGTKButton");
4668 scan_timeout_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_timeout) );
4669 scan_timeout_button->show();
4671 scan_pbar = manage(new ProgressBar());
4672 scan_pbar->set_orientation(Gtk::PROGRESS_RIGHT_TO_LEFT);
4673 scan_pbar->set_text(_("Scan Timeout"));
4676 scan_tbox->pack_start (*scan_pbar, PACK_EXPAND_WIDGET, 4);
4677 scan_tbox->pack_start (*scan_timeout_button, PACK_SHRINK, 4);
4679 scan_dlg->get_vbox()->pack_start (*scan_tbox, PACK_SHRINK, 4);
4682 assert(scan_dlg && scan_tbox && cancel_button);
4684 if (type == X_("closeme")) {
4688 scan_dlg->set_message(type + ": " + Glib::path_get_basename(plugin));
4691 if (!can_cancel || !cancelled) {
4692 scan_timeout_button->set_sensitive(false);
4694 cancel_button->set_sensitive(can_cancel && !cancelled);
4700 ARDOUR_UI::gui_idle_handler ()
4703 /* due to idle calls, gtk_events_pending() may always return true */
4704 while (gtk_events_pending() && --timeout) {
4705 gtk_main_iteration ();
4710 ARDOUR_UI::disk_underrun_handler ()
4712 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
4714 if (!have_disk_speed_dialog_displayed) {
4715 have_disk_speed_dialog_displayed = true;
4716 MessageDialog* msg = new MessageDialog (
4717 _main_window, string_compose (_("The disk system on your computer\n\
4718 was not able to keep up with %1.\n\
4720 Specifically, it failed to read data from disk\n\
4721 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
4722 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4728 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
4730 have_disk_speed_dialog_displayed = false;
4735 ARDOUR_UI::session_dialog (std::string msg)
4737 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
4741 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
4748 ARDOUR_UI::pending_state_dialog ()
4750 HBox* hbox = manage (new HBox());
4751 Image* image = manage (new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG));
4752 ArdourDialog dialog (_("Crash Recovery"), true);
4753 Label message (string_compose (_("\
4754 This session appears to have been in the\n\
4755 middle of recording when %1 or\n\
4756 the computer was shutdown.\n\
4758 %1 can recover any captured audio for\n\
4759 you, or it can ignore it. Please decide\n\
4760 what you would like to do.\n"), PROGRAM_NAME));
4761 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4762 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4763 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4764 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4765 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
4766 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
4767 dialog.set_default_response (RESPONSE_ACCEPT);
4768 dialog.set_position (WIN_POS_CENTER);
4773 switch (dialog.run ()) {
4774 case RESPONSE_ACCEPT:
4782 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
4784 HBox* hbox = new HBox();
4785 Image* image = new Image (Stock::DIALOG_WARNING, ICON_SIZE_DIALOG);
4786 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
4787 Label message (string_compose (_("\
4788 This session was created with a sample rate of %1 Hz, but\n\
4789 %2 is currently running at %3 Hz. If you load this session,\n\
4790 audio may be played at the wrong sample rate.\n"), desired, PROGRAM_NAME, actual));
4792 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4793 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4794 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4795 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4796 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
4797 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
4798 dialog.set_default_response (RESPONSE_ACCEPT);
4799 dialog.set_position (WIN_POS_CENTER);
4804 switch (dialog.run()) {
4805 case RESPONSE_ACCEPT:
4815 ARDOUR_UI::sr_mismatch_message (framecnt_t desired, framecnt_t actual)
4817 MessageDialog msg (string_compose (_("\
4818 This session was created with a sample rate of %1 Hz, but\n\
4819 %2 is currently running at %3 Hz.\n\
4820 Audio will be recorded and played at the wrong sample rate.\n\
4821 Re-Configure the Audio Engine in\n\
4822 Menu > Window > Audio/Midi Setup"),
4823 desired, PROGRAM_NAME, actual),
4825 Gtk::MESSAGE_WARNING);
4830 ARDOUR_UI::use_config ()
4832 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
4834 set_transport_controllable_state (*node);
4839 ARDOUR_UI::update_transport_clocks (framepos_t pos)
4841 if (UIConfiguration::instance().get_primary_clock_delta_edit_cursor()) {
4842 primary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
4844 primary_clock->set (pos);
4847 if (UIConfiguration::instance().get_secondary_clock_delta_edit_cursor()) {
4848 secondary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
4850 secondary_clock->set (pos);
4853 if (big_clock_window) {
4854 big_clock->set (pos);
4856 ARDOUR_UI::instance()->video_timeline->manual_seek_video_monitor(pos);
4860 ARDOUR_UI::step_edit_status_change (bool yn)
4862 // XXX should really store pre-step edit status of things
4863 // we make insensitive
4866 rec_button.set_active_state (Gtkmm2ext::ImplicitActive);
4867 rec_button.set_sensitive (false);
4869 rec_button.unset_active_state ();;
4870 rec_button.set_sensitive (true);
4875 ARDOUR_UI::record_state_changed ()
4877 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
4879 if (!_session || !big_clock_window) {
4880 /* why bother - the clock isn't visible */
4884 if (_session->record_status () == Session::Recording && _session->have_rec_enabled_track ()) {
4885 big_clock->set_active (true);
4887 big_clock->set_active (false);
4892 ARDOUR_UI::first_idle ()
4895 _session->allow_auto_play (true);
4899 editor->first_idle();
4902 Keyboard::set_can_save_keybindings (true);
4907 ARDOUR_UI::store_clock_modes ()
4909 XMLNode* node = new XMLNode(X_("ClockModes"));
4911 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
4912 XMLNode* child = new XMLNode (X_("Clock"));
4914 child->add_property (X_("name"), (*x)->name());
4915 child->add_property (X_("mode"), enum_2_string ((*x)->mode()));
4916 child->add_property (X_("on"), ((*x)->off() ? X_("no") : X_("yes")));
4918 node->add_child_nocopy (*child);
4921 _session->add_extra_xml (*node);
4922 _session->set_dirty ();
4925 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
4926 : Controllable (name), ui (u), type(tp)
4932 ARDOUR_UI::TransportControllable::set_value (double val, PBD::Controllable::GroupControlDisposition /*group_override*/)
4935 /* do nothing: these are radio-style actions */
4939 const char *action = 0;
4943 action = X_("Roll");
4946 action = X_("Stop");
4949 action = X_("GotoStart");
4952 action = X_("GotoEnd");
4955 action = X_("Loop");
4958 action = X_("PlaySelection");
4961 action = X_("Record");
4971 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
4979 ARDOUR_UI::TransportControllable::get_value (void) const
5006 ARDOUR_UI::setup_profile ()
5008 if (gdk_screen_width() < 1200 || getenv ("ARDOUR_NARROW_SCREEN")) {
5009 Profile->set_small_screen ();
5012 if (g_getenv ("TRX")) {
5013 Profile->set_trx ();
5016 if (g_getenv ("MIXBUS")) {
5017 Profile->set_mixbus ();
5022 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
5024 MissingFileDialog dialog (s, str, type);
5029 int result = dialog.run ();
5036 return 1; // quit entire session load
5039 result = dialog.get_action ();
5045 ARDOUR_UI::ambiguous_file (std::string file, std::vector<std::string> hits)
5047 AmbiguousFileDialog dialog (file, hits);
5054 return dialog.get_which ();
5057 /** Allocate our thread-local buffers */
5059 ARDOUR_UI::get_process_buffers ()
5061 _process_thread->get_buffers ();
5064 /** Drop our thread-local buffers */
5066 ARDOUR_UI::drop_process_buffers ()
5068 _process_thread->drop_buffers ();
5072 ARDOUR_UI::feedback_detected ()
5074 _feedback_exists = true;
5078 ARDOUR_UI::successful_graph_sort ()
5080 _feedback_exists = false;
5084 ARDOUR_UI::midi_panic ()
5087 _session->midi_panic();
5092 ARDOUR_UI::session_format_mismatch (std::string xml_path, std::string backup_path)
5094 const char* start_big = "<span size=\"x-large\" weight=\"bold\">";
5095 const char* end_big = "</span>";
5096 const char* start_mono = "<tt>";
5097 const char* end_mono = "</tt>";
5099 MessageDialog msg (string_compose (_("%4This is a session from an older version of %3%5\n\n"
5100 "%3 has copied the old session file\n\n%6%1%7\n\nto\n\n%6%2%7\n\n"
5101 "From now on, use the -2000 version with older versions of %3"),
5102 xml_path, backup_path, PROGRAM_NAME,
5104 start_mono, end_mono), true);
5111 ARDOUR_UI::reset_peak_display ()
5113 if (!_session || !_session->master_out() || !editor_meter) return;
5114 editor_meter->clear_meters();
5115 editor_meter_max_peak = -INFINITY;
5116 editor_meter_peak_display.set_active_state ( Gtkmm2ext::Off );
5120 ARDOUR_UI::reset_group_peak_display (RouteGroup* group)
5122 if (!_session || !_session->master_out()) return;
5123 if (group == _session->master_out()->route_group()) {
5124 reset_peak_display ();
5129 ARDOUR_UI::reset_route_peak_display (Route* route)
5131 if (!_session || !_session->master_out()) return;
5132 if (_session->master_out().get() == route) {
5133 reset_peak_display ();
5138 ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate)
5140 audio_midi_setup->set_desired_sample_rate (desired_sample_rate);
5141 audio_midi_setup->set_position (WIN_POS_CENTER);
5143 // TODO make this a preference.
5144 // (engine state is parsed by the GUI, but currently saved
5145 // in preferences: ARDOUR::Config->extra_xml
5146 // soooo where should this option go?)
5147 if (getenv("TRY_AUTOSTART_ENGINE")) {
5148 audio_midi_setup->try_autostart ();
5149 if (ARDOUR::AudioEngine::instance()->running()) {
5155 int response = audio_midi_setup->run();
5157 case Gtk::RESPONSE_OK:
5158 if (!AudioEngine::instance()->running()) {
5172 ARDOUR_UI::transport_numpad_timeout ()
5174 _numpad_locate_happening = false;
5175 if (_numpad_timeout_connection.connected() )
5176 _numpad_timeout_connection.disconnect();
5181 ARDOUR_UI::transport_numpad_decimal ()
5183 _numpad_timeout_connection.disconnect();
5185 if (_numpad_locate_happening) {
5186 if (editor) editor->goto_nth_marker(_pending_locate_num - 1);
5187 _numpad_locate_happening = false;
5189 _pending_locate_num = 0;
5190 _numpad_locate_happening = true;
5191 _numpad_timeout_connection = Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::transport_numpad_timeout), 2*1000);
5196 ARDOUR_UI::transport_numpad_event (int num)
5198 if ( _numpad_locate_happening ) {
5199 _pending_locate_num = _pending_locate_num*10 + num;
5202 case 0: toggle_roll(false, false); break;
5203 case 1: transport_rewind(1); break;
5204 case 2: transport_forward(1); break;
5205 case 3: transport_record(true); break;
5206 case 4: toggle_session_auto_loop(); break;
5207 case 5: transport_record(false); toggle_session_auto_loop(); break;
5208 case 6: toggle_punch(); break;
5209 case 7: toggle_click(); break;
5210 case 8: toggle_auto_return(); break;
5211 case 9: toggle_follow_edits(); break;
5217 ARDOUR_UI::set_flat_buttons ()
5219 CairoWidget::set_flat_buttons( UIConfiguration::instance().get_flat_buttons() );
5223 ARDOUR_UI::audioengine_became_silent ()
5225 MessageDialog msg (string_compose (_("This is a free/demo copy of %1. It has just switched to silent mode."), PROGRAM_NAME),
5227 Gtk::MESSAGE_WARNING,
5231 msg.set_title (string_compose (_("%1 is now silent"), PROGRAM_NAME));
5233 Gtk::Label pay_label (string_compose (_("Please consider paying for a copy of %1 - you can pay whatever you want."), PROGRAM_NAME));
5234 Gtk::Label subscribe_label (_("Better yet become a subscriber - subscriptions start at US$1 per month."));
5235 Gtk::Button pay_button (_("Pay for a copy (via the web)"));
5236 Gtk::Button subscribe_button (_("Become a subscriber (via the web)"));
5237 Gtk::HBox pay_button_box;
5238 Gtk::HBox subscribe_button_box;
5240 pay_button_box.pack_start (pay_button, true, false);
5241 subscribe_button_box.pack_start (subscribe_button, true, false);
5243 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 */
5245 pay_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://ardour.org/download")));
5246 subscribe_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://community.ardour.org/s/subscribe")));
5248 msg.get_vbox()->pack_start (pay_label);
5249 msg.get_vbox()->pack_start (pay_button_box);
5250 msg.get_vbox()->pack_start (subscribe_label);
5251 msg.get_vbox()->pack_start (subscribe_button_box);
5253 msg.get_vbox()->show_all ();
5255 msg.add_button (_("Remain silent"), Gtk::RESPONSE_CANCEL);
5256 msg.add_button (_("Save and quit"), Gtk::RESPONSE_NO);
5257 msg.add_button (_("Give me more time"), Gtk::RESPONSE_YES);
5262 case Gtk::RESPONSE_YES:
5263 AudioEngine::instance()->reset_silence_countdown ();
5266 case Gtk::RESPONSE_NO:
5268 save_state_canfail ("");
5272 case Gtk::RESPONSE_CANCEL:
5274 /* don't reset, save session and exit */
5280 ARDOUR_UI::hide_application ()
5282 Application::instance ()-> hide ();
5286 ARDOUR_UI::setup_toplevel_window (Gtk::Window& window, const string& name, void* owner)
5288 /* icons, titles, WM stuff */
5290 static list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
5292 if (window_icons.empty()) {
5293 Glib::RefPtr<Gdk::Pixbuf> icon;
5294 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
5295 window_icons.push_back (icon);
5297 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
5298 window_icons.push_back (icon);
5300 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
5301 window_icons.push_back (icon);
5303 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
5304 window_icons.push_back (icon);
5308 if (!window_icons.empty()) {
5309 window.set_default_icon_list (window_icons);
5312 Gtkmm2ext::WindowTitle title (Glib::get_application_name());
5314 if (!name.empty()) {
5318 window.set_title (title.get_string());
5319 window.set_wmclass (string_compose (X_("%1_%1"), downcase (PROGRAM_NAME), downcase (name)), PROGRAM_NAME);
5321 window.set_flags (CAN_FOCUS);
5322 window.add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
5324 /* This is a hack to ensure that GTK-accelerators continue to
5325 * work. Once we switch over to entirely native bindings, this will be
5326 * unnecessary and should be removed
5328 window.add_accel_group (ActionManager::ui_manager->get_accel_group());
5330 window.signal_configure_event().connect (sigc::mem_fun (*this, &ARDOUR_UI::configure_handler));
5331 window.signal_window_state_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::tabbed_window_state_event_handler), owner));
5332 window.signal_key_press_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5333 window.signal_key_release_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5337 ARDOUR_UI::key_event_handler (GdkEventKey* ev, Gtk::Window* event_window)
5339 Gtkmm2ext::Bindings* bindings = 0;
5340 Gtk::Window* window = 0;
5342 /* until we get ardour bindings working, we are not handling key
5346 if (ev->type != GDK_KEY_PRESS) {
5350 if (event_window == &_main_window) {
5352 window = event_window;
5354 /* find current tab contents */
5356 Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page());
5358 /* see if it uses the ardour binding system */
5361 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(w->get_data ("ardour-bindings"));
5364 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("main window key event, bindings = %1, global = %2\n", bindings, &global_bindings));
5368 window = event_window;
5370 /* see if window uses ardour binding system */
5372 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(window->get_data ("ardour-bindings"));
5375 /* An empty binding set is treated as if it doesn't exist */
5377 if (bindings && bindings->empty()) {
5381 return key_press_focus_accelerator_handler (*window, ev, bindings);
5384 static Gtkmm2ext::Bindings*
5385 get_bindings_from_widget_heirarchy (GtkWidget* w)
5390 if ((p = g_object_get_data (G_OBJECT(w), "ardour-bindings")) != 0) {
5393 w = gtk_widget_get_parent (w);
5396 return reinterpret_cast<Gtkmm2ext::Bindings*> (p);
5400 ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev, Gtkmm2ext::Bindings* bindings)
5402 GtkWindow* win = window.gobj();
5403 GtkWidget* focus = gtk_window_get_focus (win);
5404 bool special_handling_of_unmodified_accelerators = false;
5405 const guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK));
5409 /* some widget has keyboard focus */
5411 if (GTK_IS_ENTRY(focus) || Keyboard::some_magic_widget_has_focus()) {
5413 /* A particular kind of focusable widget currently has keyboard
5414 * focus. All unmodified key events should go to that widget
5415 * first and not be used as an accelerator by default
5418 special_handling_of_unmodified_accelerators = true;
5422 Gtkmm2ext::Bindings* focus_bindings = get_bindings_from_widget_heirarchy (focus);
5423 if (focus_bindings) {
5424 bindings = focus_bindings;
5425 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Switch bindings based on focus widget, now using %1\n", bindings->name()));
5430 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",
5433 show_gdk_event_state (ev->state),
5434 special_handling_of_unmodified_accelerators,
5435 Keyboard::some_magic_widget_has_focus(),
5437 (focus ? gtk_widget_get_name (focus) : "no focus widget"),
5438 ((ev->state & mask) ? "yes" : "no"),
5439 window.get_title()));
5441 /* This exists to allow us to override the way GTK handles
5442 key events. The normal sequence is:
5444 a) event is delivered to a GtkWindow
5445 b) accelerators/mnemonics are activated
5446 c) if (b) didn't handle the event, propagate to
5447 the focus widget and/or focus chain
5449 The problem with this is that if the accelerators include
5450 keys without modifiers, such as the space bar or the
5451 letter "e", then pressing the key while typing into
5452 a text entry widget results in the accelerator being
5453 activated, instead of the desired letter appearing
5456 There is no good way of fixing this, but this
5457 represents a compromise. The idea is that
5458 key events involving modifiers (not Shift)
5459 get routed into the activation pathway first, then
5460 get propagated to the focus widget if necessary.
5462 If the key event doesn't involve modifiers,
5463 we deliver to the focus widget first, thus allowing
5464 it to get "normal text" without interference
5467 Of course, this can also be problematic: if there
5468 is a widget with focus, then it will swallow
5469 all "normal text" accelerators.
5473 if (!special_handling_of_unmodified_accelerators || (ev->state & mask)) {
5475 /* no special handling or there are modifiers in effect: accelerate first */
5477 DEBUG_TRACE (DEBUG::Accelerators, "\tactivate, then propagate\n");
5478 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tevent send-event:%1 time:%2 length:%3 name %7 string:%4 hardware_keycode:%5 group:%6\n",
5479 ev->send_event, ev->time, ev->length, ev->string, ev->hardware_keycode, ev->group, gdk_keyval_name (ev->keyval)));
5481 DEBUG_TRACE (DEBUG::Accelerators, "\tsending to window\n");
5482 KeyboardKey k (ev->state, ev->keyval);
5486 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tusing Ardour bindings %1 @ %2 for this event\n", bindings->name(), bindings));
5488 if (bindings->activate (k, Bindings::Press)) {
5489 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5494 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5496 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5497 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5501 DEBUG_TRACE (DEBUG::Accelerators, "\tnot accelerated, now propagate\n");
5503 if (gtk_window_propagate_key_event (win, ev)) {
5504 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate handled\n");
5510 /* no modifiers, propagate first */
5512 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate, then activate\n");
5514 if (gtk_window_propagate_key_event (win, ev)) {
5515 DEBUG_TRACE (DEBUG::Accelerators, "\thandled by propagate\n");
5519 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagation didn't handle, so activate\n");
5520 KeyboardKey k (ev->state, ev->keyval);
5524 DEBUG_TRACE (DEBUG::Accelerators, "\tusing Ardour bindings for this window\n");
5527 if (bindings->activate (k, Bindings::Press)) {
5528 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5534 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5536 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5537 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5542 DEBUG_TRACE (DEBUG::Accelerators, "\tnot handled\n");
5547 ARDOUR_UI::load_bindings ()
5549 if ((global_bindings = Bindings::get_bindings (X_("Global"), global_actions)) == 0) {
5550 error << _("Global keybindings are missing") << endmsg;
5555 ARDOUR_UI::cancel_solo ()
5558 if (_session->soloing()) {
5559 _session->set_solo (_session->get_routes(), false);
5560 } else if (_session->listening()) {
5561 _session->set_listen (_session->get_routes(), false);
5564 _session->clear_all_solo_state (_session->get_routes()); // safeguard, ideally this won't do anything, check the log-window