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"
95 #include "ardour/track.h"
96 #include "ardour/vca_manager.h"
97 #include "ardour/utils.h"
99 #include "LuaBridge/LuaBridge.h"
101 #ifdef WINDOWS_VST_SUPPORT
104 #ifdef AUDIOUNIT_SUPPORT
105 #include "ardour/audio_unit.h"
108 // fix for OSX (nsm.h has a check function, AU/Apple defines check)
113 #include "timecode/time.h"
115 typedef uint64_t microseconds_t;
120 #include "add_route_dialog.h"
121 #include "ambiguous_file_dialog.h"
122 #include "ardour_ui.h"
123 #include "audio_clock.h"
124 #include "audio_region_view.h"
125 #include "big_clock_window.h"
126 #include "bundle_manager.h"
127 #include "duplicate_routes_dialog.h"
129 #include "engine_dialog.h"
130 #include "export_video_dialog.h"
131 #include "export_video_infobox.h"
132 #include "gain_meter.h"
133 #include "global_port_matrix.h"
134 #include "gui_object.h"
135 #include "gui_thread.h"
136 #include "keyboard.h"
137 #include "keyeditor.h"
138 #include "location_ui.h"
139 #include "lua_script_manager.h"
140 #include "luawindow.h"
141 #include "main_clock.h"
142 #include "missing_file_dialog.h"
143 #include "missing_plugin_dialog.h"
144 #include "mixer_ui.h"
145 #include "meterbridge.h"
146 #include "mouse_cursors.h"
149 #include "pingback.h"
150 #include "processor_box.h"
151 #include "prompter.h"
152 #include "public_editor.h"
153 #include "rc_option_editor.h"
154 #include "route_time_axis.h"
155 #include "route_params_ui.h"
156 #include "save_as_dialog.h"
157 #include "script_selector.h"
158 #include "session_dialog.h"
159 #include "session_metadata_dialog.h"
160 #include "session_option_editor.h"
161 #include "shuttle_control.h"
162 #include "speaker_dialog.h"
165 #include "theme_manager.h"
166 #include "time_axis_view_item.h"
169 #include "video_server_dialog.h"
170 #include "add_video_dialog.h"
171 #include "transcode_video_dialog.h"
175 using namespace ARDOUR;
176 using namespace ARDOUR_UI_UTILS;
178 using namespace Gtkmm2ext;
181 using namespace Editing;
183 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
185 sigc::signal<void, framepos_t, bool, framepos_t> ARDOUR_UI::Clock;
186 sigc::signal<void> ARDOUR_UI::CloseAllDialogs;
189 ask_about_configuration_copy (string const & old_dir, string const & new_dir, int version)
191 MessageDialog msg (string_compose (_("%1 %2.x has discovered configuration files from %1 %3.x.\n\n"
192 "Would you like these files to be copied and used for %1 %2.x?\n\n"
193 "(This will require you to restart %1.)"),
194 PROGRAM_NAME, PROGRAM_VERSION, version),
195 false, /* no markup */
198 true /* modal, though it hardly matters since it is the only window */
201 msg.set_default_response (Gtk::RESPONSE_YES);
204 return (msg.run() == Gtk::RESPONSE_YES);
208 libxml_generic_error_func (void* /* parsing_context*/,
216 vsnprintf (buf, sizeof (buf), msg, ap);
217 error << buf << endmsg;
222 libxml_structured_error_func (void* /* parsing_context*/,
230 replace_all (msg, "\n", "");
233 if (err->file && err->line) {
234 error << X_("XML error: ") << msg << " in " << err->file << " at line " << err->line;
237 error << ':' << err->int2;
242 error << X_("XML error: ") << msg << endmsg;
248 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
249 : Gtkmm2ext::UI (PROGRAM_NAME, X_("gui"), argcp, argvp)
250 , session_loaded (false)
251 , gui_object_state (new GUIObjectState)
252 , primary_clock (new MainClock (X_("primary"), X_("transport"), true ))
253 , secondary_clock (new MainClock (X_("secondary"), X_("secondary"), false))
254 , big_clock (new AudioClock (X_("bigclock"), false, "big", true, true, false, false))
256 , global_actions (X_("global"))
257 , ignore_dual_punch (false)
258 , main_window_visibility (0)
263 , _mixer_on_top (false)
264 , _initial_verbose_plugin_scan (false)
265 , first_time_engine_run (true)
266 , roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll))
267 , stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop))
268 , goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart))
269 , goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd))
270 , auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop))
271 , play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection))
272 , rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable))
273 , auto_return_button (ArdourButton::led_default_elements)
274 , follow_edits_button (ArdourButton::led_default_elements)
275 , auto_input_button (ArdourButton::led_default_elements)
276 , auditioning_alert_button (_("Audition"))
277 , solo_alert_button (_("Solo"))
278 , feedback_alert_button (_("Feedback"))
279 , error_alert_button ( ArdourButton::just_led_default_elements )
281 , editor_meter_peak_display()
282 , _numpad_locate_happening (false)
283 , _session_is_new (false)
284 , last_key_press_time (0)
288 , rc_option_editor (0)
289 , speaker_config_window (X_("speaker-config"), _("Speaker Configuration"))
290 , add_route_dialog (X_("add-routes"), _("Add Tracks/Busses"))
291 , about (X_("about"), _("About"))
292 , location_ui (X_("locations"), _("Locations"))
293 , route_params (X_("inspector"), _("Tracks and Busses"))
294 , audio_midi_setup (X_("audio-midi-setup"), _("Audio/MIDI Setup"))
295 , export_video_dialog (X_("video-export"), _("Video Export Dialog"))
296 , lua_script_window (X_("script-manager"), _("Script Manager"))
297 , session_option_editor (X_("session-options-editor"), _("Properties"), boost::bind (&ARDOUR_UI::create_session_option_editor, this))
298 , add_video_dialog (X_("add-video"), _("Add Video"), boost::bind (&ARDOUR_UI::create_add_video_dialog, this))
299 , bundle_manager (X_("bundle-manager"), _("Bundle Manager"), boost::bind (&ARDOUR_UI::create_bundle_manager, this))
300 , big_clock_window (X_("big-clock"), _("Big Clock"), boost::bind (&ARDOUR_UI::create_big_clock_window, this))
301 , audio_port_matrix (X_("audio-connection-manager"), _("Audio Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::AUDIO))
302 , midi_port_matrix (X_("midi-connection-manager"), _("MIDI Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::MIDI))
303 , key_editor (X_("key-editor"), _("Bindings Editor"), boost::bind (&ARDOUR_UI::create_key_editor, this))
304 , video_server_process (0)
306 , have_configure_timeout (false)
307 , last_configure_time (0)
309 , have_disk_speed_dialog_displayed (false)
310 , _status_bar_visibility (X_("status-bar"))
311 , _feedback_exists (false)
312 , _log_not_acknowledged (LogLevelNone)
313 , duplicate_routes_dialog (0)
314 , editor_visibility_button (S_("Window|Editor"))
315 , mixer_visibility_button (S_("Window|Mixer"))
316 , prefs_visibility_button (S_("Window|Preferences"))
318 Gtkmm2ext::init (localedir);
320 UIConfiguration::instance().post_gui_init ();
322 if (ARDOUR::handle_old_configuration_files (boost::bind (ask_about_configuration_copy, _1, _2, _3))) {
323 MessageDialog msg (string_compose (_("Your configuration files were copied. You can now restart %1."), PROGRAM_NAME), true);
325 /* configuration was modified, exit immediately */
329 if (theArdourUI == 0) {
333 /* track main window visibility */
335 main_window_visibility = new VisibilityTracker (_main_window);
337 /* stop libxml from spewing to stdout/stderr */
339 xmlSetGenericErrorFunc (this, libxml_generic_error_func);
340 xmlSetStructuredErrorFunc (this, libxml_structured_error_func);
342 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::parameter_changed));
343 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
344 UIConfiguration::instance().map_parameters (pc);
346 roll_button.set_controllable (roll_controllable);
347 stop_button.set_controllable (stop_controllable);
348 goto_start_button.set_controllable (goto_start_controllable);
349 goto_end_button.set_controllable (goto_end_controllable);
350 auto_loop_button.set_controllable (auto_loop_controllable);
351 play_selection_button.set_controllable (play_selection_controllable);
352 rec_button.set_controllable (rec_controllable);
354 roll_button.set_name ("transport button");
355 stop_button.set_name ("transport button");
356 goto_start_button.set_name ("transport button");
357 goto_end_button.set_name ("transport button");
358 auto_loop_button.set_name ("transport button");
359 play_selection_button.set_name ("transport button");
360 rec_button.set_name ("transport recenable button");
361 midi_panic_button.set_name ("transport button");
363 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
364 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
366 ARDOUR::Session::VersionMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_format_mismatch, this, _1, _2), gui_context());
368 /* handle dialog requests */
370 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
372 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
374 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
376 /* handle Audio/MIDI setup when session requires it */
378 ARDOUR::Session::AudioEngineSetupRequired.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::do_audio_midi_setup, this, _1));
380 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
382 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
384 /* handle sr mismatch with a dialog - cross-thread from engine */
385 ARDOUR::Session::NotifyAboutSampleRateMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::sr_mismatch_message, this, _1, _2), gui_context ());
387 /* handle requests to quit (coming from JACK session) */
389 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::finish, this), gui_context ());
391 /* tell the user about feedback */
393 ARDOUR::Session::FeedbackDetected.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::feedback_detected, this), gui_context ());
394 ARDOUR::Session::SuccessfulGraphSort.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::successful_graph_sort, this), gui_context ());
396 /* handle requests to deal with missing files */
398 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
400 /* and ambiguous files */
402 ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2));
404 /* also plugin scan messages */
405 ARDOUR::PluginScanMessage.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_dialog, this, _1, _2, _3), gui_context());
406 ARDOUR::PluginScanTimeout.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_timeout, this, _1), gui_context());
408 ARDOUR::GUIIdle.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::gui_idle_handler, this), gui_context());
410 Config->ParameterChanged.connect ( forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::set_flat_buttons, this), gui_context() );
413 /* lets get this party started */
415 setup_gtk_ardour_enums ();
418 SessionEvent::create_per_thread_pool ("GUI", 4096);
420 /* we like keyboards */
422 keyboard = new ArdourKeyboard(*this);
424 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
426 keyboard->set_state (*node, Stateful::loading_state_version);
429 UIConfiguration::instance().reset_dpi ();
431 TimeAxisViewItem::set_constant_heights ();
433 /* Set this up so that our window proxies can register actions */
435 ActionManager::init ();
437 /* The following must happen after ARDOUR::init() so that Config is set up */
439 const XMLNode* ui_xml = Config->extra_xml (X_("UI"));
442 key_editor.set_state (*ui_xml, 0);
443 session_option_editor.set_state (*ui_xml, 0);
444 speaker_config_window.set_state (*ui_xml, 0);
445 about.set_state (*ui_xml, 0);
446 add_route_dialog.set_state (*ui_xml, 0);
447 add_video_dialog.set_state (*ui_xml, 0);
448 route_params.set_state (*ui_xml, 0);
449 bundle_manager.set_state (*ui_xml, 0);
450 location_ui.set_state (*ui_xml, 0);
451 big_clock_window.set_state (*ui_xml, 0);
452 audio_port_matrix.set_state (*ui_xml, 0);
453 midi_port_matrix.set_state (*ui_xml, 0);
454 export_video_dialog.set_state (*ui_xml, 0);
455 lua_script_window.set_state (*ui_xml, 0);
458 /* Separate windows */
460 WM::Manager::instance().register_window (&key_editor);
461 WM::Manager::instance().register_window (&session_option_editor);
462 WM::Manager::instance().register_window (&speaker_config_window);
463 WM::Manager::instance().register_window (&about);
464 WM::Manager::instance().register_window (&add_route_dialog);
465 WM::Manager::instance().register_window (&add_video_dialog);
466 WM::Manager::instance().register_window (&route_params);
467 WM::Manager::instance().register_window (&audio_midi_setup);
468 WM::Manager::instance().register_window (&export_video_dialog);
469 WM::Manager::instance().register_window (&lua_script_window);
470 WM::Manager::instance().register_window (&bundle_manager);
471 WM::Manager::instance().register_window (&location_ui);
472 WM::Manager::instance().register_window (&big_clock_window);
473 WM::Manager::instance().register_window (&audio_port_matrix);
474 WM::Manager::instance().register_window (&midi_port_matrix);
476 /* Trigger setting up the color scheme and loading the GTK RC file */
478 UIConfiguration::instance().load_rc_file (false);
480 _process_thread = new ProcessThread ();
481 _process_thread->init ();
483 UIConfiguration::instance().DPIReset.connect (sigc::mem_fun (*this, &ARDOUR_UI::resize_text_widgets));
488 GlobalPortMatrixWindow*
489 ARDOUR_UI::create_global_port_matrix (ARDOUR::DataType type)
494 return new GlobalPortMatrixWindow (_session, type);
498 ARDOUR_UI::attach_to_engine ()
500 AudioEngine::instance()->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
501 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
505 ARDOUR_UI::engine_stopped ()
507 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
508 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
509 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
510 update_sample_rate (0);
515 ARDOUR_UI::engine_running ()
517 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
518 if (first_time_engine_run) {
520 first_time_engine_run = false;
524 _session->reset_xrun_count ();
526 update_disk_space ();
528 update_xrun_count ();
529 update_sample_rate (AudioEngine::instance()->sample_rate());
530 update_timecode_format ();
531 update_peak_thread_work ();
532 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, true);
533 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, false);
537 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
539 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
540 /* we can't rely on the original string continuing to exist when we are called
541 again in the GUI thread, so make a copy and note that we need to
544 char *copy = strdup (reason);
545 Gtkmm2ext::UI::instance()->call_slot (MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
549 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
550 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
552 update_sample_rate (0);
556 /* if the reason is a non-empty string, it means that the backend was shutdown
557 rather than just Ardour.
560 if (strlen (reason)) {
561 msgstr = string_compose (_("The audio backend was shutdown because:\n\n%1"), reason);
563 msgstr = string_compose (_("\
564 The audio backend has either been shutdown or it\n\
565 disconnected %1 because %1\n\
566 was not fast enough. Try to restart\n\
567 the audio backend and save the session."), PROGRAM_NAME);
570 MessageDialog msg (_main_window, msgstr);
571 pop_back_splash (msg);
575 free (const_cast<char*> (reason));
580 ARDOUR_UI::post_engine ()
582 /* Things to be done once (and once ONLY) after we have a backend running in the AudioEngine
584 #ifdef AUDIOUNIT_SUPPORT
586 if (AUPluginInfo::au_get_crashlog(au_msg)) {
587 popup_error(_("Audio Unit Plugin Scan Failed. Automatic AU scanning has been disabled. Please see the log window for further details."));
588 error << _("Audio Unit Plugin Scan Failed:") << endmsg;
589 info << au_msg << endmsg;
593 ARDOUR::init_post_engine ();
595 /* connect to important signals */
597 AudioEngine::instance()->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
598 AudioEngine::instance()->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
599 AudioEngine::instance()->BufferSizeChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
600 AudioEngine::instance()->Halted.connect_same_thread (halt_connection, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
601 AudioEngine::instance()->BecameSilent.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::audioengine_became_silent, this), gui_context());
603 if (setup_windows ()) {
604 throw failed_constructor ();
607 /* Do this after setup_windows (), as that's when the _status_bar_visibility is created */
608 XMLNode* n = Config->extra_xml (X_("UI"));
610 _status_bar_visibility.set_state (*n);
613 check_memory_locking();
615 /* this is the first point at which all the possible actions are
616 * available, because some of the available actions are dependent on
617 * aspects of the engine/backend.
620 if (ARDOUR_COMMAND_LINE::show_key_actions) {
623 vector<string> paths;
624 vector<string> labels;
625 vector<string> tooltips;
627 vector<Glib::RefPtr<Gtk::Action> > actions;
629 Gtkmm2ext::ActionMap::get_all_actions (paths, labels, tooltips, keys, actions);
631 vector<string>::iterator k;
632 vector<string>::iterator p;
634 for (p = paths.begin(), k = keys.begin(); p != paths.end(); ++k, ++p) {
639 cout << *p << " => " << *k << endl;
643 halt_connection.disconnect ();
644 AudioEngine::instance()->stop ();
648 /* this being a GUI and all, we want peakfiles */
650 AudioFileSource::set_build_peakfiles (true);
651 AudioFileSource::set_build_missing_peakfiles (true);
653 /* set default clock modes */
655 primary_clock->set_mode (AudioClock::Timecode);
656 secondary_clock->set_mode (AudioClock::BBT);
658 /* start the time-of-day-clock */
661 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
662 update_wall_clock ();
663 Glib::signal_timeout().connect_seconds (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 1);
668 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
669 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
670 Config->map_parameters (pc);
672 UIConfiguration::instance().map_parameters (pc);
676 ARDOUR_UI::~ARDOUR_UI ()
678 UIConfiguration::instance().save_state();
682 if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
683 // don't bother at 'real' exit. the OS cleans up for us.
684 delete big_clock; big_clock = 0;
685 delete primary_clock; primary_clock = 0;
686 delete secondary_clock; secondary_clock = 0;
687 delete _process_thread; _process_thread = 0;
688 delete meterbridge; meterbridge = 0;
689 delete luawindow; luawindow = 0;
690 delete editor; editor = 0;
691 delete mixer; mixer = 0;
693 delete gui_object_state; gui_object_state = 0;
694 delete main_window_visibility;
695 FastMeter::flush_pattern_cache ();
696 PixFader::flush_pattern_cache ();
700 /* Small trick to flush main-thread event pool.
701 * Other thread-pools are destroyed at pthread_exit(),
702 * but tmain thread termination is too late to trigger Pool::~Pool()
704 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.
705 delete ev->event_pool();
710 ARDOUR_UI::pop_back_splash (Gtk::Window& win)
712 if (Splash::instance()) {
713 Splash::instance()->pop_back_for (win);
718 ARDOUR_UI::configure_timeout ()
720 if (last_configure_time == 0) {
721 /* no configure events yet */
725 /* force a gap of 0.5 seconds since the last configure event
728 if (get_microseconds() - last_configure_time < 500000) {
731 have_configure_timeout = false;
732 save_ardour_state ();
738 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
740 if (have_configure_timeout) {
741 last_configure_time = get_microseconds();
743 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
744 have_configure_timeout = true;
751 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
753 XMLProperty const * prop;
755 if ((prop = node.property ("roll")) != 0) {
756 roll_controllable->set_id (prop->value());
758 if ((prop = node.property ("stop")) != 0) {
759 stop_controllable->set_id (prop->value());
761 if ((prop = node.property ("goto-start")) != 0) {
762 goto_start_controllable->set_id (prop->value());
764 if ((prop = node.property ("goto-end")) != 0) {
765 goto_end_controllable->set_id (prop->value());
767 if ((prop = node.property ("auto-loop")) != 0) {
768 auto_loop_controllable->set_id (prop->value());
770 if ((prop = node.property ("play-selection")) != 0) {
771 play_selection_controllable->set_id (prop->value());
773 if ((prop = node.property ("rec")) != 0) {
774 rec_controllable->set_id (prop->value());
776 if ((prop = node.property ("shuttle")) != 0) {
777 shuttle_box->controllable()->set_id (prop->value());
782 ARDOUR_UI::get_transport_controllable_state ()
784 XMLNode* node = new XMLNode(X_("TransportControllables"));
787 roll_controllable->id().print (buf, sizeof (buf));
788 node->add_property (X_("roll"), buf);
789 stop_controllable->id().print (buf, sizeof (buf));
790 node->add_property (X_("stop"), buf);
791 goto_start_controllable->id().print (buf, sizeof (buf));
792 node->add_property (X_("goto_start"), buf);
793 goto_end_controllable->id().print (buf, sizeof (buf));
794 node->add_property (X_("goto_end"), buf);
795 auto_loop_controllable->id().print (buf, sizeof (buf));
796 node->add_property (X_("auto_loop"), buf);
797 play_selection_controllable->id().print (buf, sizeof (buf));
798 node->add_property (X_("play_selection"), buf);
799 rec_controllable->id().print (buf, sizeof (buf));
800 node->add_property (X_("rec"), buf);
801 shuttle_box->controllable()->id().print (buf, sizeof (buf));
802 node->add_property (X_("shuttle"), buf);
808 ARDOUR_UI::save_session_at_its_request (std::string snapshot_name)
811 _session->save_state (snapshot_name);
816 ARDOUR_UI::autosave_session ()
818 if (g_main_depth() > 1) {
819 /* inside a recursive main loop,
820 give up because we may not be able to
826 if (!Config->get_periodic_safety_backups()) {
831 _session->maybe_write_autosave();
838 ARDOUR_UI::session_dirty_changed ()
845 ARDOUR_UI::update_autosave ()
847 if (_session && _session->dirty()) {
848 if (_autosave_connection.connected()) {
849 _autosave_connection.disconnect();
852 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
853 Config->get_periodic_safety_backup_interval() * 1000);
856 if (_autosave_connection.connected()) {
857 _autosave_connection.disconnect();
863 ARDOUR_UI::check_announcements ()
866 string _annc_filename;
869 _annc_filename = PROGRAM_NAME "_announcements_osx_";
870 #elif defined PLATFORM_WINDOWS
871 _annc_filename = PROGRAM_NAME "_announcements_windows_";
873 _annc_filename = PROGRAM_NAME "_announcements_linux_";
875 _annc_filename.append (VERSIONSTRING);
877 _announce_string = "";
879 std::string path = Glib::build_filename (user_config_directory(), _annc_filename);
880 FILE* fin = g_fopen (path.c_str(), "rb");
882 while (!feof (fin)) {
885 if ((len = fread (tmp, sizeof(char), 1024, fin)) == 0 || ferror (fin)) {
888 _announce_string.append (tmp, len);
893 pingback (VERSIONSTRING, path);
898 _hide_splash (gpointer arg)
900 ((ARDOUR_UI*)arg)->hide_splash();
905 ARDOUR_UI::starting ()
907 Application* app = Application::instance ();
909 bool brand_new_user = ArdourStartup::required ();
911 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
912 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::load_from_application_api));
914 if (ARDOUR_COMMAND_LINE::check_announcements) {
915 check_announcements ();
920 /* we need to create this early because it may need to set the
921 * audio backend end up.
925 audio_midi_setup.get (true);
927 std::cerr << "audio-midi engine setup failed."<< std::endl;
931 if ((nsm_url = g_getenv ("NSM_URL")) != 0) {
932 nsm = new NSM_Client;
933 if (!nsm->init (nsm_url)) {
934 /* the ardour executable may have different names:
936 * waf's obj.target for distro versions: eg ardour4, ardourvst4
937 * Ardour4, Mixbus3 for bundled versions + full path on OSX & windows
938 * argv[0] does not apply since we need the wrapper-script (not the binary itself)
940 * The wrapper startup script should set the environment variable 'ARDOUR_SELF'
942 const char *process_name = g_getenv ("ARDOUR_SELF");
943 nsm->announce (PROGRAM_NAME, ":dirty:", process_name ? process_name : "ardour4");
946 // wait for announce reply from nsm server
947 for ( i = 0; i < 5000; ++i) {
951 if (nsm->is_active()) {
956 error << _("NSM server did not announce itself") << endmsg;
959 // wait for open command from nsm server
960 for ( i = 0; i < 5000; ++i) {
963 if (nsm->client_id ()) {
969 error << _("NSM: no client ID provided") << endmsg;
973 if (_session && nsm) {
974 _session->set_nsm_state( nsm->is_active() );
976 error << _("NSM: no session created") << endmsg;
980 // nsm requires these actions disabled
981 vector<string> action_names;
982 action_names.push_back("SaveAs");
983 action_names.push_back("Rename");
984 action_names.push_back("New");
985 action_names.push_back("Open");
986 action_names.push_back("Recent");
987 action_names.push_back("Close");
989 for (vector<string>::const_iterator n = action_names.begin(); n != action_names.end(); ++n) {
990 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), (*n).c_str());
992 act->set_sensitive (false);
999 error << _("NSM: initialization failed") << endmsg;
1005 if (brand_new_user) {
1006 _initial_verbose_plugin_scan = true;
1011 _initial_verbose_plugin_scan = false;
1012 switch (s.response ()) {
1013 case Gtk::RESPONSE_OK:
1020 #ifdef NO_PLUGIN_STATE
1022 ARDOUR::RecentSessions rs;
1023 ARDOUR::read_recent_sessions (rs);
1025 string path = Glib::build_filename (user_config_directory(), ".iknowaboutfreeversion");
1027 if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS) && !rs.empty()) {
1029 /* already used Ardour, have sessions ... warn about plugin state */
1031 ArdourDialog d (_("Free/Demo Version Warning"), true);
1033 Button b (string_compose (_("Subscribe and support development of %1"), PROGRAM_NAME));
1034 CheckButton c (_("Don't warn me about this again"));
1036 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"),
1037 string_compose (_("This is a free/demo version of %1"), PROGRAM_NAME),
1038 _("It will not restore OR save any plugin settings"),
1039 _("If you load an existing session with plugin settings\n"
1040 "they will not be used and will be lost."),
1041 _("To get full access to updates without this limitation\n"
1042 "consider becoming a subscriber for a low cost every month.")));
1043 l.set_justify (JUSTIFY_CENTER);
1045 b.signal_clicked().connect (mem_fun(*this, &ARDOUR_UI::launch_subscribe));
1047 d.get_vbox()->pack_start (l, true, true);
1048 d.get_vbox()->pack_start (b, false, false, 12);
1049 d.get_vbox()->pack_start (c, false, false, 12);
1051 d.add_button (_("Quit now"), RESPONSE_CANCEL);
1052 d.add_button (string_compose (_("Continue using %1"), PROGRAM_NAME), RESPONSE_OK);
1056 c.signal_toggled().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (toggle_file_existence), path)));
1058 if (d.run () != RESPONSE_OK) {
1064 /* go get a session */
1066 const bool new_session_required = (ARDOUR_COMMAND_LINE::new_session || brand_new_user);
1068 if (get_session_parameters (false, new_session_required, ARDOUR_COMMAND_LINE::load_template)) {
1069 std::cerr << "Cannot get session parameters."<< std::endl;
1076 WM::Manager::instance().show_visible ();
1078 /* We have to do this here since goto_editor_window() ends up calling show_all() on the
1079 * editor window, and we may want stuff to be hidden.
1081 _status_bar_visibility.update ();
1083 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
1085 if (splash && splash->is_visible()) {
1086 // in 1 second, hide the splash screen
1087 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
1090 /* all other dialogs are created conditionally */
1096 ARDOUR_UI::check_memory_locking ()
1098 #if defined(__APPLE__) || defined(PLATFORM_WINDOWS)
1099 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
1103 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
1105 if (AudioEngine::instance()->is_realtime() && memory_warning_node == 0) {
1107 struct rlimit limits;
1109 long pages, page_size;
1111 size_t pages_len=sizeof(pages);
1112 if ((page_size = getpagesize()) < 0 ||
1113 sysctlbyname("hw.availpages", &pages, &pages_len, NULL, 0))
1115 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0)
1120 ram = (int64_t) pages * (int64_t) page_size;
1123 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
1127 if (limits.rlim_cur != RLIM_INFINITY) {
1129 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
1133 _("WARNING: Your system has a limit for maximum amount of locked memory. "
1134 "This might cause %1 to run out of memory before your system "
1135 "runs out of memory. \n\n"
1136 "You can view the memory limit with 'ulimit -l', "
1137 "and it is normally controlled by %2"),
1140 X_("/etc/login.conf")
1142 X_(" /etc/security/limits.conf")
1146 msg.set_default_response (RESPONSE_OK);
1148 VBox* vbox = msg.get_vbox();
1150 CheckButton cb (_("Do not show this window again"));
1151 hbox.pack_start (cb, true, false);
1152 vbox->pack_start (hbox);
1157 pop_back_splash (msg);
1161 if (cb.get_active()) {
1162 XMLNode node (X_("no-memory-warning"));
1163 Config->add_instant_xml (node);
1168 #endif // !__APPLE__
1173 ARDOUR_UI::queue_finish ()
1175 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
1179 ARDOUR_UI::idle_finish ()
1182 return false; /* do not call again */
1189 ARDOUR_UI::instance()->video_timeline->sync_session_state();
1191 if (_session->dirty()) {
1192 vector<string> actions;
1193 actions.push_back (_("Don't quit"));
1194 actions.push_back (_("Just quit"));
1195 actions.push_back (_("Save and quit"));
1196 switch (ask_about_saving_session(actions)) {
1201 /* use the default name */
1202 if (save_state_canfail ("")) {
1203 /* failed - don't quit */
1204 MessageDialog msg (_main_window,
1205 string_compose (_("\
1206 %1 was unable to save your session.\n\n\
1207 If you still wish to quit, please use the\n\n\
1208 \"Just quit\" option."), PROGRAM_NAME));
1209 pop_back_splash(msg);
1219 second_connection.disconnect ();
1220 point_one_second_connection.disconnect ();
1221 point_zero_something_second_connection.disconnect();
1222 fps_connection.disconnect();
1225 delete ARDOUR_UI::instance()->video_timeline;
1226 ARDOUR_UI::instance()->video_timeline = NULL;
1227 stop_video_server();
1229 /* Save state before deleting the session, as that causes some
1230 windows to be destroyed before their visible state can be
1233 save_ardour_state ();
1235 close_all_dialogs ();
1238 _session->set_clean ();
1239 _session->remove_pending_capture_state ();
1244 halt_connection.disconnect ();
1245 AudioEngine::instance()->stop ();
1246 #ifdef WINDOWS_VST_SUPPORT
1247 fst_stop_threading();
1253 ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
1255 ArdourDialog window (_("Unsaved Session"));
1256 Gtk::HBox dhbox; // the hbox for the image and text
1257 Gtk::Label prompt_label;
1258 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
1262 assert (actions.size() >= 3);
1264 window.add_button (actions[0], RESPONSE_REJECT);
1265 window.add_button (actions[1], RESPONSE_APPLY);
1266 window.add_button (actions[2], RESPONSE_ACCEPT);
1268 window.set_default_response (RESPONSE_ACCEPT);
1270 Gtk::Button noquit_button (msg);
1271 noquit_button.set_name ("EditorGTKButton");
1275 if (_session->snap_name() == _session->name()) {
1276 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?"),
1277 _session->snap_name());
1279 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?"),
1280 _session->snap_name());
1283 prompt_label.set_text (prompt);
1284 prompt_label.set_name (X_("PrompterLabel"));
1285 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
1287 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
1288 dhbox.set_homogeneous (false);
1289 dhbox.pack_start (*dimage, false, false, 5);
1290 dhbox.pack_start (prompt_label, true, false, 5);
1291 window.get_vbox()->pack_start (dhbox);
1293 window.set_name (_("Prompter"));
1294 window.set_modal (true);
1295 window.set_resizable (false);
1298 prompt_label.show();
1303 ResponseType r = (ResponseType) window.run();
1308 case RESPONSE_ACCEPT: // save and get out of here
1310 case RESPONSE_APPLY: // get out of here
1321 ARDOUR_UI::every_second ()
1324 update_xrun_count ();
1325 update_buffer_load ();
1326 update_disk_space ();
1327 update_timecode_format ();
1328 update_peak_thread_work ();
1330 if (nsm && nsm->is_active ()) {
1333 if (!_was_dirty && _session->dirty ()) {
1337 else if (_was_dirty && !_session->dirty ()){
1345 ARDOUR_UI::every_point_one_seconds ()
1347 // TODO get rid of this..
1348 // ShuttleControl is updated directly via TransportStateChange signal
1352 ARDOUR_UI::every_point_zero_something_seconds ()
1354 // august 2007: actual update frequency: 25Hz (40ms), not 100Hz
1356 if (editor_meter && UIConfiguration::instance().get_show_editor_meter()) {
1357 float mpeak = editor_meter->update_meters();
1358 if (mpeak > editor_meter_max_peak) {
1359 if (mpeak >= UIConfiguration::instance().get_meter_peak()) {
1360 editor_meter_peak_display.set_active_state ( Gtkmm2ext::ExplicitActive );
1367 ARDOUR_UI::set_fps_timeout_connection ()
1369 unsigned int interval = 40;
1370 if (!_session) return;
1371 if (_session->timecode_frames_per_second() != 0) {
1372 /* ideally we'll use a select() to sleep and not accumulate
1373 * idle time to provide a regular periodic signal.
1374 * See linux_vst_gui_support.cc 'elapsed_time_ms'.
1375 * However, that'll require a dedicated thread and cross-thread
1376 * signals to the GUI Thread..
1378 interval = floor(500. /* update twice per FPS, since Glib::signal_timeout is very irregular */
1379 * _session->frame_rate() / _session->nominal_frame_rate()
1380 / _session->timecode_frames_per_second()
1382 #ifdef PLATFORM_WINDOWS
1383 // the smallest windows scheduler time-slice is ~15ms.
1384 // periodic GUI timeouts shorter than that will cause
1385 // WaitForSingleObject to spinlock (100% of one CPU Core)
1386 // and gtk never enters idle mode.
1387 // also changing timeBeginPeriod(1) does not affect that in
1388 // any beneficial way, so we just limit the max rate for now.
1389 interval = std::max(30u, interval); // at most ~33Hz.
1391 interval = std::max(8u, interval); // at most 120Hz.
1394 fps_connection.disconnect();
1395 Timers::set_fps_interval (interval);
1399 ARDOUR_UI::update_sample_rate (framecnt_t)
1403 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
1405 if (!AudioEngine::instance()->connected()) {
1407 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1411 framecnt_t rate = AudioEngine::instance()->sample_rate();
1414 /* no sample rate available */
1415 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1418 if (fmod (rate, 1000.0) != 0.0) {
1419 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
1420 (float) rate / 1000.0f,
1421 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1423 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
1425 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1429 sample_rate_label.set_markup (buf);
1433 ARDOUR_UI::update_format ()
1436 format_label.set_text ("");
1441 s << _("File:") << X_(" <span foreground=\"green\">");
1443 switch (_session->config.get_native_file_header_format ()) {
1475 switch (_session->config.get_native_file_data_format ()) {
1489 format_label.set_markup (s.str ());
1493 ARDOUR_UI::update_xrun_count ()
1497 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1498 should also be changed.
1502 const unsigned int x = _session->get_xrun_count ();
1504 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">>10K</span>"), X_("red"));
1506 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">%u</span>"), x > 0 ? X_("red") : X_("green"), x);
1509 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">?</span>"), X_("yellow"));
1511 xrun_label.set_markup (buf);
1512 set_tip (xrun_label, _("Audio dropouts. Shift+click to reset"));
1516 ARDOUR_UI::update_cpu_load ()
1520 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1521 should also be changed.
1524 double const c = AudioEngine::instance()->get_dsp_load ();
1525 snprintf (buf, sizeof (buf), _("DSP: <span foreground=\"%s\">%5.1f%%</span>"), c >= 90 ? X_("red") : X_("green"), c);
1526 cpu_load_label.set_markup (buf);
1530 ARDOUR_UI::update_peak_thread_work ()
1533 const int c = SourceFactory::peak_work_queue_length ();
1535 snprintf (buf, sizeof (buf), _("PkBld: <span foreground=\"%s\">%d</span>"), c >= 2 ? X_("red") : X_("green"), c);
1536 peak_thread_work_label.set_markup (buf);
1538 peak_thread_work_label.set_markup (X_(""));
1543 ARDOUR_UI::update_buffer_load ()
1547 uint32_t const playback = _session ? _session->playback_load () : 100;
1548 uint32_t const capture = _session ? _session->capture_load () : 100;
1550 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1551 should also be changed.
1557 _("Buffers: <span foreground=\"green\">p:</span><span foreground=\"%s\">%" PRIu32 "%%</span> "
1558 "<span foreground=\"green\">c:</span><span foreground=\"%s\">%" PRIu32 "%%</span>"),
1559 playback <= 5 ? X_("red") : X_("green"),
1561 capture <= 5 ? X_("red") : X_("green"),
1565 buffer_load_label.set_markup (buf);
1567 buffer_load_label.set_text ("");
1572 ARDOUR_UI::count_recenabled_streams (Route& route)
1574 Track* track = dynamic_cast<Track*>(&route);
1575 if (track && track->rec_enable_control()->get_value()) {
1576 rec_enabled_streams += track->n_inputs().n_total();
1581 ARDOUR_UI::update_disk_space()
1583 if (_session == 0) {
1587 boost::optional<framecnt_t> opt_frames = _session->available_capture_duration();
1589 framecnt_t fr = _session->frame_rate();
1592 /* skip update - no SR available */
1597 /* Available space is unknown */
1598 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">Unknown</span>"));
1599 } else if (opt_frames.get_value_or (0) == max_framecnt) {
1600 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">24hrs+</span>"));
1602 rec_enabled_streams = 0;
1603 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams, false);
1605 framecnt_t frames = opt_frames.get_value_or (0);
1607 if (rec_enabled_streams) {
1608 frames /= rec_enabled_streams;
1615 hrs = frames / (fr * 3600);
1618 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">>24 hrs</span>"));
1620 frames -= hrs * fr * 3600;
1621 mins = frames / (fr * 60);
1622 frames -= mins * fr * 60;
1625 bool const low = (hrs == 0 && mins <= 30);
1629 _("Disk: <span foreground=\"%s\">%02dh:%02dm:%02ds</span>"),
1630 low ? X_("red") : X_("green"),
1636 disk_space_label.set_markup (buf);
1640 ARDOUR_UI::update_timecode_format ()
1646 TimecodeSlave* tcslave;
1647 SyncSource sync_src = Config->get_sync_source();
1649 if ((sync_src == LTC || sync_src == MTC) && (tcslave = dynamic_cast<TimecodeSlave*>(_session->slave())) != 0) {
1650 matching = (tcslave->apparent_timecode_format() == _session->config.get_timecode_format());
1655 snprintf (buf, sizeof (buf), S_("Timecode|TC: <span foreground=\"%s\">%s</span>"),
1656 matching ? X_("green") : X_("red"),
1657 Timecode::timecode_format_name (_session->config.get_timecode_format()).c_str());
1659 snprintf (buf, sizeof (buf), "TC: n/a");
1662 timecode_format_label.set_markup (buf);
1666 ARDOUR_UI::update_wall_clock ()
1670 static int last_min = -1;
1673 tm_now = localtime (&now);
1674 if (last_min != tm_now->tm_min) {
1676 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1677 wall_clock_label.set_text (buf);
1678 last_min = tm_now->tm_min;
1685 ARDOUR_UI::open_recent_session ()
1687 bool can_return = (_session != 0);
1689 SessionDialog recent_session_dialog;
1693 ResponseType r = (ResponseType) recent_session_dialog.run ();
1696 case RESPONSE_ACCEPT:
1700 recent_session_dialog.hide();
1707 recent_session_dialog.hide();
1711 std::string path = recent_session_dialog.session_folder();
1712 std::string state = recent_session_dialog.session_name (should_be_new);
1714 if (should_be_new == true) {
1718 _session_is_new = false;
1720 if (load_session (path, state) == 0) {
1726 if (splash && splash->is_visible()) {
1727 // in 1 second, hide the splash screen
1728 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
1733 ARDOUR_UI::check_audioengine (Gtk::Window& parent)
1735 if (!AudioEngine::instance()->connected()) {
1736 MessageDialog msg (parent, string_compose (
1737 _("%1 is not connected to any audio backend.\n"
1738 "You cannot open or close sessions in this condition"),
1740 pop_back_splash (msg);
1748 ARDOUR_UI::open_session ()
1750 if (!check_audioengine (_main_window)) {
1754 /* ardour sessions are folders */
1755 Gtk::FileChooserDialog open_session_selector(_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1756 open_session_selector.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1757 open_session_selector.add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1758 open_session_selector.set_default_response(Gtk::RESPONSE_ACCEPT);
1761 string session_parent_dir = Glib::path_get_dirname(_session->path());
1762 open_session_selector.set_current_folder(session_parent_dir);
1764 open_session_selector.set_current_folder(Config->get_default_session_parent_dir());
1767 Gtkmm2ext::add_volume_shortcuts (open_session_selector);
1769 /* add_shortcut_folder throws an exception if the folder being added already has a shortcut */
1770 string default_session_folder = Config->get_default_session_parent_dir();
1771 open_session_selector.add_shortcut_folder (default_session_folder);
1773 catch (Glib::Error & e) {
1774 std::cerr << "open_session_selector.add_shortcut_folder() threw Glib::Error " << e.what() << std::endl;
1777 FileFilter session_filter;
1778 session_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::statefile_suffix));
1779 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1780 open_session_selector.add_filter (session_filter);
1781 open_session_selector.set_filter (session_filter);
1783 int response = open_session_selector.run();
1784 open_session_selector.hide ();
1786 if (response == Gtk::RESPONSE_CANCEL) {
1790 string session_path = open_session_selector.get_filename();
1794 if (session_path.length() > 0) {
1795 if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1796 _session_is_new = isnew;
1797 load_session (path, name);
1803 ARDOUR_UI::session_add_vca (const string& name_template, uint32_t n)
1809 _session->vca_manager().create_vca (n, name_template);
1813 ARDOUR_UI::session_add_mixed_track (
1814 const ChanCount& input,
1815 const ChanCount& output,
1816 RouteGroup* route_group,
1818 const string& name_template,
1820 PluginInfoPtr instrument,
1821 Plugin::PresetRecord* pset,
1822 ARDOUR::PresentationInfo::order_t order)
1824 list<boost::shared_ptr<MidiTrack> > tracks;
1826 if (_session == 0) {
1827 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1832 tracks = _session->new_midi_track (input, output, instrument, pset, route_group, how_many, name_template, order, ARDOUR::Normal);
1834 if (tracks.size() != how_many) {
1835 error << string_compose(P_("could not create %1 new mixed track", "could not create %1 new mixed tracks", how_many), how_many) << endmsg;
1840 display_insufficient_ports_message ();
1845 for (list<boost::shared_ptr<MidiTrack> >::iterator i = tracks.begin(); i != tracks.end(); ++i) {
1846 (*i)->set_strict_io (true);
1852 ARDOUR_UI::session_add_midi_bus (
1853 RouteGroup* route_group,
1855 const string& name_template,
1857 PluginInfoPtr instrument,
1858 Plugin::PresetRecord* pset,
1859 ARDOUR::PresentationInfo::order_t order)
1863 if (_session == 0) {
1864 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1870 routes = _session->new_midi_route (route_group, how_many, name_template, instrument, pset, PresentationInfo::MidiBus, order);
1871 if (routes.size() != how_many) {
1872 error << string_compose(P_("could not create %1 new Midi Bus", "could not create %1 new Midi Busses", how_many), how_many) << endmsg;
1877 display_insufficient_ports_message ();
1882 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
1883 (*i)->set_strict_io (true);
1889 ARDOUR_UI::session_add_midi_route (
1891 RouteGroup* route_group,
1893 const string& name_template,
1895 PluginInfoPtr instrument,
1896 Plugin::PresetRecord* pset,
1897 ARDOUR::PresentationInfo::order_t order)
1899 ChanCount one_midi_channel;
1900 one_midi_channel.set (DataType::MIDI, 1);
1903 session_add_mixed_track (one_midi_channel, one_midi_channel, route_group, how_many, name_template, strict_io, order, instrument, pset);
1905 session_add_midi_bus (route_group, how_many, name_template, strict_io, order, instrument, pset);
1910 ARDOUR_UI::session_add_audio_route (
1912 int32_t input_channels,
1913 int32_t output_channels,
1914 ARDOUR::TrackMode mode,
1915 RouteGroup* route_group,
1917 string const & name_template,
1919 ARDOUR::PresentationInfo::order_t order)
1921 list<boost::shared_ptr<AudioTrack> > tracks;
1924 if (_session == 0) {
1925 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1931 tracks = _session->new_audio_track (input_channels, output_channels, route_group, how_many, name_template, order, mode);
1933 if (tracks.size() != how_many) {
1934 error << string_compose (P_("could not create %1 new audio track", "could not create %1 new audio tracks", how_many), how_many)
1940 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template, PresentationInfo::AudioBus, order);
1942 if (routes.size() != how_many) {
1943 error << string_compose (P_("could not create %1 new audio bus", "could not create %1 new audio busses", how_many), how_many)
1950 display_insufficient_ports_message ();
1955 for (list<boost::shared_ptr<AudioTrack> >::iterator i = tracks.begin(); i != tracks.end(); ++i) {
1956 (*i)->set_strict_io (true);
1958 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
1959 (*i)->set_strict_io (true);
1965 ARDOUR_UI::display_insufficient_ports_message ()
1967 MessageDialog msg (_main_window,
1968 string_compose (_("There are insufficient ports available\n\
1969 to create a new track or bus.\n\
1970 You should save %1, exit and\n\
1971 restart with more ports."), PROGRAM_NAME));
1972 pop_back_splash (msg);
1977 ARDOUR_UI::transport_goto_start ()
1980 _session->goto_start();
1982 /* force displayed area in editor to start no matter
1983 what "follow playhead" setting is.
1987 editor->center_screen (_session->current_start_frame ());
1993 ARDOUR_UI::transport_goto_zero ()
1996 _session->request_locate (0);
1998 /* force displayed area in editor to start no matter
1999 what "follow playhead" setting is.
2003 editor->reset_x_origin (0);
2009 ARDOUR_UI::transport_goto_wallclock ()
2011 if (_session && editor) {
2018 localtime_r (&now, &tmnow);
2020 framecnt_t frame_rate = _session->frame_rate();
2022 if (frame_rate == 0) {
2023 /* no frame rate available */
2027 frames = tmnow.tm_hour * (60 * 60 * frame_rate);
2028 frames += tmnow.tm_min * (60 * frame_rate);
2029 frames += tmnow.tm_sec * frame_rate;
2031 _session->request_locate (frames, _session->transport_rolling ());
2033 /* force displayed area in editor to start no matter
2034 what "follow playhead" setting is.
2038 editor->center_screen (frames);
2044 ARDOUR_UI::transport_goto_end ()
2047 framepos_t const frame = _session->current_end_frame();
2048 _session->request_locate (frame);
2050 /* force displayed area in editor to start no matter
2051 what "follow playhead" setting is.
2055 editor->center_screen (frame);
2061 ARDOUR_UI::transport_stop ()
2067 if (_session->is_auditioning()) {
2068 _session->cancel_audition ();
2072 _session->request_stop (false, true);
2075 /** Check if any tracks are record enabled. If none are, record enable all of them.
2076 * @return true if track record-enabled status was changed, false otherwise.
2079 ARDOUR_UI::trx_record_enable_all_tracks ()
2085 boost::shared_ptr<RouteList> rl = _session->get_tracks ();
2086 bool none_record_enabled = true;
2088 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
2089 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*r);
2092 if (t->rec_enable_control()->get_value()) {
2093 none_record_enabled = false;
2098 if (none_record_enabled) {
2099 _session->set_controls (route_list_to_control_list (rl, &Track::rec_enable_control), 1.0, Controllable::NoGroup);
2102 return none_record_enabled;
2106 ARDOUR_UI::transport_record (bool roll)
2109 switch (_session->record_status()) {
2110 case Session::Disabled:
2111 if (_session->ntracks() == 0) {
2112 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."));
2116 if (Profile->get_trx()) {
2117 roll = trx_record_enable_all_tracks ();
2119 _session->maybe_enable_record ();
2124 case Session::Recording:
2126 _session->request_stop();
2128 _session->disable_record (false, true);
2132 case Session::Enabled:
2133 _session->disable_record (false, true);
2139 ARDOUR_UI::transport_roll ()
2145 if (_session->is_auditioning()) {
2150 if (_session->config.get_external_sync()) {
2151 switch (Config->get_sync_source()) {
2155 /* transport controlled by the master */
2161 bool rolling = _session->transport_rolling();
2163 if (_session->get_play_loop()) {
2165 /* If loop playback is not a mode, then we should cancel
2166 it when this action is requested. If it is a mode
2167 we just leave it in place.
2170 if (!Config->get_loop_is_mode()) {
2171 /* XXX it is not possible to just leave seamless loop and keep
2172 playing at present (nov 4th 2009)
2174 if (!Config->get_seamless_loop()) {
2175 /* stop loop playback and stop rolling */
2176 _session->request_play_loop (false, true);
2177 } else if (rolling) {
2178 /* stop loop playback but keep rolling */
2179 _session->request_play_loop (false, false);
2183 } else if (_session->get_play_range () ) {
2184 /* stop playing a range if we currently are */
2185 _session->request_play_range (0, true);
2189 _session->request_transport_speed (1.0f);
2194 ARDOUR_UI::get_smart_mode() const
2196 return ( editor->get_smart_mode() );
2201 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
2207 if (_session->is_auditioning()) {
2208 _session->cancel_audition ();
2212 if (_session->config.get_external_sync()) {
2213 switch (Config->get_sync_source()) {
2217 /* transport controlled by the master */
2222 bool rolling = _session->transport_rolling();
2223 bool affect_transport = true;
2225 if (rolling && roll_out_of_bounded_mode) {
2226 /* drop out of loop/range playback but leave transport rolling */
2227 if (_session->get_play_loop()) {
2228 if (_session->actively_recording()) {
2230 /* just stop using the loop, then actually stop
2233 _session->request_play_loop (false, affect_transport);
2236 if (Config->get_seamless_loop()) {
2237 /* the disk buffers contain copies of the loop - we can't
2238 just keep playing, so stop the transport. the user
2239 can restart as they wish.
2241 affect_transport = true;
2243 /* disk buffers are normal, so we can keep playing */
2244 affect_transport = false;
2246 _session->request_play_loop (false, affect_transport);
2248 } else if (_session->get_play_range ()) {
2249 affect_transport = false;
2250 _session->request_play_range (0, true);
2254 if (affect_transport) {
2256 _session->request_stop (with_abort, true);
2258 /* the only external sync condition we can be in here
2259 * would be Engine (JACK) sync, in which case we still
2263 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
2264 _session->request_play_range (&editor->get_selection().time, true);
2265 _session->set_requested_return_frame( editor->get_selection().time.front().start ); //force an auto-return here
2267 _session->request_transport_speed (1.0f);
2273 ARDOUR_UI::toggle_session_auto_loop ()
2279 Location * looploc = _session->locations()->auto_loop_location();
2285 if (_session->get_play_loop()) {
2287 /* looping enabled, our job is to disable it */
2289 _session->request_play_loop (false);
2293 /* looping not enabled, our job is to enable it.
2295 loop-is-NOT-mode: this action always starts the transport rolling.
2296 loop-IS-mode: this action simply sets the loop play mechanism, but
2297 does not start transport.
2299 if (Config->get_loop_is_mode()) {
2300 _session->request_play_loop (true, false);
2302 _session->request_play_loop (true, true);
2306 //show the loop markers
2307 looploc->set_hidden (false, this);
2311 ARDOUR_UI::transport_play_selection ()
2317 editor->play_selection ();
2321 ARDOUR_UI::transport_play_preroll ()
2326 editor->play_with_preroll ();
2330 ARDOUR_UI::transport_rewind (int option)
2332 float current_transport_speed;
2335 current_transport_speed = _session->transport_speed();
2337 if (current_transport_speed >= 0.0f) {
2340 _session->request_transport_speed (-1.0f);
2343 _session->request_transport_speed (-4.0f);
2346 _session->request_transport_speed (-0.5f);
2351 _session->request_transport_speed (current_transport_speed * 1.5f);
2357 ARDOUR_UI::transport_forward (int option)
2363 float current_transport_speed = _session->transport_speed();
2365 if (current_transport_speed <= 0.0f) {
2368 _session->request_transport_speed (1.0f);
2371 _session->request_transport_speed (4.0f);
2374 _session->request_transport_speed (0.5f);
2379 _session->request_transport_speed (current_transport_speed * 1.5f);
2384 ARDOUR_UI::toggle_record_enable (uint16_t rid)
2390 boost::shared_ptr<Route> r;
2392 if ((r = _session->get_remote_nth_route (rid)) != 0) {
2394 boost::shared_ptr<Track> t;
2396 if ((t = boost::dynamic_pointer_cast<Track>(r)) != 0) {
2397 t->rec_enable_control()->set_value (!t->rec_enable_control()->get_value(), Controllable::UseGroup);
2403 ARDOUR_UI::map_transport_state ()
2406 auto_loop_button.unset_active_state ();
2407 play_selection_button.unset_active_state ();
2408 roll_button.unset_active_state ();
2409 stop_button.set_active_state (Gtkmm2ext::ExplicitActive);
2413 shuttle_box->map_transport_state ();
2415 float sp = _session->transport_speed();
2421 if (_session->get_play_range()) {
2423 play_selection_button.set_active_state (Gtkmm2ext::ExplicitActive);
2424 roll_button.unset_active_state ();
2425 auto_loop_button.unset_active_state ();
2427 } else if (_session->get_play_loop ()) {
2429 auto_loop_button.set_active (true);
2430 play_selection_button.set_active (false);
2431 if (Config->get_loop_is_mode()) {
2432 roll_button.set_active (true);
2434 roll_button.set_active (false);
2439 roll_button.set_active (true);
2440 play_selection_button.set_active (false);
2441 auto_loop_button.set_active (false);
2444 if (UIConfiguration::instance().get_follow_edits() && !_session->config.get_external_sync()) {
2445 /* light up both roll and play-selection if they are joined */
2446 roll_button.set_active (true);
2447 play_selection_button.set_active (true);
2450 stop_button.set_active (false);
2454 stop_button.set_active (true);
2455 roll_button.set_active (false);
2456 play_selection_button.set_active (false);
2457 if (Config->get_loop_is_mode ()) {
2458 auto_loop_button.set_active (_session->get_play_loop());
2460 auto_loop_button.set_active (false);
2462 update_disk_space ();
2467 ARDOUR_UI::blink_handler (bool blink_on)
2469 transport_rec_enable_blink (blink_on);
2470 solo_blink (blink_on);
2471 sync_blink (blink_on);
2472 audition_blink (blink_on);
2473 feedback_blink (blink_on);
2474 error_blink (blink_on);
2478 ARDOUR_UI::update_clocks ()
2480 if (!_session) return;
2482 if (editor && !editor->dragging_playhead()) {
2483 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD)); /* EMIT_SIGNAL */
2488 ARDOUR_UI::start_clocking ()
2490 if (UIConfiguration::instance().get_super_rapid_clock_update()) {
2491 clock_signal_connection = Timers::fps_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2493 clock_signal_connection = Timers::rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2498 ARDOUR_UI::stop_clocking ()
2500 clock_signal_connection.disconnect ();
2504 ARDOUR_UI::save_as_progress_update (float fraction, int64_t cnt, int64_t total, Gtk::Label* label, Gtk::ProgressBar* bar)
2508 snprintf (buf, sizeof (buf), _("Copied %" PRId64 " of %" PRId64), cnt, total);
2510 label->set_text (buf);
2511 bar->set_fraction (fraction);
2513 /* process events, redraws, etc. */
2515 while (gtk_events_pending()) {
2516 gtk_main_iteration ();
2519 return true; /* continue with save-as */
2523 ARDOUR_UI::save_session_as ()
2529 if (!save_as_dialog) {
2530 save_as_dialog = new SaveAsDialog;
2533 save_as_dialog->set_name (_session->name());
2535 int response = save_as_dialog->run ();
2537 save_as_dialog->hide ();
2540 case Gtk::RESPONSE_OK:
2549 sa.new_parent_folder = save_as_dialog->new_parent_folder ();
2550 sa.new_name = save_as_dialog->new_name ();
2551 sa.switch_to = save_as_dialog->switch_to();
2552 sa.copy_media = save_as_dialog->copy_media();
2553 sa.copy_external = save_as_dialog->copy_external();
2554 sa.include_media = save_as_dialog->include_media ();
2556 /* Only bother with a progress dialog if we're going to copy
2557 media into the save-as target. Without that choice, this
2558 will be very fast because we're only talking about a few kB's to
2559 perhaps a couple of MB's of data.
2562 ArdourDialog progress_dialog (_("Save As"), true);
2564 if (sa.include_media && sa.copy_media) {
2567 Gtk::ProgressBar progress_bar;
2569 progress_dialog.get_vbox()->pack_start (label);
2570 progress_dialog.get_vbox()->pack_start (progress_bar);
2572 progress_bar.show ();
2574 /* this signal will be emitted from within this, the calling thread,
2575 * after every file is copied. It provides information on percentage
2576 * complete (in terms of total data to copy), the number of files
2577 * copied so far, and the total number to copy.
2582 sa.Progress.connect_same_thread (c, boost::bind (&ARDOUR_UI::save_as_progress_update, this, _1, _2, _3, &label, &progress_bar));
2584 progress_dialog.show_all ();
2585 progress_dialog.present ();
2588 if (_session->save_as (sa)) {
2590 MessageDialog msg (string_compose (_("Save As failed: %1"), sa.failure_message));
2594 if (!sa.include_media) {
2595 unload_session (false);
2596 load_session (sa.final_session_folder_name, sa.new_name);
2601 ARDOUR_UI::quick_snapshot_session (bool switch_to_it)
2605 struct tm local_time;
2608 localtime_r (&n, &local_time);
2609 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2611 save_state (timebuf, switch_to_it);
2616 ARDOUR_UI::process_snapshot_session_prompter (ArdourPrompter& prompter, bool switch_to_it)
2620 prompter.get_result (snapname);
2622 bool do_save = (snapname.length() != 0);
2625 char illegal = Session::session_name_is_legal(snapname);
2627 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2628 "snapshot names may not contain a '%1' character"), illegal));
2634 vector<std::string> p;
2635 get_state_files_in_directory (_session->session_directory().root_path(), p);
2636 vector<string> n = get_file_names_no_extension (p);
2638 if (find (n.begin(), n.end(), snapname) != n.end()) {
2640 do_save = overwrite_file_dialog (prompter,
2641 _("Confirm Snapshot Overwrite"),
2642 _("A snapshot already exists with that name. Do you want to overwrite it?"));
2646 save_state (snapname, switch_to_it);
2656 /** Ask the user for the name of a new snapshot and then take it.
2660 ARDOUR_UI::snapshot_session (bool switch_to_it)
2662 ArdourPrompter prompter (true);
2664 prompter.set_name ("Prompter");
2665 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2667 prompter.set_title (_("Snapshot and switch"));
2668 prompter.set_prompt (_("New session name"));
2670 prompter.set_title (_("Take Snapshot"));
2671 prompter.set_prompt (_("Name of new snapshot"));
2675 prompter.set_initial_text (_session->snap_name());
2679 struct tm local_time;
2682 localtime_r (&n, &local_time);
2683 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2684 prompter.set_initial_text (timebuf);
2687 bool finished = false;
2689 switch (prompter.run()) {
2690 case RESPONSE_ACCEPT:
2692 finished = process_snapshot_session_prompter (prompter, switch_to_it);
2703 /** Ask the user for a new session name and then rename the session to it.
2707 ARDOUR_UI::rename_session ()
2713 ArdourPrompter prompter (true);
2716 prompter.set_name ("Prompter");
2717 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2718 prompter.set_title (_("Rename Session"));
2719 prompter.set_prompt (_("New session name"));
2722 switch (prompter.run()) {
2723 case RESPONSE_ACCEPT:
2725 prompter.get_result (name);
2727 bool do_rename = (name.length() != 0);
2730 char illegal = Session::session_name_is_legal (name);
2733 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2734 "session names may not contain a '%1' character"), illegal));
2739 switch (_session->rename (name)) {
2741 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
2742 msg.set_position (WIN_POS_MOUSE);
2750 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
2751 msg.set_position (WIN_POS_MOUSE);
2767 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2769 if (!_session || _session->deletion_in_progress()) {
2773 XMLNode* node = new XMLNode (X_("UI"));
2775 WM::Manager::instance().add_state (*node);
2777 node->add_child_nocopy (gui_object_state->get_state());
2779 _session->add_extra_xml (*node);
2781 if (export_video_dialog) {
2782 _session->add_extra_xml (export_video_dialog->get_state());
2785 save_state_canfail (name, switch_to_it);
2789 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2794 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2799 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2804 ARDOUR_UI::primary_clock_value_changed ()
2807 _session->request_locate (primary_clock->current_time ());
2812 ARDOUR_UI::big_clock_value_changed ()
2815 _session->request_locate (big_clock->current_time ());
2820 ARDOUR_UI::secondary_clock_value_changed ()
2823 _session->request_locate (secondary_clock->current_time ());
2828 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2830 if (_session == 0) {
2834 if (_session->step_editing()) {
2838 Session::RecordState const r = _session->record_status ();
2839 bool const h = _session->have_rec_enabled_track ();
2841 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2843 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2845 rec_button.set_active_state (Gtkmm2ext::Off);
2847 } else if (r == Session::Recording && h) {
2848 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2850 rec_button.unset_active_state ();
2855 ARDOUR_UI::process_save_template_prompter (ArdourPrompter& prompter)
2859 prompter.get_result (name);
2861 if (name.length()) {
2862 int failed = _session->save_template (name);
2864 if (failed == -2) { /* file already exists. */
2865 bool overwrite = overwrite_file_dialog (prompter,
2866 _("Confirm Template Overwrite"),
2867 _("A template already exists with that name. Do you want to overwrite it?"));
2870 _session->save_template (name, true);
2882 ARDOUR_UI::save_template ()
2884 ArdourPrompter prompter (true);
2886 if (!check_audioengine (_main_window)) {
2890 prompter.set_name (X_("Prompter"));
2891 prompter.set_title (_("Save Template"));
2892 prompter.set_prompt (_("Name for template:"));
2893 prompter.set_initial_text(_session->name() + _("-template"));
2894 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2896 bool finished = false;
2898 switch (prompter.run()) {
2899 case RESPONSE_ACCEPT:
2900 finished = process_save_template_prompter (prompter);
2911 ARDOUR_UI::edit_metadata ()
2913 SessionMetadataEditor dialog;
2914 dialog.set_session (_session);
2915 dialog.grab_focus ();
2920 ARDOUR_UI::import_metadata ()
2922 SessionMetadataImporter dialog;
2923 dialog.set_session (_session);
2928 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
2930 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2932 MessageDialog msg (str,
2934 Gtk::MESSAGE_WARNING,
2935 Gtk::BUTTONS_YES_NO,
2939 msg.set_name (X_("OpenExistingDialog"));
2940 msg.set_title (_("Open Existing Session"));
2941 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
2942 msg.set_position (Gtk::WIN_POS_CENTER);
2943 pop_back_splash (msg);
2945 switch (msg.run()) {
2954 ARDOUR_UI::build_session_from_dialog (SessionDialog& sd, const std::string& session_path, const std::string& session_name)
2956 BusProfile bus_profile;
2960 bus_profile.master_out_channels = 2;
2961 bus_profile.input_ac = AutoConnectPhysical;
2962 bus_profile.output_ac = AutoConnectMaster;
2963 bus_profile.requested_physical_in = 0; // use all available
2964 bus_profile.requested_physical_out = 0; // use all available
2968 /* get settings from advanced section of NSD */
2970 if (sd.create_master_bus()) {
2971 bus_profile.master_out_channels = (uint32_t) sd.master_channel_count();
2973 bus_profile.master_out_channels = 0;
2976 if (sd.connect_inputs()) {
2977 bus_profile.input_ac = AutoConnectPhysical;
2979 bus_profile.input_ac = AutoConnectOption (0);
2982 bus_profile.output_ac = AutoConnectOption (0);
2984 if (sd.connect_outputs ()) {
2985 if (sd.connect_outs_to_master()) {
2986 bus_profile.output_ac = AutoConnectMaster;
2987 } else if (sd.connect_outs_to_physical()) {
2988 bus_profile.output_ac = AutoConnectPhysical;
2992 bus_profile.requested_physical_in = (uint32_t) sd.input_limit_count();
2993 bus_profile.requested_physical_out = (uint32_t) sd.output_limit_count();
2996 if (build_session (session_path, session_name, bus_profile)) {
3004 ARDOUR_UI::load_from_application_api (const std::string& path)
3006 ARDOUR_COMMAND_LINE::session_name = path;
3007 /* Cancel SessionDialog if it's visible to make OSX delegates work.
3009 * ARDOUR_UI::starting connects app->ShouldLoad signal and then shows a SessionDialog
3011 * - ShouldLoad does not arrive in time, ARDOUR_COMMAND_LINE::session_name is empty:
3012 * -> ARDOUR_UI::get_session_parameters starts a SessionDialog.
3013 * - ShouldLoad signal arrives, this function is called and sets ARDOUR_COMMAND_LINE::session_name
3014 * -> SessionDialog is not displayed
3017 if (_session_dialog) {
3018 std::string session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3019 std::string session_path = path;
3020 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_REGULAR)) {
3021 session_path = Glib::path_get_dirname (session_path);
3023 // signal the existing dialog in ARDOUR_UI::get_session_parameters()
3024 _session_dialog->set_provided_session (session_name, session_path);
3025 _session_dialog->response (RESPONSE_NONE);
3026 _session_dialog->hide();
3031 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
3032 /* /path/to/foo => /path/to/foo, foo */
3033 rv = load_session (path, basename_nosuffix (path));
3035 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
3036 rv =load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
3039 // if load_session fails -> pop up SessionDialog.
3041 ARDOUR_COMMAND_LINE::session_name = "";
3043 if (get_session_parameters (true, false)) {
3049 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
3051 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
3053 string session_name;
3054 string session_path;
3055 string template_name;
3057 bool likely_new = false;
3058 bool cancel_not_quit;
3060 /* deal with any existing DIRTY session now, rather than later. don't
3061 * treat a non-dirty session this way, so that it stays visible
3062 * as we bring up the new session dialog.
3065 if (_session && ARDOUR_UI::instance()->video_timeline) {
3066 ARDOUR_UI::instance()->video_timeline->sync_session_state();
3069 /* if there is already a session, relabel the button
3070 on the SessionDialog so that we don't Quit directly
3072 cancel_not_quit = (_session != 0);
3074 if (_session && _session->dirty()) {
3075 if (unload_session (false)) {
3076 /* unload cancelled by user */
3079 ARDOUR_COMMAND_LINE::session_name = "";
3082 if (!load_template.empty()) {
3083 should_be_new = true;
3084 template_name = load_template;
3087 session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3088 session_path = ARDOUR_COMMAND_LINE::session_name;
3090 if (!session_path.empty()) {
3091 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_EXISTS)) {
3092 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_IS_REGULAR)) {
3093 /* session/snapshot file, change path to be dir */
3094 session_path = Glib::path_get_dirname (session_path);
3099 SessionDialog session_dialog (should_be_new, session_name, session_path, load_template, cancel_not_quit);
3101 _session_dialog = &session_dialog;
3104 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
3106 /* if they named a specific statefile, use it, otherwise they are
3107 just giving a session folder, and we want to use it as is
3108 to find the session.
3111 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
3113 if (suffix != string::npos) {
3114 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
3115 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
3116 session_name = Glib::path_get_basename (session_name);
3118 session_path = ARDOUR_COMMAND_LINE::session_name;
3119 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
3124 session_dialog.clear_given ();
3127 if (should_be_new || session_name.empty()) {
3128 /* need the dialog to get info from user */
3130 cerr << "run dialog\n";
3132 switch (session_dialog.run()) {
3133 case RESPONSE_ACCEPT:
3136 /* this is used for async * app->ShouldLoad(). */
3137 continue; // while loop
3140 if (quit_on_cancel) {
3141 // JE - Currently (July 2014) this section can only get reached if the
3142 // user quits from the main 'Session Setup' dialog (i.e. reaching this
3143 // point does NOT indicate an abnormal termination). Therefore, let's
3144 // behave gracefully (i.e. let's do some cleanup) before we call exit()
3146 pthread_cancel_all ();
3154 session_dialog.hide ();
3157 /* if we run the startup dialog again, offer more than just "new session" */
3159 should_be_new = false;
3161 session_name = session_dialog.session_name (likely_new);
3162 session_path = session_dialog.session_folder ();
3168 string::size_type suffix = session_name.find (statefile_suffix);
3170 if (suffix != string::npos) {
3171 session_name = session_name.substr (0, suffix);
3174 /* this shouldn't happen, but we catch it just in case it does */
3176 if (session_name.empty()) {
3180 if (session_dialog.use_session_template()) {
3181 template_name = session_dialog.session_template_name();
3182 _session_is_new = true;
3185 if (session_name[0] == G_DIR_SEPARATOR ||
3186 #ifdef PLATFORM_WINDOWS
3187 (session_name.length() > 3 && session_name[1] == ':' && session_name[2] == G_DIR_SEPARATOR)
3189 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
3190 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)
3195 /* absolute path or cwd-relative path specified for session name: infer session folder
3196 from what was given.
3199 session_path = Glib::path_get_dirname (session_name);
3200 session_name = Glib::path_get_basename (session_name);
3204 session_path = session_dialog.session_folder();
3206 char illegal = Session::session_name_is_legal (session_name);
3209 MessageDialog msg (session_dialog,
3210 string_compose (_("To ensure compatibility with various systems\n"
3211 "session names may not contain a '%1' character"),
3214 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3219 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
3222 if (likely_new && !nsm) {
3224 std::string existing = Glib::build_filename (session_path, session_name);
3226 if (!ask_about_loading_existing_session (existing)) {
3227 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3232 _session_is_new = false;
3237 pop_back_splash (session_dialog);
3238 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
3240 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3244 char illegal = Session::session_name_is_legal(session_name);
3247 pop_back_splash (session_dialog);
3248 MessageDialog msg (session_dialog, string_compose(_("To ensure compatibility with various systems\n"
3249 "session names may not contain a '%1' character"), illegal));
3251 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3255 _session_is_new = true;
3258 if (likely_new && template_name.empty()) {
3260 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3264 ret = load_session (session_path, session_name, template_name);
3267 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
3271 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
3272 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
3276 /* clear this to avoid endless attempts to load the
3280 ARDOUR_COMMAND_LINE::session_name = "";
3284 _session_dialog = NULL;
3290 ARDOUR_UI::close_session()
3292 if (!check_audioengine (_main_window)) {
3296 if (unload_session (true)) {
3300 ARDOUR_COMMAND_LINE::session_name = "";
3302 if (get_session_parameters (true, false)) {
3305 if (splash && splash->is_visible()) {
3306 // in 1 second, hide the splash screen
3307 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
3311 /** @param snap_name Snapshot name (without .ardour suffix).
3312 * @return -2 if the load failed because we are not connected to the AudioEngine.
3315 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
3317 Session *new_session;
3322 unload_status = unload_session ();
3324 if (unload_status < 0) {
3326 } else if (unload_status > 0) {
3332 session_loaded = false;
3334 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
3337 new_session = new Session (*AudioEngine::instance(), path, snap_name, 0, mix_template);
3340 /* this one is special */
3342 catch (AudioEngine::PortRegistrationFailure& err) {
3344 MessageDialog msg (err.what(),
3347 Gtk::BUTTONS_CLOSE);
3349 msg.set_title (_("Port Registration Error"));
3350 msg.set_secondary_text (_("Click the Close button to try again."));
3351 msg.set_position (Gtk::WIN_POS_CENTER);
3352 pop_back_splash (msg);
3355 int response = msg.run ();
3360 case RESPONSE_CANCEL:
3367 catch (SessionException e) {
3368 MessageDialog msg (string_compose(
3369 _("Session \"%1 (snapshot %2)\" did not load successfully: %3"),
3370 path, snap_name, e.what()),
3375 msg.set_title (_("Loading Error"));
3376 msg.set_position (Gtk::WIN_POS_CENTER);
3377 pop_back_splash (msg);
3389 MessageDialog msg (string_compose(
3390 _("Session \"%1 (snapshot %2)\" did not load successfully"),
3396 msg.set_title (_("Loading Error"));
3397 msg.set_position (Gtk::WIN_POS_CENTER);
3398 pop_back_splash (msg);
3410 list<string> const u = new_session->unknown_processors ();
3412 MissingPluginDialog d (_session, u);
3417 if (!new_session->writable()) {
3418 MessageDialog msg (_("This session has been opened in read-only mode.\n\nYou will not be able to record or save."),
3423 msg.set_title (_("Read-only Session"));
3424 msg.set_position (Gtk::WIN_POS_CENTER);
3425 pop_back_splash (msg);
3432 /* Now the session been created, add the transport controls */
3433 new_session->add_controllable(roll_controllable);
3434 new_session->add_controllable(stop_controllable);
3435 new_session->add_controllable(goto_start_controllable);
3436 new_session->add_controllable(goto_end_controllable);
3437 new_session->add_controllable(auto_loop_controllable);
3438 new_session->add_controllable(play_selection_controllable);
3439 new_session->add_controllable(rec_controllable);
3441 set_session (new_session);
3443 session_loaded = true;
3446 _session->set_clean ();
3449 #ifdef WINDOWS_VST_SUPPORT
3450 fst_stop_threading();
3454 Timers::TimerSuspender t;
3458 #ifdef WINDOWS_VST_SUPPORT
3459 fst_start_threading();
3468 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
3470 Session *new_session;
3473 session_loaded = false;
3474 x = unload_session ();
3482 _session_is_new = true;
3485 new_session = new Session (*AudioEngine::instance(), path, snap_name, &bus_profile);
3488 catch (SessionException e) {
3490 MessageDialog msg (string_compose(_("Could not create session in \"%1\": %2"), path, e.what()));
3491 msg.set_title (_("Loading Error"));
3492 msg.set_position (Gtk::WIN_POS_CENTER);
3493 pop_back_splash (msg);
3499 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
3500 msg.set_title (_("Loading Error"));
3501 msg.set_position (Gtk::WIN_POS_CENTER);
3502 pop_back_splash (msg);
3507 /* Give the new session the default GUI state, if such things exist */
3510 n = Config->instant_xml (X_("Editor"));
3512 n->remove_nodes_and_delete ("Selection"); // no not apply selection to new sessions.
3513 new_session->add_instant_xml (*n, false);
3515 n = Config->instant_xml (X_("Mixer"));
3517 new_session->add_instant_xml (*n, false);
3520 /* Put the playhead at 0 and scroll fully left */
3521 n = new_session->instant_xml (X_("Editor"));
3523 n->add_property (X_("playhead"), X_("0"));
3524 n->add_property (X_("left-frame"), X_("0"));
3527 set_session (new_session);
3529 session_loaded = true;
3531 new_session->save_state(new_session->name());
3537 ARDOUR_UI::launch_chat ()
3539 MessageDialog dialog(_("<b>Just ask and wait for an answer.\nIt may take from minutes to hours.</b>"), true);
3541 dialog.set_title (_("About the Chat"));
3542 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."));
3544 switch (dialog.run()) {
3547 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
3548 #elif defined PLATFORM_WINDOWS
3549 open_uri("http://webchat.freenode.net/?channels=ardour-windows");
3551 open_uri("http://webchat.freenode.net/?channels=ardour");
3560 ARDOUR_UI::launch_manual ()
3562 PBD::open_uri (Config->get_tutorial_manual_url());
3566 ARDOUR_UI::launch_reference ()
3568 PBD::open_uri (Config->get_reference_manual_url());
3572 ARDOUR_UI::launch_tracker ()
3574 PBD::open_uri ("http://tracker.ardour.org");
3578 ARDOUR_UI::launch_subscribe ()
3580 PBD::open_uri ("https://community.ardour.org/s/subscribe");
3584 ARDOUR_UI::launch_cheat_sheet ()
3587 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheat_sheet_osx.pdf");
3589 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheatsheet.pdf");
3594 ARDOUR_UI::launch_website ()
3596 PBD::open_uri ("http://ardour.org");
3600 ARDOUR_UI::launch_website_dev ()
3602 PBD::open_uri ("http://ardour.org/development.html");
3606 ARDOUR_UI::launch_forums ()
3608 PBD::open_uri ("https://community.ardour.org/forums");
3612 ARDOUR_UI::launch_howto_report ()
3614 PBD::open_uri ("http://ardour.org/reporting_bugs");
3618 ARDOUR_UI::loading_message (const std::string& msg)
3620 if (ARDOUR_COMMAND_LINE::no_splash) {
3628 splash->message (msg);
3632 ARDOUR_UI::show_splash ()
3636 splash = new Splash;
3646 ARDOUR_UI::hide_splash ()
3653 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title, const bool msg_delete)
3657 removed = rep.paths.size();
3660 MessageDialog msgd (_main_window,
3661 _("No files were ready for clean-up"),
3665 msgd.set_title (_("Clean-up"));
3666 msgd.set_secondary_text (_("If this seems suprising, \n\
3667 check for any existing snapshots.\n\
3668 These may still include regions that\n\
3669 require some unused files to continue to exist."));
3675 ArdourDialog results (_("Clean-up"), true, false);
3677 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
3678 CleanupResultsModelColumns() {
3682 Gtk::TreeModelColumn<std::string> visible_name;
3683 Gtk::TreeModelColumn<std::string> fullpath;
3687 CleanupResultsModelColumns results_columns;
3688 Glib::RefPtr<Gtk::ListStore> results_model;
3689 Gtk::TreeView results_display;
3691 results_model = ListStore::create (results_columns);
3692 results_display.set_model (results_model);
3693 results_display.append_column (list_title, results_columns.visible_name);
3695 results_display.set_name ("CleanupResultsList");
3696 results_display.set_headers_visible (true);
3697 results_display.set_headers_clickable (false);
3698 results_display.set_reorderable (false);
3700 Gtk::ScrolledWindow list_scroller;
3703 Gtk::HBox dhbox; // the hbox for the image and text
3704 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
3705 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
3707 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
3709 const string dead_directory = _session->session_directory().dead_path();
3712 %1 - number of files removed
3713 %2 - location of "dead"
3714 %3 - size of files affected
3715 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
3718 const char* bprefix;
3719 double space_adjusted = 0;
3721 if (rep.space < 1000) {
3723 space_adjusted = rep.space;
3724 } else if (rep.space < 1000000) {
3725 bprefix = _("kilo");
3726 space_adjusted = floorf((float)rep.space / 1000.0);
3727 } else if (rep.space < 1000000 * 1000) {
3728 bprefix = _("mega");
3729 space_adjusted = floorf((float)rep.space / (1000.0 * 1000.0));
3731 bprefix = _("giga");
3732 space_adjusted = floorf((float)rep.space / (1000.0 * 1000 * 1000.0));
3736 txt.set_markup (string_compose (P_("\
3737 The following file was deleted from %2,\n\
3738 releasing %3 %4bytes of disk space", "\
3739 The following %1 files were deleted from %2,\n\
3740 releasing %3 %4bytes of disk space", removed),
3741 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3743 txt.set_markup (string_compose (P_("\
3744 The following file was not in use and \n\
3745 has been moved to: %2\n\n\
3746 After a restart of %5\n\n\
3747 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3748 will release an additional %3 %4bytes of disk space.\n", "\
3749 The following %1 files were not in use and \n\
3750 have been moved to: %2\n\n\
3751 After a restart of %5\n\n\
3752 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3753 will release an additional %3 %4bytes of disk space.\n", removed),
3754 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3757 dhbox.pack_start (*dimage, true, false, 5);
3758 dhbox.pack_start (txt, true, false, 5);
3760 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
3761 TreeModel::Row row = *(results_model->append());
3762 row[results_columns.visible_name] = *i;
3763 row[results_columns.fullpath] = *i;
3766 list_scroller.add (results_display);
3767 list_scroller.set_size_request (-1, 150);
3768 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
3770 dvbox.pack_start (dhbox, true, false, 5);
3771 dvbox.pack_start (list_scroller, true, false, 5);
3772 ddhbox.pack_start (dvbox, true, false, 5);
3774 results.get_vbox()->pack_start (ddhbox, true, false, 5);
3775 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
3776 results.set_default_response (RESPONSE_CLOSE);
3777 results.set_position (Gtk::WIN_POS_MOUSE);
3779 results_display.show();
3780 list_scroller.show();
3787 //results.get_vbox()->show();
3788 results.set_resizable (false);
3795 ARDOUR_UI::cleanup ()
3797 if (_session == 0) {
3798 /* shouldn't happen: menu item is insensitive */
3803 MessageDialog checker (_("Are you sure you want to clean-up?"),
3805 Gtk::MESSAGE_QUESTION,
3808 checker.set_title (_("Clean-up"));
3810 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
3811 ALL undo/redo information will be lost if you clean-up.\n\
3812 Clean-up will move all unused files to a \"dead\" location."));
3814 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3815 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
3816 checker.set_default_response (RESPONSE_CANCEL);
3818 checker.set_name (_("CleanupDialog"));
3819 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3820 checker.set_position (Gtk::WIN_POS_MOUSE);
3822 switch (checker.run()) {
3823 case RESPONSE_ACCEPT:
3829 ARDOUR::CleanupReport rep;
3831 editor->prepare_for_cleanup ();
3833 /* do not allow flush until a session is reloaded */
3835 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3837 act->set_sensitive (false);
3840 if (_session->cleanup_sources (rep)) {
3841 editor->finish_cleanup ();
3845 editor->finish_cleanup ();
3848 display_cleanup_results (rep, _("Cleaned Files"), false);
3852 ARDOUR_UI::flush_trash ()
3854 if (_session == 0) {
3855 /* shouldn't happen: menu item is insensitive */
3859 ARDOUR::CleanupReport rep;
3861 if (_session->cleanup_trash_sources (rep)) {
3865 display_cleanup_results (rep, _("deleted file"), true);
3869 ARDOUR_UI::cleanup_peakfiles ()
3871 if (_session == 0) {
3872 /* shouldn't happen: menu item is insensitive */
3876 if (! _session->can_cleanup_peakfiles ()) {
3880 // get all region-views in this session
3882 TrackViewList empty;
3884 editor->get_regions_after(rs, (framepos_t) 0, empty);
3885 std::list<RegionView*> views = rs.by_layer();
3887 // remove displayed audio-region-views waveforms
3888 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
3889 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
3890 if (!arv) { continue ; }
3891 arv->delete_waves();
3894 // cleanup peak files:
3895 // - stop pending peakfile threads
3896 // - close peakfiles if any
3897 // - remove peak dir in session
3898 // - setup peakfiles (background thread)
3899 _session->cleanup_peakfiles ();
3901 // re-add waves to ARV
3902 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
3903 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
3904 if (!arv) { continue ; }
3905 arv->create_waves();
3909 PresentationInfo::order_t
3910 ARDOUR_UI::translate_order (AddRouteDialog::InsertAt place)
3912 if (editor->get_selection().tracks.empty()) {
3913 return PresentationInfo::max_order;
3916 PresentationInfo::order_t order_hint = PresentationInfo::max_order;
3919 we want the new routes to have their order keys set starting from
3920 the highest order key in the selection + 1 (if available).
3923 if (place == AddRouteDialog::AfterSelection) {
3924 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.back());
3926 order_hint = rtav->route()->presentation_info().group_order();
3929 } else if (place == AddRouteDialog::BeforeSelection) {
3930 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.front());
3932 order_hint = rtav->route()->presentation_info().group_order();
3934 } else if (place == AddRouteDialog::First) {
3937 /* leave order_hint at max_order */
3944 ARDOUR_UI::start_duplicate_routes ()
3946 if (!duplicate_routes_dialog) {
3947 duplicate_routes_dialog = new DuplicateRouteDialog;
3950 if (duplicate_routes_dialog->restart (_session)) {
3954 duplicate_routes_dialog->present ();
3958 ARDOUR_UI::add_route ()
3966 if (add_route_dialog->is_visible()) {
3967 /* we're already doing this */
3971 ResponseType r = (ResponseType) add_route_dialog->run ();
3973 add_route_dialog->hide();
3976 case RESPONSE_ACCEPT:
3983 if ((count = add_route_dialog->count()) <= 0) {
3987 PresentationInfo::order_t order = translate_order (add_route_dialog->insert_at());
3988 string template_path = add_route_dialog->track_template();
3989 DisplaySuspender ds;
3991 if (!template_path.empty()) {
3992 if (add_route_dialog->name_template_is_default()) {
3993 _session->new_route_from_template (count, template_path, string());
3995 _session->new_route_from_template (count, template_path, add_route_dialog->name_template());
4000 ChanCount input_chan= add_route_dialog->channels ();
4001 ChanCount output_chan;
4002 string name_template = add_route_dialog->name_template ();
4003 PluginInfoPtr instrument = add_route_dialog->requested_instrument ();
4004 RouteGroup* route_group = add_route_dialog->route_group ();
4005 AutoConnectOption oac = Config->get_output_auto_connect();
4006 bool strict_io = add_route_dialog->use_strict_io ();
4008 if (oac & AutoConnectMaster) {
4009 output_chan.set (DataType::AUDIO, (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan.n_audio()));
4010 output_chan.set (DataType::MIDI, 0);
4012 output_chan = input_chan;
4015 /* XXX do something with name template */
4017 switch (add_route_dialog->type_wanted()) {
4018 case AddRouteDialog::AudioTrack:
4019 session_add_audio_track (input_chan.n_audio(), output_chan.n_audio(), add_route_dialog->mode(), route_group, count, name_template, strict_io, order);
4021 case AddRouteDialog::MidiTrack:
4022 session_add_midi_track (route_group, count, name_template, strict_io, instrument, 0, order);
4024 case AddRouteDialog::MixedTrack:
4025 session_add_mixed_track (input_chan, output_chan, route_group, count, name_template, strict_io, instrument, 0, order);
4027 case AddRouteDialog::AudioBus:
4028 session_add_audio_bus (input_chan.n_audio(), output_chan.n_audio(), route_group, count, name_template, strict_io, order);
4030 case AddRouteDialog::MidiBus:
4031 session_add_midi_bus (route_group, count, name_template, strict_io, instrument, 0, order);
4033 case AddRouteDialog::VCAMaster:
4034 session_add_vca (name_template, count);
4040 ARDOUR_UI::add_lua_script ()
4046 LuaScriptInfoPtr spi;
4047 ScriptSelector ss ("Add Lua Session Script", LuaScriptInfo::Session);
4048 switch (ss.run ()) {
4049 case Gtk::RESPONSE_ACCEPT:
4057 std::string script = "";
4060 script = Glib::file_get_contents (spi->path);
4061 } catch (Glib::FileError e) {
4062 string msg = string_compose (_("Cannot read session script '%1': %2"), spi->path, e.what());
4063 MessageDialog am (msg);
4068 LuaScriptParamList lsp = LuaScriptParams::script_params (spi, "sess_params");
4069 std::vector<std::string> reg = _session->registered_lua_functions ();
4071 ScriptParameterDialog spd (_("Set Script Parameters"), spi, reg, lsp);
4072 switch (spd.run ()) {
4073 case Gtk::RESPONSE_ACCEPT:
4080 _session->register_lua_function (spd.name(), script, lsp);
4081 } catch (luabridge::LuaException const& e) {
4082 string msg = string_compose (_("Session script '%1' instantiation failed: %2"), spd.name(), e.what ());
4083 MessageDialog am (msg);
4085 } catch (SessionException e) {
4086 string msg = string_compose (_("Loading Session script '%1' failed: %2"), spd.name(), e.what ());
4087 MessageDialog am (msg);
4093 ARDOUR_UI::remove_lua_script ()
4098 if (_session->registered_lua_function_count () == 0) {
4099 string msg = _("There are no active Lua session scripts present in this session.");
4100 MessageDialog am (msg);
4105 std::vector<std::string> reg = _session->registered_lua_functions ();
4106 SessionScriptManager sm ("Remove Lua Session Script", reg);
4107 switch (sm.run ()) {
4108 case Gtk::RESPONSE_ACCEPT:
4114 _session->unregister_lua_function (sm.name());
4115 } catch (luabridge::LuaException const& e) {
4116 string msg = string_compose (_("Session script '%1' removal failed: %2"), sm.name(), e.what ());
4117 MessageDialog am (msg);
4123 ARDOUR_UI::stop_video_server (bool ask_confirm)
4125 if (!video_server_process && ask_confirm) {
4126 warning << string_compose (_("Video-Server was not launched by %1. The request to stop it is ignored."), PROGRAM_NAME) << endmsg;
4128 if (video_server_process) {
4130 ArdourDialog confirm (_("Stop Video-Server"), true);
4131 Label m (_("Do you really want to stop the Video Server?"));
4132 confirm.get_vbox()->pack_start (m, true, true);
4133 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
4134 confirm.add_button (_("Yes, Stop It"), Gtk::RESPONSE_ACCEPT);
4135 confirm.show_all ();
4136 if (confirm.run() == RESPONSE_CANCEL) {
4140 delete video_server_process;
4141 video_server_process =0;
4146 ARDOUR_UI::start_video_server_menu (Gtk::Window* float_window)
4148 ARDOUR_UI::start_video_server( float_window, true);
4152 ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg)
4158 if (ARDOUR_UI::instance()->video_timeline->check_server()) {
4159 if (video_server_process) {
4160 popup_error(_("The Video Server is already started."));
4162 popup_error(_("An external Video Server is configured and can be reached. Not starting a new instance."));
4168 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4170 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4172 VideoServerDialog *video_server_dialog = new VideoServerDialog (_session);
4174 video_server_dialog->set_transient_for (*float_window);
4177 if (!Config->get_show_video_server_dialog() && firsttime < 2) {
4178 video_server_dialog->hide();
4180 ResponseType r = (ResponseType) video_server_dialog->run ();
4181 video_server_dialog->hide();
4182 if (r != RESPONSE_ACCEPT) { return false; }
4183 if (video_server_dialog->show_again()) {
4184 Config->set_show_video_server_dialog(false);
4188 std::string icsd_exec = video_server_dialog->get_exec_path();
4189 std::string icsd_docroot = video_server_dialog->get_docroot();
4190 if (icsd_docroot.empty()) {
4191 #ifndef PLATFORM_WINDOWS
4192 icsd_docroot = X_("/");
4194 icsd_docroot = X_("C:\\");
4199 if (g_lstat (icsd_docroot.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode)) {
4200 warning << _("Specified docroot is not an existing directory.") << endmsg;
4203 #ifndef PLATFORM_WINDOWS
4204 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4205 || (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0 ) {
4206 warning << _("Given Video Server is not an executable file.") << endmsg;
4210 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4211 || (sb.st_mode & (S_IXUSR)) == 0 ) {
4212 warning << _("Given Video Server is not an executable file.") << endmsg;
4218 argp=(char**) calloc(9,sizeof(char*));
4219 argp[0] = strdup(icsd_exec.c_str());
4220 argp[1] = strdup("-P");
4221 argp[2] = (char*) calloc(16,sizeof(char)); snprintf(argp[2], 16, "%s", video_server_dialog->get_listenaddr().c_str());
4222 argp[3] = strdup("-p");
4223 argp[4] = (char*) calloc(6,sizeof(char)); snprintf(argp[4], 6, "%i", video_server_dialog->get_listenport());
4224 argp[5] = strdup("-C");
4225 argp[6] = (char*) calloc(6,sizeof(char)); snprintf(argp[6], 6, "%i", video_server_dialog->get_cachesize());
4226 argp[7] = strdup(icsd_docroot.c_str());
4228 stop_video_server();
4230 if (icsd_docroot == X_("/") || icsd_docroot == X_("C:\\")) {
4231 Config->set_video_advanced_setup(false);
4233 std::ostringstream osstream;
4234 osstream << "http://127.0.0.1:" << video_server_dialog->get_listenport() << "/";
4235 Config->set_video_server_url(osstream.str());
4236 Config->set_video_server_docroot(icsd_docroot);
4237 Config->set_video_advanced_setup(true);
4240 if (video_server_process) {
4241 delete video_server_process;
4244 video_server_process = new ARDOUR::SystemExec(icsd_exec, argp);
4245 if (video_server_process->start()) {
4246 warning << _("Cannot launch the video-server") << endmsg;
4249 int timeout = 120; // 6 sec
4250 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4251 Glib::usleep (50000);
4253 if (--timeout <= 0 || !video_server_process->is_running()) break;
4256 warning << _("Video-server was started but does not respond to requests...") << endmsg;
4258 if (!ARDOUR_UI::instance()->video_timeline->check_server_docroot()) {
4259 delete video_server_process;
4260 video_server_process = 0;
4268 ARDOUR_UI::add_video (Gtk::Window* float_window)
4274 if (!start_video_server(float_window, false)) {
4275 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4280 add_video_dialog->set_transient_for (*float_window);
4283 if (add_video_dialog->is_visible()) {
4284 /* we're already doing this */
4288 ResponseType r = (ResponseType) add_video_dialog->run ();
4289 add_video_dialog->hide();
4290 if (r != RESPONSE_ACCEPT) { return; }
4292 bool local_file, orig_local_file;
4293 std::string path = add_video_dialog->file_name(local_file);
4295 std::string orig_path = path;
4296 orig_local_file = local_file;
4298 bool auto_set_session_fps = add_video_dialog->auto_set_session_fps();
4300 if (local_file && !Glib::file_test(path, Glib::FILE_TEST_EXISTS)) {
4301 warning << string_compose(_("could not open %1"), path) << endmsg;
4304 if (!local_file && path.length() == 0) {
4305 warning << _("no video-file selected") << endmsg;
4309 std::string audio_from_video;
4310 bool detect_ltc = false;
4312 switch (add_video_dialog->import_option()) {
4313 case VTL_IMPORT_TRANSCODE:
4315 TranscodeVideoDialog *transcode_video_dialog;
4316 transcode_video_dialog = new TranscodeVideoDialog (_session, path);
4317 ResponseType r = (ResponseType) transcode_video_dialog->run ();
4318 transcode_video_dialog->hide();
4319 if (r != RESPONSE_ACCEPT) {
4320 delete transcode_video_dialog;
4324 audio_from_video = transcode_video_dialog->get_audiofile();
4326 if (!audio_from_video.empty() && transcode_video_dialog->detect_ltc()) {
4329 else if (!audio_from_video.empty()) {
4330 editor->embed_audio_from_video(
4332 video_timeline->get_offset(),
4333 (transcode_video_dialog->import_option() != VTL_IMPORT_NO_VIDEO)
4336 switch (transcode_video_dialog->import_option()) {
4337 case VTL_IMPORT_TRANSCODED:
4338 path = transcode_video_dialog->get_filename();
4341 case VTL_IMPORT_REFERENCE:
4344 delete transcode_video_dialog;
4347 delete transcode_video_dialog;
4351 case VTL_IMPORT_NONE:
4355 /* strip _session->session_directory().video_path() from video file if possible */
4356 if (local_file && !path.compare(0, _session->session_directory().video_path().size(), _session->session_directory().video_path())) {
4357 path=path.substr(_session->session_directory().video_path().size());
4358 if (path.at(0) == G_DIR_SEPARATOR) {
4359 path=path.substr(1);
4363 video_timeline->set_update_session_fps(auto_set_session_fps);
4365 if (video_timeline->video_file_info(path, local_file)) {
4366 XMLNode* node = new XMLNode(X_("Videotimeline"));
4367 node->add_property (X_("Filename"), path);
4368 node->add_property (X_("AutoFPS"), auto_set_session_fps?X_("1"):X_("0"));
4369 node->add_property (X_("LocalFile"), local_file?X_("1"):X_("0"));
4370 if (orig_local_file) {
4371 node->add_property (X_("OriginalVideoFile"), orig_path);
4373 node->remove_property (X_("OriginalVideoFile"));
4375 _session->add_extra_xml (*node);
4376 _session->set_dirty ();
4378 if (!audio_from_video.empty() && detect_ltc) {
4379 std::vector<LTCFileReader::LTCMap> ltc_seq;
4382 /* TODO ask user about TV standard (LTC alignment if any) */
4383 LTCFileReader ltcr (audio_from_video, video_timeline->get_video_file_fps());
4384 /* TODO ASK user which channel: 0 .. ltcr->channels() - 1 */
4386 ltc_seq = ltcr.read_ltc (/*channel*/ 0, /*max LTC frames to decode*/ 15);
4388 /* TODO seek near end of file, and read LTC until end.
4389 * if it fails to find any LTC frames, scan complete file
4391 * calculate drift of LTC compared to video-duration,
4392 * ask user for reference (timecode from start/mid/end)
4395 // LTCFileReader will have written error messages
4398 ::g_unlink(audio_from_video.c_str());
4400 if (ltc_seq.size() == 0) {
4401 PBD::error << _("No LTC detected, video will not be aligned.") << endmsg;
4403 /* the very first TC in the file is somteimes not aligned properly */
4404 int i = ltc_seq.size() -1;
4405 ARDOUR::frameoffset_t video_start_offset =
4406 _session->nominal_frame_rate() * (ltc_seq[i].timecode_sec - ltc_seq[i].framepos_sec);
4407 PBD::info << string_compose (_("Align video-start to %1 [samples]"), video_start_offset) << endmsg;
4408 video_timeline->set_offset(video_start_offset);
4412 _session->maybe_update_session_range(
4413 std::max(video_timeline->get_offset(), (ARDOUR::frameoffset_t) 0),
4414 std::max(video_timeline->get_offset() + video_timeline->get_duration(), (ARDOUR::frameoffset_t) 0));
4417 if (add_video_dialog->launch_xjadeo() && local_file) {
4418 editor->set_xjadeo_sensitive(true);
4419 editor->toggle_xjadeo_proc(1);
4421 editor->toggle_xjadeo_proc(0);
4423 editor->toggle_ruler_video(true);
4428 ARDOUR_UI::remove_video ()
4430 video_timeline->close_session();
4431 editor->toggle_ruler_video(false);
4434 video_timeline->set_offset_locked(false);
4435 video_timeline->set_offset(0);
4437 /* delete session state */
4438 XMLNode* node = new XMLNode(X_("Videotimeline"));
4439 _session->add_extra_xml(*node);
4440 node = new XMLNode(X_("Videomonitor"));
4441 _session->add_extra_xml(*node);
4442 node = new XMLNode(X_("Videoexport"));
4443 _session->add_extra_xml(*node);
4444 stop_video_server();
4448 ARDOUR_UI::flush_videotimeline_cache (bool localcacheonly)
4450 if (localcacheonly) {
4451 video_timeline->vmon_update();
4453 video_timeline->flush_cache();
4455 editor->queue_visual_videotimeline_update();
4459 ARDOUR_UI::export_video (bool range)
4461 if (ARDOUR::Config->get_show_video_export_info()) {
4462 ExportVideoInfobox infobox (_session);
4463 Gtk::ResponseType rv = (Gtk::ResponseType) infobox.run();
4464 if (infobox.show_again()) {
4465 ARDOUR::Config->set_show_video_export_info(false);
4468 case GTK_RESPONSE_YES:
4469 PBD::open_uri (ARDOUR::Config->get_reference_manual_url() + "/video-timeline/operations/#export");
4475 export_video_dialog->set_session (_session);
4476 export_video_dialog->apply_state(editor->get_selection().time, range);
4477 export_video_dialog->run ();
4478 export_video_dialog->hide ();
4482 ARDOUR_UI::mixer_settings () const
4487 node = _session->instant_xml(X_("Mixer"));
4489 node = Config->instant_xml(X_("Mixer"));
4493 node = new XMLNode (X_("Mixer"));
4500 ARDOUR_UI::main_window_settings () const
4505 node = _session->instant_xml(X_("Main"));
4507 node = Config->instant_xml(X_("Main"));
4511 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4512 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4517 node = new XMLNode (X_("Main"));
4524 ARDOUR_UI::editor_settings () const
4529 node = _session->instant_xml(X_("Editor"));
4531 node = Config->instant_xml(X_("Editor"));
4535 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4536 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4541 node = new XMLNode (X_("Editor"));
4548 ARDOUR_UI::keyboard_settings () const
4552 node = Config->extra_xml(X_("Keyboard"));
4555 node = new XMLNode (X_("Keyboard"));
4562 ARDOUR_UI::create_xrun_marker (framepos_t where)
4565 Location *location = new Location (*_session, where, where, _("xrun"), Location::IsMark);
4566 _session->locations()->add (location);
4571 ARDOUR_UI::halt_on_xrun_message ()
4573 cerr << "HALT on xrun\n";
4574 MessageDialog msg (_main_window, _("Recording was stopped because your system could not keep up."));
4579 ARDOUR_UI::xrun_handler (framepos_t where)
4585 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
4587 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
4588 create_xrun_marker(where);
4591 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
4592 halt_on_xrun_message ();
4597 ARDOUR_UI::disk_overrun_handler ()
4599 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
4601 if (!have_disk_speed_dialog_displayed) {
4602 have_disk_speed_dialog_displayed = true;
4603 MessageDialog* msg = new MessageDialog (_main_window, string_compose (_("\
4604 The disk system on your computer\n\
4605 was not able to keep up with %1.\n\
4607 Specifically, it failed to write data to disk\n\
4608 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
4609 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4615 /* TODO: this is getting elaborate enough to warrant being split into a dedicated class */
4616 static MessageDialog *scan_dlg = NULL;
4617 static ProgressBar *scan_pbar = NULL;
4618 static HBox *scan_tbox = NULL;
4619 static Gtk::Button *scan_timeout_button;
4622 ARDOUR_UI::cancel_plugin_scan ()
4624 PluginManager::instance().cancel_plugin_scan();
4628 ARDOUR_UI::cancel_plugin_timeout ()
4630 PluginManager::instance().cancel_plugin_timeout();
4631 scan_timeout_button->set_sensitive (false);
4635 ARDOUR_UI::plugin_scan_timeout (int timeout)
4637 if (!scan_dlg || !scan_dlg->is_mapped() || !scan_pbar) {
4641 scan_pbar->set_sensitive (false);
4642 scan_timeout_button->set_sensitive (true);
4643 scan_pbar->set_fraction ((float) timeout / (float) Config->get_vst_scan_timeout());
4646 scan_pbar->set_sensitive (false);
4647 scan_timeout_button->set_sensitive (false);
4653 ARDOUR_UI::plugin_scan_dialog (std::string type, std::string plugin, bool can_cancel)
4655 if (type == X_("closeme") && !(scan_dlg && scan_dlg->is_mapped())) {
4659 const bool cancelled = PluginManager::instance().cancelled();
4660 if (type != X_("closeme") && (!UIConfiguration::instance().get_show_plugin_scan_window()) && !_initial_verbose_plugin_scan) {
4661 if (cancelled && scan_dlg->is_mapped()) {
4666 if (cancelled || !can_cancel) {
4671 static Gtk::Button *cancel_button;
4673 scan_dlg = new MessageDialog("", false, MESSAGE_INFO, BUTTONS_NONE); // TODO manage
4674 VBox* vbox = scan_dlg->get_vbox();
4675 vbox->set_size_request(400,-1);
4676 scan_dlg->set_title (_("Scanning for plugins"));
4678 cancel_button = manage(new Gtk::Button(_("Cancel plugin scan")));
4679 cancel_button->set_name ("EditorGTKButton");
4680 cancel_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_scan) );
4681 cancel_button->show();
4683 scan_dlg->get_vbox()->pack_start ( *cancel_button, PACK_SHRINK);
4685 scan_tbox = manage( new HBox() );
4687 scan_timeout_button = manage(new Gtk::Button(_("Stop Timeout")));
4688 scan_timeout_button->set_name ("EditorGTKButton");
4689 scan_timeout_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_timeout) );
4690 scan_timeout_button->show();
4692 scan_pbar = manage(new ProgressBar());
4693 scan_pbar->set_orientation(Gtk::PROGRESS_RIGHT_TO_LEFT);
4694 scan_pbar->set_text(_("Scan Timeout"));
4697 scan_tbox->pack_start (*scan_pbar, PACK_EXPAND_WIDGET, 4);
4698 scan_tbox->pack_start (*scan_timeout_button, PACK_SHRINK, 4);
4700 scan_dlg->get_vbox()->pack_start (*scan_tbox, PACK_SHRINK, 4);
4703 assert(scan_dlg && scan_tbox && cancel_button);
4705 if (type == X_("closeme")) {
4709 scan_dlg->set_message(type + ": " + Glib::path_get_basename(plugin));
4712 if (!can_cancel || !cancelled) {
4713 scan_timeout_button->set_sensitive(false);
4715 cancel_button->set_sensitive(can_cancel && !cancelled);
4721 ARDOUR_UI::gui_idle_handler ()
4724 /* due to idle calls, gtk_events_pending() may always return true */
4725 while (gtk_events_pending() && --timeout) {
4726 gtk_main_iteration ();
4731 ARDOUR_UI::disk_underrun_handler ()
4733 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
4735 if (!have_disk_speed_dialog_displayed) {
4736 have_disk_speed_dialog_displayed = true;
4737 MessageDialog* msg = new MessageDialog (
4738 _main_window, string_compose (_("The disk system on your computer\n\
4739 was not able to keep up with %1.\n\
4741 Specifically, it failed to read data from disk\n\
4742 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
4743 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4749 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
4751 have_disk_speed_dialog_displayed = false;
4756 ARDOUR_UI::session_dialog (std::string msg)
4758 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
4762 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
4769 ARDOUR_UI::pending_state_dialog ()
4771 HBox* hbox = manage (new HBox());
4772 Image* image = manage (new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG));
4773 ArdourDialog dialog (_("Crash Recovery"), true);
4774 Label message (string_compose (_("\
4775 This session appears to have been in the\n\
4776 middle of recording when %1 or\n\
4777 the computer was shutdown.\n\
4779 %1 can recover any captured audio for\n\
4780 you, or it can ignore it. Please decide\n\
4781 what you would like to do.\n"), PROGRAM_NAME));
4782 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4783 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4784 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4785 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4786 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
4787 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
4788 dialog.set_default_response (RESPONSE_ACCEPT);
4789 dialog.set_position (WIN_POS_CENTER);
4794 switch (dialog.run ()) {
4795 case RESPONSE_ACCEPT:
4803 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
4805 HBox* hbox = new HBox();
4806 Image* image = new Image (Stock::DIALOG_WARNING, ICON_SIZE_DIALOG);
4807 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
4808 Label message (string_compose (_("\
4809 This session was created with a sample rate of %1 Hz, but\n\
4810 %2 is currently running at %3 Hz. If you load this session,\n\
4811 audio may be played at the wrong sample rate.\n"), desired, PROGRAM_NAME, actual));
4813 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4814 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4815 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4816 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4817 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
4818 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
4819 dialog.set_default_response (RESPONSE_ACCEPT);
4820 dialog.set_position (WIN_POS_CENTER);
4825 switch (dialog.run()) {
4826 case RESPONSE_ACCEPT:
4836 ARDOUR_UI::sr_mismatch_message (framecnt_t desired, framecnt_t actual)
4838 MessageDialog msg (string_compose (_("\
4839 This session was created with a sample rate of %1 Hz, but\n\
4840 %2 is currently running at %3 Hz.\n\
4841 Audio will be recorded and played at the wrong sample rate.\n\
4842 Re-Configure the Audio Engine in\n\
4843 Menu > Window > Audio/Midi Setup"),
4844 desired, PROGRAM_NAME, actual),
4846 Gtk::MESSAGE_WARNING);
4851 ARDOUR_UI::use_config ()
4853 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
4855 set_transport_controllable_state (*node);
4860 ARDOUR_UI::update_transport_clocks (framepos_t pos)
4862 if (UIConfiguration::instance().get_primary_clock_delta_edit_cursor()) {
4863 primary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
4865 primary_clock->set (pos);
4868 if (UIConfiguration::instance().get_secondary_clock_delta_edit_cursor()) {
4869 secondary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
4871 secondary_clock->set (pos);
4874 if (big_clock_window) {
4875 big_clock->set (pos);
4877 ARDOUR_UI::instance()->video_timeline->manual_seek_video_monitor(pos);
4881 ARDOUR_UI::step_edit_status_change (bool yn)
4883 // XXX should really store pre-step edit status of things
4884 // we make insensitive
4887 rec_button.set_active_state (Gtkmm2ext::ImplicitActive);
4888 rec_button.set_sensitive (false);
4890 rec_button.unset_active_state ();;
4891 rec_button.set_sensitive (true);
4896 ARDOUR_UI::record_state_changed ()
4898 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
4900 if (!_session || !big_clock_window) {
4901 /* why bother - the clock isn't visible */
4905 if (_session->record_status () == Session::Recording && _session->have_rec_enabled_track ()) {
4906 big_clock->set_active (true);
4908 big_clock->set_active (false);
4913 ARDOUR_UI::first_idle ()
4916 _session->allow_auto_play (true);
4920 editor->first_idle();
4923 Keyboard::set_can_save_keybindings (true);
4928 ARDOUR_UI::store_clock_modes ()
4930 XMLNode* node = new XMLNode(X_("ClockModes"));
4932 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
4933 XMLNode* child = new XMLNode (X_("Clock"));
4935 child->add_property (X_("name"), (*x)->name());
4936 child->add_property (X_("mode"), enum_2_string ((*x)->mode()));
4937 child->add_property (X_("on"), ((*x)->off() ? X_("no") : X_("yes")));
4939 node->add_child_nocopy (*child);
4942 _session->add_extra_xml (*node);
4943 _session->set_dirty ();
4946 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
4947 : Controllable (name), ui (u), type(tp)
4953 ARDOUR_UI::TransportControllable::set_value (double val, PBD::Controllable::GroupControlDisposition /*group_override*/)
4956 /* do nothing: these are radio-style actions */
4960 const char *action = 0;
4964 action = X_("Roll");
4967 action = X_("Stop");
4970 action = X_("GotoStart");
4973 action = X_("GotoEnd");
4976 action = X_("Loop");
4979 action = X_("PlaySelection");
4982 action = X_("Record");
4992 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
5000 ARDOUR_UI::TransportControllable::get_value (void) const
5027 ARDOUR_UI::setup_profile ()
5029 if (gdk_screen_width() < 1200 || getenv ("ARDOUR_NARROW_SCREEN")) {
5030 Profile->set_small_screen ();
5033 if (g_getenv ("TRX")) {
5034 Profile->set_trx ();
5037 if (g_getenv ("MIXBUS")) {
5038 Profile->set_mixbus ();
5043 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
5045 MissingFileDialog dialog (s, str, type);
5050 int result = dialog.run ();
5057 return 1; // quit entire session load
5060 result = dialog.get_action ();
5066 ARDOUR_UI::ambiguous_file (std::string file, std::vector<std::string> hits)
5068 AmbiguousFileDialog dialog (file, hits);
5075 return dialog.get_which ();
5078 /** Allocate our thread-local buffers */
5080 ARDOUR_UI::get_process_buffers ()
5082 _process_thread->get_buffers ();
5085 /** Drop our thread-local buffers */
5087 ARDOUR_UI::drop_process_buffers ()
5089 _process_thread->drop_buffers ();
5093 ARDOUR_UI::feedback_detected ()
5095 _feedback_exists = true;
5099 ARDOUR_UI::successful_graph_sort ()
5101 _feedback_exists = false;
5105 ARDOUR_UI::midi_panic ()
5108 _session->midi_panic();
5113 ARDOUR_UI::session_format_mismatch (std::string xml_path, std::string backup_path)
5115 const char* start_big = "<span size=\"x-large\" weight=\"bold\">";
5116 const char* end_big = "</span>";
5117 const char* start_mono = "<tt>";
5118 const char* end_mono = "</tt>";
5120 MessageDialog msg (string_compose (_("%4This is a session from an older version of %3%5\n\n"
5121 "%3 has copied the old session file\n\n%6%1%7\n\nto\n\n%6%2%7\n\n"
5122 "From now on, use the backup copy with older versions of %3"),
5123 xml_path, backup_path, PROGRAM_NAME,
5125 start_mono, end_mono), true);
5132 ARDOUR_UI::reset_peak_display ()
5134 if (!_session || !_session->master_out() || !editor_meter) return;
5135 editor_meter->clear_meters();
5136 editor_meter_max_peak = -INFINITY;
5137 editor_meter_peak_display.set_active_state ( Gtkmm2ext::Off );
5141 ARDOUR_UI::reset_group_peak_display (RouteGroup* group)
5143 if (!_session || !_session->master_out()) return;
5144 if (group == _session->master_out()->route_group()) {
5145 reset_peak_display ();
5150 ARDOUR_UI::reset_route_peak_display (Route* route)
5152 if (!_session || !_session->master_out()) return;
5153 if (_session->master_out().get() == route) {
5154 reset_peak_display ();
5159 ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate)
5161 audio_midi_setup->set_desired_sample_rate (desired_sample_rate);
5162 audio_midi_setup->set_position (WIN_POS_CENTER);
5164 if (Config->get_try_autostart_engine () || getenv ("TRY_AUTOSTART_ENGINE")) {
5165 audio_midi_setup->try_autostart ();
5166 if (ARDOUR::AudioEngine::instance()->running()) {
5172 int response = audio_midi_setup->run();
5174 case Gtk::RESPONSE_OK:
5175 if (!AudioEngine::instance()->running()) {
5189 ARDOUR_UI::transport_numpad_timeout ()
5191 _numpad_locate_happening = false;
5192 if (_numpad_timeout_connection.connected() )
5193 _numpad_timeout_connection.disconnect();
5198 ARDOUR_UI::transport_numpad_decimal ()
5200 _numpad_timeout_connection.disconnect();
5202 if (_numpad_locate_happening) {
5203 if (editor) editor->goto_nth_marker(_pending_locate_num - 1);
5204 _numpad_locate_happening = false;
5206 _pending_locate_num = 0;
5207 _numpad_locate_happening = true;
5208 _numpad_timeout_connection = Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::transport_numpad_timeout), 2*1000);
5213 ARDOUR_UI::transport_numpad_event (int num)
5215 if ( _numpad_locate_happening ) {
5216 _pending_locate_num = _pending_locate_num*10 + num;
5219 case 0: toggle_roll(false, false); break;
5220 case 1: transport_rewind(1); break;
5221 case 2: transport_forward(1); break;
5222 case 3: transport_record(true); break;
5223 case 4: toggle_session_auto_loop(); break;
5224 case 5: transport_record(false); toggle_session_auto_loop(); break;
5225 case 6: toggle_punch(); break;
5226 case 7: toggle_click(); break;
5227 case 8: toggle_auto_return(); break;
5228 case 9: toggle_follow_edits(); break;
5234 ARDOUR_UI::set_flat_buttons ()
5236 CairoWidget::set_flat_buttons( UIConfiguration::instance().get_flat_buttons() );
5240 ARDOUR_UI::audioengine_became_silent ()
5242 MessageDialog msg (string_compose (_("This is a free/demo copy of %1. It has just switched to silent mode."), PROGRAM_NAME),
5244 Gtk::MESSAGE_WARNING,
5248 msg.set_title (string_compose (_("%1 is now silent"), PROGRAM_NAME));
5250 Gtk::Label pay_label (string_compose (_("Please consider paying for a copy of %1 - you can pay whatever you want."), PROGRAM_NAME));
5251 Gtk::Label subscribe_label (_("Better yet become a subscriber - subscriptions start at US$1 per month."));
5252 Gtk::Button pay_button (_("Pay for a copy (via the web)"));
5253 Gtk::Button subscribe_button (_("Become a subscriber (via the web)"));
5254 Gtk::HBox pay_button_box;
5255 Gtk::HBox subscribe_button_box;
5257 pay_button_box.pack_start (pay_button, true, false);
5258 subscribe_button_box.pack_start (subscribe_button, true, false);
5260 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 */
5262 pay_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://ardour.org/download")));
5263 subscribe_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://community.ardour.org/s/subscribe")));
5265 msg.get_vbox()->pack_start (pay_label);
5266 msg.get_vbox()->pack_start (pay_button_box);
5267 msg.get_vbox()->pack_start (subscribe_label);
5268 msg.get_vbox()->pack_start (subscribe_button_box);
5270 msg.get_vbox()->show_all ();
5272 msg.add_button (_("Remain silent"), Gtk::RESPONSE_CANCEL);
5273 msg.add_button (_("Save and quit"), Gtk::RESPONSE_NO);
5274 msg.add_button (_("Give me more time"), Gtk::RESPONSE_YES);
5279 case Gtk::RESPONSE_YES:
5280 AudioEngine::instance()->reset_silence_countdown ();
5283 case Gtk::RESPONSE_NO:
5285 save_state_canfail ("");
5289 case Gtk::RESPONSE_CANCEL:
5291 /* don't reset, save session and exit */
5297 ARDOUR_UI::hide_application ()
5299 Application::instance ()-> hide ();
5303 ARDOUR_UI::setup_toplevel_window (Gtk::Window& window, const string& name, void* owner)
5305 /* icons, titles, WM stuff */
5307 static list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
5309 if (window_icons.empty()) {
5310 Glib::RefPtr<Gdk::Pixbuf> icon;
5311 if ((icon = ::get_icon (PROGRAM_NAME "-icon_16px")) != 0) {
5312 window_icons.push_back (icon);
5314 if ((icon = ::get_icon (PROGRAM_NAME "-icon_22px")) != 0) {
5315 window_icons.push_back (icon);
5317 if ((icon = ::get_icon (PROGRAM_NAME "-icon_32px")) != 0) {
5318 window_icons.push_back (icon);
5320 if ((icon = ::get_icon (PROGRAM_NAME "-icon_48px")) != 0) {
5321 window_icons.push_back (icon);
5325 if (!window_icons.empty()) {
5326 window.set_default_icon_list (window_icons);
5329 Gtkmm2ext::WindowTitle title (Glib::get_application_name());
5331 if (!name.empty()) {
5335 window.set_title (title.get_string());
5336 window.set_wmclass (string_compose (X_("%1_%1"), downcase (PROGRAM_NAME), downcase (name)), PROGRAM_NAME);
5338 window.set_flags (CAN_FOCUS);
5339 window.add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
5341 /* This is a hack to ensure that GTK-accelerators continue to
5342 * work. Once we switch over to entirely native bindings, this will be
5343 * unnecessary and should be removed
5345 window.add_accel_group (ActionManager::ui_manager->get_accel_group());
5347 window.signal_configure_event().connect (sigc::mem_fun (*this, &ARDOUR_UI::configure_handler));
5348 window.signal_window_state_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::tabbed_window_state_event_handler), owner));
5349 window.signal_key_press_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5350 window.signal_key_release_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5354 ARDOUR_UI::key_event_handler (GdkEventKey* ev, Gtk::Window* event_window)
5356 Gtkmm2ext::Bindings* bindings = 0;
5357 Gtk::Window* window = 0;
5359 /* until we get ardour bindings working, we are not handling key
5363 if (ev->type != GDK_KEY_PRESS) {
5367 if (event_window == &_main_window) {
5369 window = event_window;
5371 /* find current tab contents */
5373 Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page());
5375 /* see if it uses the ardour binding system */
5378 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(w->get_data ("ardour-bindings"));
5381 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("main window key event, bindings = %1, global = %2\n", bindings, &global_bindings));
5385 window = event_window;
5387 /* see if window uses ardour binding system */
5389 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(window->get_data ("ardour-bindings"));
5392 /* An empty binding set is treated as if it doesn't exist */
5394 if (bindings && bindings->empty()) {
5398 return key_press_focus_accelerator_handler (*window, ev, bindings);
5401 static Gtkmm2ext::Bindings*
5402 get_bindings_from_widget_heirarchy (GtkWidget* w)
5407 if ((p = g_object_get_data (G_OBJECT(w), "ardour-bindings")) != 0) {
5410 w = gtk_widget_get_parent (w);
5413 return reinterpret_cast<Gtkmm2ext::Bindings*> (p);
5417 ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev, Gtkmm2ext::Bindings* bindings)
5419 GtkWindow* win = window.gobj();
5420 GtkWidget* focus = gtk_window_get_focus (win);
5421 bool special_handling_of_unmodified_accelerators = false;
5422 const guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK));
5426 /* some widget has keyboard focus */
5428 if (GTK_IS_ENTRY(focus) || Keyboard::some_magic_widget_has_focus()) {
5430 /* A particular kind of focusable widget currently has keyboard
5431 * focus. All unmodified key events should go to that widget
5432 * first and not be used as an accelerator by default
5435 special_handling_of_unmodified_accelerators = true;
5439 Gtkmm2ext::Bindings* focus_bindings = get_bindings_from_widget_heirarchy (focus);
5440 if (focus_bindings) {
5441 bindings = focus_bindings;
5442 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Switch bindings based on focus widget, now using %1\n", bindings->name()));
5447 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",
5450 show_gdk_event_state (ev->state),
5451 special_handling_of_unmodified_accelerators,
5452 Keyboard::some_magic_widget_has_focus(),
5454 (focus ? gtk_widget_get_name (focus) : "no focus widget"),
5455 ((ev->state & mask) ? "yes" : "no"),
5456 window.get_title()));
5458 /* This exists to allow us to override the way GTK handles
5459 key events. The normal sequence is:
5461 a) event is delivered to a GtkWindow
5462 b) accelerators/mnemonics are activated
5463 c) if (b) didn't handle the event, propagate to
5464 the focus widget and/or focus chain
5466 The problem with this is that if the accelerators include
5467 keys without modifiers, such as the space bar or the
5468 letter "e", then pressing the key while typing into
5469 a text entry widget results in the accelerator being
5470 activated, instead of the desired letter appearing
5473 There is no good way of fixing this, but this
5474 represents a compromise. The idea is that
5475 key events involving modifiers (not Shift)
5476 get routed into the activation pathway first, then
5477 get propagated to the focus widget if necessary.
5479 If the key event doesn't involve modifiers,
5480 we deliver to the focus widget first, thus allowing
5481 it to get "normal text" without interference
5484 Of course, this can also be problematic: if there
5485 is a widget with focus, then it will swallow
5486 all "normal text" accelerators.
5490 if (!special_handling_of_unmodified_accelerators || (ev->state & mask)) {
5492 /* no special handling or there are modifiers in effect: accelerate first */
5494 DEBUG_TRACE (DEBUG::Accelerators, "\tactivate, then propagate\n");
5495 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tevent send-event:%1 time:%2 length:%3 name %7 string:%4 hardware_keycode:%5 group:%6\n",
5496 ev->send_event, ev->time, ev->length, ev->string, ev->hardware_keycode, ev->group, gdk_keyval_name (ev->keyval)));
5498 DEBUG_TRACE (DEBUG::Accelerators, "\tsending to window\n");
5499 KeyboardKey k (ev->state, ev->keyval);
5503 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tusing Ardour bindings %1 @ %2 for this event\n", bindings->name(), bindings));
5505 if (bindings->activate (k, Bindings::Press)) {
5506 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5511 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5513 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5514 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5518 DEBUG_TRACE (DEBUG::Accelerators, "\tnot accelerated, now propagate\n");
5520 if (gtk_window_propagate_key_event (win, ev)) {
5521 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate handled\n");
5527 /* no modifiers, propagate first */
5529 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate, then activate\n");
5531 if (gtk_window_propagate_key_event (win, ev)) {
5532 DEBUG_TRACE (DEBUG::Accelerators, "\thandled by propagate\n");
5536 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagation didn't handle, so activate\n");
5537 KeyboardKey k (ev->state, ev->keyval);
5541 DEBUG_TRACE (DEBUG::Accelerators, "\tusing Ardour bindings for this window\n");
5544 if (bindings->activate (k, Bindings::Press)) {
5545 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5551 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5553 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5554 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5559 DEBUG_TRACE (DEBUG::Accelerators, "\tnot handled\n");
5564 ARDOUR_UI::load_bindings ()
5566 if ((global_bindings = Bindings::get_bindings (X_("Global"), global_actions)) == 0) {
5567 error << _("Global keybindings are missing") << endmsg;
5572 ARDOUR_UI::cancel_solo ()
5576 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Route::solo_control), 0.0, Controllable::NoGroup);
5578 _session->clear_all_solo_state (_session->get_routes()); // safeguard, ideally this won't do anything, check the log-window