2 Copyright (C) 1999-2013 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include "gtk2ardour-config.h"
22 #include "gtk2ardour-version.h"
32 #ifndef PLATFORM_WINDOWS
33 #include <sys/resource.h>
43 #include "pbd/gstdio_compat.h"
45 #include <gtkmm/messagedialog.h>
46 #include <gtkmm/accelmap.h>
48 #include "pbd/error.h"
49 #include "pbd/basename.h"
50 #include "pbd/compose.h"
51 #include "pbd/convert.h"
52 #include "pbd/failed_constructor.h"
53 #include "pbd/enumwriter.h"
54 #include "pbd/memento_command.h"
55 #include "pbd/openuri.h"
56 #include "pbd/stl_delete.h"
57 #include "pbd/file_utils.h"
58 #include "pbd/localtime_r.h"
59 #include "pbd/pthread_utils.h"
60 #include "pbd/replace_all.h"
61 #include "pbd/xml++.h"
63 #include "gtkmm2ext/application.h"
64 #include "gtkmm2ext/bindings.h"
65 #include "gtkmm2ext/gtk_ui.h"
66 #include "gtkmm2ext/utils.h"
67 #include "gtkmm2ext/click_box.h"
68 #include "gtkmm2ext/fastmeter.h"
69 #include "gtkmm2ext/popup.h"
70 #include "gtkmm2ext/window_title.h"
72 #include "ardour/ardour.h"
73 #include "ardour/audio_backend.h"
74 #include "ardour/audio_track.h"
75 #include "ardour/audioengine.h"
76 #include "ardour/audiofilesource.h"
77 #include "ardour/automation_watch.h"
78 #include "ardour/diskstream.h"
79 #include "ardour/filename_extensions.h"
80 #include "ardour/filesystem_paths.h"
81 #include "ardour/ltc_file_reader.h"
82 #include "ardour/midi_track.h"
83 #include "ardour/port.h"
84 #include "ardour/plugin_manager.h"
85 #include "ardour/process_thread.h"
86 #include "ardour/profile.h"
87 #include "ardour/recent_sessions.h"
88 #include "ardour/session_directory.h"
89 #include "ardour/session_route.h"
90 #include "ardour/session_state_utils.h"
91 #include "ardour/session_utils.h"
92 #include "ardour/source_factory.h"
93 #include "ardour/slave.h"
94 #include "ardour/system_exec.h"
96 #include "LuaBridge/LuaBridge.h"
98 #ifdef WINDOWS_VST_SUPPORT
101 #ifdef AUDIOUNIT_SUPPORT
102 #include "ardour/audio_unit.h"
105 // fix for OSX (nsm.h has a check function, AU/Apple defines check)
110 #include "timecode/time.h"
112 typedef uint64_t microseconds_t;
117 #include "add_route_dialog.h"
118 #include "ambiguous_file_dialog.h"
119 #include "ardour_ui.h"
120 #include "audio_clock.h"
121 #include "audio_region_view.h"
122 #include "big_clock_window.h"
123 #include "bundle_manager.h"
124 #include "duplicate_routes_dialog.h"
126 #include "engine_dialog.h"
127 #include "export_video_dialog.h"
128 #include "export_video_infobox.h"
129 #include "gain_meter.h"
130 #include "global_port_matrix.h"
131 #include "gui_object.h"
132 #include "gui_thread.h"
133 #include "keyboard.h"
134 #include "keyeditor.h"
135 #include "location_ui.h"
136 #include "lua_script_manager.h"
137 #include "luawindow.h"
138 #include "main_clock.h"
139 #include "missing_file_dialog.h"
140 #include "missing_plugin_dialog.h"
141 #include "mixer_ui.h"
142 #include "meterbridge.h"
143 #include "mouse_cursors.h"
146 #include "pingback.h"
147 #include "processor_box.h"
148 #include "prompter.h"
149 #include "public_editor.h"
150 #include "rc_option_editor.h"
151 #include "route_time_axis.h"
152 #include "route_params_ui.h"
153 #include "save_as_dialog.h"
154 #include "script_selector.h"
155 #include "session_dialog.h"
156 #include "session_metadata_dialog.h"
157 #include "session_option_editor.h"
158 #include "shuttle_control.h"
159 #include "speaker_dialog.h"
162 #include "theme_manager.h"
163 #include "time_axis_view_item.h"
166 #include "video_server_dialog.h"
167 #include "add_video_dialog.h"
168 #include "transcode_video_dialog.h"
172 using namespace ARDOUR;
173 using namespace ARDOUR_UI_UTILS;
175 using namespace Gtkmm2ext;
178 using namespace Editing;
180 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
182 sigc::signal<void, framepos_t, bool, framepos_t> ARDOUR_UI::Clock;
183 sigc::signal<void> ARDOUR_UI::CloseAllDialogs;
186 ask_about_configuration_copy (string const & old_dir, string const & new_dir, int version)
188 MessageDialog msg (string_compose (_("%1 %2.x has discovered configuration files from %1 %3.x.\n\n"
189 "Would you like these files to be copied and used for %1 %2.x?\n\n"
190 "(This will require you to restart %1.)"),
191 PROGRAM_NAME, PROGRAM_VERSION, version),
192 false, /* no markup */
195 true /* modal, though it hardly matters since it is the only window */
198 msg.set_default_response (Gtk::RESPONSE_YES);
201 return (msg.run() == Gtk::RESPONSE_YES);
205 libxml_generic_error_func (void* /* parsing_context*/,
213 vsnprintf (buf, sizeof (buf), msg, ap);
214 error << buf << endmsg;
219 libxml_structured_error_func (void* /* parsing_context*/,
227 replace_all (msg, "\n", "");
230 if (err->file && err->line) {
231 error << X_("XML error: ") << msg << " in " << err->file << " at line " << err->line;
234 error << ':' << err->int2;
239 error << X_("XML error: ") << msg << endmsg;
245 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
246 : Gtkmm2ext::UI (PROGRAM_NAME, X_("gui"), argcp, argvp)
247 , session_loaded (false)
248 , gui_object_state (new GUIObjectState)
249 , primary_clock (new MainClock (X_("primary"), X_("transport"), true ))
250 , secondary_clock (new MainClock (X_("secondary"), X_("secondary"), false))
251 , big_clock (new AudioClock (X_("bigclock"), false, "big", true, true, false, false))
253 , global_actions (X_("global"))
254 , ignore_dual_punch (false)
255 , main_window_visibility (0)
260 , _mixer_on_top (false)
261 , _initial_verbose_plugin_scan (false)
262 , first_time_engine_run (true)
263 , roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll))
264 , stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop))
265 , goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart))
266 , goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd))
267 , auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop))
268 , play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection))
269 , rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable))
270 , auto_return_button (ArdourButton::led_default_elements)
271 , follow_edits_button (ArdourButton::led_default_elements)
272 , auto_input_button (ArdourButton::led_default_elements)
273 , auditioning_alert_button (_("Audition"))
274 , solo_alert_button (_("Solo"))
275 , feedback_alert_button (_("Feedback"))
276 , error_alert_button ( ArdourButton::just_led_default_elements )
278 , editor_meter_peak_display()
279 , _numpad_locate_happening (false)
280 , _session_is_new (false)
281 , last_key_press_time (0)
285 , rc_option_editor (0)
286 , speaker_config_window (X_("speaker-config"), _("Speaker Configuration"))
287 , add_route_dialog (X_("add-routes"), _("Add Tracks/Busses"))
288 , about (X_("about"), _("About"))
289 , location_ui (X_("locations"), _("Locations"))
290 , route_params (X_("inspector"), _("Tracks and Busses"))
291 , audio_midi_setup (X_("audio-midi-setup"), _("Audio/MIDI Setup"))
292 , export_video_dialog (X_("video-export"), _("Video Export Dialog"))
293 , lua_script_window (X_("script-manager"), _("Script Manager"))
294 , session_option_editor (X_("session-options-editor"), _("Properties"), boost::bind (&ARDOUR_UI::create_session_option_editor, this))
295 , add_video_dialog (X_("add-video"), _("Add Video"), boost::bind (&ARDOUR_UI::create_add_video_dialog, this))
296 , bundle_manager (X_("bundle-manager"), _("Bundle Manager"), boost::bind (&ARDOUR_UI::create_bundle_manager, this))
297 , big_clock_window (X_("big-clock"), _("Big Clock"), boost::bind (&ARDOUR_UI::create_big_clock_window, this))
298 , audio_port_matrix (X_("audio-connection-manager"), _("Audio Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::AUDIO))
299 , midi_port_matrix (X_("midi-connection-manager"), _("MIDI Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::MIDI))
300 , key_editor (X_("key-editor"), _("Bindings Editor"), boost::bind (&ARDOUR_UI::create_key_editor, this))
301 , video_server_process (0)
303 , have_configure_timeout (false)
304 , last_configure_time (0)
306 , have_disk_speed_dialog_displayed (false)
307 , _status_bar_visibility (X_("status-bar"))
308 , _feedback_exists (false)
309 , _log_not_acknowledged (LogLevelNone)
310 , duplicate_routes_dialog (0)
311 , editor_visibility_button (S_("Window|Editor"))
312 , mixer_visibility_button (S_("Window|Mixer"))
313 , prefs_visibility_button (S_("Window|Preferences"))
315 Gtkmm2ext::init (localedir);
317 UIConfiguration::instance().post_gui_init ();
319 if (ARDOUR::handle_old_configuration_files (boost::bind (ask_about_configuration_copy, _1, _2, _3))) {
320 MessageDialog msg (string_compose (_("Your configuration files were copied. You can now restart %1."), PROGRAM_NAME), true);
322 /* configuration was modified, exit immediately */
326 if (theArdourUI == 0) {
330 /* track main window visibility */
332 main_window_visibility = new VisibilityTracker (_main_window);
334 /* stop libxml from spewing to stdout/stderr */
336 xmlSetGenericErrorFunc (this, libxml_generic_error_func);
337 xmlSetStructuredErrorFunc (this, libxml_structured_error_func);
339 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::parameter_changed));
340 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
341 UIConfiguration::instance().map_parameters (pc);
343 roll_button.set_controllable (roll_controllable);
344 stop_button.set_controllable (stop_controllable);
345 goto_start_button.set_controllable (goto_start_controllable);
346 goto_end_button.set_controllable (goto_end_controllable);
347 auto_loop_button.set_controllable (auto_loop_controllable);
348 play_selection_button.set_controllable (play_selection_controllable);
349 rec_button.set_controllable (rec_controllable);
351 roll_button.set_name ("transport button");
352 stop_button.set_name ("transport button");
353 goto_start_button.set_name ("transport button");
354 goto_end_button.set_name ("transport button");
355 auto_loop_button.set_name ("transport button");
356 play_selection_button.set_name ("transport button");
357 rec_button.set_name ("transport recenable button");
358 midi_panic_button.set_name ("transport button");
360 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
361 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
363 ARDOUR::Session::VersionMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_format_mismatch, this, _1, _2), gui_context());
365 /* handle dialog requests */
367 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
369 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
371 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
373 /* handle Audio/MIDI setup when session requires it */
375 ARDOUR::Session::AudioEngineSetupRequired.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::do_audio_midi_setup, this, _1));
377 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
379 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
381 /* handle sr mismatch with a dialog - cross-thread from engine */
382 ARDOUR::Session::NotifyAboutSampleRateMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::sr_mismatch_message, this, _1, _2), gui_context ());
384 /* handle requests to quit (coming from JACK session) */
386 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::finish, this), gui_context ());
388 /* tell the user about feedback */
390 ARDOUR::Session::FeedbackDetected.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::feedback_detected, this), gui_context ());
391 ARDOUR::Session::SuccessfulGraphSort.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::successful_graph_sort, this), gui_context ());
393 /* handle requests to deal with missing files */
395 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
397 /* and ambiguous files */
399 ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2));
401 /* also plugin scan messages */
402 ARDOUR::PluginScanMessage.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_dialog, this, _1, _2, _3), gui_context());
403 ARDOUR::PluginScanTimeout.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_timeout, this, _1), gui_context());
405 ARDOUR::GUIIdle.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::gui_idle_handler, this), gui_context());
407 Config->ParameterChanged.connect ( forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::set_flat_buttons, this), gui_context() );
410 /* lets get this party started */
412 setup_gtk_ardour_enums ();
415 SessionEvent::create_per_thread_pool ("GUI", 4096);
417 /* we like keyboards */
419 keyboard = new ArdourKeyboard(*this);
421 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
423 keyboard->set_state (*node, Stateful::loading_state_version);
426 UIConfiguration::instance().reset_dpi ();
428 TimeAxisViewItem::set_constant_heights ();
430 /* Set this up so that our window proxies can register actions */
432 ActionManager::init ();
434 /* The following must happen after ARDOUR::init() so that Config is set up */
436 const XMLNode* ui_xml = Config->extra_xml (X_("UI"));
439 key_editor.set_state (*ui_xml, 0);
440 session_option_editor.set_state (*ui_xml, 0);
441 speaker_config_window.set_state (*ui_xml, 0);
442 about.set_state (*ui_xml, 0);
443 add_route_dialog.set_state (*ui_xml, 0);
444 add_video_dialog.set_state (*ui_xml, 0);
445 route_params.set_state (*ui_xml, 0);
446 bundle_manager.set_state (*ui_xml, 0);
447 location_ui.set_state (*ui_xml, 0);
448 big_clock_window.set_state (*ui_xml, 0);
449 audio_port_matrix.set_state (*ui_xml, 0);
450 midi_port_matrix.set_state (*ui_xml, 0);
451 export_video_dialog.set_state (*ui_xml, 0);
452 lua_script_window.set_state (*ui_xml, 0);
455 /* Separate windows */
457 WM::Manager::instance().register_window (&key_editor);
458 WM::Manager::instance().register_window (&session_option_editor);
459 WM::Manager::instance().register_window (&speaker_config_window);
460 WM::Manager::instance().register_window (&about);
461 WM::Manager::instance().register_window (&add_route_dialog);
462 WM::Manager::instance().register_window (&add_video_dialog);
463 WM::Manager::instance().register_window (&route_params);
464 WM::Manager::instance().register_window (&audio_midi_setup);
465 WM::Manager::instance().register_window (&export_video_dialog);
466 WM::Manager::instance().register_window (&lua_script_window);
467 WM::Manager::instance().register_window (&bundle_manager);
468 WM::Manager::instance().register_window (&location_ui);
469 WM::Manager::instance().register_window (&big_clock_window);
470 WM::Manager::instance().register_window (&audio_port_matrix);
471 WM::Manager::instance().register_window (&midi_port_matrix);
473 /* Trigger setting up the color scheme and loading the GTK RC file */
475 UIConfiguration::instance().load_rc_file (false);
477 _process_thread = new ProcessThread ();
478 _process_thread->init ();
480 UIConfiguration::instance().DPIReset.connect (sigc::mem_fun (*this, &ARDOUR_UI::resize_text_widgets));
485 GlobalPortMatrixWindow*
486 ARDOUR_UI::create_global_port_matrix (ARDOUR::DataType type)
491 return new GlobalPortMatrixWindow (_session, type);
495 ARDOUR_UI::attach_to_engine ()
497 AudioEngine::instance()->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
498 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
502 ARDOUR_UI::engine_stopped ()
504 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
505 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
506 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
507 update_sample_rate (0);
512 ARDOUR_UI::engine_running ()
514 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
515 if (first_time_engine_run) {
517 first_time_engine_run = false;
521 _session->reset_xrun_count ();
523 update_disk_space ();
525 update_xrun_count ();
526 update_sample_rate (AudioEngine::instance()->sample_rate());
527 update_timecode_format ();
528 update_peak_thread_work ();
529 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, true);
530 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, false);
534 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
536 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
537 /* we can't rely on the original string continuing to exist when we are called
538 again in the GUI thread, so make a copy and note that we need to
541 char *copy = strdup (reason);
542 Gtkmm2ext::UI::instance()->call_slot (MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
546 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
547 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
549 update_sample_rate (0);
553 /* if the reason is a non-empty string, it means that the backend was shutdown
554 rather than just Ardour.
557 if (strlen (reason)) {
558 msgstr = string_compose (_("The audio backend was shutdown because:\n\n%1"), reason);
560 msgstr = string_compose (_("\
561 The audio backend has either been shutdown or it\n\
562 disconnected %1 because %1\n\
563 was not fast enough. Try to restart\n\
564 the audio backend and save the session."), PROGRAM_NAME);
567 MessageDialog msg (_main_window, msgstr);
568 pop_back_splash (msg);
572 free (const_cast<char*> (reason));
577 ARDOUR_UI::post_engine ()
579 /* Things to be done once (and once ONLY) after we have a backend running in the AudioEngine
581 #ifdef AUDIOUNIT_SUPPORT
583 if (AUPluginInfo::au_get_crashlog(au_msg)) {
584 popup_error(_("Audio Unit Plugin Scan Failed. Automatic AU scanning has been disabled. Please see the log window for further details."));
585 error << _("Audio Unit Plugin Scan Failed:") << endmsg;
586 info << au_msg << endmsg;
590 ARDOUR::init_post_engine ();
592 /* connect to important signals */
594 AudioEngine::instance()->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
595 AudioEngine::instance()->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
596 AudioEngine::instance()->BufferSizeChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
597 AudioEngine::instance()->Halted.connect_same_thread (halt_connection, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
598 AudioEngine::instance()->BecameSilent.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::audioengine_became_silent, this), gui_context());
600 if (setup_windows ()) {
601 throw failed_constructor ();
604 /* Do this after setup_windows (), as that's when the _status_bar_visibility is created */
605 XMLNode* n = Config->extra_xml (X_("UI"));
607 _status_bar_visibility.set_state (*n);
610 check_memory_locking();
612 /* this is the first point at which all the possible actions are
613 * available, because some of the available actions are dependent on
614 * aspects of the engine/backend.
617 if (ARDOUR_COMMAND_LINE::show_key_actions) {
620 vector<string> paths;
621 vector<string> labels;
622 vector<string> tooltips;
624 vector<Glib::RefPtr<Gtk::Action> > actions;
626 Gtkmm2ext::ActionMap::get_all_actions (paths, labels, tooltips, keys, actions);
628 vector<string>::iterator k;
629 vector<string>::iterator p;
631 for (p = paths.begin(), k = keys.begin(); p != paths.end(); ++k, ++p) {
636 cout << *p << " => " << *k << endl;
640 halt_connection.disconnect ();
641 AudioEngine::instance()->stop ();
645 /* this being a GUI and all, we want peakfiles */
647 AudioFileSource::set_build_peakfiles (true);
648 AudioFileSource::set_build_missing_peakfiles (true);
650 /* set default clock modes */
652 primary_clock->set_mode (AudioClock::Timecode);
653 secondary_clock->set_mode (AudioClock::BBT);
655 /* start the time-of-day-clock */
658 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
659 update_wall_clock ();
660 Glib::signal_timeout().connect_seconds (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 1);
665 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
666 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
667 Config->map_parameters (pc);
669 UIConfiguration::instance().map_parameters (pc);
673 ARDOUR_UI::~ARDOUR_UI ()
675 UIConfiguration::instance().save_state();
679 if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
680 // don't bother at 'real' exit. the OS cleans up for us.
681 delete big_clock; big_clock = 0;
682 delete primary_clock; primary_clock = 0;
683 delete secondary_clock; secondary_clock = 0;
684 delete _process_thread; _process_thread = 0;
685 delete meterbridge; meterbridge = 0;
686 delete luawindow; luawindow = 0;
687 delete editor; editor = 0;
688 delete mixer; mixer = 0;
690 delete gui_object_state; gui_object_state = 0;
691 delete main_window_visibility;
692 FastMeter::flush_pattern_cache ();
693 PixFader::flush_pattern_cache ();
697 /* Small trick to flush main-thread event pool.
698 * Other thread-pools are destroyed at pthread_exit(),
699 * but tmain thread termination is too late to trigger Pool::~Pool()
701 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.
702 delete ev->event_pool();
707 ARDOUR_UI::pop_back_splash (Gtk::Window& win)
709 if (Splash::instance()) {
710 Splash::instance()->pop_back_for (win);
715 ARDOUR_UI::configure_timeout ()
717 if (last_configure_time == 0) {
718 /* no configure events yet */
722 /* force a gap of 0.5 seconds since the last configure event
725 if (get_microseconds() - last_configure_time < 500000) {
728 have_configure_timeout = false;
729 save_ardour_state ();
735 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
737 if (have_configure_timeout) {
738 last_configure_time = get_microseconds();
740 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
741 have_configure_timeout = true;
748 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
750 XMLProperty const * prop;
752 if ((prop = node.property ("roll")) != 0) {
753 roll_controllable->set_id (prop->value());
755 if ((prop = node.property ("stop")) != 0) {
756 stop_controllable->set_id (prop->value());
758 if ((prop = node.property ("goto-start")) != 0) {
759 goto_start_controllable->set_id (prop->value());
761 if ((prop = node.property ("goto-end")) != 0) {
762 goto_end_controllable->set_id (prop->value());
764 if ((prop = node.property ("auto-loop")) != 0) {
765 auto_loop_controllable->set_id (prop->value());
767 if ((prop = node.property ("play-selection")) != 0) {
768 play_selection_controllable->set_id (prop->value());
770 if ((prop = node.property ("rec")) != 0) {
771 rec_controllable->set_id (prop->value());
773 if ((prop = node.property ("shuttle")) != 0) {
774 shuttle_box->controllable()->set_id (prop->value());
779 ARDOUR_UI::get_transport_controllable_state ()
781 XMLNode* node = new XMLNode(X_("TransportControllables"));
784 roll_controllable->id().print (buf, sizeof (buf));
785 node->add_property (X_("roll"), buf);
786 stop_controllable->id().print (buf, sizeof (buf));
787 node->add_property (X_("stop"), buf);
788 goto_start_controllable->id().print (buf, sizeof (buf));
789 node->add_property (X_("goto_start"), buf);
790 goto_end_controllable->id().print (buf, sizeof (buf));
791 node->add_property (X_("goto_end"), buf);
792 auto_loop_controllable->id().print (buf, sizeof (buf));
793 node->add_property (X_("auto_loop"), buf);
794 play_selection_controllable->id().print (buf, sizeof (buf));
795 node->add_property (X_("play_selection"), buf);
796 rec_controllable->id().print (buf, sizeof (buf));
797 node->add_property (X_("rec"), buf);
798 shuttle_box->controllable()->id().print (buf, sizeof (buf));
799 node->add_property (X_("shuttle"), buf);
805 ARDOUR_UI::save_session_at_its_request (std::string snapshot_name)
808 _session->save_state (snapshot_name);
813 ARDOUR_UI::autosave_session ()
815 if (g_main_depth() > 1) {
816 /* inside a recursive main loop,
817 give up because we may not be able to
823 if (!Config->get_periodic_safety_backups()) {
828 _session->maybe_write_autosave();
835 ARDOUR_UI::session_dirty_changed ()
842 ARDOUR_UI::update_autosave ()
844 if (_session && _session->dirty()) {
845 if (_autosave_connection.connected()) {
846 _autosave_connection.disconnect();
849 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
850 Config->get_periodic_safety_backup_interval() * 1000);
853 if (_autosave_connection.connected()) {
854 _autosave_connection.disconnect();
860 ARDOUR_UI::check_announcements ()
863 string _annc_filename;
866 _annc_filename = PROGRAM_NAME "_announcements_osx_";
867 #elif defined PLATFORM_WINDOWS
868 _annc_filename = PROGRAM_NAME "_announcements_windows_";
870 _annc_filename = PROGRAM_NAME "_announcements_linux_";
872 _annc_filename.append (VERSIONSTRING);
874 _announce_string = "";
876 std::string path = Glib::build_filename (user_config_directory(), _annc_filename);
877 FILE* fin = g_fopen (path.c_str(), "rb");
879 while (!feof (fin)) {
882 if ((len = fread (tmp, sizeof(char), 1024, fin)) == 0 || ferror (fin)) {
885 _announce_string.append (tmp, len);
890 pingback (VERSIONSTRING, path);
895 _hide_splash (gpointer arg)
897 ((ARDOUR_UI*)arg)->hide_splash();
902 ARDOUR_UI::starting ()
904 Application* app = Application::instance ();
906 bool brand_new_user = ArdourStartup::required ();
908 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
909 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::load_from_application_api));
911 if (ARDOUR_COMMAND_LINE::check_announcements) {
912 check_announcements ();
917 /* we need to create this early because it may need to set the
918 * audio backend end up.
922 audio_midi_setup.get (true);
924 std::cerr << "audio-midi engine setup failed."<< std::endl;
928 if ((nsm_url = g_getenv ("NSM_URL")) != 0) {
929 nsm = new NSM_Client;
930 if (!nsm->init (nsm_url)) {
931 /* the ardour executable may have different names:
933 * waf's obj.target for distro versions: eg ardour4, ardourvst4
934 * Ardour4, Mixbus3 for bundled versions + full path on OSX & windows
935 * argv[0] does not apply since we need the wrapper-script (not the binary itself)
937 * The wrapper startup script should set the environment variable 'ARDOUR_SELF'
939 const char *process_name = g_getenv ("ARDOUR_SELF");
940 nsm->announce (PROGRAM_NAME, ":dirty:", process_name ? process_name : "ardour4");
943 // wait for announce reply from nsm server
944 for ( i = 0; i < 5000; ++i) {
948 if (nsm->is_active()) {
953 error << _("NSM server did not announce itself") << endmsg;
956 // wait for open command from nsm server
957 for ( i = 0; i < 5000; ++i) {
960 if (nsm->client_id ()) {
966 error << _("NSM: no client ID provided") << endmsg;
970 if (_session && nsm) {
971 _session->set_nsm_state( nsm->is_active() );
973 error << _("NSM: no session created") << endmsg;
977 // nsm requires these actions disabled
978 vector<string> action_names;
979 action_names.push_back("SaveAs");
980 action_names.push_back("Rename");
981 action_names.push_back("New");
982 action_names.push_back("Open");
983 action_names.push_back("Recent");
984 action_names.push_back("Close");
986 for (vector<string>::const_iterator n = action_names.begin(); n != action_names.end(); ++n) {
987 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), (*n).c_str());
989 act->set_sensitive (false);
996 error << _("NSM: initialization failed") << endmsg;
1002 if (brand_new_user) {
1003 _initial_verbose_plugin_scan = true;
1008 _initial_verbose_plugin_scan = false;
1009 switch (s.response ()) {
1010 case Gtk::RESPONSE_OK:
1017 #ifdef NO_PLUGIN_STATE
1019 ARDOUR::RecentSessions rs;
1020 ARDOUR::read_recent_sessions (rs);
1022 string path = Glib::build_filename (user_config_directory(), ".iknowaboutfreeversion");
1024 if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS) && !rs.empty()) {
1026 /* already used Ardour, have sessions ... warn about plugin state */
1028 ArdourDialog d (_("Free/Demo Version Warning"), true);
1030 Button b (string_compose (_("Subscribe and support development of %1"), PROGRAM_NAME));
1031 CheckButton c (_("Don't warn me about this again"));
1033 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"),
1034 string_compose (_("This is a free/demo version of %1"), PROGRAM_NAME),
1035 _("It will not restore OR save any plugin settings"),
1036 _("If you load an existing session with plugin settings\n"
1037 "they will not be used and will be lost."),
1038 _("To get full access to updates without this limitation\n"
1039 "consider becoming a subscriber for a low cost every month.")));
1040 l.set_justify (JUSTIFY_CENTER);
1042 b.signal_clicked().connect (mem_fun(*this, &ARDOUR_UI::launch_subscribe));
1044 d.get_vbox()->pack_start (l, true, true);
1045 d.get_vbox()->pack_start (b, false, false, 12);
1046 d.get_vbox()->pack_start (c, false, false, 12);
1048 d.add_button (_("Quit now"), RESPONSE_CANCEL);
1049 d.add_button (string_compose (_("Continue using %1"), PROGRAM_NAME), RESPONSE_OK);
1053 c.signal_toggled().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (toggle_file_existence), path)));
1055 if (d.run () != RESPONSE_OK) {
1061 /* go get a session */
1063 const bool new_session_required = (ARDOUR_COMMAND_LINE::new_session || brand_new_user);
1065 if (get_session_parameters (false, new_session_required, ARDOUR_COMMAND_LINE::load_template)) {
1066 std::cerr << "Cannot get session parameters."<< std::endl;
1073 WM::Manager::instance().show_visible ();
1075 /* We have to do this here since goto_editor_window() ends up calling show_all() on the
1076 * editor window, and we may want stuff to be hidden.
1078 _status_bar_visibility.update ();
1080 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
1082 if (splash && splash->is_visible()) {
1083 // in 1 second, hide the splash screen
1084 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
1087 /* all other dialogs are created conditionally */
1093 ARDOUR_UI::check_memory_locking ()
1095 #if defined(__APPLE__) || defined(PLATFORM_WINDOWS)
1096 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
1100 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
1102 if (AudioEngine::instance()->is_realtime() && memory_warning_node == 0) {
1104 struct rlimit limits;
1106 long pages, page_size;
1108 size_t pages_len=sizeof(pages);
1109 if ((page_size = getpagesize()) < 0 ||
1110 sysctlbyname("hw.availpages", &pages, &pages_len, NULL, 0))
1112 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0)
1117 ram = (int64_t) pages * (int64_t) page_size;
1120 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
1124 if (limits.rlim_cur != RLIM_INFINITY) {
1126 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
1130 _("WARNING: Your system has a limit for maximum amount of locked memory. "
1131 "This might cause %1 to run out of memory before your system "
1132 "runs out of memory. \n\n"
1133 "You can view the memory limit with 'ulimit -l', "
1134 "and it is normally controlled by %2"),
1137 X_("/etc/login.conf")
1139 X_(" /etc/security/limits.conf")
1143 msg.set_default_response (RESPONSE_OK);
1145 VBox* vbox = msg.get_vbox();
1147 CheckButton cb (_("Do not show this window again"));
1148 hbox.pack_start (cb, true, false);
1149 vbox->pack_start (hbox);
1154 pop_back_splash (msg);
1158 if (cb.get_active()) {
1159 XMLNode node (X_("no-memory-warning"));
1160 Config->add_instant_xml (node);
1165 #endif // !__APPLE__
1170 ARDOUR_UI::queue_finish ()
1172 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
1176 ARDOUR_UI::idle_finish ()
1179 return false; /* do not call again */
1186 ARDOUR_UI::instance()->video_timeline->sync_session_state();
1188 if (_session->dirty()) {
1189 vector<string> actions;
1190 actions.push_back (_("Don't quit"));
1191 actions.push_back (_("Just quit"));
1192 actions.push_back (_("Save and quit"));
1193 switch (ask_about_saving_session(actions)) {
1198 /* use the default name */
1199 if (save_state_canfail ("")) {
1200 /* failed - don't quit */
1201 MessageDialog msg (_main_window,
1202 string_compose (_("\
1203 %1 was unable to save your session.\n\n\
1204 If you still wish to quit, please use the\n\n\
1205 \"Just quit\" option."), PROGRAM_NAME));
1206 pop_back_splash(msg);
1216 second_connection.disconnect ();
1217 point_one_second_connection.disconnect ();
1218 point_zero_something_second_connection.disconnect();
1219 fps_connection.disconnect();
1222 delete ARDOUR_UI::instance()->video_timeline;
1223 ARDOUR_UI::instance()->video_timeline = NULL;
1224 stop_video_server();
1226 /* Save state before deleting the session, as that causes some
1227 windows to be destroyed before their visible state can be
1230 save_ardour_state ();
1232 close_all_dialogs ();
1235 _session->set_clean ();
1236 _session->remove_pending_capture_state ();
1241 halt_connection.disconnect ();
1242 AudioEngine::instance()->stop ();
1243 #ifdef WINDOWS_VST_SUPPORT
1244 fst_stop_threading();
1250 ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
1252 ArdourDialog window (_("Unsaved Session"));
1253 Gtk::HBox dhbox; // the hbox for the image and text
1254 Gtk::Label prompt_label;
1255 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
1259 assert (actions.size() >= 3);
1261 window.add_button (actions[0], RESPONSE_REJECT);
1262 window.add_button (actions[1], RESPONSE_APPLY);
1263 window.add_button (actions[2], RESPONSE_ACCEPT);
1265 window.set_default_response (RESPONSE_ACCEPT);
1267 Gtk::Button noquit_button (msg);
1268 noquit_button.set_name ("EditorGTKButton");
1272 if (_session->snap_name() == _session->name()) {
1273 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?"),
1274 _session->snap_name());
1276 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?"),
1277 _session->snap_name());
1280 prompt_label.set_text (prompt);
1281 prompt_label.set_name (X_("PrompterLabel"));
1282 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
1284 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
1285 dhbox.set_homogeneous (false);
1286 dhbox.pack_start (*dimage, false, false, 5);
1287 dhbox.pack_start (prompt_label, true, false, 5);
1288 window.get_vbox()->pack_start (dhbox);
1290 window.set_name (_("Prompter"));
1291 window.set_modal (true);
1292 window.set_resizable (false);
1295 prompt_label.show();
1300 ResponseType r = (ResponseType) window.run();
1305 case RESPONSE_ACCEPT: // save and get out of here
1307 case RESPONSE_APPLY: // get out of here
1318 ARDOUR_UI::every_second ()
1321 update_xrun_count ();
1322 update_buffer_load ();
1323 update_disk_space ();
1324 update_timecode_format ();
1325 update_peak_thread_work ();
1327 if (nsm && nsm->is_active ()) {
1330 if (!_was_dirty && _session->dirty ()) {
1334 else if (_was_dirty && !_session->dirty ()){
1342 ARDOUR_UI::every_point_one_seconds ()
1344 // TODO get rid of this..
1345 // ShuttleControl is updated directly via TransportStateChange signal
1349 ARDOUR_UI::every_point_zero_something_seconds ()
1351 // august 2007: actual update frequency: 25Hz (40ms), not 100Hz
1353 if (editor_meter && UIConfiguration::instance().get_show_editor_meter()) {
1354 float mpeak = editor_meter->update_meters();
1355 if (mpeak > editor_meter_max_peak) {
1356 if (mpeak >= UIConfiguration::instance().get_meter_peak()) {
1357 editor_meter_peak_display.set_active_state ( Gtkmm2ext::ExplicitActive );
1364 ARDOUR_UI::set_fps_timeout_connection ()
1366 unsigned int interval = 40;
1367 if (!_session) return;
1368 if (_session->timecode_frames_per_second() != 0) {
1369 /* ideally we'll use a select() to sleep and not accumulate
1370 * idle time to provide a regular periodic signal.
1371 * See linux_vst_gui_support.cc 'elapsed_time_ms'.
1372 * However, that'll require a dedicated thread and cross-thread
1373 * signals to the GUI Thread..
1375 interval = floor(500. /* update twice per FPS, since Glib::signal_timeout is very irregular */
1376 * _session->frame_rate() / _session->nominal_frame_rate()
1377 / _session->timecode_frames_per_second()
1379 #ifdef PLATFORM_WINDOWS
1380 // the smallest windows scheduler time-slice is ~15ms.
1381 // periodic GUI timeouts shorter than that will cause
1382 // WaitForSingleObject to spinlock (100% of one CPU Core)
1383 // and gtk never enters idle mode.
1384 // also changing timeBeginPeriod(1) does not affect that in
1385 // any beneficial way, so we just limit the max rate for now.
1386 interval = std::max(30u, interval); // at most ~33Hz.
1388 interval = std::max(8u, interval); // at most 120Hz.
1391 fps_connection.disconnect();
1392 Timers::set_fps_interval (interval);
1396 ARDOUR_UI::update_sample_rate (framecnt_t)
1400 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
1402 if (!AudioEngine::instance()->connected()) {
1404 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1408 framecnt_t rate = AudioEngine::instance()->sample_rate();
1411 /* no sample rate available */
1412 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1415 if (fmod (rate, 1000.0) != 0.0) {
1416 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
1417 (float) rate / 1000.0f,
1418 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1420 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
1422 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1426 sample_rate_label.set_markup (buf);
1430 ARDOUR_UI::update_format ()
1433 format_label.set_text ("");
1438 s << _("File:") << X_(" <span foreground=\"green\">");
1440 switch (_session->config.get_native_file_header_format ()) {
1472 switch (_session->config.get_native_file_data_format ()) {
1486 format_label.set_markup (s.str ());
1490 ARDOUR_UI::update_xrun_count ()
1494 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1495 should also be changed.
1499 const unsigned int x = _session->get_xrun_count ();
1501 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">>10K</span>"), X_("red"));
1503 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">%u</span>"), x > 0 ? X_("red") : X_("green"), x);
1506 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">?</span>"), X_("yellow"));
1508 xrun_label.set_markup (buf);
1509 set_tip (xrun_label, _("Audio dropouts. Shift+click to reset"));
1513 ARDOUR_UI::update_cpu_load ()
1517 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1518 should also be changed.
1521 double const c = AudioEngine::instance()->get_dsp_load ();
1522 snprintf (buf, sizeof (buf), _("DSP: <span foreground=\"%s\">%5.1f%%</span>"), c >= 90 ? X_("red") : X_("green"), c);
1523 cpu_load_label.set_markup (buf);
1527 ARDOUR_UI::update_peak_thread_work ()
1530 const int c = SourceFactory::peak_work_queue_length ();
1532 snprintf (buf, sizeof (buf), _("PkBld: <span foreground=\"%s\">%d</span>"), c >= 2 ? X_("red") : X_("green"), c);
1533 peak_thread_work_label.set_markup (buf);
1535 peak_thread_work_label.set_markup (X_(""));
1540 ARDOUR_UI::update_buffer_load ()
1544 uint32_t const playback = _session ? _session->playback_load () : 100;
1545 uint32_t const capture = _session ? _session->capture_load () : 100;
1547 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1548 should also be changed.
1554 _("Buffers: <span foreground=\"green\">p:</span><span foreground=\"%s\">%" PRIu32 "%%</span> "
1555 "<span foreground=\"green\">c:</span><span foreground=\"%s\">%" PRIu32 "%%</span>"),
1556 playback <= 5 ? X_("red") : X_("green"),
1558 capture <= 5 ? X_("red") : X_("green"),
1562 buffer_load_label.set_markup (buf);
1564 buffer_load_label.set_text ("");
1569 ARDOUR_UI::count_recenabled_streams (Route& route)
1571 Track* track = dynamic_cast<Track*>(&route);
1572 if (track && track->record_enabled()) {
1573 rec_enabled_streams += track->n_inputs().n_total();
1578 ARDOUR_UI::update_disk_space()
1580 if (_session == 0) {
1584 boost::optional<framecnt_t> opt_frames = _session->available_capture_duration();
1586 framecnt_t fr = _session->frame_rate();
1589 /* skip update - no SR available */
1594 /* Available space is unknown */
1595 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">Unknown</span>"));
1596 } else if (opt_frames.get_value_or (0) == max_framecnt) {
1597 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">24hrs+</span>"));
1599 rec_enabled_streams = 0;
1600 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams, false);
1602 framecnt_t frames = opt_frames.get_value_or (0);
1604 if (rec_enabled_streams) {
1605 frames /= rec_enabled_streams;
1612 hrs = frames / (fr * 3600);
1615 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">>24 hrs</span>"));
1617 frames -= hrs * fr * 3600;
1618 mins = frames / (fr * 60);
1619 frames -= mins * fr * 60;
1622 bool const low = (hrs == 0 && mins <= 30);
1626 _("Disk: <span foreground=\"%s\">%02dh:%02dm:%02ds</span>"),
1627 low ? X_("red") : X_("green"),
1633 disk_space_label.set_markup (buf);
1637 ARDOUR_UI::update_timecode_format ()
1643 TimecodeSlave* tcslave;
1644 SyncSource sync_src = Config->get_sync_source();
1646 if ((sync_src == LTC || sync_src == MTC) && (tcslave = dynamic_cast<TimecodeSlave*>(_session->slave())) != 0) {
1647 matching = (tcslave->apparent_timecode_format() == _session->config.get_timecode_format());
1652 snprintf (buf, sizeof (buf), S_("Timecode|TC: <span foreground=\"%s\">%s</span>"),
1653 matching ? X_("green") : X_("red"),
1654 Timecode::timecode_format_name (_session->config.get_timecode_format()).c_str());
1656 snprintf (buf, sizeof (buf), "TC: n/a");
1659 timecode_format_label.set_markup (buf);
1663 ARDOUR_UI::update_wall_clock ()
1667 static int last_min = -1;
1670 tm_now = localtime (&now);
1671 if (last_min != tm_now->tm_min) {
1673 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1674 wall_clock_label.set_text (buf);
1675 last_min = tm_now->tm_min;
1682 ARDOUR_UI::open_recent_session ()
1684 bool can_return = (_session != 0);
1686 SessionDialog recent_session_dialog;
1690 ResponseType r = (ResponseType) recent_session_dialog.run ();
1693 case RESPONSE_ACCEPT:
1697 recent_session_dialog.hide();
1704 recent_session_dialog.hide();
1708 std::string path = recent_session_dialog.session_folder();
1709 std::string state = recent_session_dialog.session_name (should_be_new);
1711 if (should_be_new == true) {
1715 _session_is_new = false;
1717 if (load_session (path, state) == 0) {
1723 if (splash && splash->is_visible()) {
1724 // in 1 second, hide the splash screen
1725 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
1730 ARDOUR_UI::check_audioengine (Gtk::Window& parent)
1732 if (!AudioEngine::instance()->connected()) {
1733 MessageDialog msg (parent, string_compose (
1734 _("%1 is not connected to any audio backend.\n"
1735 "You cannot open or close sessions in this condition"),
1737 pop_back_splash (msg);
1745 ARDOUR_UI::open_session ()
1747 if (!check_audioengine (_main_window)) {
1751 /* ardour sessions are folders */
1752 Gtk::FileChooserDialog open_session_selector(_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1753 open_session_selector.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1754 open_session_selector.add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1755 open_session_selector.set_default_response(Gtk::RESPONSE_ACCEPT);
1758 string session_parent_dir = Glib::path_get_dirname(_session->path());
1759 open_session_selector.set_current_folder(session_parent_dir);
1761 open_session_selector.set_current_folder(Config->get_default_session_parent_dir());
1764 Gtkmm2ext::add_volume_shortcuts (open_session_selector);
1766 /* add_shortcut_folder throws an exception if the folder being added already has a shortcut */
1767 string default_session_folder = Config->get_default_session_parent_dir();
1768 open_session_selector.add_shortcut_folder (default_session_folder);
1770 catch (Glib::Error & e) {
1771 std::cerr << "open_session_selector.add_shortcut_folder() threw Glib::Error " << e.what() << std::endl;
1774 FileFilter session_filter;
1775 session_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::statefile_suffix));
1776 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1777 open_session_selector.add_filter (session_filter);
1778 open_session_selector.set_filter (session_filter);
1780 int response = open_session_selector.run();
1781 open_session_selector.hide ();
1783 if (response == Gtk::RESPONSE_CANCEL) {
1787 string session_path = open_session_selector.get_filename();
1791 if (session_path.length() > 0) {
1792 if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1793 _session_is_new = isnew;
1794 load_session (path, name);
1800 ARDOUR_UI::session_add_mixed_track (
1801 const ChanCount& input,
1802 const ChanCount& output,
1803 RouteGroup* route_group,
1805 const string& name_template,
1807 PluginInfoPtr instrument,
1808 Plugin::PresetRecord* pset)
1810 list<boost::shared_ptr<MidiTrack> > tracks;
1812 if (_session == 0) {
1813 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1818 tracks = _session->new_midi_track (input, output, instrument, ARDOUR::Normal, route_group, how_many, name_template, pset);
1820 if (tracks.size() != how_many) {
1821 error << string_compose(P_("could not create %1 new mixed track", "could not create %1 new mixed tracks", how_many), how_many) << endmsg;
1826 display_insufficient_ports_message ();
1831 for (list<boost::shared_ptr<MidiTrack> >::iterator i = tracks.begin(); i != tracks.end(); ++i) {
1832 (*i)->set_strict_io (true);
1838 ARDOUR_UI::session_add_midi_bus (
1839 RouteGroup* route_group,
1841 const string& name_template,
1843 PluginInfoPtr instrument,
1844 Plugin::PresetRecord* pset)
1848 if (_session == 0) {
1849 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1854 routes = _session->new_midi_route (route_group, how_many, name_template, instrument, pset);
1855 if (routes.size() != how_many) {
1856 error << string_compose(P_("could not create %1 new Midi Bus", "could not create %1 new Midi Busses", how_many), how_many) << endmsg;
1861 display_insufficient_ports_message ();
1866 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
1867 (*i)->set_strict_io (true);
1873 ARDOUR_UI::session_add_midi_route (
1875 RouteGroup* route_group,
1877 const string& name_template,
1879 PluginInfoPtr instrument,
1880 Plugin::PresetRecord* pset)
1882 ChanCount one_midi_channel;
1883 one_midi_channel.set (DataType::MIDI, 1);
1886 session_add_mixed_track (one_midi_channel, one_midi_channel, route_group, how_many, name_template, strict_io, instrument, pset);
1888 session_add_midi_bus (route_group, how_many, name_template, strict_io, instrument, pset);
1893 ARDOUR_UI::session_add_audio_route (
1895 int32_t input_channels,
1896 int32_t output_channels,
1897 ARDOUR::TrackMode mode,
1898 RouteGroup* route_group,
1900 string const & name_template,
1904 list<boost::shared_ptr<AudioTrack> > tracks;
1907 if (_session == 0) {
1908 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1914 tracks = _session->new_audio_track (input_channels, output_channels, mode, route_group, how_many, name_template);
1916 if (tracks.size() != how_many) {
1917 error << string_compose (P_("could not create %1 new audio track", "could not create %1 new audio tracks", how_many), how_many)
1923 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template);
1925 if (routes.size() != how_many) {
1926 error << string_compose (P_("could not create %1 new audio bus", "could not create %1 new audio busses", how_many), how_many)
1933 display_insufficient_ports_message ();
1938 for (list<boost::shared_ptr<AudioTrack> >::iterator i = tracks.begin(); i != tracks.end(); ++i) {
1939 (*i)->set_strict_io (true);
1941 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
1942 (*i)->set_strict_io (true);
1948 ARDOUR_UI::display_insufficient_ports_message ()
1950 MessageDialog msg (_main_window,
1951 string_compose (_("There are insufficient ports available\n\
1952 to create a new track or bus.\n\
1953 You should save %1, exit and\n\
1954 restart with more ports."), PROGRAM_NAME));
1955 pop_back_splash (msg);
1960 ARDOUR_UI::transport_goto_start ()
1963 _session->goto_start();
1965 /* force displayed area in editor to start no matter
1966 what "follow playhead" setting is.
1970 editor->center_screen (_session->current_start_frame ());
1976 ARDOUR_UI::transport_goto_zero ()
1979 _session->request_locate (0);
1981 /* force displayed area in editor to start no matter
1982 what "follow playhead" setting is.
1986 editor->reset_x_origin (0);
1992 ARDOUR_UI::transport_goto_wallclock ()
1994 if (_session && editor) {
2001 localtime_r (&now, &tmnow);
2003 framecnt_t frame_rate = _session->frame_rate();
2005 if (frame_rate == 0) {
2006 /* no frame rate available */
2010 frames = tmnow.tm_hour * (60 * 60 * frame_rate);
2011 frames += tmnow.tm_min * (60 * frame_rate);
2012 frames += tmnow.tm_sec * frame_rate;
2014 _session->request_locate (frames, _session->transport_rolling ());
2016 /* force displayed area in editor to start no matter
2017 what "follow playhead" setting is.
2021 editor->center_screen (frames);
2027 ARDOUR_UI::transport_goto_end ()
2030 framepos_t const frame = _session->current_end_frame();
2031 _session->request_locate (frame);
2033 /* force displayed area in editor to start no matter
2034 what "follow playhead" setting is.
2038 editor->center_screen (frame);
2044 ARDOUR_UI::transport_stop ()
2050 if (_session->is_auditioning()) {
2051 _session->cancel_audition ();
2055 _session->request_stop (false, true);
2058 /** Check if any tracks are record enabled. If none are, record enable all of them.
2059 * @return true if track record-enabled status was changed, false otherwise.
2062 ARDOUR_UI::trx_record_enable_all_tracks ()
2068 boost::shared_ptr<RouteList> rl = _session->get_tracks ();
2069 bool none_record_enabled = true;
2071 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
2072 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*r);
2075 if (t->record_enabled()) {
2076 none_record_enabled = false;
2081 if (none_record_enabled) {
2082 _session->set_record_enabled (rl, true, Session::rt_cleanup);
2085 return none_record_enabled;
2089 ARDOUR_UI::transport_record (bool roll)
2092 switch (_session->record_status()) {
2093 case Session::Disabled:
2094 if (_session->ntracks() == 0) {
2095 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."));
2099 if (Profile->get_trx()) {
2100 roll = trx_record_enable_all_tracks ();
2102 _session->maybe_enable_record ();
2107 case Session::Recording:
2109 _session->request_stop();
2111 _session->disable_record (false, true);
2115 case Session::Enabled:
2116 _session->disable_record (false, true);
2122 ARDOUR_UI::transport_roll ()
2128 if (_session->is_auditioning()) {
2133 if (_session->config.get_external_sync()) {
2134 switch (Config->get_sync_source()) {
2138 /* transport controlled by the master */
2144 bool rolling = _session->transport_rolling();
2146 if (_session->get_play_loop()) {
2148 /* If loop playback is not a mode, then we should cancel
2149 it when this action is requested. If it is a mode
2150 we just leave it in place.
2153 if (!Config->get_loop_is_mode()) {
2154 /* XXX it is not possible to just leave seamless loop and keep
2155 playing at present (nov 4th 2009)
2157 if (!Config->get_seamless_loop()) {
2158 /* stop loop playback and stop rolling */
2159 _session->request_play_loop (false, true);
2160 } else if (rolling) {
2161 /* stop loop playback but keep rolling */
2162 _session->request_play_loop (false, false);
2166 } else if (_session->get_play_range () ) {
2167 /* stop playing a range if we currently are */
2168 _session->request_play_range (0, true);
2172 _session->request_transport_speed (1.0f);
2177 ARDOUR_UI::get_smart_mode() const
2179 return ( editor->get_smart_mode() );
2184 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
2190 if (_session->is_auditioning()) {
2191 _session->cancel_audition ();
2195 if (_session->config.get_external_sync()) {
2196 switch (Config->get_sync_source()) {
2200 /* transport controlled by the master */
2205 bool rolling = _session->transport_rolling();
2206 bool affect_transport = true;
2208 if (rolling && roll_out_of_bounded_mode) {
2209 /* drop out of loop/range playback but leave transport rolling */
2210 if (_session->get_play_loop()) {
2211 if (_session->actively_recording()) {
2213 /* just stop using the loop, then actually stop
2216 _session->request_play_loop (false, affect_transport);
2219 if (Config->get_seamless_loop()) {
2220 /* the disk buffers contain copies of the loop - we can't
2221 just keep playing, so stop the transport. the user
2222 can restart as they wish.
2224 affect_transport = true;
2226 /* disk buffers are normal, so we can keep playing */
2227 affect_transport = false;
2229 _session->request_play_loop (false, affect_transport);
2231 } else if (_session->get_play_range ()) {
2232 affect_transport = false;
2233 _session->request_play_range (0, true);
2237 if (affect_transport) {
2239 _session->request_stop (with_abort, true);
2241 /* the only external sync condition we can be in here
2242 * would be Engine (JACK) sync, in which case we still
2246 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
2247 _session->request_play_range (&editor->get_selection().time, true);
2248 _session->set_requested_return_frame( editor->get_selection().time.front().start ); //force an auto-return here
2250 _session->request_transport_speed (1.0f);
2256 ARDOUR_UI::toggle_session_auto_loop ()
2262 Location * looploc = _session->locations()->auto_loop_location();
2268 if (_session->get_play_loop()) {
2270 /* looping enabled, our job is to disable it */
2272 _session->request_play_loop (false);
2276 /* looping not enabled, our job is to enable it.
2278 loop-is-NOT-mode: this action always starts the transport rolling.
2279 loop-IS-mode: this action simply sets the loop play mechanism, but
2280 does not start transport.
2282 if (Config->get_loop_is_mode()) {
2283 _session->request_play_loop (true, false);
2285 _session->request_play_loop (true, true);
2289 //show the loop markers
2290 looploc->set_hidden (false, this);
2294 ARDOUR_UI::transport_play_selection ()
2300 editor->play_selection ();
2304 ARDOUR_UI::transport_play_preroll ()
2309 editor->play_with_preroll ();
2313 ARDOUR_UI::transport_rewind (int option)
2315 float current_transport_speed;
2318 current_transport_speed = _session->transport_speed();
2320 if (current_transport_speed >= 0.0f) {
2323 _session->request_transport_speed (-1.0f);
2326 _session->request_transport_speed (-4.0f);
2329 _session->request_transport_speed (-0.5f);
2334 _session->request_transport_speed (current_transport_speed * 1.5f);
2340 ARDOUR_UI::transport_forward (int option)
2346 float current_transport_speed = _session->transport_speed();
2348 if (current_transport_speed <= 0.0f) {
2351 _session->request_transport_speed (1.0f);
2354 _session->request_transport_speed (4.0f);
2357 _session->request_transport_speed (0.5f);
2362 _session->request_transport_speed (current_transport_speed * 1.5f);
2367 ARDOUR_UI::toggle_record_enable (uint32_t rid)
2373 boost::shared_ptr<Route> r;
2375 if ((r = _session->route_by_remote_id (rid)) != 0) {
2377 boost::shared_ptr<Track> t;
2379 if ((t = boost::dynamic_pointer_cast<Track>(r)) != 0) {
2380 t->set_record_enabled (!t->record_enabled(), Controllable::UseGroup);
2386 ARDOUR_UI::map_transport_state ()
2389 auto_loop_button.unset_active_state ();
2390 play_selection_button.unset_active_state ();
2391 roll_button.unset_active_state ();
2392 stop_button.set_active_state (Gtkmm2ext::ExplicitActive);
2396 shuttle_box->map_transport_state ();
2398 float sp = _session->transport_speed();
2404 if (_session->get_play_range()) {
2406 play_selection_button.set_active_state (Gtkmm2ext::ExplicitActive);
2407 roll_button.unset_active_state ();
2408 auto_loop_button.unset_active_state ();
2410 } else if (_session->get_play_loop ()) {
2412 auto_loop_button.set_active (true);
2413 play_selection_button.set_active (false);
2414 if (Config->get_loop_is_mode()) {
2415 roll_button.set_active (true);
2417 roll_button.set_active (false);
2422 roll_button.set_active (true);
2423 play_selection_button.set_active (false);
2424 auto_loop_button.set_active (false);
2427 if (UIConfiguration::instance().get_follow_edits() && !_session->config.get_external_sync()) {
2428 /* light up both roll and play-selection if they are joined */
2429 roll_button.set_active (true);
2430 play_selection_button.set_active (true);
2433 stop_button.set_active (false);
2437 stop_button.set_active (true);
2438 roll_button.set_active (false);
2439 play_selection_button.set_active (false);
2440 if (Config->get_loop_is_mode ()) {
2441 auto_loop_button.set_active (_session->get_play_loop());
2443 auto_loop_button.set_active (false);
2445 update_disk_space ();
2450 ARDOUR_UI::blink_handler (bool blink_on)
2452 transport_rec_enable_blink (blink_on);
2453 solo_blink (blink_on);
2454 sync_blink (blink_on);
2455 audition_blink (blink_on);
2456 feedback_blink (blink_on);
2457 error_blink (blink_on);
2461 ARDOUR_UI::update_clocks ()
2463 if (!_session) return;
2465 if (editor && !editor->dragging_playhead()) {
2466 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD)); /* EMIT_SIGNAL */
2471 ARDOUR_UI::start_clocking ()
2473 if (UIConfiguration::instance().get_super_rapid_clock_update()) {
2474 clock_signal_connection = Timers::fps_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2476 clock_signal_connection = Timers::rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2481 ARDOUR_UI::stop_clocking ()
2483 clock_signal_connection.disconnect ();
2487 ARDOUR_UI::save_as_progress_update (float fraction, int64_t cnt, int64_t total, Gtk::Label* label, Gtk::ProgressBar* bar)
2491 snprintf (buf, sizeof (buf), _("Copied %" PRId64 " of %" PRId64), cnt, total);
2493 label->set_text (buf);
2494 bar->set_fraction (fraction);
2496 /* process events, redraws, etc. */
2498 while (gtk_events_pending()) {
2499 gtk_main_iteration ();
2502 return true; /* continue with save-as */
2506 ARDOUR_UI::save_session_as ()
2512 if (!save_as_dialog) {
2513 save_as_dialog = new SaveAsDialog;
2516 save_as_dialog->set_name (_session->name());
2518 int response = save_as_dialog->run ();
2520 save_as_dialog->hide ();
2523 case Gtk::RESPONSE_OK:
2532 sa.new_parent_folder = save_as_dialog->new_parent_folder ();
2533 sa.new_name = save_as_dialog->new_name ();
2534 sa.switch_to = save_as_dialog->switch_to();
2535 sa.copy_media = save_as_dialog->copy_media();
2536 sa.copy_external = save_as_dialog->copy_external();
2537 sa.include_media = save_as_dialog->include_media ();
2539 /* Only bother with a progress dialog if we're going to copy
2540 media into the save-as target. Without that choice, this
2541 will be very fast because we're only talking about a few kB's to
2542 perhaps a couple of MB's of data.
2545 ArdourDialog progress_dialog (_("Save As"), true);
2547 if (sa.include_media && sa.copy_media) {
2550 Gtk::ProgressBar progress_bar;
2552 progress_dialog.get_vbox()->pack_start (label);
2553 progress_dialog.get_vbox()->pack_start (progress_bar);
2555 progress_bar.show ();
2557 /* this signal will be emitted from within this, the calling thread,
2558 * after every file is copied. It provides information on percentage
2559 * complete (in terms of total data to copy), the number of files
2560 * copied so far, and the total number to copy.
2565 sa.Progress.connect_same_thread (c, boost::bind (&ARDOUR_UI::save_as_progress_update, this, _1, _2, _3, &label, &progress_bar));
2567 progress_dialog.show_all ();
2568 progress_dialog.present ();
2571 if (_session->save_as (sa)) {
2573 MessageDialog msg (string_compose (_("Save As failed: %1"), sa.failure_message));
2577 if (!sa.include_media) {
2578 unload_session (false);
2579 load_session (sa.final_session_folder_name, sa.new_name);
2584 ARDOUR_UI::quick_snapshot_session (bool switch_to_it)
2588 struct tm local_time;
2591 localtime_r (&n, &local_time);
2592 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2594 save_state (timebuf, switch_to_it);
2599 ARDOUR_UI::process_snapshot_session_prompter (ArdourPrompter& prompter, bool switch_to_it)
2603 prompter.get_result (snapname);
2605 bool do_save = (snapname.length() != 0);
2608 char illegal = Session::session_name_is_legal(snapname);
2610 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2611 "snapshot names may not contain a '%1' character"), illegal));
2617 vector<std::string> p;
2618 get_state_files_in_directory (_session->session_directory().root_path(), p);
2619 vector<string> n = get_file_names_no_extension (p);
2621 if (find (n.begin(), n.end(), snapname) != n.end()) {
2623 do_save = overwrite_file_dialog (prompter,
2624 _("Confirm Snapshot Overwrite"),
2625 _("A snapshot already exists with that name. Do you want to overwrite it?"));
2629 save_state (snapname, switch_to_it);
2639 /** Ask the user for the name of a new snapshot and then take it.
2643 ARDOUR_UI::snapshot_session (bool switch_to_it)
2645 ArdourPrompter prompter (true);
2647 prompter.set_name ("Prompter");
2648 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2650 prompter.set_title (_("Snapshot and switch"));
2651 prompter.set_prompt (_("New session name"));
2653 prompter.set_title (_("Take Snapshot"));
2654 prompter.set_prompt (_("Name of new snapshot"));
2658 prompter.set_initial_text (_session->snap_name());
2662 struct tm local_time;
2665 localtime_r (&n, &local_time);
2666 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2667 prompter.set_initial_text (timebuf);
2670 bool finished = false;
2672 switch (prompter.run()) {
2673 case RESPONSE_ACCEPT:
2675 finished = process_snapshot_session_prompter (prompter, switch_to_it);
2686 /** Ask the user for a new session name and then rename the session to it.
2690 ARDOUR_UI::rename_session ()
2696 ArdourPrompter prompter (true);
2699 prompter.set_name ("Prompter");
2700 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2701 prompter.set_title (_("Rename Session"));
2702 prompter.set_prompt (_("New session name"));
2705 switch (prompter.run()) {
2706 case RESPONSE_ACCEPT:
2708 prompter.get_result (name);
2710 bool do_rename = (name.length() != 0);
2713 char illegal = Session::session_name_is_legal (name);
2716 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2717 "session names may not contain a '%1' character"), illegal));
2722 switch (_session->rename (name)) {
2724 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
2725 msg.set_position (WIN_POS_MOUSE);
2733 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
2734 msg.set_position (WIN_POS_MOUSE);
2750 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2752 if (!_session || _session->deletion_in_progress()) {
2756 XMLNode* node = new XMLNode (X_("UI"));
2758 WM::Manager::instance().add_state (*node);
2760 node->add_child_nocopy (gui_object_state->get_state());
2762 _session->add_extra_xml (*node);
2764 if (export_video_dialog) {
2765 _session->add_extra_xml (export_video_dialog->get_state());
2768 save_state_canfail (name, switch_to_it);
2772 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2777 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2782 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2787 ARDOUR_UI::primary_clock_value_changed ()
2790 _session->request_locate (primary_clock->current_time ());
2795 ARDOUR_UI::big_clock_value_changed ()
2798 _session->request_locate (big_clock->current_time ());
2803 ARDOUR_UI::secondary_clock_value_changed ()
2806 _session->request_locate (secondary_clock->current_time ());
2811 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2813 if (_session == 0) {
2817 if (_session->step_editing()) {
2821 Session::RecordState const r = _session->record_status ();
2822 bool const h = _session->have_rec_enabled_track ();
2824 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2826 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2828 rec_button.set_active_state (Gtkmm2ext::Off);
2830 } else if (r == Session::Recording && h) {
2831 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2833 rec_button.unset_active_state ();
2838 ARDOUR_UI::process_save_template_prompter (ArdourPrompter& prompter)
2842 prompter.get_result (name);
2844 if (name.length()) {
2845 int failed = _session->save_template (name);
2847 if (failed == -2) { /* file already exists. */
2848 bool overwrite = overwrite_file_dialog (prompter,
2849 _("Confirm Template Overwrite"),
2850 _("A template already exists with that name. Do you want to overwrite it?"));
2853 _session->save_template (name, true);
2865 ARDOUR_UI::save_template ()
2867 ArdourPrompter prompter (true);
2869 if (!check_audioengine (_main_window)) {
2873 prompter.set_name (X_("Prompter"));
2874 prompter.set_title (_("Save Template"));
2875 prompter.set_prompt (_("Name for template:"));
2876 prompter.set_initial_text(_session->name() + _("-template"));
2877 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2879 bool finished = false;
2881 switch (prompter.run()) {
2882 case RESPONSE_ACCEPT:
2883 finished = process_save_template_prompter (prompter);
2894 ARDOUR_UI::edit_metadata ()
2896 SessionMetadataEditor dialog;
2897 dialog.set_session (_session);
2898 dialog.grab_focus ();
2903 ARDOUR_UI::import_metadata ()
2905 SessionMetadataImporter dialog;
2906 dialog.set_session (_session);
2911 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
2913 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2915 MessageDialog msg (str,
2917 Gtk::MESSAGE_WARNING,
2918 Gtk::BUTTONS_YES_NO,
2922 msg.set_name (X_("OpenExistingDialog"));
2923 msg.set_title (_("Open Existing Session"));
2924 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
2925 msg.set_position (Gtk::WIN_POS_CENTER);
2926 pop_back_splash (msg);
2928 switch (msg.run()) {
2937 ARDOUR_UI::build_session_from_dialog (SessionDialog& sd, const std::string& session_path, const std::string& session_name)
2939 BusProfile bus_profile;
2943 bus_profile.master_out_channels = 2;
2944 bus_profile.input_ac = AutoConnectPhysical;
2945 bus_profile.output_ac = AutoConnectMaster;
2946 bus_profile.requested_physical_in = 0; // use all available
2947 bus_profile.requested_physical_out = 0; // use all available
2951 /* get settings from advanced section of NSD */
2953 if (sd.create_master_bus()) {
2954 bus_profile.master_out_channels = (uint32_t) sd.master_channel_count();
2956 bus_profile.master_out_channels = 0;
2959 if (sd.connect_inputs()) {
2960 bus_profile.input_ac = AutoConnectPhysical;
2962 bus_profile.input_ac = AutoConnectOption (0);
2965 bus_profile.output_ac = AutoConnectOption (0);
2967 if (sd.connect_outputs ()) {
2968 if (sd.connect_outs_to_master()) {
2969 bus_profile.output_ac = AutoConnectMaster;
2970 } else if (sd.connect_outs_to_physical()) {
2971 bus_profile.output_ac = AutoConnectPhysical;
2975 bus_profile.requested_physical_in = (uint32_t) sd.input_limit_count();
2976 bus_profile.requested_physical_out = (uint32_t) sd.output_limit_count();
2979 if (build_session (session_path, session_name, bus_profile)) {
2987 ARDOUR_UI::load_from_application_api (const std::string& path)
2989 ARDOUR_COMMAND_LINE::session_name = path;
2990 /* Cancel SessionDialog if it's visible to make OSX delegates work.
2992 * ARDOUR_UI::starting connects app->ShouldLoad signal and then shows a SessionDialog
2994 * - ShouldLoad does not arrive in time, ARDOUR_COMMAND_LINE::session_name is empty:
2995 * -> ARDOUR_UI::get_session_parameters starts a SessionDialog.
2996 * - ShouldLoad signal arrives, this function is called and sets ARDOUR_COMMAND_LINE::session_name
2997 * -> SessionDialog is not displayed
3000 if (_session_dialog) {
3001 std::string session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3002 std::string session_path = path;
3003 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_REGULAR)) {
3004 session_path = Glib::path_get_dirname (session_path);
3006 // signal the existing dialog in ARDOUR_UI::get_session_parameters()
3007 _session_dialog->set_provided_session (session_name, session_path);
3008 _session_dialog->response (RESPONSE_NONE);
3009 _session_dialog->hide();
3014 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
3015 /* /path/to/foo => /path/to/foo, foo */
3016 rv = load_session (path, basename_nosuffix (path));
3018 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
3019 rv =load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
3022 // if load_session fails -> pop up SessionDialog.
3024 ARDOUR_COMMAND_LINE::session_name = "";
3026 if (get_session_parameters (true, false)) {
3032 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
3034 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
3036 string session_name;
3037 string session_path;
3038 string template_name;
3040 bool likely_new = false;
3041 bool cancel_not_quit;
3043 /* deal with any existing DIRTY session now, rather than later. don't
3044 * treat a non-dirty session this way, so that it stays visible
3045 * as we bring up the new session dialog.
3048 if (_session && ARDOUR_UI::instance()->video_timeline) {
3049 ARDOUR_UI::instance()->video_timeline->sync_session_state();
3052 /* if there is already a session, relabel the button
3053 on the SessionDialog so that we don't Quit directly
3055 cancel_not_quit = (_session != 0);
3057 if (_session && _session->dirty()) {
3058 if (unload_session (false)) {
3059 /* unload cancelled by user */
3062 ARDOUR_COMMAND_LINE::session_name = "";
3065 if (!load_template.empty()) {
3066 should_be_new = true;
3067 template_name = load_template;
3070 session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3071 session_path = ARDOUR_COMMAND_LINE::session_name;
3073 if (!session_path.empty()) {
3074 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_EXISTS)) {
3075 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_IS_REGULAR)) {
3076 /* session/snapshot file, change path to be dir */
3077 session_path = Glib::path_get_dirname (session_path);
3082 SessionDialog session_dialog (should_be_new, session_name, session_path, load_template, cancel_not_quit);
3084 _session_dialog = &session_dialog;
3087 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
3089 /* if they named a specific statefile, use it, otherwise they are
3090 just giving a session folder, and we want to use it as is
3091 to find the session.
3094 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
3096 if (suffix != string::npos) {
3097 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
3098 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
3099 session_name = Glib::path_get_basename (session_name);
3101 session_path = ARDOUR_COMMAND_LINE::session_name;
3102 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
3107 session_dialog.clear_given ();
3110 if (should_be_new || session_name.empty()) {
3111 /* need the dialog to get info from user */
3113 cerr << "run dialog\n";
3115 switch (session_dialog.run()) {
3116 case RESPONSE_ACCEPT:
3119 /* this is used for async * app->ShouldLoad(). */
3120 continue; // while loop
3123 if (quit_on_cancel) {
3124 // JE - Currently (July 2014) this section can only get reached if the
3125 // user quits from the main 'Session Setup' dialog (i.e. reaching this
3126 // point does NOT indicate an abnormal termination). Therefore, let's
3127 // behave gracefully (i.e. let's do some cleanup) before we call exit()
3129 pthread_cancel_all ();
3137 session_dialog.hide ();
3140 /* if we run the startup dialog again, offer more than just "new session" */
3142 should_be_new = false;
3144 session_name = session_dialog.session_name (likely_new);
3145 session_path = session_dialog.session_folder ();
3151 string::size_type suffix = session_name.find (statefile_suffix);
3153 if (suffix != string::npos) {
3154 session_name = session_name.substr (0, suffix);
3157 /* this shouldn't happen, but we catch it just in case it does */
3159 if (session_name.empty()) {
3163 if (session_dialog.use_session_template()) {
3164 template_name = session_dialog.session_template_name();
3165 _session_is_new = true;
3168 if (session_name[0] == G_DIR_SEPARATOR ||
3169 #ifdef PLATFORM_WINDOWS
3170 (session_name.length() > 3 && session_name[1] == ':' && session_name[2] == G_DIR_SEPARATOR)
3172 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
3173 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)
3178 /* absolute path or cwd-relative path specified for session name: infer session folder
3179 from what was given.
3182 session_path = Glib::path_get_dirname (session_name);
3183 session_name = Glib::path_get_basename (session_name);
3187 session_path = session_dialog.session_folder();
3189 char illegal = Session::session_name_is_legal (session_name);
3192 MessageDialog msg (session_dialog,
3193 string_compose (_("To ensure compatibility with various systems\n"
3194 "session names may not contain a '%1' character"),
3197 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3202 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
3205 if (likely_new && !nsm) {
3207 std::string existing = Glib::build_filename (session_path, session_name);
3209 if (!ask_about_loading_existing_session (existing)) {
3210 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3215 _session_is_new = false;
3220 pop_back_splash (session_dialog);
3221 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
3223 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3227 char illegal = Session::session_name_is_legal(session_name);
3230 pop_back_splash (session_dialog);
3231 MessageDialog msg (session_dialog, string_compose(_("To ensure compatibility with various systems\n"
3232 "session names may not contain a '%1' character"), illegal));
3234 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3238 _session_is_new = true;
3241 if (likely_new && template_name.empty()) {
3243 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3247 ret = load_session (session_path, session_name, template_name);
3250 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
3254 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
3255 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
3259 /* clear this to avoid endless attempts to load the
3263 ARDOUR_COMMAND_LINE::session_name = "";
3267 _session_dialog = NULL;
3273 ARDOUR_UI::close_session()
3275 if (!check_audioengine (_main_window)) {
3279 if (unload_session (true)) {
3283 ARDOUR_COMMAND_LINE::session_name = "";
3285 if (get_session_parameters (true, false)) {
3288 if (splash && splash->is_visible()) {
3289 // in 1 second, hide the splash screen
3290 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
3294 /** @param snap_name Snapshot name (without .ardour suffix).
3295 * @return -2 if the load failed because we are not connected to the AudioEngine.
3298 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
3300 Session *new_session;
3305 unload_status = unload_session ();
3307 if (unload_status < 0) {
3309 } else if (unload_status > 0) {
3315 session_loaded = false;
3317 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
3320 new_session = new Session (*AudioEngine::instance(), path, snap_name, 0, mix_template);
3323 /* this one is special */
3325 catch (AudioEngine::PortRegistrationFailure& err) {
3327 MessageDialog msg (err.what(),
3330 Gtk::BUTTONS_CLOSE);
3332 msg.set_title (_("Port Registration Error"));
3333 msg.set_secondary_text (_("Click the Close button to try again."));
3334 msg.set_position (Gtk::WIN_POS_CENTER);
3335 pop_back_splash (msg);
3338 int response = msg.run ();
3343 case RESPONSE_CANCEL:
3350 catch (SessionException e) {
3351 MessageDialog msg (string_compose(
3352 _("Session \"%1 (snapshot %2)\" did not load successfully: %3"),
3353 path, snap_name, e.what()),
3358 msg.set_title (_("Loading Error"));
3359 msg.set_position (Gtk::WIN_POS_CENTER);
3360 pop_back_splash (msg);
3372 MessageDialog msg (string_compose(
3373 _("Session \"%1 (snapshot %2)\" did not load successfully"),
3379 msg.set_title (_("Loading Error"));
3380 msg.set_position (Gtk::WIN_POS_CENTER);
3381 pop_back_splash (msg);
3393 list<string> const u = new_session->unknown_processors ();
3395 MissingPluginDialog d (_session, u);
3400 if (!new_session->writable()) {
3401 MessageDialog msg (_("This session has been opened in read-only mode.\n\nYou will not be able to record or save."),
3406 msg.set_title (_("Read-only Session"));
3407 msg.set_position (Gtk::WIN_POS_CENTER);
3408 pop_back_splash (msg);
3415 /* Now the session been created, add the transport controls */
3416 new_session->add_controllable(roll_controllable);
3417 new_session->add_controllable(stop_controllable);
3418 new_session->add_controllable(goto_start_controllable);
3419 new_session->add_controllable(goto_end_controllable);
3420 new_session->add_controllable(auto_loop_controllable);
3421 new_session->add_controllable(play_selection_controllable);
3422 new_session->add_controllable(rec_controllable);
3424 set_session (new_session);
3426 session_loaded = true;
3429 _session->set_clean ();
3432 #ifdef WINDOWS_VST_SUPPORT
3433 fst_stop_threading();
3437 Timers::TimerSuspender t;
3441 #ifdef WINDOWS_VST_SUPPORT
3442 fst_start_threading();
3451 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
3453 Session *new_session;
3456 session_loaded = false;
3457 x = unload_session ();
3465 _session_is_new = true;
3468 new_session = new Session (*AudioEngine::instance(), path, snap_name, &bus_profile);
3471 catch (SessionException e) {
3473 MessageDialog msg (string_compose(_("Could not create session in \"%1\": %2"), path, e.what()));
3474 msg.set_title (_("Loading Error"));
3475 msg.set_position (Gtk::WIN_POS_CENTER);
3476 pop_back_splash (msg);
3482 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
3483 msg.set_title (_("Loading Error"));
3484 msg.set_position (Gtk::WIN_POS_CENTER);
3485 pop_back_splash (msg);
3490 /* Give the new session the default GUI state, if such things exist */
3493 n = Config->instant_xml (X_("Editor"));
3495 n->remove_nodes_and_delete ("Selection"); // no not apply selection to new sessions.
3496 new_session->add_instant_xml (*n, false);
3498 n = Config->instant_xml (X_("Mixer"));
3500 new_session->add_instant_xml (*n, false);
3503 /* Put the playhead at 0 and scroll fully left */
3504 n = new_session->instant_xml (X_("Editor"));
3506 n->add_property (X_("playhead"), X_("0"));
3507 n->add_property (X_("left-frame"), X_("0"));
3510 set_session (new_session);
3512 session_loaded = true;
3514 new_session->save_state(new_session->name());
3520 ARDOUR_UI::launch_chat ()
3522 MessageDialog dialog(_("<b>Just ask and wait for an answer.\nIt may take from minutes to hours.</b>"), true);
3524 dialog.set_title (_("About the Chat"));
3525 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."));
3527 switch (dialog.run()) {
3530 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
3531 #elif defined PLATFORM_WINDOWS
3532 open_uri("http://webchat.freenode.net/?channels=ardour-windows");
3534 open_uri("http://webchat.freenode.net/?channels=ardour");
3543 ARDOUR_UI::launch_manual ()
3545 PBD::open_uri (Config->get_tutorial_manual_url());
3549 ARDOUR_UI::launch_reference ()
3551 PBD::open_uri (Config->get_reference_manual_url());
3555 ARDOUR_UI::launch_tracker ()
3557 PBD::open_uri ("http://tracker.ardour.org");
3561 ARDOUR_UI::launch_subscribe ()
3563 PBD::open_uri ("https://community.ardour.org/s/subscribe");
3567 ARDOUR_UI::launch_cheat_sheet ()
3570 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheat_sheet_osx.pdf");
3572 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheatsheet.pdf");
3577 ARDOUR_UI::launch_website ()
3579 PBD::open_uri ("http://ardour.org");
3583 ARDOUR_UI::launch_website_dev ()
3585 PBD::open_uri ("http://ardour.org/development.html");
3589 ARDOUR_UI::launch_forums ()
3591 PBD::open_uri ("https://community.ardour.org/forums");
3595 ARDOUR_UI::launch_howto_report ()
3597 PBD::open_uri ("http://ardour.org/reporting_bugs");
3601 ARDOUR_UI::loading_message (const std::string& msg)
3603 if (ARDOUR_COMMAND_LINE::no_splash) {
3611 splash->message (msg);
3615 ARDOUR_UI::show_splash ()
3619 splash = new Splash;
3629 ARDOUR_UI::hide_splash ()
3636 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title, const bool msg_delete)
3640 removed = rep.paths.size();
3643 MessageDialog msgd (_main_window,
3644 _("No files were ready for clean-up"),
3648 msgd.set_title (_("Clean-up"));
3649 msgd.set_secondary_text (_("If this seems suprising, \n\
3650 check for any existing snapshots.\n\
3651 These may still include regions that\n\
3652 require some unused files to continue to exist."));
3658 ArdourDialog results (_("Clean-up"), true, false);
3660 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
3661 CleanupResultsModelColumns() {
3665 Gtk::TreeModelColumn<std::string> visible_name;
3666 Gtk::TreeModelColumn<std::string> fullpath;
3670 CleanupResultsModelColumns results_columns;
3671 Glib::RefPtr<Gtk::ListStore> results_model;
3672 Gtk::TreeView results_display;
3674 results_model = ListStore::create (results_columns);
3675 results_display.set_model (results_model);
3676 results_display.append_column (list_title, results_columns.visible_name);
3678 results_display.set_name ("CleanupResultsList");
3679 results_display.set_headers_visible (true);
3680 results_display.set_headers_clickable (false);
3681 results_display.set_reorderable (false);
3683 Gtk::ScrolledWindow list_scroller;
3686 Gtk::HBox dhbox; // the hbox for the image and text
3687 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
3688 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
3690 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
3692 const string dead_directory = _session->session_directory().dead_path();
3695 %1 - number of files removed
3696 %2 - location of "dead"
3697 %3 - size of files affected
3698 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
3701 const char* bprefix;
3702 double space_adjusted = 0;
3704 if (rep.space < 1000) {
3706 space_adjusted = rep.space;
3707 } else if (rep.space < 1000000) {
3708 bprefix = _("kilo");
3709 space_adjusted = floorf((float)rep.space / 1000.0);
3710 } else if (rep.space < 1000000 * 1000) {
3711 bprefix = _("mega");
3712 space_adjusted = floorf((float)rep.space / (1000.0 * 1000.0));
3714 bprefix = _("giga");
3715 space_adjusted = floorf((float)rep.space / (1000.0 * 1000 * 1000.0));
3719 txt.set_markup (string_compose (P_("\
3720 The following file was deleted from %2,\n\
3721 releasing %3 %4bytes of disk space", "\
3722 The following %1 files were deleted from %2,\n\
3723 releasing %3 %4bytes of disk space", removed),
3724 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3726 txt.set_markup (string_compose (P_("\
3727 The following file was not in use and \n\
3728 has been moved to: %2\n\n\
3729 After a restart of %5\n\n\
3730 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3731 will release an additional %3 %4bytes of disk space.\n", "\
3732 The following %1 files were not in use and \n\
3733 have been moved to: %2\n\n\
3734 After a restart of %5\n\n\
3735 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3736 will release an additional %3 %4bytes of disk space.\n", removed),
3737 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3740 dhbox.pack_start (*dimage, true, false, 5);
3741 dhbox.pack_start (txt, true, false, 5);
3743 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
3744 TreeModel::Row row = *(results_model->append());
3745 row[results_columns.visible_name] = *i;
3746 row[results_columns.fullpath] = *i;
3749 list_scroller.add (results_display);
3750 list_scroller.set_size_request (-1, 150);
3751 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
3753 dvbox.pack_start (dhbox, true, false, 5);
3754 dvbox.pack_start (list_scroller, true, false, 5);
3755 ddhbox.pack_start (dvbox, true, false, 5);
3757 results.get_vbox()->pack_start (ddhbox, true, false, 5);
3758 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
3759 results.set_default_response (RESPONSE_CLOSE);
3760 results.set_position (Gtk::WIN_POS_MOUSE);
3762 results_display.show();
3763 list_scroller.show();
3770 //results.get_vbox()->show();
3771 results.set_resizable (false);
3778 ARDOUR_UI::cleanup ()
3780 if (_session == 0) {
3781 /* shouldn't happen: menu item is insensitive */
3786 MessageDialog checker (_("Are you sure you want to clean-up?"),
3788 Gtk::MESSAGE_QUESTION,
3791 checker.set_title (_("Clean-up"));
3793 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
3794 ALL undo/redo information will be lost if you clean-up.\n\
3795 Clean-up will move all unused files to a \"dead\" location."));
3797 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3798 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
3799 checker.set_default_response (RESPONSE_CANCEL);
3801 checker.set_name (_("CleanupDialog"));
3802 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3803 checker.set_position (Gtk::WIN_POS_MOUSE);
3805 switch (checker.run()) {
3806 case RESPONSE_ACCEPT:
3812 ARDOUR::CleanupReport rep;
3814 editor->prepare_for_cleanup ();
3816 /* do not allow flush until a session is reloaded */
3818 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3820 act->set_sensitive (false);
3823 if (_session->cleanup_sources (rep)) {
3824 editor->finish_cleanup ();
3828 editor->finish_cleanup ();
3831 display_cleanup_results (rep, _("Cleaned Files"), false);
3835 ARDOUR_UI::flush_trash ()
3837 if (_session == 0) {
3838 /* shouldn't happen: menu item is insensitive */
3842 ARDOUR::CleanupReport rep;
3844 if (_session->cleanup_trash_sources (rep)) {
3848 display_cleanup_results (rep, _("deleted file"), true);
3852 ARDOUR_UI::cleanup_peakfiles ()
3854 if (_session == 0) {
3855 /* shouldn't happen: menu item is insensitive */
3859 if (! _session->can_cleanup_peakfiles ()) {
3863 // get all region-views in this session
3865 TrackViewList empty;
3867 editor->get_regions_after(rs, (framepos_t) 0, empty);
3868 std::list<RegionView*> views = rs.by_layer();
3870 // remove displayed audio-region-views waveforms
3871 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
3872 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
3873 if (!arv) { continue ; }
3874 arv->delete_waves();
3877 // cleanup peak files:
3878 // - stop pending peakfile threads
3879 // - close peakfiles if any
3880 // - remove peak dir in session
3881 // - setup peakfiles (background thread)
3882 _session->cleanup_peakfiles ();
3884 // re-add waves to ARV
3885 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
3886 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
3887 if (!arv) { continue ; }
3888 arv->create_waves();
3893 ARDOUR_UI::setup_order_hint (AddRouteDialog::InsertAt place)
3895 uint32_t order_hint = UINT32_MAX;
3897 if (editor->get_selection().tracks.empty()) {
3902 we want the new routes to have their order keys set starting from
3903 the highest order key in the selection + 1 (if available).
3906 if (place == AddRouteDialog::AfterSelection) {
3907 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.back());
3909 order_hint = rtav->route()->order_key();
3912 } else if (place == AddRouteDialog::BeforeSelection) {
3913 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.front());
3915 order_hint = rtav->route()->order_key();
3917 } else if (place == AddRouteDialog::First) {
3920 /* leave order_hint at UINT32_MAX */
3923 if (order_hint == UINT32_MAX) {
3924 /** AddRouteDialog::Last or selection with first/last not a RouteTimeAxisView
3925 * not setting an order hint will place new routes last.
3930 _session->set_order_hint (order_hint);
3932 /* create a gap in the existing route order keys to accomodate new routes.*/
3933 boost::shared_ptr <RouteList> rd = _session->get_routes();
3934 for (RouteList::iterator ri = rd->begin(); ri != rd->end(); ++ri) {
3935 boost::shared_ptr<Route> rt (*ri);
3937 if (rt->is_monitor()) {
3941 if (rt->order_key () >= order_hint) {
3942 rt->set_order_key (rt->order_key () + add_route_dialog->count());
3948 ARDOUR_UI::start_duplicate_routes ()
3950 if (!duplicate_routes_dialog) {
3951 duplicate_routes_dialog = new DuplicateRouteDialog;
3954 if (duplicate_routes_dialog->restart (_session)) {
3958 duplicate_routes_dialog->present ();
3962 ARDOUR_UI::add_route ()
3970 if (add_route_dialog->is_visible()) {
3971 /* we're already doing this */
3975 ResponseType r = (ResponseType) add_route_dialog->run ();
3977 add_route_dialog->hide();
3980 case RESPONSE_ACCEPT:
3987 if ((count = add_route_dialog->count()) <= 0) {
3991 setup_order_hint(add_route_dialog->insert_at());
3992 string template_path = add_route_dialog->track_template();
3993 DisplaySuspender ds;
3995 if (!template_path.empty()) {
3996 if (add_route_dialog->name_template_is_default()) {
3997 _session->new_route_from_template (count, template_path, string());
3999 _session->new_route_from_template (count, template_path, add_route_dialog->name_template());
4004 ChanCount input_chan= add_route_dialog->channels ();
4005 ChanCount output_chan;
4006 string name_template = add_route_dialog->name_template ();
4007 PluginInfoPtr instrument = add_route_dialog->requested_instrument ();
4008 RouteGroup* route_group = add_route_dialog->route_group ();
4009 AutoConnectOption oac = Config->get_output_auto_connect();
4010 bool strict_io = add_route_dialog->use_strict_io ();
4012 if (oac & AutoConnectMaster) {
4013 output_chan.set (DataType::AUDIO, (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan.n_audio()));
4014 output_chan.set (DataType::MIDI, 0);
4016 output_chan = input_chan;
4019 /* XXX do something with name template */
4021 switch (add_route_dialog->type_wanted()) {
4022 case AddRouteDialog::AudioTrack:
4023 session_add_audio_track (input_chan.n_audio(), output_chan.n_audio(), add_route_dialog->mode(), route_group, count, name_template, strict_io);
4025 case AddRouteDialog::MidiTrack:
4026 session_add_midi_track (route_group, count, name_template, strict_io, instrument);
4028 case AddRouteDialog::MixedTrack:
4029 session_add_mixed_track (input_chan, output_chan, route_group, count, name_template, strict_io, instrument, 0);
4031 case AddRouteDialog::AudioBus:
4032 session_add_audio_bus (input_chan.n_audio(), output_chan.n_audio(), route_group, count, name_template, strict_io);
4034 case AddRouteDialog::MidiBus:
4035 session_add_midi_bus (route_group, count, name_template, strict_io, instrument, 0);
4041 ARDOUR_UI::add_lua_script ()
4047 LuaScriptInfoPtr spi;
4048 ScriptSelector ss ("Add Lua Session Script", LuaScriptInfo::Session);
4049 switch (ss.run ()) {
4050 case Gtk::RESPONSE_ACCEPT:
4058 std::string script = "";
4061 script = Glib::file_get_contents (spi->path);
4062 } catch (Glib::FileError e) {
4063 string msg = string_compose (_("Cannot read session script '%1': %2"), spi->path, e.what());
4064 MessageDialog am (msg);
4069 LuaScriptParamList lsp = LuaScriptParams::script_params (spi, "sess_params");
4070 std::vector<std::string> reg = _session->registered_lua_functions ();
4072 ScriptParameterDialog spd (_("Set Script Parameters"), spi, reg, lsp);
4073 switch (spd.run ()) {
4074 case Gtk::RESPONSE_ACCEPT:
4081 _session->register_lua_function (spd.name(), script, lsp);
4082 } catch (luabridge::LuaException const& e) {
4083 string msg = string_compose (_("Session script '%1' instantiation failed: %2"), spd.name(), e.what ());
4084 MessageDialog am (msg);
4086 } catch (SessionException e) {
4087 string msg = string_compose (_("Loading Session script '%1' failed: %2"), spd.name(), e.what ());
4088 MessageDialog am (msg);
4094 ARDOUR_UI::remove_lua_script ()
4099 if (_session->registered_lua_function_count () == 0) {
4100 string msg = _("There are no active Lua session scripts present in this session.");
4101 MessageDialog am (msg);
4106 std::vector<std::string> reg = _session->registered_lua_functions ();
4107 SessionScriptManager sm ("Remove Lua Session Script", reg);
4108 switch (sm.run ()) {
4109 case Gtk::RESPONSE_ACCEPT:
4115 _session->unregister_lua_function (sm.name());
4116 } catch (luabridge::LuaException const& e) {
4117 string msg = string_compose (_("Session script '%1' removal failed: %2"), sm.name(), e.what ());
4118 MessageDialog am (msg);
4124 ARDOUR_UI::stop_video_server (bool ask_confirm)
4126 if (!video_server_process && ask_confirm) {
4127 warning << string_compose (_("Video-Server was not launched by %1. The request to stop it is ignored."), PROGRAM_NAME) << endmsg;
4129 if (video_server_process) {
4131 ArdourDialog confirm (_("Stop Video-Server"), true);
4132 Label m (_("Do you really want to stop the Video Server?"));
4133 confirm.get_vbox()->pack_start (m, true, true);
4134 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
4135 confirm.add_button (_("Yes, Stop It"), Gtk::RESPONSE_ACCEPT);
4136 confirm.show_all ();
4137 if (confirm.run() == RESPONSE_CANCEL) {
4141 delete video_server_process;
4142 video_server_process =0;
4147 ARDOUR_UI::start_video_server_menu (Gtk::Window* float_window)
4149 ARDOUR_UI::start_video_server( float_window, true);
4153 ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg)
4159 if (ARDOUR_UI::instance()->video_timeline->check_server()) {
4160 if (video_server_process) {
4161 popup_error(_("The Video Server is already started."));
4163 popup_error(_("An external Video Server is configured and can be reached. Not starting a new instance."));
4169 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4171 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4173 VideoServerDialog *video_server_dialog = new VideoServerDialog (_session);
4175 video_server_dialog->set_transient_for (*float_window);
4178 if (!Config->get_show_video_server_dialog() && firsttime < 2) {
4179 video_server_dialog->hide();
4181 ResponseType r = (ResponseType) video_server_dialog->run ();
4182 video_server_dialog->hide();
4183 if (r != RESPONSE_ACCEPT) { return false; }
4184 if (video_server_dialog->show_again()) {
4185 Config->set_show_video_server_dialog(false);
4189 std::string icsd_exec = video_server_dialog->get_exec_path();
4190 std::string icsd_docroot = video_server_dialog->get_docroot();
4191 if (icsd_docroot.empty()) {
4192 #ifndef PLATFORM_WINDOWS
4193 icsd_docroot = X_("/");
4195 icsd_docroot = X_("C:\\");
4200 if (g_lstat (icsd_docroot.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode)) {
4201 warning << _("Specified docroot is not an existing directory.") << endmsg;
4204 #ifndef PLATFORM_WINDOWS
4205 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4206 || (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0 ) {
4207 warning << _("Given Video Server is not an executable file.") << endmsg;
4211 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4212 || (sb.st_mode & (S_IXUSR)) == 0 ) {
4213 warning << _("Given Video Server is not an executable file.") << endmsg;
4219 argp=(char**) calloc(9,sizeof(char*));
4220 argp[0] = strdup(icsd_exec.c_str());
4221 argp[1] = strdup("-P");
4222 argp[2] = (char*) calloc(16,sizeof(char)); snprintf(argp[2], 16, "%s", video_server_dialog->get_listenaddr().c_str());
4223 argp[3] = strdup("-p");
4224 argp[4] = (char*) calloc(6,sizeof(char)); snprintf(argp[4], 6, "%i", video_server_dialog->get_listenport());
4225 argp[5] = strdup("-C");
4226 argp[6] = (char*) calloc(6,sizeof(char)); snprintf(argp[6], 6, "%i", video_server_dialog->get_cachesize());
4227 argp[7] = strdup(icsd_docroot.c_str());
4229 stop_video_server();
4231 if (icsd_docroot == X_("/") || icsd_docroot == X_("C:\\")) {
4232 Config->set_video_advanced_setup(false);
4234 std::ostringstream osstream;
4235 osstream << "http://127.0.0.1:" << video_server_dialog->get_listenport() << "/";
4236 Config->set_video_server_url(osstream.str());
4237 Config->set_video_server_docroot(icsd_docroot);
4238 Config->set_video_advanced_setup(true);
4241 if (video_server_process) {
4242 delete video_server_process;
4245 video_server_process = new ARDOUR::SystemExec(icsd_exec, argp);
4246 if (video_server_process->start()) {
4247 warning << _("Cannot launch the video-server") << endmsg;
4250 int timeout = 120; // 6 sec
4251 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4252 Glib::usleep (50000);
4254 if (--timeout <= 0 || !video_server_process->is_running()) break;
4257 warning << _("Video-server was started but does not respond to requests...") << endmsg;
4259 if (!ARDOUR_UI::instance()->video_timeline->check_server_docroot()) {
4260 delete video_server_process;
4261 video_server_process = 0;
4269 ARDOUR_UI::add_video (Gtk::Window* float_window)
4275 if (!start_video_server(float_window, false)) {
4276 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4281 add_video_dialog->set_transient_for (*float_window);
4284 if (add_video_dialog->is_visible()) {
4285 /* we're already doing this */
4289 ResponseType r = (ResponseType) add_video_dialog->run ();
4290 add_video_dialog->hide();
4291 if (r != RESPONSE_ACCEPT) { return; }
4293 bool local_file, orig_local_file;
4294 std::string path = add_video_dialog->file_name(local_file);
4296 std::string orig_path = path;
4297 orig_local_file = local_file;
4299 bool auto_set_session_fps = add_video_dialog->auto_set_session_fps();
4301 if (local_file && !Glib::file_test(path, Glib::FILE_TEST_EXISTS)) {
4302 warning << string_compose(_("could not open %1"), path) << endmsg;
4305 if (!local_file && path.length() == 0) {
4306 warning << _("no video-file selected") << endmsg;
4310 std::string audio_from_video;
4311 bool detect_ltc = false;
4313 switch (add_video_dialog->import_option()) {
4314 case VTL_IMPORT_TRANSCODE:
4316 TranscodeVideoDialog *transcode_video_dialog;
4317 transcode_video_dialog = new TranscodeVideoDialog (_session, path);
4318 ResponseType r = (ResponseType) transcode_video_dialog->run ();
4319 transcode_video_dialog->hide();
4320 if (r != RESPONSE_ACCEPT) {
4321 delete transcode_video_dialog;
4325 audio_from_video = transcode_video_dialog->get_audiofile();
4327 if (!audio_from_video.empty() && transcode_video_dialog->detect_ltc()) {
4330 else if (!audio_from_video.empty()) {
4331 editor->embed_audio_from_video(
4333 video_timeline->get_offset(),
4334 (transcode_video_dialog->import_option() != VTL_IMPORT_NO_VIDEO)
4337 switch (transcode_video_dialog->import_option()) {
4338 case VTL_IMPORT_TRANSCODED:
4339 path = transcode_video_dialog->get_filename();
4342 case VTL_IMPORT_REFERENCE:
4345 delete transcode_video_dialog;
4348 delete transcode_video_dialog;
4352 case VTL_IMPORT_NONE:
4356 /* strip _session->session_directory().video_path() from video file if possible */
4357 if (local_file && !path.compare(0, _session->session_directory().video_path().size(), _session->session_directory().video_path())) {
4358 path=path.substr(_session->session_directory().video_path().size());
4359 if (path.at(0) == G_DIR_SEPARATOR) {
4360 path=path.substr(1);
4364 video_timeline->set_update_session_fps(auto_set_session_fps);
4366 if (video_timeline->video_file_info(path, local_file)) {
4367 XMLNode* node = new XMLNode(X_("Videotimeline"));
4368 node->add_property (X_("Filename"), path);
4369 node->add_property (X_("AutoFPS"), auto_set_session_fps?X_("1"):X_("0"));
4370 node->add_property (X_("LocalFile"), local_file?X_("1"):X_("0"));
4371 if (orig_local_file) {
4372 node->add_property (X_("OriginalVideoFile"), orig_path);
4374 node->remove_property (X_("OriginalVideoFile"));
4376 _session->add_extra_xml (*node);
4377 _session->set_dirty ();
4379 if (!audio_from_video.empty() && detect_ltc) {
4380 std::vector<LTCFileReader::LTCMap> ltc_seq;
4383 /* TODO ask user about TV standard (LTC alignment if any) */
4384 LTCFileReader ltcr (audio_from_video, video_timeline->get_video_file_fps());
4385 /* TODO ASK user which channel: 0 .. ltcr->channels() - 1 */
4387 ltc_seq = ltcr.read_ltc (/*channel*/ 0, /*max LTC frames to decode*/ 15);
4389 /* TODO seek near end of file, and read LTC until end.
4390 * if it fails to find any LTC frames, scan complete file
4392 * calculate drift of LTC compared to video-duration,
4393 * ask user for reference (timecode from start/mid/end)
4396 // LTCFileReader will have written error messages
4399 ::g_unlink(audio_from_video.c_str());
4401 if (ltc_seq.size() == 0) {
4402 PBD::error << _("No LTC detected, video will not be aligned.") << endmsg;
4404 /* the very first TC in the file is somteimes not aligned properly */
4405 int i = ltc_seq.size() -1;
4406 ARDOUR::frameoffset_t video_start_offset =
4407 _session->nominal_frame_rate() * (ltc_seq[i].timecode_sec - ltc_seq[i].framepos_sec);
4408 PBD::info << string_compose (_("Align video-start to %1 [samples]"), video_start_offset) << endmsg;
4409 video_timeline->set_offset(video_start_offset);
4413 _session->maybe_update_session_range(
4414 std::max(video_timeline->get_offset(), (ARDOUR::frameoffset_t) 0),
4415 std::max(video_timeline->get_offset() + video_timeline->get_duration(), (ARDOUR::frameoffset_t) 0));
4418 if (add_video_dialog->launch_xjadeo() && local_file) {
4419 editor->set_xjadeo_sensitive(true);
4420 editor->toggle_xjadeo_proc(1);
4422 editor->toggle_xjadeo_proc(0);
4424 editor->toggle_ruler_video(true);
4429 ARDOUR_UI::remove_video ()
4431 video_timeline->close_session();
4432 editor->toggle_ruler_video(false);
4435 video_timeline->set_offset_locked(false);
4436 video_timeline->set_offset(0);
4438 /* delete session state */
4439 XMLNode* node = new XMLNode(X_("Videotimeline"));
4440 _session->add_extra_xml(*node);
4441 node = new XMLNode(X_("Videomonitor"));
4442 _session->add_extra_xml(*node);
4443 node = new XMLNode(X_("Videoexport"));
4444 _session->add_extra_xml(*node);
4445 stop_video_server();
4449 ARDOUR_UI::flush_videotimeline_cache (bool localcacheonly)
4451 if (localcacheonly) {
4452 video_timeline->vmon_update();
4454 video_timeline->flush_cache();
4456 editor->queue_visual_videotimeline_update();
4460 ARDOUR_UI::export_video (bool range)
4462 if (ARDOUR::Config->get_show_video_export_info()) {
4463 ExportVideoInfobox infobox (_session);
4464 Gtk::ResponseType rv = (Gtk::ResponseType) infobox.run();
4465 if (infobox.show_again()) {
4466 ARDOUR::Config->set_show_video_export_info(false);
4469 case GTK_RESPONSE_YES:
4470 PBD::open_uri (ARDOUR::Config->get_reference_manual_url() + "/video-timeline/operations/#export");
4476 export_video_dialog->set_session (_session);
4477 export_video_dialog->apply_state(editor->get_selection().time, range);
4478 export_video_dialog->run ();
4479 export_video_dialog->hide ();
4483 ARDOUR_UI::mixer_settings () const
4488 node = _session->instant_xml(X_("Mixer"));
4490 node = Config->instant_xml(X_("Mixer"));
4494 node = new XMLNode (X_("Mixer"));
4501 ARDOUR_UI::main_window_settings () const
4506 node = _session->instant_xml(X_("Main"));
4508 node = Config->instant_xml(X_("Main"));
4512 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4513 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4518 node = new XMLNode (X_("Main"));
4525 ARDOUR_UI::editor_settings () const
4530 node = _session->instant_xml(X_("Editor"));
4532 node = Config->instant_xml(X_("Editor"));
4536 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4537 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4542 node = new XMLNode (X_("Editor"));
4549 ARDOUR_UI::keyboard_settings () const
4553 node = Config->extra_xml(X_("Keyboard"));
4556 node = new XMLNode (X_("Keyboard"));
4563 ARDOUR_UI::create_xrun_marker (framepos_t where)
4566 Location *location = new Location (*_session, where, where, _("xrun"), Location::IsMark);
4567 _session->locations()->add (location);
4572 ARDOUR_UI::halt_on_xrun_message ()
4574 cerr << "HALT on xrun\n";
4575 MessageDialog msg (_main_window, _("Recording was stopped because your system could not keep up."));
4580 ARDOUR_UI::xrun_handler (framepos_t where)
4586 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
4588 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
4589 create_xrun_marker(where);
4592 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
4593 halt_on_xrun_message ();
4598 ARDOUR_UI::disk_overrun_handler ()
4600 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
4602 if (!have_disk_speed_dialog_displayed) {
4603 have_disk_speed_dialog_displayed = true;
4604 MessageDialog* msg = new MessageDialog (_main_window, string_compose (_("\
4605 The disk system on your computer\n\
4606 was not able to keep up with %1.\n\
4608 Specifically, it failed to write data to disk\n\
4609 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
4610 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4616 /* TODO: this is getting elaborate enough to warrant being split into a dedicated class */
4617 static MessageDialog *scan_dlg = NULL;
4618 static ProgressBar *scan_pbar = NULL;
4619 static HBox *scan_tbox = NULL;
4620 static Gtk::Button *scan_timeout_button;
4623 ARDOUR_UI::cancel_plugin_scan ()
4625 PluginManager::instance().cancel_plugin_scan();
4629 ARDOUR_UI::cancel_plugin_timeout ()
4631 PluginManager::instance().cancel_plugin_timeout();
4632 scan_timeout_button->set_sensitive (false);
4636 ARDOUR_UI::plugin_scan_timeout (int timeout)
4638 if (!scan_dlg || !scan_dlg->is_mapped() || !scan_pbar) {
4642 scan_pbar->set_sensitive (false);
4643 scan_timeout_button->set_sensitive (true);
4644 scan_pbar->set_fraction ((float) timeout / (float) Config->get_vst_scan_timeout());
4647 scan_pbar->set_sensitive (false);
4648 scan_timeout_button->set_sensitive (false);
4654 ARDOUR_UI::plugin_scan_dialog (std::string type, std::string plugin, bool can_cancel)
4656 if (type == X_("closeme") && !(scan_dlg && scan_dlg->is_mapped())) {
4660 const bool cancelled = PluginManager::instance().cancelled();
4661 if (type != X_("closeme") && (!UIConfiguration::instance().get_show_plugin_scan_window()) && !_initial_verbose_plugin_scan) {
4662 if (cancelled && scan_dlg->is_mapped()) {
4667 if (cancelled || !can_cancel) {
4672 static Gtk::Button *cancel_button;
4674 scan_dlg = new MessageDialog("", false, MESSAGE_INFO, BUTTONS_NONE); // TODO manage
4675 VBox* vbox = scan_dlg->get_vbox();
4676 vbox->set_size_request(400,-1);
4677 scan_dlg->set_title (_("Scanning for plugins"));
4679 cancel_button = manage(new Gtk::Button(_("Cancel plugin scan")));
4680 cancel_button->set_name ("EditorGTKButton");
4681 cancel_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_scan) );
4682 cancel_button->show();
4684 scan_dlg->get_vbox()->pack_start ( *cancel_button, PACK_SHRINK);
4686 scan_tbox = manage( new HBox() );
4688 scan_timeout_button = manage(new Gtk::Button(_("Stop Timeout")));
4689 scan_timeout_button->set_name ("EditorGTKButton");
4690 scan_timeout_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_timeout) );
4691 scan_timeout_button->show();
4693 scan_pbar = manage(new ProgressBar());
4694 scan_pbar->set_orientation(Gtk::PROGRESS_RIGHT_TO_LEFT);
4695 scan_pbar->set_text(_("Scan Timeout"));
4698 scan_tbox->pack_start (*scan_pbar, PACK_EXPAND_WIDGET, 4);
4699 scan_tbox->pack_start (*scan_timeout_button, PACK_SHRINK, 4);
4701 scan_dlg->get_vbox()->pack_start (*scan_tbox, PACK_SHRINK, 4);
4704 assert(scan_dlg && scan_tbox && cancel_button);
4706 if (type == X_("closeme")) {
4710 scan_dlg->set_message(type + ": " + Glib::path_get_basename(plugin));
4713 if (!can_cancel || !cancelled) {
4714 scan_timeout_button->set_sensitive(false);
4716 cancel_button->set_sensitive(can_cancel && !cancelled);
4722 ARDOUR_UI::gui_idle_handler ()
4725 /* due to idle calls, gtk_events_pending() may always return true */
4726 while (gtk_events_pending() && --timeout) {
4727 gtk_main_iteration ();
4732 ARDOUR_UI::disk_underrun_handler ()
4734 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
4736 if (!have_disk_speed_dialog_displayed) {
4737 have_disk_speed_dialog_displayed = true;
4738 MessageDialog* msg = new MessageDialog (
4739 _main_window, string_compose (_("The disk system on your computer\n\
4740 was not able to keep up with %1.\n\
4742 Specifically, it failed to read data from disk\n\
4743 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
4744 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4750 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
4752 have_disk_speed_dialog_displayed = false;
4757 ARDOUR_UI::session_dialog (std::string msg)
4759 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
4763 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
4770 ARDOUR_UI::pending_state_dialog ()
4772 HBox* hbox = manage (new HBox());
4773 Image* image = manage (new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG));
4774 ArdourDialog dialog (_("Crash Recovery"), true);
4775 Label message (string_compose (_("\
4776 This session appears to have been in the\n\
4777 middle of recording when %1 or\n\
4778 the computer was shutdown.\n\
4780 %1 can recover any captured audio for\n\
4781 you, or it can ignore it. Please decide\n\
4782 what you would like to do.\n"), PROGRAM_NAME));
4783 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4784 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4785 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4786 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4787 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
4788 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
4789 dialog.set_default_response (RESPONSE_ACCEPT);
4790 dialog.set_position (WIN_POS_CENTER);
4795 switch (dialog.run ()) {
4796 case RESPONSE_ACCEPT:
4804 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
4806 HBox* hbox = new HBox();
4807 Image* image = new Image (Stock::DIALOG_WARNING, ICON_SIZE_DIALOG);
4808 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
4809 Label message (string_compose (_("\
4810 This session was created with a sample rate of %1 Hz, but\n\
4811 %2 is currently running at %3 Hz. If you load this session,\n\
4812 audio may be played at the wrong sample rate.\n"), desired, PROGRAM_NAME, actual));
4814 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4815 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4816 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4817 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4818 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
4819 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
4820 dialog.set_default_response (RESPONSE_ACCEPT);
4821 dialog.set_position (WIN_POS_CENTER);
4826 switch (dialog.run()) {
4827 case RESPONSE_ACCEPT:
4837 ARDOUR_UI::sr_mismatch_message (framecnt_t desired, framecnt_t actual)
4839 MessageDialog msg (string_compose (_("\
4840 This session was created with a sample rate of %1 Hz, but\n\
4841 %2 is currently running at %3 Hz.\n\
4842 Audio will be recorded and played at the wrong sample rate.\n\
4843 Re-Configure the Audio Engine in\n\
4844 Menu > Window > Audio/Midi Setup"),
4845 desired, PROGRAM_NAME, actual),
4847 Gtk::MESSAGE_WARNING);
4852 ARDOUR_UI::use_config ()
4854 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
4856 set_transport_controllable_state (*node);
4861 ARDOUR_UI::update_transport_clocks (framepos_t pos)
4863 if (UIConfiguration::instance().get_primary_clock_delta_edit_cursor()) {
4864 primary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
4866 primary_clock->set (pos);
4869 if (UIConfiguration::instance().get_secondary_clock_delta_edit_cursor()) {
4870 secondary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
4872 secondary_clock->set (pos);
4875 if (big_clock_window) {
4876 big_clock->set (pos);
4878 ARDOUR_UI::instance()->video_timeline->manual_seek_video_monitor(pos);
4882 ARDOUR_UI::step_edit_status_change (bool yn)
4884 // XXX should really store pre-step edit status of things
4885 // we make insensitive
4888 rec_button.set_active_state (Gtkmm2ext::ImplicitActive);
4889 rec_button.set_sensitive (false);
4891 rec_button.unset_active_state ();;
4892 rec_button.set_sensitive (true);
4897 ARDOUR_UI::record_state_changed ()
4899 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
4901 if (!_session || !big_clock_window) {
4902 /* why bother - the clock isn't visible */
4906 if (_session->record_status () == Session::Recording && _session->have_rec_enabled_track ()) {
4907 big_clock->set_active (true);
4909 big_clock->set_active (false);
4914 ARDOUR_UI::first_idle ()
4917 _session->allow_auto_play (true);
4921 editor->first_idle();
4924 Keyboard::set_can_save_keybindings (true);
4929 ARDOUR_UI::store_clock_modes ()
4931 XMLNode* node = new XMLNode(X_("ClockModes"));
4933 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
4934 XMLNode* child = new XMLNode (X_("Clock"));
4936 child->add_property (X_("name"), (*x)->name());
4937 child->add_property (X_("mode"), enum_2_string ((*x)->mode()));
4938 child->add_property (X_("on"), ((*x)->off() ? X_("no") : X_("yes")));
4940 node->add_child_nocopy (*child);
4943 _session->add_extra_xml (*node);
4944 _session->set_dirty ();
4947 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
4948 : Controllable (name), ui (u), type(tp)
4954 ARDOUR_UI::TransportControllable::set_value (double val, PBD::Controllable::GroupControlDisposition /*group_override*/)
4957 /* do nothing: these are radio-style actions */
4961 const char *action = 0;
4965 action = X_("Roll");
4968 action = X_("Stop");
4971 action = X_("GotoStart");
4974 action = X_("GotoEnd");
4977 action = X_("Loop");
4980 action = X_("PlaySelection");
4983 action = X_("Record");
4993 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
5001 ARDOUR_UI::TransportControllable::get_value (void) const
5028 ARDOUR_UI::setup_profile ()
5030 if (gdk_screen_width() < 1200 || getenv ("ARDOUR_NARROW_SCREEN")) {
5031 Profile->set_small_screen ();
5034 if (g_getenv ("TRX")) {
5035 Profile->set_trx ();
5038 if (g_getenv ("MIXBUS")) {
5039 Profile->set_mixbus ();
5044 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
5046 MissingFileDialog dialog (s, str, type);
5051 int result = dialog.run ();
5058 return 1; // quit entire session load
5061 result = dialog.get_action ();
5067 ARDOUR_UI::ambiguous_file (std::string file, std::vector<std::string> hits)
5069 AmbiguousFileDialog dialog (file, hits);
5076 return dialog.get_which ();
5079 /** Allocate our thread-local buffers */
5081 ARDOUR_UI::get_process_buffers ()
5083 _process_thread->get_buffers ();
5086 /** Drop our thread-local buffers */
5088 ARDOUR_UI::drop_process_buffers ()
5090 _process_thread->drop_buffers ();
5094 ARDOUR_UI::feedback_detected ()
5096 _feedback_exists = true;
5100 ARDOUR_UI::successful_graph_sort ()
5102 _feedback_exists = false;
5106 ARDOUR_UI::midi_panic ()
5109 _session->midi_panic();
5114 ARDOUR_UI::session_format_mismatch (std::string xml_path, std::string backup_path)
5116 const char* start_big = "<span size=\"x-large\" weight=\"bold\">";
5117 const char* end_big = "</span>";
5118 const char* start_mono = "<tt>";
5119 const char* end_mono = "</tt>";
5121 MessageDialog msg (string_compose (_("%4This is a session from an older version of %3%5\n\n"
5122 "%3 has copied the old session file\n\n%6%1%7\n\nto\n\n%6%2%7\n\n"
5123 "From now on, use the -2000 version with older versions of %3"),
5124 xml_path, backup_path, PROGRAM_NAME,
5126 start_mono, end_mono), true);
5133 ARDOUR_UI::reset_peak_display ()
5135 if (!_session || !_session->master_out() || !editor_meter) return;
5136 editor_meter->clear_meters();
5137 editor_meter_max_peak = -INFINITY;
5138 editor_meter_peak_display.set_active_state ( Gtkmm2ext::Off );
5142 ARDOUR_UI::reset_group_peak_display (RouteGroup* group)
5144 if (!_session || !_session->master_out()) return;
5145 if (group == _session->master_out()->route_group()) {
5146 reset_peak_display ();
5151 ARDOUR_UI::reset_route_peak_display (Route* route)
5153 if (!_session || !_session->master_out()) return;
5154 if (_session->master_out().get() == route) {
5155 reset_peak_display ();
5160 ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate)
5162 audio_midi_setup->set_desired_sample_rate (desired_sample_rate);
5163 audio_midi_setup->set_position (WIN_POS_CENTER);
5165 if (Config->get_try_autostart_engine () || getenv ("TRY_AUTOSTART_ENGINE")) {
5166 audio_midi_setup->try_autostart ();
5167 if (ARDOUR::AudioEngine::instance()->running()) {
5173 int response = audio_midi_setup->run();
5175 case Gtk::RESPONSE_OK:
5176 if (!AudioEngine::instance()->running()) {
5190 ARDOUR_UI::transport_numpad_timeout ()
5192 _numpad_locate_happening = false;
5193 if (_numpad_timeout_connection.connected() )
5194 _numpad_timeout_connection.disconnect();
5199 ARDOUR_UI::transport_numpad_decimal ()
5201 _numpad_timeout_connection.disconnect();
5203 if (_numpad_locate_happening) {
5204 if (editor) editor->goto_nth_marker(_pending_locate_num - 1);
5205 _numpad_locate_happening = false;
5207 _pending_locate_num = 0;
5208 _numpad_locate_happening = true;
5209 _numpad_timeout_connection = Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::transport_numpad_timeout), 2*1000);
5214 ARDOUR_UI::transport_numpad_event (int num)
5216 if ( _numpad_locate_happening ) {
5217 _pending_locate_num = _pending_locate_num*10 + num;
5220 case 0: toggle_roll(false, false); break;
5221 case 1: transport_rewind(1); break;
5222 case 2: transport_forward(1); break;
5223 case 3: transport_record(true); break;
5224 case 4: toggle_session_auto_loop(); break;
5225 case 5: transport_record(false); toggle_session_auto_loop(); break;
5226 case 6: toggle_punch(); break;
5227 case 7: toggle_click(); break;
5228 case 8: toggle_auto_return(); break;
5229 case 9: toggle_follow_edits(); break;
5235 ARDOUR_UI::set_flat_buttons ()
5237 CairoWidget::set_flat_buttons( UIConfiguration::instance().get_flat_buttons() );
5241 ARDOUR_UI::audioengine_became_silent ()
5243 MessageDialog msg (string_compose (_("This is a free/demo copy of %1. It has just switched to silent mode."), PROGRAM_NAME),
5245 Gtk::MESSAGE_WARNING,
5249 msg.set_title (string_compose (_("%1 is now silent"), PROGRAM_NAME));
5251 Gtk::Label pay_label (string_compose (_("Please consider paying for a copy of %1 - you can pay whatever you want."), PROGRAM_NAME));
5252 Gtk::Label subscribe_label (_("Better yet become a subscriber - subscriptions start at US$1 per month."));
5253 Gtk::Button pay_button (_("Pay for a copy (via the web)"));
5254 Gtk::Button subscribe_button (_("Become a subscriber (via the web)"));
5255 Gtk::HBox pay_button_box;
5256 Gtk::HBox subscribe_button_box;
5258 pay_button_box.pack_start (pay_button, true, false);
5259 subscribe_button_box.pack_start (subscribe_button, true, false);
5261 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 */
5263 pay_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://ardour.org/download")));
5264 subscribe_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://community.ardour.org/s/subscribe")));
5266 msg.get_vbox()->pack_start (pay_label);
5267 msg.get_vbox()->pack_start (pay_button_box);
5268 msg.get_vbox()->pack_start (subscribe_label);
5269 msg.get_vbox()->pack_start (subscribe_button_box);
5271 msg.get_vbox()->show_all ();
5273 msg.add_button (_("Remain silent"), Gtk::RESPONSE_CANCEL);
5274 msg.add_button (_("Save and quit"), Gtk::RESPONSE_NO);
5275 msg.add_button (_("Give me more time"), Gtk::RESPONSE_YES);
5280 case Gtk::RESPONSE_YES:
5281 AudioEngine::instance()->reset_silence_countdown ();
5284 case Gtk::RESPONSE_NO:
5286 save_state_canfail ("");
5290 case Gtk::RESPONSE_CANCEL:
5292 /* don't reset, save session and exit */
5298 ARDOUR_UI::hide_application ()
5300 Application::instance ()-> hide ();
5304 ARDOUR_UI::setup_toplevel_window (Gtk::Window& window, const string& name, void* owner)
5306 /* icons, titles, WM stuff */
5308 static list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
5310 if (window_icons.empty()) {
5311 Glib::RefPtr<Gdk::Pixbuf> icon;
5312 if ((icon = ::get_icon (PROGRAM_NAME "-icon_16px")) != 0) {
5313 window_icons.push_back (icon);
5315 if ((icon = ::get_icon (PROGRAM_NAME "-icon_22px")) != 0) {
5316 window_icons.push_back (icon);
5318 if ((icon = ::get_icon (PROGRAM_NAME "-icon_32px")) != 0) {
5319 window_icons.push_back (icon);
5321 if ((icon = ::get_icon (PROGRAM_NAME "-icon_48px")) != 0) {
5322 window_icons.push_back (icon);
5326 if (!window_icons.empty()) {
5327 window.set_default_icon_list (window_icons);
5330 Gtkmm2ext::WindowTitle title (Glib::get_application_name());
5332 if (!name.empty()) {
5336 window.set_title (title.get_string());
5337 window.set_wmclass (string_compose (X_("%1_%1"), downcase (PROGRAM_NAME), downcase (name)), PROGRAM_NAME);
5339 window.set_flags (CAN_FOCUS);
5340 window.add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
5342 /* This is a hack to ensure that GTK-accelerators continue to
5343 * work. Once we switch over to entirely native bindings, this will be
5344 * unnecessary and should be removed
5346 window.add_accel_group (ActionManager::ui_manager->get_accel_group());
5348 window.signal_configure_event().connect (sigc::mem_fun (*this, &ARDOUR_UI::configure_handler));
5349 window.signal_window_state_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::tabbed_window_state_event_handler), owner));
5350 window.signal_key_press_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5351 window.signal_key_release_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5355 ARDOUR_UI::key_event_handler (GdkEventKey* ev, Gtk::Window* event_window)
5357 Gtkmm2ext::Bindings* bindings = 0;
5358 Gtk::Window* window = 0;
5360 /* until we get ardour bindings working, we are not handling key
5364 if (ev->type != GDK_KEY_PRESS) {
5368 if (event_window == &_main_window) {
5370 window = event_window;
5372 /* find current tab contents */
5374 Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page());
5376 /* see if it uses the ardour binding system */
5379 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(w->get_data ("ardour-bindings"));
5382 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("main window key event, bindings = %1, global = %2\n", bindings, &global_bindings));
5386 window = event_window;
5388 /* see if window uses ardour binding system */
5390 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(window->get_data ("ardour-bindings"));
5393 /* An empty binding set is treated as if it doesn't exist */
5395 if (bindings && bindings->empty()) {
5399 return key_press_focus_accelerator_handler (*window, ev, bindings);
5402 static Gtkmm2ext::Bindings*
5403 get_bindings_from_widget_heirarchy (GtkWidget* w)
5408 if ((p = g_object_get_data (G_OBJECT(w), "ardour-bindings")) != 0) {
5411 w = gtk_widget_get_parent (w);
5414 return reinterpret_cast<Gtkmm2ext::Bindings*> (p);
5418 ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev, Gtkmm2ext::Bindings* bindings)
5420 GtkWindow* win = window.gobj();
5421 GtkWidget* focus = gtk_window_get_focus (win);
5422 bool special_handling_of_unmodified_accelerators = false;
5423 const guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK));
5427 /* some widget has keyboard focus */
5429 if (GTK_IS_ENTRY(focus) || Keyboard::some_magic_widget_has_focus()) {
5431 /* A particular kind of focusable widget currently has keyboard
5432 * focus. All unmodified key events should go to that widget
5433 * first and not be used as an accelerator by default
5436 special_handling_of_unmodified_accelerators = true;
5440 Gtkmm2ext::Bindings* focus_bindings = get_bindings_from_widget_heirarchy (focus);
5441 if (focus_bindings) {
5442 bindings = focus_bindings;
5443 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Switch bindings based on focus widget, now using %1\n", bindings->name()));
5448 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",
5451 show_gdk_event_state (ev->state),
5452 special_handling_of_unmodified_accelerators,
5453 Keyboard::some_magic_widget_has_focus(),
5455 (focus ? gtk_widget_get_name (focus) : "no focus widget"),
5456 ((ev->state & mask) ? "yes" : "no"),
5457 window.get_title()));
5459 /* This exists to allow us to override the way GTK handles
5460 key events. The normal sequence is:
5462 a) event is delivered to a GtkWindow
5463 b) accelerators/mnemonics are activated
5464 c) if (b) didn't handle the event, propagate to
5465 the focus widget and/or focus chain
5467 The problem with this is that if the accelerators include
5468 keys without modifiers, such as the space bar or the
5469 letter "e", then pressing the key while typing into
5470 a text entry widget results in the accelerator being
5471 activated, instead of the desired letter appearing
5474 There is no good way of fixing this, but this
5475 represents a compromise. The idea is that
5476 key events involving modifiers (not Shift)
5477 get routed into the activation pathway first, then
5478 get propagated to the focus widget if necessary.
5480 If the key event doesn't involve modifiers,
5481 we deliver to the focus widget first, thus allowing
5482 it to get "normal text" without interference
5485 Of course, this can also be problematic: if there
5486 is a widget with focus, then it will swallow
5487 all "normal text" accelerators.
5491 if (!special_handling_of_unmodified_accelerators || (ev->state & mask)) {
5493 /* no special handling or there are modifiers in effect: accelerate first */
5495 DEBUG_TRACE (DEBUG::Accelerators, "\tactivate, then propagate\n");
5496 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tevent send-event:%1 time:%2 length:%3 name %7 string:%4 hardware_keycode:%5 group:%6\n",
5497 ev->send_event, ev->time, ev->length, ev->string, ev->hardware_keycode, ev->group, gdk_keyval_name (ev->keyval)));
5499 DEBUG_TRACE (DEBUG::Accelerators, "\tsending to window\n");
5500 KeyboardKey k (ev->state, ev->keyval);
5504 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tusing Ardour bindings %1 @ %2 for this event\n", bindings->name(), bindings));
5506 if (bindings->activate (k, Bindings::Press)) {
5507 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5512 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5514 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5515 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5519 DEBUG_TRACE (DEBUG::Accelerators, "\tnot accelerated, now propagate\n");
5521 if (gtk_window_propagate_key_event (win, ev)) {
5522 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate handled\n");
5528 /* no modifiers, propagate first */
5530 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate, then activate\n");
5532 if (gtk_window_propagate_key_event (win, ev)) {
5533 DEBUG_TRACE (DEBUG::Accelerators, "\thandled by propagate\n");
5537 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagation didn't handle, so activate\n");
5538 KeyboardKey k (ev->state, ev->keyval);
5542 DEBUG_TRACE (DEBUG::Accelerators, "\tusing Ardour bindings for this window\n");
5545 if (bindings->activate (k, Bindings::Press)) {
5546 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5552 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5554 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5555 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5560 DEBUG_TRACE (DEBUG::Accelerators, "\tnot handled\n");
5565 ARDOUR_UI::load_bindings ()
5567 if ((global_bindings = Bindings::get_bindings (X_("Global"), global_actions)) == 0) {
5568 error << _("Global keybindings are missing") << endmsg;
5573 ARDOUR_UI::cancel_solo ()
5576 if (_session->soloing()) {
5577 _session->set_solo (_session->get_routes(), false);
5578 } else if (_session->listening()) {
5579 _session->set_listen (_session->get_routes(), false);
5582 _session->clear_all_solo_state (_session->get_routes()); // safeguard, ideally this won't do anything, check the log-window