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)
1823 list<boost::shared_ptr<MidiTrack> > tracks;
1825 if (_session == 0) {
1826 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1831 tracks = _session->new_midi_track (input, output, instrument, ARDOUR::Normal, route_group, how_many, name_template, pset);
1833 if (tracks.size() != how_many) {
1834 error << string_compose(P_("could not create %1 new mixed track", "could not create %1 new mixed tracks", how_many), how_many) << endmsg;
1839 display_insufficient_ports_message ();
1844 for (list<boost::shared_ptr<MidiTrack> >::iterator i = tracks.begin(); i != tracks.end(); ++i) {
1845 (*i)->set_strict_io (true);
1851 ARDOUR_UI::session_add_midi_bus (
1852 RouteGroup* route_group,
1854 const string& name_template,
1856 PluginInfoPtr instrument,
1857 Plugin::PresetRecord* pset)
1861 if (_session == 0) {
1862 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1867 routes = _session->new_midi_route (route_group, how_many, name_template, instrument, pset);
1868 if (routes.size() != how_many) {
1869 error << string_compose(P_("could not create %1 new Midi Bus", "could not create %1 new Midi Busses", how_many), how_many) << endmsg;
1874 display_insufficient_ports_message ();
1879 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
1880 (*i)->set_strict_io (true);
1886 ARDOUR_UI::session_add_midi_route (
1888 RouteGroup* route_group,
1890 const string& name_template,
1892 PluginInfoPtr instrument,
1893 Plugin::PresetRecord* pset)
1895 ChanCount one_midi_channel;
1896 one_midi_channel.set (DataType::MIDI, 1);
1899 session_add_mixed_track (one_midi_channel, one_midi_channel, route_group, how_many, name_template, strict_io, instrument, pset);
1901 session_add_midi_bus (route_group, how_many, name_template, strict_io, instrument, pset);
1906 ARDOUR_UI::session_add_audio_route (
1908 int32_t input_channels,
1909 int32_t output_channels,
1910 ARDOUR::TrackMode mode,
1911 RouteGroup* route_group,
1913 string const & name_template,
1917 list<boost::shared_ptr<AudioTrack> > tracks;
1920 if (_session == 0) {
1921 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1927 tracks = _session->new_audio_track (input_channels, output_channels, mode, route_group, how_many, name_template);
1929 if (tracks.size() != how_many) {
1930 error << string_compose (P_("could not create %1 new audio track", "could not create %1 new audio tracks", how_many), how_many)
1936 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template);
1938 if (routes.size() != how_many) {
1939 error << string_compose (P_("could not create %1 new audio bus", "could not create %1 new audio busses", how_many), how_many)
1946 display_insufficient_ports_message ();
1951 for (list<boost::shared_ptr<AudioTrack> >::iterator i = tracks.begin(); i != tracks.end(); ++i) {
1952 (*i)->set_strict_io (true);
1954 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
1955 (*i)->set_strict_io (true);
1961 ARDOUR_UI::display_insufficient_ports_message ()
1963 MessageDialog msg (_main_window,
1964 string_compose (_("There are insufficient ports available\n\
1965 to create a new track or bus.\n\
1966 You should save %1, exit and\n\
1967 restart with more ports."), PROGRAM_NAME));
1968 pop_back_splash (msg);
1973 ARDOUR_UI::transport_goto_start ()
1976 _session->goto_start();
1978 /* force displayed area in editor to start no matter
1979 what "follow playhead" setting is.
1983 editor->center_screen (_session->current_start_frame ());
1989 ARDOUR_UI::transport_goto_zero ()
1992 _session->request_locate (0);
1994 /* force displayed area in editor to start no matter
1995 what "follow playhead" setting is.
1999 editor->reset_x_origin (0);
2005 ARDOUR_UI::transport_goto_wallclock ()
2007 if (_session && editor) {
2014 localtime_r (&now, &tmnow);
2016 framecnt_t frame_rate = _session->frame_rate();
2018 if (frame_rate == 0) {
2019 /* no frame rate available */
2023 frames = tmnow.tm_hour * (60 * 60 * frame_rate);
2024 frames += tmnow.tm_min * (60 * frame_rate);
2025 frames += tmnow.tm_sec * frame_rate;
2027 _session->request_locate (frames, _session->transport_rolling ());
2029 /* force displayed area in editor to start no matter
2030 what "follow playhead" setting is.
2034 editor->center_screen (frames);
2040 ARDOUR_UI::transport_goto_end ()
2043 framepos_t const frame = _session->current_end_frame();
2044 _session->request_locate (frame);
2046 /* force displayed area in editor to start no matter
2047 what "follow playhead" setting is.
2051 editor->center_screen (frame);
2057 ARDOUR_UI::transport_stop ()
2063 if (_session->is_auditioning()) {
2064 _session->cancel_audition ();
2068 _session->request_stop (false, true);
2071 /** Check if any tracks are record enabled. If none are, record enable all of them.
2072 * @return true if track record-enabled status was changed, false otherwise.
2075 ARDOUR_UI::trx_record_enable_all_tracks ()
2081 boost::shared_ptr<RouteList> rl = _session->get_tracks ();
2082 bool none_record_enabled = true;
2084 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
2085 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*r);
2088 if (t->rec_enable_control()->get_value()) {
2089 none_record_enabled = false;
2094 if (none_record_enabled) {
2095 _session->set_controls (route_list_to_control_list (rl, &Track::rec_enable_control), 1.0, Controllable::NoGroup);
2098 return none_record_enabled;
2102 ARDOUR_UI::transport_record (bool roll)
2105 switch (_session->record_status()) {
2106 case Session::Disabled:
2107 if (_session->ntracks() == 0) {
2108 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."));
2112 if (Profile->get_trx()) {
2113 roll = trx_record_enable_all_tracks ();
2115 _session->maybe_enable_record ();
2120 case Session::Recording:
2122 _session->request_stop();
2124 _session->disable_record (false, true);
2128 case Session::Enabled:
2129 _session->disable_record (false, true);
2135 ARDOUR_UI::transport_roll ()
2141 if (_session->is_auditioning()) {
2146 if (_session->config.get_external_sync()) {
2147 switch (Config->get_sync_source()) {
2151 /* transport controlled by the master */
2157 bool rolling = _session->transport_rolling();
2159 if (_session->get_play_loop()) {
2161 /* If loop playback is not a mode, then we should cancel
2162 it when this action is requested. If it is a mode
2163 we just leave it in place.
2166 if (!Config->get_loop_is_mode()) {
2167 /* XXX it is not possible to just leave seamless loop and keep
2168 playing at present (nov 4th 2009)
2170 if (!Config->get_seamless_loop()) {
2171 /* stop loop playback and stop rolling */
2172 _session->request_play_loop (false, true);
2173 } else if (rolling) {
2174 /* stop loop playback but keep rolling */
2175 _session->request_play_loop (false, false);
2179 } else if (_session->get_play_range () ) {
2180 /* stop playing a range if we currently are */
2181 _session->request_play_range (0, true);
2185 _session->request_transport_speed (1.0f);
2190 ARDOUR_UI::get_smart_mode() const
2192 return ( editor->get_smart_mode() );
2197 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
2203 if (_session->is_auditioning()) {
2204 _session->cancel_audition ();
2208 if (_session->config.get_external_sync()) {
2209 switch (Config->get_sync_source()) {
2213 /* transport controlled by the master */
2218 bool rolling = _session->transport_rolling();
2219 bool affect_transport = true;
2221 if (rolling && roll_out_of_bounded_mode) {
2222 /* drop out of loop/range playback but leave transport rolling */
2223 if (_session->get_play_loop()) {
2224 if (_session->actively_recording()) {
2226 /* just stop using the loop, then actually stop
2229 _session->request_play_loop (false, affect_transport);
2232 if (Config->get_seamless_loop()) {
2233 /* the disk buffers contain copies of the loop - we can't
2234 just keep playing, so stop the transport. the user
2235 can restart as they wish.
2237 affect_transport = true;
2239 /* disk buffers are normal, so we can keep playing */
2240 affect_transport = false;
2242 _session->request_play_loop (false, affect_transport);
2244 } else if (_session->get_play_range ()) {
2245 affect_transport = false;
2246 _session->request_play_range (0, true);
2250 if (affect_transport) {
2252 _session->request_stop (with_abort, true);
2254 /* the only external sync condition we can be in here
2255 * would be Engine (JACK) sync, in which case we still
2259 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
2260 _session->request_play_range (&editor->get_selection().time, true);
2261 _session->set_requested_return_frame( editor->get_selection().time.front().start ); //force an auto-return here
2263 _session->request_transport_speed (1.0f);
2269 ARDOUR_UI::toggle_session_auto_loop ()
2275 Location * looploc = _session->locations()->auto_loop_location();
2281 if (_session->get_play_loop()) {
2283 /* looping enabled, our job is to disable it */
2285 _session->request_play_loop (false);
2289 /* looping not enabled, our job is to enable it.
2291 loop-is-NOT-mode: this action always starts the transport rolling.
2292 loop-IS-mode: this action simply sets the loop play mechanism, but
2293 does not start transport.
2295 if (Config->get_loop_is_mode()) {
2296 _session->request_play_loop (true, false);
2298 _session->request_play_loop (true, true);
2302 //show the loop markers
2303 looploc->set_hidden (false, this);
2307 ARDOUR_UI::transport_play_selection ()
2313 editor->play_selection ();
2317 ARDOUR_UI::transport_play_preroll ()
2322 editor->play_with_preroll ();
2326 ARDOUR_UI::transport_rewind (int option)
2328 float current_transport_speed;
2331 current_transport_speed = _session->transport_speed();
2333 if (current_transport_speed >= 0.0f) {
2336 _session->request_transport_speed (-1.0f);
2339 _session->request_transport_speed (-4.0f);
2342 _session->request_transport_speed (-0.5f);
2347 _session->request_transport_speed (current_transport_speed * 1.5f);
2353 ARDOUR_UI::transport_forward (int option)
2359 float current_transport_speed = _session->transport_speed();
2361 if (current_transport_speed <= 0.0f) {
2364 _session->request_transport_speed (1.0f);
2367 _session->request_transport_speed (4.0f);
2370 _session->request_transport_speed (0.5f);
2375 _session->request_transport_speed (current_transport_speed * 1.5f);
2380 ARDOUR_UI::toggle_record_enable (uint32_t rid)
2386 boost::shared_ptr<Route> r;
2388 if ((r = _session->route_by_remote_id (rid)) != 0) {
2390 boost::shared_ptr<Track> t;
2392 if ((t = boost::dynamic_pointer_cast<Track>(r)) != 0) {
2393 t->rec_enable_control()->set_value (!t->rec_enable_control()->get_value(), Controllable::UseGroup);
2399 ARDOUR_UI::map_transport_state ()
2402 auto_loop_button.unset_active_state ();
2403 play_selection_button.unset_active_state ();
2404 roll_button.unset_active_state ();
2405 stop_button.set_active_state (Gtkmm2ext::ExplicitActive);
2409 shuttle_box->map_transport_state ();
2411 float sp = _session->transport_speed();
2417 if (_session->get_play_range()) {
2419 play_selection_button.set_active_state (Gtkmm2ext::ExplicitActive);
2420 roll_button.unset_active_state ();
2421 auto_loop_button.unset_active_state ();
2423 } else if (_session->get_play_loop ()) {
2425 auto_loop_button.set_active (true);
2426 play_selection_button.set_active (false);
2427 if (Config->get_loop_is_mode()) {
2428 roll_button.set_active (true);
2430 roll_button.set_active (false);
2435 roll_button.set_active (true);
2436 play_selection_button.set_active (false);
2437 auto_loop_button.set_active (false);
2440 if (UIConfiguration::instance().get_follow_edits() && !_session->config.get_external_sync()) {
2441 /* light up both roll and play-selection if they are joined */
2442 roll_button.set_active (true);
2443 play_selection_button.set_active (true);
2446 stop_button.set_active (false);
2450 stop_button.set_active (true);
2451 roll_button.set_active (false);
2452 play_selection_button.set_active (false);
2453 if (Config->get_loop_is_mode ()) {
2454 auto_loop_button.set_active (_session->get_play_loop());
2456 auto_loop_button.set_active (false);
2458 update_disk_space ();
2463 ARDOUR_UI::blink_handler (bool blink_on)
2465 transport_rec_enable_blink (blink_on);
2466 solo_blink (blink_on);
2467 sync_blink (blink_on);
2468 audition_blink (blink_on);
2469 feedback_blink (blink_on);
2470 error_blink (blink_on);
2474 ARDOUR_UI::update_clocks ()
2476 if (!_session) return;
2478 if (editor && !editor->dragging_playhead()) {
2479 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD)); /* EMIT_SIGNAL */
2484 ARDOUR_UI::start_clocking ()
2486 if (UIConfiguration::instance().get_super_rapid_clock_update()) {
2487 clock_signal_connection = Timers::fps_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2489 clock_signal_connection = Timers::rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2494 ARDOUR_UI::stop_clocking ()
2496 clock_signal_connection.disconnect ();
2500 ARDOUR_UI::save_as_progress_update (float fraction, int64_t cnt, int64_t total, Gtk::Label* label, Gtk::ProgressBar* bar)
2504 snprintf (buf, sizeof (buf), _("Copied %" PRId64 " of %" PRId64), cnt, total);
2506 label->set_text (buf);
2507 bar->set_fraction (fraction);
2509 /* process events, redraws, etc. */
2511 while (gtk_events_pending()) {
2512 gtk_main_iteration ();
2515 return true; /* continue with save-as */
2519 ARDOUR_UI::save_session_as ()
2525 if (!save_as_dialog) {
2526 save_as_dialog = new SaveAsDialog;
2529 save_as_dialog->set_name (_session->name());
2531 int response = save_as_dialog->run ();
2533 save_as_dialog->hide ();
2536 case Gtk::RESPONSE_OK:
2545 sa.new_parent_folder = save_as_dialog->new_parent_folder ();
2546 sa.new_name = save_as_dialog->new_name ();
2547 sa.switch_to = save_as_dialog->switch_to();
2548 sa.copy_media = save_as_dialog->copy_media();
2549 sa.copy_external = save_as_dialog->copy_external();
2550 sa.include_media = save_as_dialog->include_media ();
2552 /* Only bother with a progress dialog if we're going to copy
2553 media into the save-as target. Without that choice, this
2554 will be very fast because we're only talking about a few kB's to
2555 perhaps a couple of MB's of data.
2558 ArdourDialog progress_dialog (_("Save As"), true);
2560 if (sa.include_media && sa.copy_media) {
2563 Gtk::ProgressBar progress_bar;
2565 progress_dialog.get_vbox()->pack_start (label);
2566 progress_dialog.get_vbox()->pack_start (progress_bar);
2568 progress_bar.show ();
2570 /* this signal will be emitted from within this, the calling thread,
2571 * after every file is copied. It provides information on percentage
2572 * complete (in terms of total data to copy), the number of files
2573 * copied so far, and the total number to copy.
2578 sa.Progress.connect_same_thread (c, boost::bind (&ARDOUR_UI::save_as_progress_update, this, _1, _2, _3, &label, &progress_bar));
2580 progress_dialog.show_all ();
2581 progress_dialog.present ();
2584 if (_session->save_as (sa)) {
2586 MessageDialog msg (string_compose (_("Save As failed: %1"), sa.failure_message));
2590 if (!sa.include_media) {
2591 unload_session (false);
2592 load_session (sa.final_session_folder_name, sa.new_name);
2597 ARDOUR_UI::quick_snapshot_session (bool switch_to_it)
2601 struct tm local_time;
2604 localtime_r (&n, &local_time);
2605 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2607 save_state (timebuf, switch_to_it);
2612 ARDOUR_UI::process_snapshot_session_prompter (ArdourPrompter& prompter, bool switch_to_it)
2616 prompter.get_result (snapname);
2618 bool do_save = (snapname.length() != 0);
2621 char illegal = Session::session_name_is_legal(snapname);
2623 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2624 "snapshot names may not contain a '%1' character"), illegal));
2630 vector<std::string> p;
2631 get_state_files_in_directory (_session->session_directory().root_path(), p);
2632 vector<string> n = get_file_names_no_extension (p);
2634 if (find (n.begin(), n.end(), snapname) != n.end()) {
2636 do_save = overwrite_file_dialog (prompter,
2637 _("Confirm Snapshot Overwrite"),
2638 _("A snapshot already exists with that name. Do you want to overwrite it?"));
2642 save_state (snapname, switch_to_it);
2652 /** Ask the user for the name of a new snapshot and then take it.
2656 ARDOUR_UI::snapshot_session (bool switch_to_it)
2658 ArdourPrompter prompter (true);
2660 prompter.set_name ("Prompter");
2661 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2663 prompter.set_title (_("Snapshot and switch"));
2664 prompter.set_prompt (_("New session name"));
2666 prompter.set_title (_("Take Snapshot"));
2667 prompter.set_prompt (_("Name of new snapshot"));
2671 prompter.set_initial_text (_session->snap_name());
2675 struct tm local_time;
2678 localtime_r (&n, &local_time);
2679 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2680 prompter.set_initial_text (timebuf);
2683 bool finished = false;
2685 switch (prompter.run()) {
2686 case RESPONSE_ACCEPT:
2688 finished = process_snapshot_session_prompter (prompter, switch_to_it);
2699 /** Ask the user for a new session name and then rename the session to it.
2703 ARDOUR_UI::rename_session ()
2709 ArdourPrompter prompter (true);
2712 prompter.set_name ("Prompter");
2713 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2714 prompter.set_title (_("Rename Session"));
2715 prompter.set_prompt (_("New session name"));
2718 switch (prompter.run()) {
2719 case RESPONSE_ACCEPT:
2721 prompter.get_result (name);
2723 bool do_rename = (name.length() != 0);
2726 char illegal = Session::session_name_is_legal (name);
2729 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2730 "session names may not contain a '%1' character"), illegal));
2735 switch (_session->rename (name)) {
2737 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
2738 msg.set_position (WIN_POS_MOUSE);
2746 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
2747 msg.set_position (WIN_POS_MOUSE);
2763 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2765 if (!_session || _session->deletion_in_progress()) {
2769 XMLNode* node = new XMLNode (X_("UI"));
2771 WM::Manager::instance().add_state (*node);
2773 node->add_child_nocopy (gui_object_state->get_state());
2775 _session->add_extra_xml (*node);
2777 if (export_video_dialog) {
2778 _session->add_extra_xml (export_video_dialog->get_state());
2781 save_state_canfail (name, switch_to_it);
2785 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2790 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2795 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2800 ARDOUR_UI::primary_clock_value_changed ()
2803 _session->request_locate (primary_clock->current_time ());
2808 ARDOUR_UI::big_clock_value_changed ()
2811 _session->request_locate (big_clock->current_time ());
2816 ARDOUR_UI::secondary_clock_value_changed ()
2819 _session->request_locate (secondary_clock->current_time ());
2824 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2826 if (_session == 0) {
2830 if (_session->step_editing()) {
2834 Session::RecordState const r = _session->record_status ();
2835 bool const h = _session->have_rec_enabled_track ();
2837 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2839 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2841 rec_button.set_active_state (Gtkmm2ext::Off);
2843 } else if (r == Session::Recording && h) {
2844 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2846 rec_button.unset_active_state ();
2851 ARDOUR_UI::process_save_template_prompter (ArdourPrompter& prompter)
2855 prompter.get_result (name);
2857 if (name.length()) {
2858 int failed = _session->save_template (name);
2860 if (failed == -2) { /* file already exists. */
2861 bool overwrite = overwrite_file_dialog (prompter,
2862 _("Confirm Template Overwrite"),
2863 _("A template already exists with that name. Do you want to overwrite it?"));
2866 _session->save_template (name, true);
2878 ARDOUR_UI::save_template ()
2880 ArdourPrompter prompter (true);
2882 if (!check_audioengine (_main_window)) {
2886 prompter.set_name (X_("Prompter"));
2887 prompter.set_title (_("Save Template"));
2888 prompter.set_prompt (_("Name for template:"));
2889 prompter.set_initial_text(_session->name() + _("-template"));
2890 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2892 bool finished = false;
2894 switch (prompter.run()) {
2895 case RESPONSE_ACCEPT:
2896 finished = process_save_template_prompter (prompter);
2907 ARDOUR_UI::edit_metadata ()
2909 SessionMetadataEditor dialog;
2910 dialog.set_session (_session);
2911 dialog.grab_focus ();
2916 ARDOUR_UI::import_metadata ()
2918 SessionMetadataImporter dialog;
2919 dialog.set_session (_session);
2924 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
2926 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2928 MessageDialog msg (str,
2930 Gtk::MESSAGE_WARNING,
2931 Gtk::BUTTONS_YES_NO,
2935 msg.set_name (X_("OpenExistingDialog"));
2936 msg.set_title (_("Open Existing Session"));
2937 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
2938 msg.set_position (Gtk::WIN_POS_CENTER);
2939 pop_back_splash (msg);
2941 switch (msg.run()) {
2950 ARDOUR_UI::build_session_from_dialog (SessionDialog& sd, const std::string& session_path, const std::string& session_name)
2952 BusProfile bus_profile;
2956 bus_profile.master_out_channels = 2;
2957 bus_profile.input_ac = AutoConnectPhysical;
2958 bus_profile.output_ac = AutoConnectMaster;
2959 bus_profile.requested_physical_in = 0; // use all available
2960 bus_profile.requested_physical_out = 0; // use all available
2964 /* get settings from advanced section of NSD */
2966 if (sd.create_master_bus()) {
2967 bus_profile.master_out_channels = (uint32_t) sd.master_channel_count();
2969 bus_profile.master_out_channels = 0;
2972 if (sd.connect_inputs()) {
2973 bus_profile.input_ac = AutoConnectPhysical;
2975 bus_profile.input_ac = AutoConnectOption (0);
2978 bus_profile.output_ac = AutoConnectOption (0);
2980 if (sd.connect_outputs ()) {
2981 if (sd.connect_outs_to_master()) {
2982 bus_profile.output_ac = AutoConnectMaster;
2983 } else if (sd.connect_outs_to_physical()) {
2984 bus_profile.output_ac = AutoConnectPhysical;
2988 bus_profile.requested_physical_in = (uint32_t) sd.input_limit_count();
2989 bus_profile.requested_physical_out = (uint32_t) sd.output_limit_count();
2992 if (build_session (session_path, session_name, bus_profile)) {
3000 ARDOUR_UI::load_from_application_api (const std::string& path)
3002 ARDOUR_COMMAND_LINE::session_name = path;
3003 /* Cancel SessionDialog if it's visible to make OSX delegates work.
3005 * ARDOUR_UI::starting connects app->ShouldLoad signal and then shows a SessionDialog
3007 * - ShouldLoad does not arrive in time, ARDOUR_COMMAND_LINE::session_name is empty:
3008 * -> ARDOUR_UI::get_session_parameters starts a SessionDialog.
3009 * - ShouldLoad signal arrives, this function is called and sets ARDOUR_COMMAND_LINE::session_name
3010 * -> SessionDialog is not displayed
3013 if (_session_dialog) {
3014 std::string session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3015 std::string session_path = path;
3016 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_REGULAR)) {
3017 session_path = Glib::path_get_dirname (session_path);
3019 // signal the existing dialog in ARDOUR_UI::get_session_parameters()
3020 _session_dialog->set_provided_session (session_name, session_path);
3021 _session_dialog->response (RESPONSE_NONE);
3022 _session_dialog->hide();
3027 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
3028 /* /path/to/foo => /path/to/foo, foo */
3029 rv = load_session (path, basename_nosuffix (path));
3031 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
3032 rv =load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
3035 // if load_session fails -> pop up SessionDialog.
3037 ARDOUR_COMMAND_LINE::session_name = "";
3039 if (get_session_parameters (true, false)) {
3045 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
3047 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
3049 string session_name;
3050 string session_path;
3051 string template_name;
3053 bool likely_new = false;
3054 bool cancel_not_quit;
3056 /* deal with any existing DIRTY session now, rather than later. don't
3057 * treat a non-dirty session this way, so that it stays visible
3058 * as we bring up the new session dialog.
3061 if (_session && ARDOUR_UI::instance()->video_timeline) {
3062 ARDOUR_UI::instance()->video_timeline->sync_session_state();
3065 /* if there is already a session, relabel the button
3066 on the SessionDialog so that we don't Quit directly
3068 cancel_not_quit = (_session != 0);
3070 if (_session && _session->dirty()) {
3071 if (unload_session (false)) {
3072 /* unload cancelled by user */
3075 ARDOUR_COMMAND_LINE::session_name = "";
3078 if (!load_template.empty()) {
3079 should_be_new = true;
3080 template_name = load_template;
3083 session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3084 session_path = ARDOUR_COMMAND_LINE::session_name;
3086 if (!session_path.empty()) {
3087 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_EXISTS)) {
3088 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_IS_REGULAR)) {
3089 /* session/snapshot file, change path to be dir */
3090 session_path = Glib::path_get_dirname (session_path);
3095 SessionDialog session_dialog (should_be_new, session_name, session_path, load_template, cancel_not_quit);
3097 _session_dialog = &session_dialog;
3100 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
3102 /* if they named a specific statefile, use it, otherwise they are
3103 just giving a session folder, and we want to use it as is
3104 to find the session.
3107 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
3109 if (suffix != string::npos) {
3110 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
3111 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
3112 session_name = Glib::path_get_basename (session_name);
3114 session_path = ARDOUR_COMMAND_LINE::session_name;
3115 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
3120 session_dialog.clear_given ();
3123 if (should_be_new || session_name.empty()) {
3124 /* need the dialog to get info from user */
3126 cerr << "run dialog\n";
3128 switch (session_dialog.run()) {
3129 case RESPONSE_ACCEPT:
3132 /* this is used for async * app->ShouldLoad(). */
3133 continue; // while loop
3136 if (quit_on_cancel) {
3137 // JE - Currently (July 2014) this section can only get reached if the
3138 // user quits from the main 'Session Setup' dialog (i.e. reaching this
3139 // point does NOT indicate an abnormal termination). Therefore, let's
3140 // behave gracefully (i.e. let's do some cleanup) before we call exit()
3142 pthread_cancel_all ();
3150 session_dialog.hide ();
3153 /* if we run the startup dialog again, offer more than just "new session" */
3155 should_be_new = false;
3157 session_name = session_dialog.session_name (likely_new);
3158 session_path = session_dialog.session_folder ();
3164 string::size_type suffix = session_name.find (statefile_suffix);
3166 if (suffix != string::npos) {
3167 session_name = session_name.substr (0, suffix);
3170 /* this shouldn't happen, but we catch it just in case it does */
3172 if (session_name.empty()) {
3176 if (session_dialog.use_session_template()) {
3177 template_name = session_dialog.session_template_name();
3178 _session_is_new = true;
3181 if (session_name[0] == G_DIR_SEPARATOR ||
3182 #ifdef PLATFORM_WINDOWS
3183 (session_name.length() > 3 && session_name[1] == ':' && session_name[2] == G_DIR_SEPARATOR)
3185 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
3186 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)
3191 /* absolute path or cwd-relative path specified for session name: infer session folder
3192 from what was given.
3195 session_path = Glib::path_get_dirname (session_name);
3196 session_name = Glib::path_get_basename (session_name);
3200 session_path = session_dialog.session_folder();
3202 char illegal = Session::session_name_is_legal (session_name);
3205 MessageDialog msg (session_dialog,
3206 string_compose (_("To ensure compatibility with various systems\n"
3207 "session names may not contain a '%1' character"),
3210 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3215 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
3218 if (likely_new && !nsm) {
3220 std::string existing = Glib::build_filename (session_path, session_name);
3222 if (!ask_about_loading_existing_session (existing)) {
3223 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3228 _session_is_new = false;
3233 pop_back_splash (session_dialog);
3234 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
3236 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3240 char illegal = Session::session_name_is_legal(session_name);
3243 pop_back_splash (session_dialog);
3244 MessageDialog msg (session_dialog, string_compose(_("To ensure compatibility with various systems\n"
3245 "session names may not contain a '%1' character"), illegal));
3247 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3251 _session_is_new = true;
3254 if (likely_new && template_name.empty()) {
3256 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3260 ret = load_session (session_path, session_name, template_name);
3263 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
3267 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
3268 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
3272 /* clear this to avoid endless attempts to load the
3276 ARDOUR_COMMAND_LINE::session_name = "";
3280 _session_dialog = NULL;
3286 ARDOUR_UI::close_session()
3288 if (!check_audioengine (_main_window)) {
3292 if (unload_session (true)) {
3296 ARDOUR_COMMAND_LINE::session_name = "";
3298 if (get_session_parameters (true, false)) {
3301 if (splash && splash->is_visible()) {
3302 // in 1 second, hide the splash screen
3303 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
3307 /** @param snap_name Snapshot name (without .ardour suffix).
3308 * @return -2 if the load failed because we are not connected to the AudioEngine.
3311 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
3313 Session *new_session;
3318 unload_status = unload_session ();
3320 if (unload_status < 0) {
3322 } else if (unload_status > 0) {
3328 session_loaded = false;
3330 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
3333 new_session = new Session (*AudioEngine::instance(), path, snap_name, 0, mix_template);
3336 /* this one is special */
3338 catch (AudioEngine::PortRegistrationFailure& err) {
3340 MessageDialog msg (err.what(),
3343 Gtk::BUTTONS_CLOSE);
3345 msg.set_title (_("Port Registration Error"));
3346 msg.set_secondary_text (_("Click the Close button to try again."));
3347 msg.set_position (Gtk::WIN_POS_CENTER);
3348 pop_back_splash (msg);
3351 int response = msg.run ();
3356 case RESPONSE_CANCEL:
3363 catch (SessionException e) {
3364 MessageDialog msg (string_compose(
3365 _("Session \"%1 (snapshot %2)\" did not load successfully: %3"),
3366 path, snap_name, e.what()),
3371 msg.set_title (_("Loading Error"));
3372 msg.set_position (Gtk::WIN_POS_CENTER);
3373 pop_back_splash (msg);
3385 MessageDialog msg (string_compose(
3386 _("Session \"%1 (snapshot %2)\" did not load successfully"),
3392 msg.set_title (_("Loading Error"));
3393 msg.set_position (Gtk::WIN_POS_CENTER);
3394 pop_back_splash (msg);
3406 list<string> const u = new_session->unknown_processors ();
3408 MissingPluginDialog d (_session, u);
3413 if (!new_session->writable()) {
3414 MessageDialog msg (_("This session has been opened in read-only mode.\n\nYou will not be able to record or save."),
3419 msg.set_title (_("Read-only Session"));
3420 msg.set_position (Gtk::WIN_POS_CENTER);
3421 pop_back_splash (msg);
3428 /* Now the session been created, add the transport controls */
3429 new_session->add_controllable(roll_controllable);
3430 new_session->add_controllable(stop_controllable);
3431 new_session->add_controllable(goto_start_controllable);
3432 new_session->add_controllable(goto_end_controllable);
3433 new_session->add_controllable(auto_loop_controllable);
3434 new_session->add_controllable(play_selection_controllable);
3435 new_session->add_controllable(rec_controllable);
3437 set_session (new_session);
3439 session_loaded = true;
3442 _session->set_clean ();
3445 #ifdef WINDOWS_VST_SUPPORT
3446 fst_stop_threading();
3450 Timers::TimerSuspender t;
3454 #ifdef WINDOWS_VST_SUPPORT
3455 fst_start_threading();
3464 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
3466 Session *new_session;
3469 session_loaded = false;
3470 x = unload_session ();
3478 _session_is_new = true;
3481 new_session = new Session (*AudioEngine::instance(), path, snap_name, &bus_profile);
3484 catch (SessionException e) {
3486 MessageDialog msg (string_compose(_("Could not create session in \"%1\": %2"), path, e.what()));
3487 msg.set_title (_("Loading Error"));
3488 msg.set_position (Gtk::WIN_POS_CENTER);
3489 pop_back_splash (msg);
3495 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
3496 msg.set_title (_("Loading Error"));
3497 msg.set_position (Gtk::WIN_POS_CENTER);
3498 pop_back_splash (msg);
3503 /* Give the new session the default GUI state, if such things exist */
3506 n = Config->instant_xml (X_("Editor"));
3508 n->remove_nodes_and_delete ("Selection"); // no not apply selection to new sessions.
3509 new_session->add_instant_xml (*n, false);
3511 n = Config->instant_xml (X_("Mixer"));
3513 new_session->add_instant_xml (*n, false);
3516 /* Put the playhead at 0 and scroll fully left */
3517 n = new_session->instant_xml (X_("Editor"));
3519 n->add_property (X_("playhead"), X_("0"));
3520 n->add_property (X_("left-frame"), X_("0"));
3523 set_session (new_session);
3525 session_loaded = true;
3527 new_session->save_state(new_session->name());
3533 ARDOUR_UI::launch_chat ()
3535 MessageDialog dialog(_("<b>Just ask and wait for an answer.\nIt may take from minutes to hours.</b>"), true);
3537 dialog.set_title (_("About the Chat"));
3538 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."));
3540 switch (dialog.run()) {
3543 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
3544 #elif defined PLATFORM_WINDOWS
3545 open_uri("http://webchat.freenode.net/?channels=ardour-windows");
3547 open_uri("http://webchat.freenode.net/?channels=ardour");
3556 ARDOUR_UI::launch_manual ()
3558 PBD::open_uri (Config->get_tutorial_manual_url());
3562 ARDOUR_UI::launch_reference ()
3564 PBD::open_uri (Config->get_reference_manual_url());
3568 ARDOUR_UI::launch_tracker ()
3570 PBD::open_uri ("http://tracker.ardour.org");
3574 ARDOUR_UI::launch_subscribe ()
3576 PBD::open_uri ("https://community.ardour.org/s/subscribe");
3580 ARDOUR_UI::launch_cheat_sheet ()
3583 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheat_sheet_osx.pdf");
3585 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheatsheet.pdf");
3590 ARDOUR_UI::launch_website ()
3592 PBD::open_uri ("http://ardour.org");
3596 ARDOUR_UI::launch_website_dev ()
3598 PBD::open_uri ("http://ardour.org/development.html");
3602 ARDOUR_UI::launch_forums ()
3604 PBD::open_uri ("https://community.ardour.org/forums");
3608 ARDOUR_UI::launch_howto_report ()
3610 PBD::open_uri ("http://ardour.org/reporting_bugs");
3614 ARDOUR_UI::loading_message (const std::string& msg)
3616 if (ARDOUR_COMMAND_LINE::no_splash) {
3624 splash->message (msg);
3628 ARDOUR_UI::show_splash ()
3632 splash = new Splash;
3642 ARDOUR_UI::hide_splash ()
3649 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title, const bool msg_delete)
3653 removed = rep.paths.size();
3656 MessageDialog msgd (_main_window,
3657 _("No files were ready for clean-up"),
3661 msgd.set_title (_("Clean-up"));
3662 msgd.set_secondary_text (_("If this seems suprising, \n\
3663 check for any existing snapshots.\n\
3664 These may still include regions that\n\
3665 require some unused files to continue to exist."));
3671 ArdourDialog results (_("Clean-up"), true, false);
3673 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
3674 CleanupResultsModelColumns() {
3678 Gtk::TreeModelColumn<std::string> visible_name;
3679 Gtk::TreeModelColumn<std::string> fullpath;
3683 CleanupResultsModelColumns results_columns;
3684 Glib::RefPtr<Gtk::ListStore> results_model;
3685 Gtk::TreeView results_display;
3687 results_model = ListStore::create (results_columns);
3688 results_display.set_model (results_model);
3689 results_display.append_column (list_title, results_columns.visible_name);
3691 results_display.set_name ("CleanupResultsList");
3692 results_display.set_headers_visible (true);
3693 results_display.set_headers_clickable (false);
3694 results_display.set_reorderable (false);
3696 Gtk::ScrolledWindow list_scroller;
3699 Gtk::HBox dhbox; // the hbox for the image and text
3700 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
3701 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
3703 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
3705 const string dead_directory = _session->session_directory().dead_path();
3708 %1 - number of files removed
3709 %2 - location of "dead"
3710 %3 - size of files affected
3711 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
3714 const char* bprefix;
3715 double space_adjusted = 0;
3717 if (rep.space < 1000) {
3719 space_adjusted = rep.space;
3720 } else if (rep.space < 1000000) {
3721 bprefix = _("kilo");
3722 space_adjusted = floorf((float)rep.space / 1000.0);
3723 } else if (rep.space < 1000000 * 1000) {
3724 bprefix = _("mega");
3725 space_adjusted = floorf((float)rep.space / (1000.0 * 1000.0));
3727 bprefix = _("giga");
3728 space_adjusted = floorf((float)rep.space / (1000.0 * 1000 * 1000.0));
3732 txt.set_markup (string_compose (P_("\
3733 The following file was deleted from %2,\n\
3734 releasing %3 %4bytes of disk space", "\
3735 The following %1 files were deleted from %2,\n\
3736 releasing %3 %4bytes of disk space", removed),
3737 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3739 txt.set_markup (string_compose (P_("\
3740 The following file was not in use and \n\
3741 has been moved to: %2\n\n\
3742 After a restart of %5\n\n\
3743 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3744 will release an additional %3 %4bytes of disk space.\n", "\
3745 The following %1 files were not in use and \n\
3746 have been moved to: %2\n\n\
3747 After a restart of %5\n\n\
3748 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3749 will release an additional %3 %4bytes of disk space.\n", removed),
3750 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3753 dhbox.pack_start (*dimage, true, false, 5);
3754 dhbox.pack_start (txt, true, false, 5);
3756 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
3757 TreeModel::Row row = *(results_model->append());
3758 row[results_columns.visible_name] = *i;
3759 row[results_columns.fullpath] = *i;
3762 list_scroller.add (results_display);
3763 list_scroller.set_size_request (-1, 150);
3764 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
3766 dvbox.pack_start (dhbox, true, false, 5);
3767 dvbox.pack_start (list_scroller, true, false, 5);
3768 ddhbox.pack_start (dvbox, true, false, 5);
3770 results.get_vbox()->pack_start (ddhbox, true, false, 5);
3771 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
3772 results.set_default_response (RESPONSE_CLOSE);
3773 results.set_position (Gtk::WIN_POS_MOUSE);
3775 results_display.show();
3776 list_scroller.show();
3783 //results.get_vbox()->show();
3784 results.set_resizable (false);
3791 ARDOUR_UI::cleanup ()
3793 if (_session == 0) {
3794 /* shouldn't happen: menu item is insensitive */
3799 MessageDialog checker (_("Are you sure you want to clean-up?"),
3801 Gtk::MESSAGE_QUESTION,
3804 checker.set_title (_("Clean-up"));
3806 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
3807 ALL undo/redo information will be lost if you clean-up.\n\
3808 Clean-up will move all unused files to a \"dead\" location."));
3810 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3811 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
3812 checker.set_default_response (RESPONSE_CANCEL);
3814 checker.set_name (_("CleanupDialog"));
3815 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3816 checker.set_position (Gtk::WIN_POS_MOUSE);
3818 switch (checker.run()) {
3819 case RESPONSE_ACCEPT:
3825 ARDOUR::CleanupReport rep;
3827 editor->prepare_for_cleanup ();
3829 /* do not allow flush until a session is reloaded */
3831 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3833 act->set_sensitive (false);
3836 if (_session->cleanup_sources (rep)) {
3837 editor->finish_cleanup ();
3841 editor->finish_cleanup ();
3844 display_cleanup_results (rep, _("Cleaned Files"), false);
3848 ARDOUR_UI::flush_trash ()
3850 if (_session == 0) {
3851 /* shouldn't happen: menu item is insensitive */
3855 ARDOUR::CleanupReport rep;
3857 if (_session->cleanup_trash_sources (rep)) {
3861 display_cleanup_results (rep, _("deleted file"), true);
3865 ARDOUR_UI::cleanup_peakfiles ()
3867 if (_session == 0) {
3868 /* shouldn't happen: menu item is insensitive */
3872 if (! _session->can_cleanup_peakfiles ()) {
3876 // get all region-views in this session
3878 TrackViewList empty;
3880 editor->get_regions_after(rs, (framepos_t) 0, empty);
3881 std::list<RegionView*> views = rs.by_layer();
3883 // remove displayed audio-region-views waveforms
3884 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
3885 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
3886 if (!arv) { continue ; }
3887 arv->delete_waves();
3890 // cleanup peak files:
3891 // - stop pending peakfile threads
3892 // - close peakfiles if any
3893 // - remove peak dir in session
3894 // - setup peakfiles (background thread)
3895 _session->cleanup_peakfiles ();
3897 // re-add waves to ARV
3898 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
3899 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
3900 if (!arv) { continue ; }
3901 arv->create_waves();
3906 ARDOUR_UI::setup_order_hint (AddRouteDialog::InsertAt place)
3908 uint32_t order_hint = UINT32_MAX;
3910 if (editor->get_selection().tracks.empty()) {
3915 we want the new routes to have their order keys set starting from
3916 the highest order key in the selection + 1 (if available).
3919 if (place == AddRouteDialog::AfterSelection) {
3920 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.back());
3922 order_hint = rtav->route()->order_key();
3925 } else if (place == AddRouteDialog::BeforeSelection) {
3926 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.front());
3928 order_hint = rtav->route()->order_key();
3930 } else if (place == AddRouteDialog::First) {
3933 /* leave order_hint at UINT32_MAX */
3936 if (order_hint == UINT32_MAX) {
3937 /** AddRouteDialog::Last or selection with first/last not a RouteTimeAxisView
3938 * not setting an order hint will place new routes last.
3943 _session->set_order_hint (order_hint);
3945 /* create a gap in the existing route order keys to accomodate new routes.*/
3946 boost::shared_ptr <RouteList> rd = _session->get_routes();
3947 for (RouteList::iterator ri = rd->begin(); ri != rd->end(); ++ri) {
3948 boost::shared_ptr<Route> rt (*ri);
3950 if (rt->is_monitor()) {
3954 if (rt->order_key () >= order_hint) {
3955 rt->set_order_key (rt->order_key () + add_route_dialog->count());
3961 ARDOUR_UI::start_duplicate_routes ()
3963 if (!duplicate_routes_dialog) {
3964 duplicate_routes_dialog = new DuplicateRouteDialog;
3967 if (duplicate_routes_dialog->restart (_session)) {
3971 duplicate_routes_dialog->present ();
3975 ARDOUR_UI::add_route ()
3983 if (add_route_dialog->is_visible()) {
3984 /* we're already doing this */
3988 ResponseType r = (ResponseType) add_route_dialog->run ();
3990 add_route_dialog->hide();
3993 case RESPONSE_ACCEPT:
4000 if ((count = add_route_dialog->count()) <= 0) {
4004 setup_order_hint(add_route_dialog->insert_at());
4005 string template_path = add_route_dialog->track_template();
4006 DisplaySuspender ds;
4008 if (!template_path.empty()) {
4009 if (add_route_dialog->name_template_is_default()) {
4010 _session->new_route_from_template (count, template_path, string());
4012 _session->new_route_from_template (count, template_path, add_route_dialog->name_template());
4017 ChanCount input_chan= add_route_dialog->channels ();
4018 ChanCount output_chan;
4019 string name_template = add_route_dialog->name_template ();
4020 PluginInfoPtr instrument = add_route_dialog->requested_instrument ();
4021 RouteGroup* route_group = add_route_dialog->route_group ();
4022 AutoConnectOption oac = Config->get_output_auto_connect();
4023 bool strict_io = add_route_dialog->use_strict_io ();
4025 if (oac & AutoConnectMaster) {
4026 output_chan.set (DataType::AUDIO, (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan.n_audio()));
4027 output_chan.set (DataType::MIDI, 0);
4029 output_chan = input_chan;
4032 /* XXX do something with name template */
4034 switch (add_route_dialog->type_wanted()) {
4035 case AddRouteDialog::AudioTrack:
4036 session_add_audio_track (input_chan.n_audio(), output_chan.n_audio(), add_route_dialog->mode(), route_group, count, name_template, strict_io);
4038 case AddRouteDialog::MidiTrack:
4039 session_add_midi_track (route_group, count, name_template, strict_io, instrument);
4041 case AddRouteDialog::MixedTrack:
4042 session_add_mixed_track (input_chan, output_chan, route_group, count, name_template, strict_io, instrument, 0);
4044 case AddRouteDialog::AudioBus:
4045 session_add_audio_bus (input_chan.n_audio(), output_chan.n_audio(), route_group, count, name_template, strict_io);
4047 case AddRouteDialog::MidiBus:
4048 session_add_midi_bus (route_group, count, name_template, strict_io, instrument, 0);
4050 case AddRouteDialog::VCAMaster:
4051 session_add_vca (name_template, count);
4057 ARDOUR_UI::add_lua_script ()
4063 LuaScriptInfoPtr spi;
4064 ScriptSelector ss ("Add Lua Session Script", LuaScriptInfo::Session);
4065 switch (ss.run ()) {
4066 case Gtk::RESPONSE_ACCEPT:
4074 std::string script = "";
4077 script = Glib::file_get_contents (spi->path);
4078 } catch (Glib::FileError e) {
4079 string msg = string_compose (_("Cannot read session script '%1': %2"), spi->path, e.what());
4080 MessageDialog am (msg);
4085 LuaScriptParamList lsp = LuaScriptParams::script_params (spi, "sess_params");
4086 std::vector<std::string> reg = _session->registered_lua_functions ();
4088 ScriptParameterDialog spd (_("Set Script Parameters"), spi, reg, lsp);
4089 switch (spd.run ()) {
4090 case Gtk::RESPONSE_ACCEPT:
4097 _session->register_lua_function (spd.name(), script, lsp);
4098 } catch (luabridge::LuaException const& e) {
4099 string msg = string_compose (_("Session script '%1' instantiation failed: %2"), spd.name(), e.what ());
4100 MessageDialog am (msg);
4102 } catch (SessionException e) {
4103 string msg = string_compose (_("Loading Session script '%1' failed: %2"), spd.name(), e.what ());
4104 MessageDialog am (msg);
4110 ARDOUR_UI::remove_lua_script ()
4115 if (_session->registered_lua_function_count () == 0) {
4116 string msg = _("There are no active Lua session scripts present in this session.");
4117 MessageDialog am (msg);
4122 std::vector<std::string> reg = _session->registered_lua_functions ();
4123 SessionScriptManager sm ("Remove Lua Session Script", reg);
4124 switch (sm.run ()) {
4125 case Gtk::RESPONSE_ACCEPT:
4131 _session->unregister_lua_function (sm.name());
4132 } catch (luabridge::LuaException const& e) {
4133 string msg = string_compose (_("Session script '%1' removal failed: %2"), sm.name(), e.what ());
4134 MessageDialog am (msg);
4140 ARDOUR_UI::stop_video_server (bool ask_confirm)
4142 if (!video_server_process && ask_confirm) {
4143 warning << string_compose (_("Video-Server was not launched by %1. The request to stop it is ignored."), PROGRAM_NAME) << endmsg;
4145 if (video_server_process) {
4147 ArdourDialog confirm (_("Stop Video-Server"), true);
4148 Label m (_("Do you really want to stop the Video Server?"));
4149 confirm.get_vbox()->pack_start (m, true, true);
4150 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
4151 confirm.add_button (_("Yes, Stop It"), Gtk::RESPONSE_ACCEPT);
4152 confirm.show_all ();
4153 if (confirm.run() == RESPONSE_CANCEL) {
4157 delete video_server_process;
4158 video_server_process =0;
4163 ARDOUR_UI::start_video_server_menu (Gtk::Window* float_window)
4165 ARDOUR_UI::start_video_server( float_window, true);
4169 ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg)
4175 if (ARDOUR_UI::instance()->video_timeline->check_server()) {
4176 if (video_server_process) {
4177 popup_error(_("The Video Server is already started."));
4179 popup_error(_("An external Video Server is configured and can be reached. Not starting a new instance."));
4185 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4187 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4189 VideoServerDialog *video_server_dialog = new VideoServerDialog (_session);
4191 video_server_dialog->set_transient_for (*float_window);
4194 if (!Config->get_show_video_server_dialog() && firsttime < 2) {
4195 video_server_dialog->hide();
4197 ResponseType r = (ResponseType) video_server_dialog->run ();
4198 video_server_dialog->hide();
4199 if (r != RESPONSE_ACCEPT) { return false; }
4200 if (video_server_dialog->show_again()) {
4201 Config->set_show_video_server_dialog(false);
4205 std::string icsd_exec = video_server_dialog->get_exec_path();
4206 std::string icsd_docroot = video_server_dialog->get_docroot();
4207 if (icsd_docroot.empty()) {
4208 #ifndef PLATFORM_WINDOWS
4209 icsd_docroot = X_("/");
4211 icsd_docroot = X_("C:\\");
4216 if (g_lstat (icsd_docroot.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode)) {
4217 warning << _("Specified docroot is not an existing directory.") << endmsg;
4220 #ifndef PLATFORM_WINDOWS
4221 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4222 || (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0 ) {
4223 warning << _("Given Video Server is not an executable file.") << endmsg;
4227 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4228 || (sb.st_mode & (S_IXUSR)) == 0 ) {
4229 warning << _("Given Video Server is not an executable file.") << endmsg;
4235 argp=(char**) calloc(9,sizeof(char*));
4236 argp[0] = strdup(icsd_exec.c_str());
4237 argp[1] = strdup("-P");
4238 argp[2] = (char*) calloc(16,sizeof(char)); snprintf(argp[2], 16, "%s", video_server_dialog->get_listenaddr().c_str());
4239 argp[3] = strdup("-p");
4240 argp[4] = (char*) calloc(6,sizeof(char)); snprintf(argp[4], 6, "%i", video_server_dialog->get_listenport());
4241 argp[5] = strdup("-C");
4242 argp[6] = (char*) calloc(6,sizeof(char)); snprintf(argp[6], 6, "%i", video_server_dialog->get_cachesize());
4243 argp[7] = strdup(icsd_docroot.c_str());
4245 stop_video_server();
4247 if (icsd_docroot == X_("/") || icsd_docroot == X_("C:\\")) {
4248 Config->set_video_advanced_setup(false);
4250 std::ostringstream osstream;
4251 osstream << "http://127.0.0.1:" << video_server_dialog->get_listenport() << "/";
4252 Config->set_video_server_url(osstream.str());
4253 Config->set_video_server_docroot(icsd_docroot);
4254 Config->set_video_advanced_setup(true);
4257 if (video_server_process) {
4258 delete video_server_process;
4261 video_server_process = new ARDOUR::SystemExec(icsd_exec, argp);
4262 if (video_server_process->start()) {
4263 warning << _("Cannot launch the video-server") << endmsg;
4266 int timeout = 120; // 6 sec
4267 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4268 Glib::usleep (50000);
4270 if (--timeout <= 0 || !video_server_process->is_running()) break;
4273 warning << _("Video-server was started but does not respond to requests...") << endmsg;
4275 if (!ARDOUR_UI::instance()->video_timeline->check_server_docroot()) {
4276 delete video_server_process;
4277 video_server_process = 0;
4285 ARDOUR_UI::add_video (Gtk::Window* float_window)
4291 if (!start_video_server(float_window, false)) {
4292 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4297 add_video_dialog->set_transient_for (*float_window);
4300 if (add_video_dialog->is_visible()) {
4301 /* we're already doing this */
4305 ResponseType r = (ResponseType) add_video_dialog->run ();
4306 add_video_dialog->hide();
4307 if (r != RESPONSE_ACCEPT) { return; }
4309 bool local_file, orig_local_file;
4310 std::string path = add_video_dialog->file_name(local_file);
4312 std::string orig_path = path;
4313 orig_local_file = local_file;
4315 bool auto_set_session_fps = add_video_dialog->auto_set_session_fps();
4317 if (local_file && !Glib::file_test(path, Glib::FILE_TEST_EXISTS)) {
4318 warning << string_compose(_("could not open %1"), path) << endmsg;
4321 if (!local_file && path.length() == 0) {
4322 warning << _("no video-file selected") << endmsg;
4326 std::string audio_from_video;
4327 bool detect_ltc = false;
4329 switch (add_video_dialog->import_option()) {
4330 case VTL_IMPORT_TRANSCODE:
4332 TranscodeVideoDialog *transcode_video_dialog;
4333 transcode_video_dialog = new TranscodeVideoDialog (_session, path);
4334 ResponseType r = (ResponseType) transcode_video_dialog->run ();
4335 transcode_video_dialog->hide();
4336 if (r != RESPONSE_ACCEPT) {
4337 delete transcode_video_dialog;
4341 audio_from_video = transcode_video_dialog->get_audiofile();
4343 if (!audio_from_video.empty() && transcode_video_dialog->detect_ltc()) {
4346 else if (!audio_from_video.empty()) {
4347 editor->embed_audio_from_video(
4349 video_timeline->get_offset(),
4350 (transcode_video_dialog->import_option() != VTL_IMPORT_NO_VIDEO)
4353 switch (transcode_video_dialog->import_option()) {
4354 case VTL_IMPORT_TRANSCODED:
4355 path = transcode_video_dialog->get_filename();
4358 case VTL_IMPORT_REFERENCE:
4361 delete transcode_video_dialog;
4364 delete transcode_video_dialog;
4368 case VTL_IMPORT_NONE:
4372 /* strip _session->session_directory().video_path() from video file if possible */
4373 if (local_file && !path.compare(0, _session->session_directory().video_path().size(), _session->session_directory().video_path())) {
4374 path=path.substr(_session->session_directory().video_path().size());
4375 if (path.at(0) == G_DIR_SEPARATOR) {
4376 path=path.substr(1);
4380 video_timeline->set_update_session_fps(auto_set_session_fps);
4382 if (video_timeline->video_file_info(path, local_file)) {
4383 XMLNode* node = new XMLNode(X_("Videotimeline"));
4384 node->add_property (X_("Filename"), path);
4385 node->add_property (X_("AutoFPS"), auto_set_session_fps?X_("1"):X_("0"));
4386 node->add_property (X_("LocalFile"), local_file?X_("1"):X_("0"));
4387 if (orig_local_file) {
4388 node->add_property (X_("OriginalVideoFile"), orig_path);
4390 node->remove_property (X_("OriginalVideoFile"));
4392 _session->add_extra_xml (*node);
4393 _session->set_dirty ();
4395 if (!audio_from_video.empty() && detect_ltc) {
4396 std::vector<LTCFileReader::LTCMap> ltc_seq;
4399 /* TODO ask user about TV standard (LTC alignment if any) */
4400 LTCFileReader ltcr (audio_from_video, video_timeline->get_video_file_fps());
4401 /* TODO ASK user which channel: 0 .. ltcr->channels() - 1 */
4403 ltc_seq = ltcr.read_ltc (/*channel*/ 0, /*max LTC frames to decode*/ 15);
4405 /* TODO seek near end of file, and read LTC until end.
4406 * if it fails to find any LTC frames, scan complete file
4408 * calculate drift of LTC compared to video-duration,
4409 * ask user for reference (timecode from start/mid/end)
4412 // LTCFileReader will have written error messages
4415 ::g_unlink(audio_from_video.c_str());
4417 if (ltc_seq.size() == 0) {
4418 PBD::error << _("No LTC detected, video will not be aligned.") << endmsg;
4420 /* the very first TC in the file is somteimes not aligned properly */
4421 int i = ltc_seq.size() -1;
4422 ARDOUR::frameoffset_t video_start_offset =
4423 _session->nominal_frame_rate() * (ltc_seq[i].timecode_sec - ltc_seq[i].framepos_sec);
4424 PBD::info << string_compose (_("Align video-start to %1 [samples]"), video_start_offset) << endmsg;
4425 video_timeline->set_offset(video_start_offset);
4429 _session->maybe_update_session_range(
4430 std::max(video_timeline->get_offset(), (ARDOUR::frameoffset_t) 0),
4431 std::max(video_timeline->get_offset() + video_timeline->get_duration(), (ARDOUR::frameoffset_t) 0));
4434 if (add_video_dialog->launch_xjadeo() && local_file) {
4435 editor->set_xjadeo_sensitive(true);
4436 editor->toggle_xjadeo_proc(1);
4438 editor->toggle_xjadeo_proc(0);
4440 editor->toggle_ruler_video(true);
4445 ARDOUR_UI::remove_video ()
4447 video_timeline->close_session();
4448 editor->toggle_ruler_video(false);
4451 video_timeline->set_offset_locked(false);
4452 video_timeline->set_offset(0);
4454 /* delete session state */
4455 XMLNode* node = new XMLNode(X_("Videotimeline"));
4456 _session->add_extra_xml(*node);
4457 node = new XMLNode(X_("Videomonitor"));
4458 _session->add_extra_xml(*node);
4459 node = new XMLNode(X_("Videoexport"));
4460 _session->add_extra_xml(*node);
4461 stop_video_server();
4465 ARDOUR_UI::flush_videotimeline_cache (bool localcacheonly)
4467 if (localcacheonly) {
4468 video_timeline->vmon_update();
4470 video_timeline->flush_cache();
4472 editor->queue_visual_videotimeline_update();
4476 ARDOUR_UI::export_video (bool range)
4478 if (ARDOUR::Config->get_show_video_export_info()) {
4479 ExportVideoInfobox infobox (_session);
4480 Gtk::ResponseType rv = (Gtk::ResponseType) infobox.run();
4481 if (infobox.show_again()) {
4482 ARDOUR::Config->set_show_video_export_info(false);
4485 case GTK_RESPONSE_YES:
4486 PBD::open_uri (ARDOUR::Config->get_reference_manual_url() + "/video-timeline/operations/#export");
4492 export_video_dialog->set_session (_session);
4493 export_video_dialog->apply_state(editor->get_selection().time, range);
4494 export_video_dialog->run ();
4495 export_video_dialog->hide ();
4499 ARDOUR_UI::mixer_settings () const
4504 node = _session->instant_xml(X_("Mixer"));
4506 node = Config->instant_xml(X_("Mixer"));
4510 node = new XMLNode (X_("Mixer"));
4517 ARDOUR_UI::main_window_settings () const
4522 node = _session->instant_xml(X_("Main"));
4524 node = Config->instant_xml(X_("Main"));
4528 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4529 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4534 node = new XMLNode (X_("Main"));
4541 ARDOUR_UI::editor_settings () const
4546 node = _session->instant_xml(X_("Editor"));
4548 node = Config->instant_xml(X_("Editor"));
4552 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4553 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4558 node = new XMLNode (X_("Editor"));
4565 ARDOUR_UI::keyboard_settings () const
4569 node = Config->extra_xml(X_("Keyboard"));
4572 node = new XMLNode (X_("Keyboard"));
4579 ARDOUR_UI::create_xrun_marker (framepos_t where)
4582 Location *location = new Location (*_session, where, where, _("xrun"), Location::IsMark);
4583 _session->locations()->add (location);
4588 ARDOUR_UI::halt_on_xrun_message ()
4590 cerr << "HALT on xrun\n";
4591 MessageDialog msg (_main_window, _("Recording was stopped because your system could not keep up."));
4596 ARDOUR_UI::xrun_handler (framepos_t where)
4602 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
4604 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
4605 create_xrun_marker(where);
4608 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
4609 halt_on_xrun_message ();
4614 ARDOUR_UI::disk_overrun_handler ()
4616 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
4618 if (!have_disk_speed_dialog_displayed) {
4619 have_disk_speed_dialog_displayed = true;
4620 MessageDialog* msg = new MessageDialog (_main_window, string_compose (_("\
4621 The disk system on your computer\n\
4622 was not able to keep up with %1.\n\
4624 Specifically, it failed to write data to disk\n\
4625 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
4626 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4632 /* TODO: this is getting elaborate enough to warrant being split into a dedicated class */
4633 static MessageDialog *scan_dlg = NULL;
4634 static ProgressBar *scan_pbar = NULL;
4635 static HBox *scan_tbox = NULL;
4636 static Gtk::Button *scan_timeout_button;
4639 ARDOUR_UI::cancel_plugin_scan ()
4641 PluginManager::instance().cancel_plugin_scan();
4645 ARDOUR_UI::cancel_plugin_timeout ()
4647 PluginManager::instance().cancel_plugin_timeout();
4648 scan_timeout_button->set_sensitive (false);
4652 ARDOUR_UI::plugin_scan_timeout (int timeout)
4654 if (!scan_dlg || !scan_dlg->is_mapped() || !scan_pbar) {
4658 scan_pbar->set_sensitive (false);
4659 scan_timeout_button->set_sensitive (true);
4660 scan_pbar->set_fraction ((float) timeout / (float) Config->get_vst_scan_timeout());
4663 scan_pbar->set_sensitive (false);
4664 scan_timeout_button->set_sensitive (false);
4670 ARDOUR_UI::plugin_scan_dialog (std::string type, std::string plugin, bool can_cancel)
4672 if (type == X_("closeme") && !(scan_dlg && scan_dlg->is_mapped())) {
4676 const bool cancelled = PluginManager::instance().cancelled();
4677 if (type != X_("closeme") && (!UIConfiguration::instance().get_show_plugin_scan_window()) && !_initial_verbose_plugin_scan) {
4678 if (cancelled && scan_dlg->is_mapped()) {
4683 if (cancelled || !can_cancel) {
4688 static Gtk::Button *cancel_button;
4690 scan_dlg = new MessageDialog("", false, MESSAGE_INFO, BUTTONS_NONE); // TODO manage
4691 VBox* vbox = scan_dlg->get_vbox();
4692 vbox->set_size_request(400,-1);
4693 scan_dlg->set_title (_("Scanning for plugins"));
4695 cancel_button = manage(new Gtk::Button(_("Cancel plugin scan")));
4696 cancel_button->set_name ("EditorGTKButton");
4697 cancel_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_scan) );
4698 cancel_button->show();
4700 scan_dlg->get_vbox()->pack_start ( *cancel_button, PACK_SHRINK);
4702 scan_tbox = manage( new HBox() );
4704 scan_timeout_button = manage(new Gtk::Button(_("Stop Timeout")));
4705 scan_timeout_button->set_name ("EditorGTKButton");
4706 scan_timeout_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_timeout) );
4707 scan_timeout_button->show();
4709 scan_pbar = manage(new ProgressBar());
4710 scan_pbar->set_orientation(Gtk::PROGRESS_RIGHT_TO_LEFT);
4711 scan_pbar->set_text(_("Scan Timeout"));
4714 scan_tbox->pack_start (*scan_pbar, PACK_EXPAND_WIDGET, 4);
4715 scan_tbox->pack_start (*scan_timeout_button, PACK_SHRINK, 4);
4717 scan_dlg->get_vbox()->pack_start (*scan_tbox, PACK_SHRINK, 4);
4720 assert(scan_dlg && scan_tbox && cancel_button);
4722 if (type == X_("closeme")) {
4726 scan_dlg->set_message(type + ": " + Glib::path_get_basename(plugin));
4729 if (!can_cancel || !cancelled) {
4730 scan_timeout_button->set_sensitive(false);
4732 cancel_button->set_sensitive(can_cancel && !cancelled);
4738 ARDOUR_UI::gui_idle_handler ()
4741 /* due to idle calls, gtk_events_pending() may always return true */
4742 while (gtk_events_pending() && --timeout) {
4743 gtk_main_iteration ();
4748 ARDOUR_UI::disk_underrun_handler ()
4750 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
4752 if (!have_disk_speed_dialog_displayed) {
4753 have_disk_speed_dialog_displayed = true;
4754 MessageDialog* msg = new MessageDialog (
4755 _main_window, string_compose (_("The disk system on your computer\n\
4756 was not able to keep up with %1.\n\
4758 Specifically, it failed to read data from disk\n\
4759 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
4760 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4766 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
4768 have_disk_speed_dialog_displayed = false;
4773 ARDOUR_UI::session_dialog (std::string msg)
4775 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
4779 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
4786 ARDOUR_UI::pending_state_dialog ()
4788 HBox* hbox = manage (new HBox());
4789 Image* image = manage (new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG));
4790 ArdourDialog dialog (_("Crash Recovery"), true);
4791 Label message (string_compose (_("\
4792 This session appears to have been in the\n\
4793 middle of recording when %1 or\n\
4794 the computer was shutdown.\n\
4796 %1 can recover any captured audio for\n\
4797 you, or it can ignore it. Please decide\n\
4798 what you would like to do.\n"), PROGRAM_NAME));
4799 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4800 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4801 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4802 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4803 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
4804 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
4805 dialog.set_default_response (RESPONSE_ACCEPT);
4806 dialog.set_position (WIN_POS_CENTER);
4811 switch (dialog.run ()) {
4812 case RESPONSE_ACCEPT:
4820 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
4822 HBox* hbox = new HBox();
4823 Image* image = new Image (Stock::DIALOG_WARNING, ICON_SIZE_DIALOG);
4824 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
4825 Label message (string_compose (_("\
4826 This session was created with a sample rate of %1 Hz, but\n\
4827 %2 is currently running at %3 Hz. If you load this session,\n\
4828 audio may be played at the wrong sample rate.\n"), desired, PROGRAM_NAME, actual));
4830 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4831 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4832 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4833 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4834 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
4835 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
4836 dialog.set_default_response (RESPONSE_ACCEPT);
4837 dialog.set_position (WIN_POS_CENTER);
4842 switch (dialog.run()) {
4843 case RESPONSE_ACCEPT:
4853 ARDOUR_UI::sr_mismatch_message (framecnt_t desired, framecnt_t actual)
4855 MessageDialog msg (string_compose (_("\
4856 This session was created with a sample rate of %1 Hz, but\n\
4857 %2 is currently running at %3 Hz.\n\
4858 Audio will be recorded and played at the wrong sample rate.\n\
4859 Re-Configure the Audio Engine in\n\
4860 Menu > Window > Audio/Midi Setup"),
4861 desired, PROGRAM_NAME, actual),
4863 Gtk::MESSAGE_WARNING);
4868 ARDOUR_UI::use_config ()
4870 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
4872 set_transport_controllable_state (*node);
4877 ARDOUR_UI::update_transport_clocks (framepos_t pos)
4879 if (UIConfiguration::instance().get_primary_clock_delta_edit_cursor()) {
4880 primary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
4882 primary_clock->set (pos);
4885 if (UIConfiguration::instance().get_secondary_clock_delta_edit_cursor()) {
4886 secondary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
4888 secondary_clock->set (pos);
4891 if (big_clock_window) {
4892 big_clock->set (pos);
4894 ARDOUR_UI::instance()->video_timeline->manual_seek_video_monitor(pos);
4898 ARDOUR_UI::step_edit_status_change (bool yn)
4900 // XXX should really store pre-step edit status of things
4901 // we make insensitive
4904 rec_button.set_active_state (Gtkmm2ext::ImplicitActive);
4905 rec_button.set_sensitive (false);
4907 rec_button.unset_active_state ();;
4908 rec_button.set_sensitive (true);
4913 ARDOUR_UI::record_state_changed ()
4915 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
4917 if (!_session || !big_clock_window) {
4918 /* why bother - the clock isn't visible */
4922 if (_session->record_status () == Session::Recording && _session->have_rec_enabled_track ()) {
4923 big_clock->set_active (true);
4925 big_clock->set_active (false);
4930 ARDOUR_UI::first_idle ()
4933 _session->allow_auto_play (true);
4937 editor->first_idle();
4940 Keyboard::set_can_save_keybindings (true);
4945 ARDOUR_UI::store_clock_modes ()
4947 XMLNode* node = new XMLNode(X_("ClockModes"));
4949 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
4950 XMLNode* child = new XMLNode (X_("Clock"));
4952 child->add_property (X_("name"), (*x)->name());
4953 child->add_property (X_("mode"), enum_2_string ((*x)->mode()));
4954 child->add_property (X_("on"), ((*x)->off() ? X_("no") : X_("yes")));
4956 node->add_child_nocopy (*child);
4959 _session->add_extra_xml (*node);
4960 _session->set_dirty ();
4963 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
4964 : Controllable (name), ui (u), type(tp)
4970 ARDOUR_UI::TransportControllable::set_value (double val, PBD::Controllable::GroupControlDisposition /*group_override*/)
4973 /* do nothing: these are radio-style actions */
4977 const char *action = 0;
4981 action = X_("Roll");
4984 action = X_("Stop");
4987 action = X_("GotoStart");
4990 action = X_("GotoEnd");
4993 action = X_("Loop");
4996 action = X_("PlaySelection");
4999 action = X_("Record");
5009 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
5017 ARDOUR_UI::TransportControllable::get_value (void) const
5044 ARDOUR_UI::setup_profile ()
5046 if (gdk_screen_width() < 1200 || getenv ("ARDOUR_NARROW_SCREEN")) {
5047 Profile->set_small_screen ();
5050 if (g_getenv ("TRX")) {
5051 Profile->set_trx ();
5054 if (g_getenv ("MIXBUS")) {
5055 Profile->set_mixbus ();
5060 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
5062 MissingFileDialog dialog (s, str, type);
5067 int result = dialog.run ();
5074 return 1; // quit entire session load
5077 result = dialog.get_action ();
5083 ARDOUR_UI::ambiguous_file (std::string file, std::vector<std::string> hits)
5085 AmbiguousFileDialog dialog (file, hits);
5092 return dialog.get_which ();
5095 /** Allocate our thread-local buffers */
5097 ARDOUR_UI::get_process_buffers ()
5099 _process_thread->get_buffers ();
5102 /** Drop our thread-local buffers */
5104 ARDOUR_UI::drop_process_buffers ()
5106 _process_thread->drop_buffers ();
5110 ARDOUR_UI::feedback_detected ()
5112 _feedback_exists = true;
5116 ARDOUR_UI::successful_graph_sort ()
5118 _feedback_exists = false;
5122 ARDOUR_UI::midi_panic ()
5125 _session->midi_panic();
5130 ARDOUR_UI::session_format_mismatch (std::string xml_path, std::string backup_path)
5132 const char* start_big = "<span size=\"x-large\" weight=\"bold\">";
5133 const char* end_big = "</span>";
5134 const char* start_mono = "<tt>";
5135 const char* end_mono = "</tt>";
5137 MessageDialog msg (string_compose (_("%4This is a session from an older version of %3%5\n\n"
5138 "%3 has copied the old session file\n\n%6%1%7\n\nto\n\n%6%2%7\n\n"
5139 "From now on, use the -2000 version with older versions of %3"),
5140 xml_path, backup_path, PROGRAM_NAME,
5142 start_mono, end_mono), true);
5149 ARDOUR_UI::reset_peak_display ()
5151 if (!_session || !_session->master_out() || !editor_meter) return;
5152 editor_meter->clear_meters();
5153 editor_meter_max_peak = -INFINITY;
5154 editor_meter_peak_display.set_active_state ( Gtkmm2ext::Off );
5158 ARDOUR_UI::reset_group_peak_display (RouteGroup* group)
5160 if (!_session || !_session->master_out()) return;
5161 if (group == _session->master_out()->route_group()) {
5162 reset_peak_display ();
5167 ARDOUR_UI::reset_route_peak_display (Route* route)
5169 if (!_session || !_session->master_out()) return;
5170 if (_session->master_out().get() == route) {
5171 reset_peak_display ();
5176 ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate)
5178 audio_midi_setup->set_desired_sample_rate (desired_sample_rate);
5179 audio_midi_setup->set_position (WIN_POS_CENTER);
5181 if (Config->get_try_autostart_engine () || getenv ("TRY_AUTOSTART_ENGINE")) {
5182 audio_midi_setup->try_autostart ();
5183 if (ARDOUR::AudioEngine::instance()->running()) {
5189 int response = audio_midi_setup->run();
5191 case Gtk::RESPONSE_OK:
5192 if (!AudioEngine::instance()->running()) {
5206 ARDOUR_UI::transport_numpad_timeout ()
5208 _numpad_locate_happening = false;
5209 if (_numpad_timeout_connection.connected() )
5210 _numpad_timeout_connection.disconnect();
5215 ARDOUR_UI::transport_numpad_decimal ()
5217 _numpad_timeout_connection.disconnect();
5219 if (_numpad_locate_happening) {
5220 if (editor) editor->goto_nth_marker(_pending_locate_num - 1);
5221 _numpad_locate_happening = false;
5223 _pending_locate_num = 0;
5224 _numpad_locate_happening = true;
5225 _numpad_timeout_connection = Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::transport_numpad_timeout), 2*1000);
5230 ARDOUR_UI::transport_numpad_event (int num)
5232 if ( _numpad_locate_happening ) {
5233 _pending_locate_num = _pending_locate_num*10 + num;
5236 case 0: toggle_roll(false, false); break;
5237 case 1: transport_rewind(1); break;
5238 case 2: transport_forward(1); break;
5239 case 3: transport_record(true); break;
5240 case 4: toggle_session_auto_loop(); break;
5241 case 5: transport_record(false); toggle_session_auto_loop(); break;
5242 case 6: toggle_punch(); break;
5243 case 7: toggle_click(); break;
5244 case 8: toggle_auto_return(); break;
5245 case 9: toggle_follow_edits(); break;
5251 ARDOUR_UI::set_flat_buttons ()
5253 CairoWidget::set_flat_buttons( UIConfiguration::instance().get_flat_buttons() );
5257 ARDOUR_UI::audioengine_became_silent ()
5259 MessageDialog msg (string_compose (_("This is a free/demo copy of %1. It has just switched to silent mode."), PROGRAM_NAME),
5261 Gtk::MESSAGE_WARNING,
5265 msg.set_title (string_compose (_("%1 is now silent"), PROGRAM_NAME));
5267 Gtk::Label pay_label (string_compose (_("Please consider paying for a copy of %1 - you can pay whatever you want."), PROGRAM_NAME));
5268 Gtk::Label subscribe_label (_("Better yet become a subscriber - subscriptions start at US$1 per month."));
5269 Gtk::Button pay_button (_("Pay for a copy (via the web)"));
5270 Gtk::Button subscribe_button (_("Become a subscriber (via the web)"));
5271 Gtk::HBox pay_button_box;
5272 Gtk::HBox subscribe_button_box;
5274 pay_button_box.pack_start (pay_button, true, false);
5275 subscribe_button_box.pack_start (subscribe_button, true, false);
5277 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 */
5279 pay_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://ardour.org/download")));
5280 subscribe_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://community.ardour.org/s/subscribe")));
5282 msg.get_vbox()->pack_start (pay_label);
5283 msg.get_vbox()->pack_start (pay_button_box);
5284 msg.get_vbox()->pack_start (subscribe_label);
5285 msg.get_vbox()->pack_start (subscribe_button_box);
5287 msg.get_vbox()->show_all ();
5289 msg.add_button (_("Remain silent"), Gtk::RESPONSE_CANCEL);
5290 msg.add_button (_("Save and quit"), Gtk::RESPONSE_NO);
5291 msg.add_button (_("Give me more time"), Gtk::RESPONSE_YES);
5296 case Gtk::RESPONSE_YES:
5297 AudioEngine::instance()->reset_silence_countdown ();
5300 case Gtk::RESPONSE_NO:
5302 save_state_canfail ("");
5306 case Gtk::RESPONSE_CANCEL:
5308 /* don't reset, save session and exit */
5314 ARDOUR_UI::hide_application ()
5316 Application::instance ()-> hide ();
5320 ARDOUR_UI::setup_toplevel_window (Gtk::Window& window, const string& name, void* owner)
5322 /* icons, titles, WM stuff */
5324 static list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
5326 if (window_icons.empty()) {
5327 Glib::RefPtr<Gdk::Pixbuf> icon;
5328 if ((icon = ::get_icon (PROGRAM_NAME "-icon_16px")) != 0) {
5329 window_icons.push_back (icon);
5331 if ((icon = ::get_icon (PROGRAM_NAME "-icon_22px")) != 0) {
5332 window_icons.push_back (icon);
5334 if ((icon = ::get_icon (PROGRAM_NAME "-icon_32px")) != 0) {
5335 window_icons.push_back (icon);
5337 if ((icon = ::get_icon (PROGRAM_NAME "-icon_48px")) != 0) {
5338 window_icons.push_back (icon);
5342 if (!window_icons.empty()) {
5343 window.set_default_icon_list (window_icons);
5346 Gtkmm2ext::WindowTitle title (Glib::get_application_name());
5348 if (!name.empty()) {
5352 window.set_title (title.get_string());
5353 window.set_wmclass (string_compose (X_("%1_%1"), downcase (PROGRAM_NAME), downcase (name)), PROGRAM_NAME);
5355 window.set_flags (CAN_FOCUS);
5356 window.add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
5358 /* This is a hack to ensure that GTK-accelerators continue to
5359 * work. Once we switch over to entirely native bindings, this will be
5360 * unnecessary and should be removed
5362 window.add_accel_group (ActionManager::ui_manager->get_accel_group());
5364 window.signal_configure_event().connect (sigc::mem_fun (*this, &ARDOUR_UI::configure_handler));
5365 window.signal_window_state_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::tabbed_window_state_event_handler), owner));
5366 window.signal_key_press_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5367 window.signal_key_release_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5371 ARDOUR_UI::key_event_handler (GdkEventKey* ev, Gtk::Window* event_window)
5373 Gtkmm2ext::Bindings* bindings = 0;
5374 Gtk::Window* window = 0;
5376 /* until we get ardour bindings working, we are not handling key
5380 if (ev->type != GDK_KEY_PRESS) {
5384 if (event_window == &_main_window) {
5386 window = event_window;
5388 /* find current tab contents */
5390 Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page());
5392 /* see if it uses the ardour binding system */
5395 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(w->get_data ("ardour-bindings"));
5398 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("main window key event, bindings = %1, global = %2\n", bindings, &global_bindings));
5402 window = event_window;
5404 /* see if window uses ardour binding system */
5406 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(window->get_data ("ardour-bindings"));
5409 /* An empty binding set is treated as if it doesn't exist */
5411 if (bindings && bindings->empty()) {
5415 return key_press_focus_accelerator_handler (*window, ev, bindings);
5418 static Gtkmm2ext::Bindings*
5419 get_bindings_from_widget_heirarchy (GtkWidget* w)
5424 if ((p = g_object_get_data (G_OBJECT(w), "ardour-bindings")) != 0) {
5427 w = gtk_widget_get_parent (w);
5430 return reinterpret_cast<Gtkmm2ext::Bindings*> (p);
5434 ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev, Gtkmm2ext::Bindings* bindings)
5436 GtkWindow* win = window.gobj();
5437 GtkWidget* focus = gtk_window_get_focus (win);
5438 bool special_handling_of_unmodified_accelerators = false;
5439 const guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK));
5443 /* some widget has keyboard focus */
5445 if (GTK_IS_ENTRY(focus) || Keyboard::some_magic_widget_has_focus()) {
5447 /* A particular kind of focusable widget currently has keyboard
5448 * focus. All unmodified key events should go to that widget
5449 * first and not be used as an accelerator by default
5452 special_handling_of_unmodified_accelerators = true;
5456 Gtkmm2ext::Bindings* focus_bindings = get_bindings_from_widget_heirarchy (focus);
5457 if (focus_bindings) {
5458 bindings = focus_bindings;
5459 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Switch bindings based on focus widget, now using %1\n", bindings->name()));
5464 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",
5467 show_gdk_event_state (ev->state),
5468 special_handling_of_unmodified_accelerators,
5469 Keyboard::some_magic_widget_has_focus(),
5471 (focus ? gtk_widget_get_name (focus) : "no focus widget"),
5472 ((ev->state & mask) ? "yes" : "no"),
5473 window.get_title()));
5475 /* This exists to allow us to override the way GTK handles
5476 key events. The normal sequence is:
5478 a) event is delivered to a GtkWindow
5479 b) accelerators/mnemonics are activated
5480 c) if (b) didn't handle the event, propagate to
5481 the focus widget and/or focus chain
5483 The problem with this is that if the accelerators include
5484 keys without modifiers, such as the space bar or the
5485 letter "e", then pressing the key while typing into
5486 a text entry widget results in the accelerator being
5487 activated, instead of the desired letter appearing
5490 There is no good way of fixing this, but this
5491 represents a compromise. The idea is that
5492 key events involving modifiers (not Shift)
5493 get routed into the activation pathway first, then
5494 get propagated to the focus widget if necessary.
5496 If the key event doesn't involve modifiers,
5497 we deliver to the focus widget first, thus allowing
5498 it to get "normal text" without interference
5501 Of course, this can also be problematic: if there
5502 is a widget with focus, then it will swallow
5503 all "normal text" accelerators.
5507 if (!special_handling_of_unmodified_accelerators || (ev->state & mask)) {
5509 /* no special handling or there are modifiers in effect: accelerate first */
5511 DEBUG_TRACE (DEBUG::Accelerators, "\tactivate, then propagate\n");
5512 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tevent send-event:%1 time:%2 length:%3 name %7 string:%4 hardware_keycode:%5 group:%6\n",
5513 ev->send_event, ev->time, ev->length, ev->string, ev->hardware_keycode, ev->group, gdk_keyval_name (ev->keyval)));
5515 DEBUG_TRACE (DEBUG::Accelerators, "\tsending to window\n");
5516 KeyboardKey k (ev->state, ev->keyval);
5520 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tusing Ardour bindings %1 @ %2 for this event\n", bindings->name(), bindings));
5522 if (bindings->activate (k, Bindings::Press)) {
5523 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5528 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5530 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5531 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5535 DEBUG_TRACE (DEBUG::Accelerators, "\tnot accelerated, now propagate\n");
5537 if (gtk_window_propagate_key_event (win, ev)) {
5538 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate handled\n");
5544 /* no modifiers, propagate first */
5546 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate, then activate\n");
5548 if (gtk_window_propagate_key_event (win, ev)) {
5549 DEBUG_TRACE (DEBUG::Accelerators, "\thandled by propagate\n");
5553 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagation didn't handle, so activate\n");
5554 KeyboardKey k (ev->state, ev->keyval);
5558 DEBUG_TRACE (DEBUG::Accelerators, "\tusing Ardour bindings for this window\n");
5561 if (bindings->activate (k, Bindings::Press)) {
5562 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5568 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5570 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5571 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5576 DEBUG_TRACE (DEBUG::Accelerators, "\tnot handled\n");
5581 ARDOUR_UI::load_bindings ()
5583 if ((global_bindings = Bindings::get_bindings (X_("Global"), global_actions)) == 0) {
5584 error << _("Global keybindings are missing") << endmsg;
5589 ARDOUR_UI::cancel_solo ()
5593 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Route::solo_control), 0.0, Controllable::NoGroup);
5595 _session->clear_all_solo_state (_session->get_routes()); // safeguard, ideally this won't do anything, check the log-window