2 Copyright (C) 1999-2013 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include "gtk2ardour-config.h"
22 #include "gtk2ardour-version.h"
32 #ifndef PLATFORM_WINDOWS
33 #include <sys/resource.h>
43 #include "pbd/gstdio_compat.h"
45 #include <gtkmm/messagedialog.h>
46 #include <gtkmm/accelmap.h>
48 #include "pbd/error.h"
49 #include "pbd/basename.h"
50 #include "pbd/compose.h"
51 #include "pbd/convert.h"
52 #include "pbd/failed_constructor.h"
53 #include "pbd/enumwriter.h"
54 #include "pbd/memento_command.h"
55 #include "pbd/openuri.h"
56 #include "pbd/stl_delete.h"
57 #include "pbd/file_utils.h"
58 #include "pbd/localtime_r.h"
59 #include "pbd/pthread_utils.h"
60 #include "pbd/replace_all.h"
61 #include "pbd/xml++.h"
63 #include "gtkmm2ext/application.h"
64 #include "gtkmm2ext/bindings.h"
65 #include "gtkmm2ext/gtk_ui.h"
66 #include "gtkmm2ext/utils.h"
67 #include "gtkmm2ext/click_box.h"
68 #include "gtkmm2ext/fastmeter.h"
69 #include "gtkmm2ext/popup.h"
70 #include "gtkmm2ext/window_title.h"
72 #include "ardour/ardour.h"
73 #include "ardour/audio_backend.h"
74 #include "ardour/audio_track.h"
75 #include "ardour/audioengine.h"
76 #include "ardour/audiofilesource.h"
77 #include "ardour/automation_watch.h"
78 #include "ardour/diskstream.h"
79 #include "ardour/filename_extensions.h"
80 #include "ardour/filesystem_paths.h"
81 #include "ardour/ltc_file_reader.h"
82 #include "ardour/midi_track.h"
83 #include "ardour/port.h"
84 #include "ardour/plugin_manager.h"
85 #include "ardour/process_thread.h"
86 #include "ardour/profile.h"
87 #include "ardour/recent_sessions.h"
88 #include "ardour/session_directory.h"
89 #include "ardour/session_route.h"
90 #include "ardour/session_state_utils.h"
91 #include "ardour/session_utils.h"
92 #include "ardour/source_factory.h"
93 #include "ardour/slave.h"
94 #include "ardour/system_exec.h"
95 #include "ardour/vca_manager.h"
97 #include "LuaBridge/LuaBridge.h"
99 #ifdef WINDOWS_VST_SUPPORT
102 #ifdef AUDIOUNIT_SUPPORT
103 #include "ardour/audio_unit.h"
106 // fix for OSX (nsm.h has a check function, AU/Apple defines check)
111 #include "timecode/time.h"
113 typedef uint64_t microseconds_t;
118 #include "add_route_dialog.h"
119 #include "ambiguous_file_dialog.h"
120 #include "ardour_ui.h"
121 #include "audio_clock.h"
122 #include "audio_region_view.h"
123 #include "big_clock_window.h"
124 #include "bundle_manager.h"
125 #include "duplicate_routes_dialog.h"
127 #include "engine_dialog.h"
128 #include "export_video_dialog.h"
129 #include "export_video_infobox.h"
130 #include "gain_meter.h"
131 #include "global_port_matrix.h"
132 #include "gui_object.h"
133 #include "gui_thread.h"
134 #include "keyboard.h"
135 #include "keyeditor.h"
136 #include "location_ui.h"
137 #include "lua_script_manager.h"
138 #include "luawindow.h"
139 #include "main_clock.h"
140 #include "missing_file_dialog.h"
141 #include "missing_plugin_dialog.h"
142 #include "mixer_ui.h"
143 #include "meterbridge.h"
144 #include "mouse_cursors.h"
147 #include "pingback.h"
148 #include "processor_box.h"
149 #include "prompter.h"
150 #include "public_editor.h"
151 #include "rc_option_editor.h"
152 #include "route_time_axis.h"
153 #include "route_params_ui.h"
154 #include "save_as_dialog.h"
155 #include "script_selector.h"
156 #include "session_dialog.h"
157 #include "session_metadata_dialog.h"
158 #include "session_option_editor.h"
159 #include "shuttle_control.h"
160 #include "speaker_dialog.h"
163 #include "theme_manager.h"
164 #include "time_axis_view_item.h"
167 #include "video_server_dialog.h"
168 #include "add_video_dialog.h"
169 #include "transcode_video_dialog.h"
173 using namespace ARDOUR;
174 using namespace ARDOUR_UI_UTILS;
176 using namespace Gtkmm2ext;
179 using namespace Editing;
181 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
183 sigc::signal<void, framepos_t, bool, framepos_t> ARDOUR_UI::Clock;
184 sigc::signal<void> ARDOUR_UI::CloseAllDialogs;
187 ask_about_configuration_copy (string const & old_dir, string const & new_dir, int version)
189 MessageDialog msg (string_compose (_("%1 %2.x has discovered configuration files from %1 %3.x.\n\n"
190 "Would you like these files to be copied and used for %1 %2.x?\n\n"
191 "(This will require you to restart %1.)"),
192 PROGRAM_NAME, PROGRAM_VERSION, version),
193 false, /* no markup */
196 true /* modal, though it hardly matters since it is the only window */
199 msg.set_default_response (Gtk::RESPONSE_YES);
202 return (msg.run() == Gtk::RESPONSE_YES);
206 libxml_generic_error_func (void* /* parsing_context*/,
214 vsnprintf (buf, sizeof (buf), msg, ap);
215 error << buf << endmsg;
220 libxml_structured_error_func (void* /* parsing_context*/,
228 replace_all (msg, "\n", "");
231 if (err->file && err->line) {
232 error << X_("XML error: ") << msg << " in " << err->file << " at line " << err->line;
235 error << ':' << err->int2;
240 error << X_("XML error: ") << msg << endmsg;
246 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
247 : Gtkmm2ext::UI (PROGRAM_NAME, X_("gui"), argcp, argvp)
248 , session_loaded (false)
249 , gui_object_state (new GUIObjectState)
250 , primary_clock (new MainClock (X_("primary"), X_("transport"), true ))
251 , secondary_clock (new MainClock (X_("secondary"), X_("secondary"), false))
252 , big_clock (new AudioClock (X_("bigclock"), false, "big", true, true, false, false))
254 , global_actions (X_("global"))
255 , ignore_dual_punch (false)
256 , main_window_visibility (0)
261 , _mixer_on_top (false)
262 , _initial_verbose_plugin_scan (false)
263 , first_time_engine_run (true)
264 , roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll))
265 , stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop))
266 , goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart))
267 , goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd))
268 , auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop))
269 , play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection))
270 , rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable))
271 , auto_return_button (ArdourButton::led_default_elements)
272 , follow_edits_button (ArdourButton::led_default_elements)
273 , auto_input_button (ArdourButton::led_default_elements)
274 , auditioning_alert_button (_("Audition"))
275 , solo_alert_button (_("Solo"))
276 , feedback_alert_button (_("Feedback"))
277 , error_alert_button ( ArdourButton::just_led_default_elements )
279 , editor_meter_peak_display()
280 , _numpad_locate_happening (false)
281 , _session_is_new (false)
282 , last_key_press_time (0)
286 , rc_option_editor (0)
287 , speaker_config_window (X_("speaker-config"), _("Speaker Configuration"))
288 , add_route_dialog (X_("add-routes"), _("Add Tracks/Busses"))
289 , about (X_("about"), _("About"))
290 , location_ui (X_("locations"), _("Locations"))
291 , route_params (X_("inspector"), _("Tracks and Busses"))
292 , audio_midi_setup (X_("audio-midi-setup"), _("Audio/MIDI Setup"))
293 , export_video_dialog (X_("video-export"), _("Video Export Dialog"))
294 , lua_script_window (X_("script-manager"), _("Script Manager"))
295 , session_option_editor (X_("session-options-editor"), _("Properties"), boost::bind (&ARDOUR_UI::create_session_option_editor, this))
296 , add_video_dialog (X_("add-video"), _("Add Video"), boost::bind (&ARDOUR_UI::create_add_video_dialog, this))
297 , bundle_manager (X_("bundle-manager"), _("Bundle Manager"), boost::bind (&ARDOUR_UI::create_bundle_manager, this))
298 , big_clock_window (X_("big-clock"), _("Big Clock"), boost::bind (&ARDOUR_UI::create_big_clock_window, this))
299 , audio_port_matrix (X_("audio-connection-manager"), _("Audio Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::AUDIO))
300 , midi_port_matrix (X_("midi-connection-manager"), _("MIDI Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::MIDI))
301 , key_editor (X_("key-editor"), _("Bindings Editor"), boost::bind (&ARDOUR_UI::create_key_editor, this))
302 , video_server_process (0)
304 , have_configure_timeout (false)
305 , last_configure_time (0)
307 , have_disk_speed_dialog_displayed (false)
308 , _status_bar_visibility (X_("status-bar"))
309 , _feedback_exists (false)
310 , _log_not_acknowledged (LogLevelNone)
311 , duplicate_routes_dialog (0)
312 , editor_visibility_button (S_("Window|Editor"))
313 , mixer_visibility_button (S_("Window|Mixer"))
314 , prefs_visibility_button (S_("Window|Preferences"))
316 Gtkmm2ext::init (localedir);
318 UIConfiguration::instance().post_gui_init ();
320 if (ARDOUR::handle_old_configuration_files (boost::bind (ask_about_configuration_copy, _1, _2, _3))) {
321 MessageDialog msg (string_compose (_("Your configuration files were copied. You can now restart %1."), PROGRAM_NAME), true);
323 /* configuration was modified, exit immediately */
327 if (theArdourUI == 0) {
331 /* track main window visibility */
333 main_window_visibility = new VisibilityTracker (_main_window);
335 /* stop libxml from spewing to stdout/stderr */
337 xmlSetGenericErrorFunc (this, libxml_generic_error_func);
338 xmlSetStructuredErrorFunc (this, libxml_structured_error_func);
340 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::parameter_changed));
341 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
342 UIConfiguration::instance().map_parameters (pc);
344 roll_button.set_controllable (roll_controllable);
345 stop_button.set_controllable (stop_controllable);
346 goto_start_button.set_controllable (goto_start_controllable);
347 goto_end_button.set_controllable (goto_end_controllable);
348 auto_loop_button.set_controllable (auto_loop_controllable);
349 play_selection_button.set_controllable (play_selection_controllable);
350 rec_button.set_controllable (rec_controllable);
352 roll_button.set_name ("transport button");
353 stop_button.set_name ("transport button");
354 goto_start_button.set_name ("transport button");
355 goto_end_button.set_name ("transport button");
356 auto_loop_button.set_name ("transport button");
357 play_selection_button.set_name ("transport button");
358 rec_button.set_name ("transport recenable button");
359 midi_panic_button.set_name ("transport button");
361 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
362 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
364 ARDOUR::Session::VersionMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_format_mismatch, this, _1, _2), gui_context());
366 /* handle dialog requests */
368 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
370 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
372 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
374 /* handle Audio/MIDI setup when session requires it */
376 ARDOUR::Session::AudioEngineSetupRequired.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::do_audio_midi_setup, this, _1));
378 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
380 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
382 /* handle sr mismatch with a dialog - cross-thread from engine */
383 ARDOUR::Session::NotifyAboutSampleRateMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::sr_mismatch_message, this, _1, _2), gui_context ());
385 /* handle requests to quit (coming from JACK session) */
387 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::finish, this), gui_context ());
389 /* tell the user about feedback */
391 ARDOUR::Session::FeedbackDetected.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::feedback_detected, this), gui_context ());
392 ARDOUR::Session::SuccessfulGraphSort.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::successful_graph_sort, this), gui_context ());
394 /* handle requests to deal with missing files */
396 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
398 /* and ambiguous files */
400 ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2));
402 /* also plugin scan messages */
403 ARDOUR::PluginScanMessage.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_dialog, this, _1, _2, _3), gui_context());
404 ARDOUR::PluginScanTimeout.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_timeout, this, _1), gui_context());
406 ARDOUR::GUIIdle.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::gui_idle_handler, this), gui_context());
408 Config->ParameterChanged.connect ( forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::set_flat_buttons, this), gui_context() );
411 /* lets get this party started */
413 setup_gtk_ardour_enums ();
416 SessionEvent::create_per_thread_pool ("GUI", 4096);
418 /* we like keyboards */
420 keyboard = new ArdourKeyboard(*this);
422 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
424 keyboard->set_state (*node, Stateful::loading_state_version);
427 UIConfiguration::instance().reset_dpi ();
429 TimeAxisViewItem::set_constant_heights ();
431 /* Set this up so that our window proxies can register actions */
433 ActionManager::init ();
435 /* The following must happen after ARDOUR::init() so that Config is set up */
437 const XMLNode* ui_xml = Config->extra_xml (X_("UI"));
440 key_editor.set_state (*ui_xml, 0);
441 session_option_editor.set_state (*ui_xml, 0);
442 speaker_config_window.set_state (*ui_xml, 0);
443 about.set_state (*ui_xml, 0);
444 add_route_dialog.set_state (*ui_xml, 0);
445 add_video_dialog.set_state (*ui_xml, 0);
446 route_params.set_state (*ui_xml, 0);
447 bundle_manager.set_state (*ui_xml, 0);
448 location_ui.set_state (*ui_xml, 0);
449 big_clock_window.set_state (*ui_xml, 0);
450 audio_port_matrix.set_state (*ui_xml, 0);
451 midi_port_matrix.set_state (*ui_xml, 0);
452 export_video_dialog.set_state (*ui_xml, 0);
453 lua_script_window.set_state (*ui_xml, 0);
456 /* Separate windows */
458 WM::Manager::instance().register_window (&key_editor);
459 WM::Manager::instance().register_window (&session_option_editor);
460 WM::Manager::instance().register_window (&speaker_config_window);
461 WM::Manager::instance().register_window (&about);
462 WM::Manager::instance().register_window (&add_route_dialog);
463 WM::Manager::instance().register_window (&add_video_dialog);
464 WM::Manager::instance().register_window (&route_params);
465 WM::Manager::instance().register_window (&audio_midi_setup);
466 WM::Manager::instance().register_window (&export_video_dialog);
467 WM::Manager::instance().register_window (&lua_script_window);
468 WM::Manager::instance().register_window (&bundle_manager);
469 WM::Manager::instance().register_window (&location_ui);
470 WM::Manager::instance().register_window (&big_clock_window);
471 WM::Manager::instance().register_window (&audio_port_matrix);
472 WM::Manager::instance().register_window (&midi_port_matrix);
474 /* Trigger setting up the color scheme and loading the GTK RC file */
476 UIConfiguration::instance().load_rc_file (false);
478 _process_thread = new ProcessThread ();
479 _process_thread->init ();
481 UIConfiguration::instance().DPIReset.connect (sigc::mem_fun (*this, &ARDOUR_UI::resize_text_widgets));
486 GlobalPortMatrixWindow*
487 ARDOUR_UI::create_global_port_matrix (ARDOUR::DataType type)
492 return new GlobalPortMatrixWindow (_session, type);
496 ARDOUR_UI::attach_to_engine ()
498 AudioEngine::instance()->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
499 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
503 ARDOUR_UI::engine_stopped ()
505 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
506 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
507 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
508 update_sample_rate (0);
513 ARDOUR_UI::engine_running ()
515 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
516 if (first_time_engine_run) {
518 first_time_engine_run = false;
522 _session->reset_xrun_count ();
524 update_disk_space ();
526 update_xrun_count ();
527 update_sample_rate (AudioEngine::instance()->sample_rate());
528 update_timecode_format ();
529 update_peak_thread_work ();
530 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, true);
531 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, false);
535 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
537 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
538 /* we can't rely on the original string continuing to exist when we are called
539 again in the GUI thread, so make a copy and note that we need to
542 char *copy = strdup (reason);
543 Gtkmm2ext::UI::instance()->call_slot (MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
547 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
548 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
550 update_sample_rate (0);
554 /* if the reason is a non-empty string, it means that the backend was shutdown
555 rather than just Ardour.
558 if (strlen (reason)) {
559 msgstr = string_compose (_("The audio backend was shutdown because:\n\n%1"), reason);
561 msgstr = string_compose (_("\
562 The audio backend has either been shutdown or it\n\
563 disconnected %1 because %1\n\
564 was not fast enough. Try to restart\n\
565 the audio backend and save the session."), PROGRAM_NAME);
568 MessageDialog msg (_main_window, msgstr);
569 pop_back_splash (msg);
573 free (const_cast<char*> (reason));
578 ARDOUR_UI::post_engine ()
580 /* Things to be done once (and once ONLY) after we have a backend running in the AudioEngine
582 #ifdef AUDIOUNIT_SUPPORT
584 if (AUPluginInfo::au_get_crashlog(au_msg)) {
585 popup_error(_("Audio Unit Plugin Scan Failed. Automatic AU scanning has been disabled. Please see the log window for further details."));
586 error << _("Audio Unit Plugin Scan Failed:") << endmsg;
587 info << au_msg << endmsg;
591 ARDOUR::init_post_engine ();
593 /* connect to important signals */
595 AudioEngine::instance()->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
596 AudioEngine::instance()->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
597 AudioEngine::instance()->BufferSizeChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
598 AudioEngine::instance()->Halted.connect_same_thread (halt_connection, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
599 AudioEngine::instance()->BecameSilent.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::audioengine_became_silent, this), gui_context());
601 if (setup_windows ()) {
602 throw failed_constructor ();
605 /* Do this after setup_windows (), as that's when the _status_bar_visibility is created */
606 XMLNode* n = Config->extra_xml (X_("UI"));
608 _status_bar_visibility.set_state (*n);
611 check_memory_locking();
613 /* this is the first point at which all the possible actions are
614 * available, because some of the available actions are dependent on
615 * aspects of the engine/backend.
618 if (ARDOUR_COMMAND_LINE::show_key_actions) {
621 vector<string> paths;
622 vector<string> labels;
623 vector<string> tooltips;
625 vector<Glib::RefPtr<Gtk::Action> > actions;
627 Gtkmm2ext::ActionMap::get_all_actions (paths, labels, tooltips, keys, actions);
629 vector<string>::iterator k;
630 vector<string>::iterator p;
632 for (p = paths.begin(), k = keys.begin(); p != paths.end(); ++k, ++p) {
637 cout << *p << " => " << *k << endl;
641 halt_connection.disconnect ();
642 AudioEngine::instance()->stop ();
646 /* this being a GUI and all, we want peakfiles */
648 AudioFileSource::set_build_peakfiles (true);
649 AudioFileSource::set_build_missing_peakfiles (true);
651 /* set default clock modes */
653 primary_clock->set_mode (AudioClock::Timecode);
654 secondary_clock->set_mode (AudioClock::BBT);
656 /* start the time-of-day-clock */
659 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
660 update_wall_clock ();
661 Glib::signal_timeout().connect_seconds (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 1);
666 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
667 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
668 Config->map_parameters (pc);
670 UIConfiguration::instance().map_parameters (pc);
674 ARDOUR_UI::~ARDOUR_UI ()
676 UIConfiguration::instance().save_state();
680 if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
681 // don't bother at 'real' exit. the OS cleans up for us.
682 delete big_clock; big_clock = 0;
683 delete primary_clock; primary_clock = 0;
684 delete secondary_clock; secondary_clock = 0;
685 delete _process_thread; _process_thread = 0;
686 delete meterbridge; meterbridge = 0;
687 delete luawindow; luawindow = 0;
688 delete editor; editor = 0;
689 delete mixer; mixer = 0;
691 delete gui_object_state; gui_object_state = 0;
692 delete main_window_visibility;
693 FastMeter::flush_pattern_cache ();
694 PixFader::flush_pattern_cache ();
698 /* Small trick to flush main-thread event pool.
699 * Other thread-pools are destroyed at pthread_exit(),
700 * but tmain thread termination is too late to trigger Pool::~Pool()
702 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.
703 delete ev->event_pool();
708 ARDOUR_UI::pop_back_splash (Gtk::Window& win)
710 if (Splash::instance()) {
711 Splash::instance()->pop_back_for (win);
716 ARDOUR_UI::configure_timeout ()
718 if (last_configure_time == 0) {
719 /* no configure events yet */
723 /* force a gap of 0.5 seconds since the last configure event
726 if (get_microseconds() - last_configure_time < 500000) {
729 have_configure_timeout = false;
730 save_ardour_state ();
736 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
738 if (have_configure_timeout) {
739 last_configure_time = get_microseconds();
741 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
742 have_configure_timeout = true;
749 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
751 XMLProperty const * prop;
753 if ((prop = node.property ("roll")) != 0) {
754 roll_controllable->set_id (prop->value());
756 if ((prop = node.property ("stop")) != 0) {
757 stop_controllable->set_id (prop->value());
759 if ((prop = node.property ("goto-start")) != 0) {
760 goto_start_controllable->set_id (prop->value());
762 if ((prop = node.property ("goto-end")) != 0) {
763 goto_end_controllable->set_id (prop->value());
765 if ((prop = node.property ("auto-loop")) != 0) {
766 auto_loop_controllable->set_id (prop->value());
768 if ((prop = node.property ("play-selection")) != 0) {
769 play_selection_controllable->set_id (prop->value());
771 if ((prop = node.property ("rec")) != 0) {
772 rec_controllable->set_id (prop->value());
774 if ((prop = node.property ("shuttle")) != 0) {
775 shuttle_box->controllable()->set_id (prop->value());
780 ARDOUR_UI::get_transport_controllable_state ()
782 XMLNode* node = new XMLNode(X_("TransportControllables"));
785 roll_controllable->id().print (buf, sizeof (buf));
786 node->add_property (X_("roll"), buf);
787 stop_controllable->id().print (buf, sizeof (buf));
788 node->add_property (X_("stop"), buf);
789 goto_start_controllable->id().print (buf, sizeof (buf));
790 node->add_property (X_("goto_start"), buf);
791 goto_end_controllable->id().print (buf, sizeof (buf));
792 node->add_property (X_("goto_end"), buf);
793 auto_loop_controllable->id().print (buf, sizeof (buf));
794 node->add_property (X_("auto_loop"), buf);
795 play_selection_controllable->id().print (buf, sizeof (buf));
796 node->add_property (X_("play_selection"), buf);
797 rec_controllable->id().print (buf, sizeof (buf));
798 node->add_property (X_("rec"), buf);
799 shuttle_box->controllable()->id().print (buf, sizeof (buf));
800 node->add_property (X_("shuttle"), buf);
806 ARDOUR_UI::save_session_at_its_request (std::string snapshot_name)
809 _session->save_state (snapshot_name);
814 ARDOUR_UI::autosave_session ()
816 if (g_main_depth() > 1) {
817 /* inside a recursive main loop,
818 give up because we may not be able to
824 if (!Config->get_periodic_safety_backups()) {
829 _session->maybe_write_autosave();
836 ARDOUR_UI::session_dirty_changed ()
843 ARDOUR_UI::update_autosave ()
845 if (_session && _session->dirty()) {
846 if (_autosave_connection.connected()) {
847 _autosave_connection.disconnect();
850 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
851 Config->get_periodic_safety_backup_interval() * 1000);
854 if (_autosave_connection.connected()) {
855 _autosave_connection.disconnect();
861 ARDOUR_UI::check_announcements ()
864 string _annc_filename;
867 _annc_filename = PROGRAM_NAME "_announcements_osx_";
868 #elif defined PLATFORM_WINDOWS
869 _annc_filename = PROGRAM_NAME "_announcements_windows_";
871 _annc_filename = PROGRAM_NAME "_announcements_linux_";
873 _annc_filename.append (VERSIONSTRING);
875 _announce_string = "";
877 std::string path = Glib::build_filename (user_config_directory(), _annc_filename);
878 FILE* fin = g_fopen (path.c_str(), "rb");
880 while (!feof (fin)) {
883 if ((len = fread (tmp, sizeof(char), 1024, fin)) == 0 || ferror (fin)) {
886 _announce_string.append (tmp, len);
891 pingback (VERSIONSTRING, path);
896 _hide_splash (gpointer arg)
898 ((ARDOUR_UI*)arg)->hide_splash();
903 ARDOUR_UI::starting ()
905 Application* app = Application::instance ();
907 bool brand_new_user = ArdourStartup::required ();
909 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
910 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::load_from_application_api));
912 if (ARDOUR_COMMAND_LINE::check_announcements) {
913 check_announcements ();
918 /* we need to create this early because it may need to set the
919 * audio backend end up.
923 audio_midi_setup.get (true);
925 std::cerr << "audio-midi engine setup failed."<< std::endl;
929 if ((nsm_url = g_getenv ("NSM_URL")) != 0) {
930 nsm = new NSM_Client;
931 if (!nsm->init (nsm_url)) {
932 /* the ardour executable may have different names:
934 * waf's obj.target for distro versions: eg ardour4, ardourvst4
935 * Ardour4, Mixbus3 for bundled versions + full path on OSX & windows
936 * argv[0] does not apply since we need the wrapper-script (not the binary itself)
938 * The wrapper startup script should set the environment variable 'ARDOUR_SELF'
940 const char *process_name = g_getenv ("ARDOUR_SELF");
941 nsm->announce (PROGRAM_NAME, ":dirty:", process_name ? process_name : "ardour4");
944 // wait for announce reply from nsm server
945 for ( i = 0; i < 5000; ++i) {
949 if (nsm->is_active()) {
954 error << _("NSM server did not announce itself") << endmsg;
957 // wait for open command from nsm server
958 for ( i = 0; i < 5000; ++i) {
961 if (nsm->client_id ()) {
967 error << _("NSM: no client ID provided") << endmsg;
971 if (_session && nsm) {
972 _session->set_nsm_state( nsm->is_active() );
974 error << _("NSM: no session created") << endmsg;
978 // nsm requires these actions disabled
979 vector<string> action_names;
980 action_names.push_back("SaveAs");
981 action_names.push_back("Rename");
982 action_names.push_back("New");
983 action_names.push_back("Open");
984 action_names.push_back("Recent");
985 action_names.push_back("Close");
987 for (vector<string>::const_iterator n = action_names.begin(); n != action_names.end(); ++n) {
988 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), (*n).c_str());
990 act->set_sensitive (false);
997 error << _("NSM: initialization failed") << endmsg;
1003 if (brand_new_user) {
1004 _initial_verbose_plugin_scan = true;
1009 _initial_verbose_plugin_scan = false;
1010 switch (s.response ()) {
1011 case Gtk::RESPONSE_OK:
1018 #ifdef NO_PLUGIN_STATE
1020 ARDOUR::RecentSessions rs;
1021 ARDOUR::read_recent_sessions (rs);
1023 string path = Glib::build_filename (user_config_directory(), ".iknowaboutfreeversion");
1025 if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS) && !rs.empty()) {
1027 /* already used Ardour, have sessions ... warn about plugin state */
1029 ArdourDialog d (_("Free/Demo Version Warning"), true);
1031 Button b (string_compose (_("Subscribe and support development of %1"), PROGRAM_NAME));
1032 CheckButton c (_("Don't warn me about this again"));
1034 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"),
1035 string_compose (_("This is a free/demo version of %1"), PROGRAM_NAME),
1036 _("It will not restore OR save any plugin settings"),
1037 _("If you load an existing session with plugin settings\n"
1038 "they will not be used and will be lost."),
1039 _("To get full access to updates without this limitation\n"
1040 "consider becoming a subscriber for a low cost every month.")));
1041 l.set_justify (JUSTIFY_CENTER);
1043 b.signal_clicked().connect (mem_fun(*this, &ARDOUR_UI::launch_subscribe));
1045 d.get_vbox()->pack_start (l, true, true);
1046 d.get_vbox()->pack_start (b, false, false, 12);
1047 d.get_vbox()->pack_start (c, false, false, 12);
1049 d.add_button (_("Quit now"), RESPONSE_CANCEL);
1050 d.add_button (string_compose (_("Continue using %1"), PROGRAM_NAME), RESPONSE_OK);
1054 c.signal_toggled().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (toggle_file_existence), path)));
1056 if (d.run () != RESPONSE_OK) {
1062 /* go get a session */
1064 const bool new_session_required = (ARDOUR_COMMAND_LINE::new_session || brand_new_user);
1066 if (get_session_parameters (false, new_session_required, ARDOUR_COMMAND_LINE::load_template)) {
1067 std::cerr << "Cannot get session parameters."<< std::endl;
1074 WM::Manager::instance().show_visible ();
1076 /* We have to do this here since goto_editor_window() ends up calling show_all() on the
1077 * editor window, and we may want stuff to be hidden.
1079 _status_bar_visibility.update ();
1081 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
1083 if (splash && splash->is_visible()) {
1084 // in 1 second, hide the splash screen
1085 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
1088 /* all other dialogs are created conditionally */
1094 ARDOUR_UI::check_memory_locking ()
1096 #if defined(__APPLE__) || defined(PLATFORM_WINDOWS)
1097 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
1101 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
1103 if (AudioEngine::instance()->is_realtime() && memory_warning_node == 0) {
1105 struct rlimit limits;
1107 long pages, page_size;
1109 size_t pages_len=sizeof(pages);
1110 if ((page_size = getpagesize()) < 0 ||
1111 sysctlbyname("hw.availpages", &pages, &pages_len, NULL, 0))
1113 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0)
1118 ram = (int64_t) pages * (int64_t) page_size;
1121 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
1125 if (limits.rlim_cur != RLIM_INFINITY) {
1127 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
1131 _("WARNING: Your system has a limit for maximum amount of locked memory. "
1132 "This might cause %1 to run out of memory before your system "
1133 "runs out of memory. \n\n"
1134 "You can view the memory limit with 'ulimit -l', "
1135 "and it is normally controlled by %2"),
1138 X_("/etc/login.conf")
1140 X_(" /etc/security/limits.conf")
1144 msg.set_default_response (RESPONSE_OK);
1146 VBox* vbox = msg.get_vbox();
1148 CheckButton cb (_("Do not show this window again"));
1149 hbox.pack_start (cb, true, false);
1150 vbox->pack_start (hbox);
1155 pop_back_splash (msg);
1159 if (cb.get_active()) {
1160 XMLNode node (X_("no-memory-warning"));
1161 Config->add_instant_xml (node);
1166 #endif // !__APPLE__
1171 ARDOUR_UI::queue_finish ()
1173 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
1177 ARDOUR_UI::idle_finish ()
1180 return false; /* do not call again */
1187 ARDOUR_UI::instance()->video_timeline->sync_session_state();
1189 if (_session->dirty()) {
1190 vector<string> actions;
1191 actions.push_back (_("Don't quit"));
1192 actions.push_back (_("Just quit"));
1193 actions.push_back (_("Save and quit"));
1194 switch (ask_about_saving_session(actions)) {
1199 /* use the default name */
1200 if (save_state_canfail ("")) {
1201 /* failed - don't quit */
1202 MessageDialog msg (_main_window,
1203 string_compose (_("\
1204 %1 was unable to save your session.\n\n\
1205 If you still wish to quit, please use the\n\n\
1206 \"Just quit\" option."), PROGRAM_NAME));
1207 pop_back_splash(msg);
1217 second_connection.disconnect ();
1218 point_one_second_connection.disconnect ();
1219 point_zero_something_second_connection.disconnect();
1220 fps_connection.disconnect();
1223 delete ARDOUR_UI::instance()->video_timeline;
1224 ARDOUR_UI::instance()->video_timeline = NULL;
1225 stop_video_server();
1227 /* Save state before deleting the session, as that causes some
1228 windows to be destroyed before their visible state can be
1231 save_ardour_state ();
1233 close_all_dialogs ();
1236 _session->set_clean ();
1237 _session->remove_pending_capture_state ();
1242 halt_connection.disconnect ();
1243 AudioEngine::instance()->stop ();
1244 #ifdef WINDOWS_VST_SUPPORT
1245 fst_stop_threading();
1251 ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
1253 ArdourDialog window (_("Unsaved Session"));
1254 Gtk::HBox dhbox; // the hbox for the image and text
1255 Gtk::Label prompt_label;
1256 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
1260 assert (actions.size() >= 3);
1262 window.add_button (actions[0], RESPONSE_REJECT);
1263 window.add_button (actions[1], RESPONSE_APPLY);
1264 window.add_button (actions[2], RESPONSE_ACCEPT);
1266 window.set_default_response (RESPONSE_ACCEPT);
1268 Gtk::Button noquit_button (msg);
1269 noquit_button.set_name ("EditorGTKButton");
1273 if (_session->snap_name() == _session->name()) {
1274 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?"),
1275 _session->snap_name());
1277 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?"),
1278 _session->snap_name());
1281 prompt_label.set_text (prompt);
1282 prompt_label.set_name (X_("PrompterLabel"));
1283 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
1285 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
1286 dhbox.set_homogeneous (false);
1287 dhbox.pack_start (*dimage, false, false, 5);
1288 dhbox.pack_start (prompt_label, true, false, 5);
1289 window.get_vbox()->pack_start (dhbox);
1291 window.set_name (_("Prompter"));
1292 window.set_modal (true);
1293 window.set_resizable (false);
1296 prompt_label.show();
1301 ResponseType r = (ResponseType) window.run();
1306 case RESPONSE_ACCEPT: // save and get out of here
1308 case RESPONSE_APPLY: // get out of here
1319 ARDOUR_UI::every_second ()
1322 update_xrun_count ();
1323 update_buffer_load ();
1324 update_disk_space ();
1325 update_timecode_format ();
1326 update_peak_thread_work ();
1328 if (nsm && nsm->is_active ()) {
1331 if (!_was_dirty && _session->dirty ()) {
1335 else if (_was_dirty && !_session->dirty ()){
1343 ARDOUR_UI::every_point_one_seconds ()
1345 // TODO get rid of this..
1346 // ShuttleControl is updated directly via TransportStateChange signal
1350 ARDOUR_UI::every_point_zero_something_seconds ()
1352 // august 2007: actual update frequency: 25Hz (40ms), not 100Hz
1354 if (editor_meter && UIConfiguration::instance().get_show_editor_meter()) {
1355 float mpeak = editor_meter->update_meters();
1356 if (mpeak > editor_meter_max_peak) {
1357 if (mpeak >= UIConfiguration::instance().get_meter_peak()) {
1358 editor_meter_peak_display.set_active_state ( Gtkmm2ext::ExplicitActive );
1365 ARDOUR_UI::set_fps_timeout_connection ()
1367 unsigned int interval = 40;
1368 if (!_session) return;
1369 if (_session->timecode_frames_per_second() != 0) {
1370 /* ideally we'll use a select() to sleep and not accumulate
1371 * idle time to provide a regular periodic signal.
1372 * See linux_vst_gui_support.cc 'elapsed_time_ms'.
1373 * However, that'll require a dedicated thread and cross-thread
1374 * signals to the GUI Thread..
1376 interval = floor(500. /* update twice per FPS, since Glib::signal_timeout is very irregular */
1377 * _session->frame_rate() / _session->nominal_frame_rate()
1378 / _session->timecode_frames_per_second()
1380 #ifdef PLATFORM_WINDOWS
1381 // the smallest windows scheduler time-slice is ~15ms.
1382 // periodic GUI timeouts shorter than that will cause
1383 // WaitForSingleObject to spinlock (100% of one CPU Core)
1384 // and gtk never enters idle mode.
1385 // also changing timeBeginPeriod(1) does not affect that in
1386 // any beneficial way, so we just limit the max rate for now.
1387 interval = std::max(30u, interval); // at most ~33Hz.
1389 interval = std::max(8u, interval); // at most 120Hz.
1392 fps_connection.disconnect();
1393 Timers::set_fps_interval (interval);
1397 ARDOUR_UI::update_sample_rate (framecnt_t)
1401 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
1403 if (!AudioEngine::instance()->connected()) {
1405 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1409 framecnt_t rate = AudioEngine::instance()->sample_rate();
1412 /* no sample rate available */
1413 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1416 if (fmod (rate, 1000.0) != 0.0) {
1417 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
1418 (float) rate / 1000.0f,
1419 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1421 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
1423 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1427 sample_rate_label.set_markup (buf);
1431 ARDOUR_UI::update_format ()
1434 format_label.set_text ("");
1439 s << _("File:") << X_(" <span foreground=\"green\">");
1441 switch (_session->config.get_native_file_header_format ()) {
1473 switch (_session->config.get_native_file_data_format ()) {
1487 format_label.set_markup (s.str ());
1491 ARDOUR_UI::update_xrun_count ()
1495 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1496 should also be changed.
1500 const unsigned int x = _session->get_xrun_count ();
1502 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">>10K</span>"), X_("red"));
1504 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">%u</span>"), x > 0 ? X_("red") : X_("green"), x);
1507 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">?</span>"), X_("yellow"));
1509 xrun_label.set_markup (buf);
1510 set_tip (xrun_label, _("Audio dropouts. Shift+click to reset"));
1514 ARDOUR_UI::update_cpu_load ()
1518 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1519 should also be changed.
1522 double const c = AudioEngine::instance()->get_dsp_load ();
1523 snprintf (buf, sizeof (buf), _("DSP: <span foreground=\"%s\">%5.1f%%</span>"), c >= 90 ? X_("red") : X_("green"), c);
1524 cpu_load_label.set_markup (buf);
1528 ARDOUR_UI::update_peak_thread_work ()
1531 const int c = SourceFactory::peak_work_queue_length ();
1533 snprintf (buf, sizeof (buf), _("PkBld: <span foreground=\"%s\">%d</span>"), c >= 2 ? X_("red") : X_("green"), c);
1534 peak_thread_work_label.set_markup (buf);
1536 peak_thread_work_label.set_markup (X_(""));
1541 ARDOUR_UI::update_buffer_load ()
1545 uint32_t const playback = _session ? _session->playback_load () : 100;
1546 uint32_t const capture = _session ? _session->capture_load () : 100;
1548 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1549 should also be changed.
1555 _("Buffers: <span foreground=\"green\">p:</span><span foreground=\"%s\">%" PRIu32 "%%</span> "
1556 "<span foreground=\"green\">c:</span><span foreground=\"%s\">%" PRIu32 "%%</span>"),
1557 playback <= 5 ? X_("red") : X_("green"),
1559 capture <= 5 ? X_("red") : X_("green"),
1563 buffer_load_label.set_markup (buf);
1565 buffer_load_label.set_text ("");
1570 ARDOUR_UI::count_recenabled_streams (Route& route)
1572 Track* track = dynamic_cast<Track*>(&route);
1573 if (track && track->record_enabled()) {
1574 rec_enabled_streams += track->n_inputs().n_total();
1579 ARDOUR_UI::update_disk_space()
1581 if (_session == 0) {
1585 boost::optional<framecnt_t> opt_frames = _session->available_capture_duration();
1587 framecnt_t fr = _session->frame_rate();
1590 /* skip update - no SR available */
1595 /* Available space is unknown */
1596 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">Unknown</span>"));
1597 } else if (opt_frames.get_value_or (0) == max_framecnt) {
1598 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">24hrs+</span>"));
1600 rec_enabled_streams = 0;
1601 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams, false);
1603 framecnt_t frames = opt_frames.get_value_or (0);
1605 if (rec_enabled_streams) {
1606 frames /= rec_enabled_streams;
1613 hrs = frames / (fr * 3600);
1616 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">>24 hrs</span>"));
1618 frames -= hrs * fr * 3600;
1619 mins = frames / (fr * 60);
1620 frames -= mins * fr * 60;
1623 bool const low = (hrs == 0 && mins <= 30);
1627 _("Disk: <span foreground=\"%s\">%02dh:%02dm:%02ds</span>"),
1628 low ? X_("red") : X_("green"),
1634 disk_space_label.set_markup (buf);
1638 ARDOUR_UI::update_timecode_format ()
1644 TimecodeSlave* tcslave;
1645 SyncSource sync_src = Config->get_sync_source();
1647 if ((sync_src == LTC || sync_src == MTC) && (tcslave = dynamic_cast<TimecodeSlave*>(_session->slave())) != 0) {
1648 matching = (tcslave->apparent_timecode_format() == _session->config.get_timecode_format());
1653 snprintf (buf, sizeof (buf), S_("Timecode|TC: <span foreground=\"%s\">%s</span>"),
1654 matching ? X_("green") : X_("red"),
1655 Timecode::timecode_format_name (_session->config.get_timecode_format()).c_str());
1657 snprintf (buf, sizeof (buf), "TC: n/a");
1660 timecode_format_label.set_markup (buf);
1664 ARDOUR_UI::update_wall_clock ()
1668 static int last_min = -1;
1671 tm_now = localtime (&now);
1672 if (last_min != tm_now->tm_min) {
1674 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1675 wall_clock_label.set_text (buf);
1676 last_min = tm_now->tm_min;
1683 ARDOUR_UI::open_recent_session ()
1685 bool can_return = (_session != 0);
1687 SessionDialog recent_session_dialog;
1691 ResponseType r = (ResponseType) recent_session_dialog.run ();
1694 case RESPONSE_ACCEPT:
1698 recent_session_dialog.hide();
1705 recent_session_dialog.hide();
1709 std::string path = recent_session_dialog.session_folder();
1710 std::string state = recent_session_dialog.session_name (should_be_new);
1712 if (should_be_new == true) {
1716 _session_is_new = false;
1718 if (load_session (path, state) == 0) {
1724 if (splash && splash->is_visible()) {
1725 // in 1 second, hide the splash screen
1726 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
1731 ARDOUR_UI::check_audioengine (Gtk::Window& parent)
1733 if (!AudioEngine::instance()->connected()) {
1734 MessageDialog msg (parent, string_compose (
1735 _("%1 is not connected to any audio backend.\n"
1736 "You cannot open or close sessions in this condition"),
1738 pop_back_splash (msg);
1746 ARDOUR_UI::open_session ()
1748 if (!check_audioengine (_main_window)) {
1752 /* ardour sessions are folders */
1753 Gtk::FileChooserDialog open_session_selector(_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1754 open_session_selector.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1755 open_session_selector.add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1756 open_session_selector.set_default_response(Gtk::RESPONSE_ACCEPT);
1759 string session_parent_dir = Glib::path_get_dirname(_session->path());
1760 open_session_selector.set_current_folder(session_parent_dir);
1762 open_session_selector.set_current_folder(Config->get_default_session_parent_dir());
1765 Gtkmm2ext::add_volume_shortcuts (open_session_selector);
1767 /* add_shortcut_folder throws an exception if the folder being added already has a shortcut */
1768 string default_session_folder = Config->get_default_session_parent_dir();
1769 open_session_selector.add_shortcut_folder (default_session_folder);
1771 catch (Glib::Error & e) {
1772 std::cerr << "open_session_selector.add_shortcut_folder() threw Glib::Error " << e.what() << std::endl;
1775 FileFilter session_filter;
1776 session_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::statefile_suffix));
1777 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1778 open_session_selector.add_filter (session_filter);
1779 open_session_selector.set_filter (session_filter);
1781 int response = open_session_selector.run();
1782 open_session_selector.hide ();
1784 if (response == Gtk::RESPONSE_CANCEL) {
1788 string session_path = open_session_selector.get_filename();
1792 if (session_path.length() > 0) {
1793 if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1794 _session_is_new = isnew;
1795 load_session (path, name);
1801 ARDOUR_UI::session_add_vca (const string& name_template)
1807 _session->vca_manager().create_vca (name_template);
1811 ARDOUR_UI::session_add_mixed_track (
1812 const ChanCount& input,
1813 const ChanCount& output,
1814 RouteGroup* route_group,
1816 const string& name_template,
1818 PluginInfoPtr instrument,
1819 Plugin::PresetRecord* pset)
1821 list<boost::shared_ptr<MidiTrack> > tracks;
1823 if (_session == 0) {
1824 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1829 tracks = _session->new_midi_track (input, output, instrument, ARDOUR::Normal, route_group, how_many, name_template, pset);
1831 if (tracks.size() != how_many) {
1832 error << string_compose(P_("could not create %1 new mixed track", "could not create %1 new mixed tracks", how_many), how_many) << endmsg;
1837 display_insufficient_ports_message ();
1842 for (list<boost::shared_ptr<MidiTrack> >::iterator i = tracks.begin(); i != tracks.end(); ++i) {
1843 (*i)->set_strict_io (true);
1849 ARDOUR_UI::session_add_midi_bus (
1850 RouteGroup* route_group,
1852 const string& name_template,
1854 PluginInfoPtr instrument,
1855 Plugin::PresetRecord* pset)
1859 if (_session == 0) {
1860 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1865 routes = _session->new_midi_route (route_group, how_many, name_template, instrument, pset);
1866 if (routes.size() != how_many) {
1867 error << string_compose(P_("could not create %1 new Midi Bus", "could not create %1 new Midi Busses", how_many), how_many) << endmsg;
1872 display_insufficient_ports_message ();
1877 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
1878 (*i)->set_strict_io (true);
1884 ARDOUR_UI::session_add_midi_route (
1886 RouteGroup* route_group,
1888 const string& name_template,
1890 PluginInfoPtr instrument,
1891 Plugin::PresetRecord* pset)
1893 ChanCount one_midi_channel;
1894 one_midi_channel.set (DataType::MIDI, 1);
1897 session_add_mixed_track (one_midi_channel, one_midi_channel, route_group, how_many, name_template, strict_io, instrument, pset);
1899 session_add_midi_bus (route_group, how_many, name_template, strict_io, instrument, pset);
1904 ARDOUR_UI::session_add_audio_route (
1906 int32_t input_channels,
1907 int32_t output_channels,
1908 ARDOUR::TrackMode mode,
1909 RouteGroup* route_group,
1911 string const & name_template,
1915 list<boost::shared_ptr<AudioTrack> > tracks;
1918 if (_session == 0) {
1919 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1925 tracks = _session->new_audio_track (input_channels, output_channels, mode, route_group, how_many, name_template);
1927 if (tracks.size() != how_many) {
1928 error << string_compose (P_("could not create %1 new audio track", "could not create %1 new audio tracks", how_many), how_many)
1934 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template);
1936 if (routes.size() != how_many) {
1937 error << string_compose (P_("could not create %1 new audio bus", "could not create %1 new audio busses", how_many), how_many)
1944 display_insufficient_ports_message ();
1949 for (list<boost::shared_ptr<AudioTrack> >::iterator i = tracks.begin(); i != tracks.end(); ++i) {
1950 (*i)->set_strict_io (true);
1952 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
1953 (*i)->set_strict_io (true);
1959 ARDOUR_UI::display_insufficient_ports_message ()
1961 MessageDialog msg (_main_window,
1962 string_compose (_("There are insufficient ports available\n\
1963 to create a new track or bus.\n\
1964 You should save %1, exit and\n\
1965 restart with more ports."), PROGRAM_NAME));
1966 pop_back_splash (msg);
1971 ARDOUR_UI::transport_goto_start ()
1974 _session->goto_start();
1976 /* force displayed area in editor to start no matter
1977 what "follow playhead" setting is.
1981 editor->center_screen (_session->current_start_frame ());
1987 ARDOUR_UI::transport_goto_zero ()
1990 _session->request_locate (0);
1992 /* force displayed area in editor to start no matter
1993 what "follow playhead" setting is.
1997 editor->reset_x_origin (0);
2003 ARDOUR_UI::transport_goto_wallclock ()
2005 if (_session && editor) {
2012 localtime_r (&now, &tmnow);
2014 framecnt_t frame_rate = _session->frame_rate();
2016 if (frame_rate == 0) {
2017 /* no frame rate available */
2021 frames = tmnow.tm_hour * (60 * 60 * frame_rate);
2022 frames += tmnow.tm_min * (60 * frame_rate);
2023 frames += tmnow.tm_sec * frame_rate;
2025 _session->request_locate (frames, _session->transport_rolling ());
2027 /* force displayed area in editor to start no matter
2028 what "follow playhead" setting is.
2032 editor->center_screen (frames);
2038 ARDOUR_UI::transport_goto_end ()
2041 framepos_t const frame = _session->current_end_frame();
2042 _session->request_locate (frame);
2044 /* force displayed area in editor to start no matter
2045 what "follow playhead" setting is.
2049 editor->center_screen (frame);
2055 ARDOUR_UI::transport_stop ()
2061 if (_session->is_auditioning()) {
2062 _session->cancel_audition ();
2066 _session->request_stop (false, true);
2069 /** Check if any tracks are record enabled. If none are, record enable all of them.
2070 * @return true if track record-enabled status was changed, false otherwise.
2073 ARDOUR_UI::trx_record_enable_all_tracks ()
2079 boost::shared_ptr<RouteList> rl = _session->get_tracks ();
2080 bool none_record_enabled = true;
2082 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
2083 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*r);
2086 if (t->record_enabled()) {
2087 none_record_enabled = false;
2092 if (none_record_enabled) {
2093 _session->set_record_enabled (rl, true, Session::rt_cleanup);
2096 return none_record_enabled;
2100 ARDOUR_UI::transport_record (bool roll)
2103 switch (_session->record_status()) {
2104 case Session::Disabled:
2105 if (_session->ntracks() == 0) {
2106 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."));
2110 if (Profile->get_trx()) {
2111 roll = trx_record_enable_all_tracks ();
2113 _session->maybe_enable_record ();
2118 case Session::Recording:
2120 _session->request_stop();
2122 _session->disable_record (false, true);
2126 case Session::Enabled:
2127 _session->disable_record (false, true);
2133 ARDOUR_UI::transport_roll ()
2139 if (_session->is_auditioning()) {
2144 if (_session->config.get_external_sync()) {
2145 switch (Config->get_sync_source()) {
2149 /* transport controlled by the master */
2155 bool rolling = _session->transport_rolling();
2157 if (_session->get_play_loop()) {
2159 /* If loop playback is not a mode, then we should cancel
2160 it when this action is requested. If it is a mode
2161 we just leave it in place.
2164 if (!Config->get_loop_is_mode()) {
2165 /* XXX it is not possible to just leave seamless loop and keep
2166 playing at present (nov 4th 2009)
2168 if (!Config->get_seamless_loop()) {
2169 /* stop loop playback and stop rolling */
2170 _session->request_play_loop (false, true);
2171 } else if (rolling) {
2172 /* stop loop playback but keep rolling */
2173 _session->request_play_loop (false, false);
2177 } else if (_session->get_play_range () ) {
2178 /* stop playing a range if we currently are */
2179 _session->request_play_range (0, true);
2183 _session->request_transport_speed (1.0f);
2188 ARDOUR_UI::get_smart_mode() const
2190 return ( editor->get_smart_mode() );
2195 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
2201 if (_session->is_auditioning()) {
2202 _session->cancel_audition ();
2206 if (_session->config.get_external_sync()) {
2207 switch (Config->get_sync_source()) {
2211 /* transport controlled by the master */
2216 bool rolling = _session->transport_rolling();
2217 bool affect_transport = true;
2219 if (rolling && roll_out_of_bounded_mode) {
2220 /* drop out of loop/range playback but leave transport rolling */
2221 if (_session->get_play_loop()) {
2222 if (_session->actively_recording()) {
2224 /* just stop using the loop, then actually stop
2227 _session->request_play_loop (false, affect_transport);
2230 if (Config->get_seamless_loop()) {
2231 /* the disk buffers contain copies of the loop - we can't
2232 just keep playing, so stop the transport. the user
2233 can restart as they wish.
2235 affect_transport = true;
2237 /* disk buffers are normal, so we can keep playing */
2238 affect_transport = false;
2240 _session->request_play_loop (false, affect_transport);
2242 } else if (_session->get_play_range ()) {
2243 affect_transport = false;
2244 _session->request_play_range (0, true);
2248 if (affect_transport) {
2250 _session->request_stop (with_abort, true);
2252 /* the only external sync condition we can be in here
2253 * would be Engine (JACK) sync, in which case we still
2257 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
2258 _session->request_play_range (&editor->get_selection().time, true);
2259 _session->set_requested_return_frame( editor->get_selection().time.front().start ); //force an auto-return here
2261 _session->request_transport_speed (1.0f);
2267 ARDOUR_UI::toggle_session_auto_loop ()
2273 Location * looploc = _session->locations()->auto_loop_location();
2279 if (_session->get_play_loop()) {
2281 /* looping enabled, our job is to disable it */
2283 _session->request_play_loop (false);
2287 /* looping not enabled, our job is to enable it.
2289 loop-is-NOT-mode: this action always starts the transport rolling.
2290 loop-IS-mode: this action simply sets the loop play mechanism, but
2291 does not start transport.
2293 if (Config->get_loop_is_mode()) {
2294 _session->request_play_loop (true, false);
2296 _session->request_play_loop (true, true);
2300 //show the loop markers
2301 looploc->set_hidden (false, this);
2305 ARDOUR_UI::transport_play_selection ()
2311 editor->play_selection ();
2315 ARDOUR_UI::transport_play_preroll ()
2320 editor->play_with_preroll ();
2324 ARDOUR_UI::transport_rewind (int option)
2326 float current_transport_speed;
2329 current_transport_speed = _session->transport_speed();
2331 if (current_transport_speed >= 0.0f) {
2334 _session->request_transport_speed (-1.0f);
2337 _session->request_transport_speed (-4.0f);
2340 _session->request_transport_speed (-0.5f);
2345 _session->request_transport_speed (current_transport_speed * 1.5f);
2351 ARDOUR_UI::transport_forward (int option)
2357 float current_transport_speed = _session->transport_speed();
2359 if (current_transport_speed <= 0.0f) {
2362 _session->request_transport_speed (1.0f);
2365 _session->request_transport_speed (4.0f);
2368 _session->request_transport_speed (0.5f);
2373 _session->request_transport_speed (current_transport_speed * 1.5f);
2378 ARDOUR_UI::toggle_record_enable (uint32_t rid)
2384 boost::shared_ptr<Route> r;
2386 if ((r = _session->route_by_remote_id (rid)) != 0) {
2388 boost::shared_ptr<Track> t;
2390 if ((t = boost::dynamic_pointer_cast<Track>(r)) != 0) {
2391 t->set_record_enabled (!t->record_enabled(), Controllable::UseGroup);
2397 ARDOUR_UI::map_transport_state ()
2400 auto_loop_button.unset_active_state ();
2401 play_selection_button.unset_active_state ();
2402 roll_button.unset_active_state ();
2403 stop_button.set_active_state (Gtkmm2ext::ExplicitActive);
2407 shuttle_box->map_transport_state ();
2409 float sp = _session->transport_speed();
2415 if (_session->get_play_range()) {
2417 play_selection_button.set_active_state (Gtkmm2ext::ExplicitActive);
2418 roll_button.unset_active_state ();
2419 auto_loop_button.unset_active_state ();
2421 } else if (_session->get_play_loop ()) {
2423 auto_loop_button.set_active (true);
2424 play_selection_button.set_active (false);
2425 if (Config->get_loop_is_mode()) {
2426 roll_button.set_active (true);
2428 roll_button.set_active (false);
2433 roll_button.set_active (true);
2434 play_selection_button.set_active (false);
2435 auto_loop_button.set_active (false);
2438 if (UIConfiguration::instance().get_follow_edits() && !_session->config.get_external_sync()) {
2439 /* light up both roll and play-selection if they are joined */
2440 roll_button.set_active (true);
2441 play_selection_button.set_active (true);
2444 stop_button.set_active (false);
2448 stop_button.set_active (true);
2449 roll_button.set_active (false);
2450 play_selection_button.set_active (false);
2451 if (Config->get_loop_is_mode ()) {
2452 auto_loop_button.set_active (_session->get_play_loop());
2454 auto_loop_button.set_active (false);
2456 update_disk_space ();
2461 ARDOUR_UI::blink_handler (bool blink_on)
2463 transport_rec_enable_blink (blink_on);
2464 solo_blink (blink_on);
2465 sync_blink (blink_on);
2466 audition_blink (blink_on);
2467 feedback_blink (blink_on);
2468 error_blink (blink_on);
2472 ARDOUR_UI::update_clocks ()
2474 if (!_session) return;
2476 if (editor && !editor->dragging_playhead()) {
2477 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD)); /* EMIT_SIGNAL */
2482 ARDOUR_UI::start_clocking ()
2484 if (UIConfiguration::instance().get_super_rapid_clock_update()) {
2485 clock_signal_connection = Timers::fps_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2487 clock_signal_connection = Timers::rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2492 ARDOUR_UI::stop_clocking ()
2494 clock_signal_connection.disconnect ();
2498 ARDOUR_UI::save_as_progress_update (float fraction, int64_t cnt, int64_t total, Gtk::Label* label, Gtk::ProgressBar* bar)
2502 snprintf (buf, sizeof (buf), _("Copied %" PRId64 " of %" PRId64), cnt, total);
2504 label->set_text (buf);
2505 bar->set_fraction (fraction);
2507 /* process events, redraws, etc. */
2509 while (gtk_events_pending()) {
2510 gtk_main_iteration ();
2513 return true; /* continue with save-as */
2517 ARDOUR_UI::save_session_as ()
2523 if (!save_as_dialog) {
2524 save_as_dialog = new SaveAsDialog;
2527 save_as_dialog->set_name (_session->name());
2529 int response = save_as_dialog->run ();
2531 save_as_dialog->hide ();
2534 case Gtk::RESPONSE_OK:
2543 sa.new_parent_folder = save_as_dialog->new_parent_folder ();
2544 sa.new_name = save_as_dialog->new_name ();
2545 sa.switch_to = save_as_dialog->switch_to();
2546 sa.copy_media = save_as_dialog->copy_media();
2547 sa.copy_external = save_as_dialog->copy_external();
2548 sa.include_media = save_as_dialog->include_media ();
2550 /* Only bother with a progress dialog if we're going to copy
2551 media into the save-as target. Without that choice, this
2552 will be very fast because we're only talking about a few kB's to
2553 perhaps a couple of MB's of data.
2556 ArdourDialog progress_dialog (_("Save As"), true);
2558 if (sa.include_media && sa.copy_media) {
2561 Gtk::ProgressBar progress_bar;
2563 progress_dialog.get_vbox()->pack_start (label);
2564 progress_dialog.get_vbox()->pack_start (progress_bar);
2566 progress_bar.show ();
2568 /* this signal will be emitted from within this, the calling thread,
2569 * after every file is copied. It provides information on percentage
2570 * complete (in terms of total data to copy), the number of files
2571 * copied so far, and the total number to copy.
2576 sa.Progress.connect_same_thread (c, boost::bind (&ARDOUR_UI::save_as_progress_update, this, _1, _2, _3, &label, &progress_bar));
2578 progress_dialog.show_all ();
2579 progress_dialog.present ();
2582 if (_session->save_as (sa)) {
2584 MessageDialog msg (string_compose (_("Save As failed: %1"), sa.failure_message));
2588 if (!sa.include_media) {
2589 unload_session (false);
2590 load_session (sa.final_session_folder_name, sa.new_name);
2595 ARDOUR_UI::quick_snapshot_session (bool switch_to_it)
2599 struct tm local_time;
2602 localtime_r (&n, &local_time);
2603 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2605 save_state (timebuf, switch_to_it);
2610 ARDOUR_UI::process_snapshot_session_prompter (ArdourPrompter& prompter, bool switch_to_it)
2614 prompter.get_result (snapname);
2616 bool do_save = (snapname.length() != 0);
2619 char illegal = Session::session_name_is_legal(snapname);
2621 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2622 "snapshot names may not contain a '%1' character"), illegal));
2628 vector<std::string> p;
2629 get_state_files_in_directory (_session->session_directory().root_path(), p);
2630 vector<string> n = get_file_names_no_extension (p);
2632 if (find (n.begin(), n.end(), snapname) != n.end()) {
2634 do_save = overwrite_file_dialog (prompter,
2635 _("Confirm Snapshot Overwrite"),
2636 _("A snapshot already exists with that name. Do you want to overwrite it?"));
2640 save_state (snapname, switch_to_it);
2650 /** Ask the user for the name of a new snapshot and then take it.
2654 ARDOUR_UI::snapshot_session (bool switch_to_it)
2656 ArdourPrompter prompter (true);
2658 prompter.set_name ("Prompter");
2659 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2661 prompter.set_title (_("Snapshot and switch"));
2662 prompter.set_prompt (_("New session name"));
2664 prompter.set_title (_("Take Snapshot"));
2665 prompter.set_prompt (_("Name of new snapshot"));
2669 prompter.set_initial_text (_session->snap_name());
2673 struct tm local_time;
2676 localtime_r (&n, &local_time);
2677 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2678 prompter.set_initial_text (timebuf);
2681 bool finished = false;
2683 switch (prompter.run()) {
2684 case RESPONSE_ACCEPT:
2686 finished = process_snapshot_session_prompter (prompter, switch_to_it);
2697 /** Ask the user for a new session name and then rename the session to it.
2701 ARDOUR_UI::rename_session ()
2707 ArdourPrompter prompter (true);
2710 prompter.set_name ("Prompter");
2711 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2712 prompter.set_title (_("Rename Session"));
2713 prompter.set_prompt (_("New session name"));
2716 switch (prompter.run()) {
2717 case RESPONSE_ACCEPT:
2719 prompter.get_result (name);
2721 bool do_rename = (name.length() != 0);
2724 char illegal = Session::session_name_is_legal (name);
2727 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2728 "session names may not contain a '%1' character"), illegal));
2733 switch (_session->rename (name)) {
2735 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
2736 msg.set_position (WIN_POS_MOUSE);
2744 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
2745 msg.set_position (WIN_POS_MOUSE);
2761 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2763 if (!_session || _session->deletion_in_progress()) {
2767 XMLNode* node = new XMLNode (X_("UI"));
2769 WM::Manager::instance().add_state (*node);
2771 node->add_child_nocopy (gui_object_state->get_state());
2773 _session->add_extra_xml (*node);
2775 if (export_video_dialog) {
2776 _session->add_extra_xml (export_video_dialog->get_state());
2779 save_state_canfail (name, switch_to_it);
2783 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2788 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2793 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2798 ARDOUR_UI::primary_clock_value_changed ()
2801 _session->request_locate (primary_clock->current_time ());
2806 ARDOUR_UI::big_clock_value_changed ()
2809 _session->request_locate (big_clock->current_time ());
2814 ARDOUR_UI::secondary_clock_value_changed ()
2817 _session->request_locate (secondary_clock->current_time ());
2822 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2824 if (_session == 0) {
2828 if (_session->step_editing()) {
2832 Session::RecordState const r = _session->record_status ();
2833 bool const h = _session->have_rec_enabled_track ();
2835 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2837 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2839 rec_button.set_active_state (Gtkmm2ext::Off);
2841 } else if (r == Session::Recording && h) {
2842 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2844 rec_button.unset_active_state ();
2849 ARDOUR_UI::process_save_template_prompter (ArdourPrompter& prompter)
2853 prompter.get_result (name);
2855 if (name.length()) {
2856 int failed = _session->save_template (name);
2858 if (failed == -2) { /* file already exists. */
2859 bool overwrite = overwrite_file_dialog (prompter,
2860 _("Confirm Template Overwrite"),
2861 _("A template already exists with that name. Do you want to overwrite it?"));
2864 _session->save_template (name, true);
2876 ARDOUR_UI::save_template ()
2878 ArdourPrompter prompter (true);
2880 if (!check_audioengine (_main_window)) {
2884 prompter.set_name (X_("Prompter"));
2885 prompter.set_title (_("Save Template"));
2886 prompter.set_prompt (_("Name for template:"));
2887 prompter.set_initial_text(_session->name() + _("-template"));
2888 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2890 bool finished = false;
2892 switch (prompter.run()) {
2893 case RESPONSE_ACCEPT:
2894 finished = process_save_template_prompter (prompter);
2905 ARDOUR_UI::edit_metadata ()
2907 SessionMetadataEditor dialog;
2908 dialog.set_session (_session);
2909 dialog.grab_focus ();
2914 ARDOUR_UI::import_metadata ()
2916 SessionMetadataImporter dialog;
2917 dialog.set_session (_session);
2922 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
2924 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2926 MessageDialog msg (str,
2928 Gtk::MESSAGE_WARNING,
2929 Gtk::BUTTONS_YES_NO,
2933 msg.set_name (X_("OpenExistingDialog"));
2934 msg.set_title (_("Open Existing Session"));
2935 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
2936 msg.set_position (Gtk::WIN_POS_CENTER);
2937 pop_back_splash (msg);
2939 switch (msg.run()) {
2948 ARDOUR_UI::build_session_from_dialog (SessionDialog& sd, const std::string& session_path, const std::string& session_name)
2950 BusProfile bus_profile;
2954 bus_profile.master_out_channels = 2;
2955 bus_profile.input_ac = AutoConnectPhysical;
2956 bus_profile.output_ac = AutoConnectMaster;
2957 bus_profile.requested_physical_in = 0; // use all available
2958 bus_profile.requested_physical_out = 0; // use all available
2962 /* get settings from advanced section of NSD */
2964 if (sd.create_master_bus()) {
2965 bus_profile.master_out_channels = (uint32_t) sd.master_channel_count();
2967 bus_profile.master_out_channels = 0;
2970 if (sd.connect_inputs()) {
2971 bus_profile.input_ac = AutoConnectPhysical;
2973 bus_profile.input_ac = AutoConnectOption (0);
2976 bus_profile.output_ac = AutoConnectOption (0);
2978 if (sd.connect_outputs ()) {
2979 if (sd.connect_outs_to_master()) {
2980 bus_profile.output_ac = AutoConnectMaster;
2981 } else if (sd.connect_outs_to_physical()) {
2982 bus_profile.output_ac = AutoConnectPhysical;
2986 bus_profile.requested_physical_in = (uint32_t) sd.input_limit_count();
2987 bus_profile.requested_physical_out = (uint32_t) sd.output_limit_count();
2990 if (build_session (session_path, session_name, bus_profile)) {
2998 ARDOUR_UI::load_from_application_api (const std::string& path)
3000 ARDOUR_COMMAND_LINE::session_name = path;
3001 /* Cancel SessionDialog if it's visible to make OSX delegates work.
3003 * ARDOUR_UI::starting connects app->ShouldLoad signal and then shows a SessionDialog
3005 * - ShouldLoad does not arrive in time, ARDOUR_COMMAND_LINE::session_name is empty:
3006 * -> ARDOUR_UI::get_session_parameters starts a SessionDialog.
3007 * - ShouldLoad signal arrives, this function is called and sets ARDOUR_COMMAND_LINE::session_name
3008 * -> SessionDialog is not displayed
3011 if (_session_dialog) {
3012 std::string session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3013 std::string session_path = path;
3014 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_REGULAR)) {
3015 session_path = Glib::path_get_dirname (session_path);
3017 // signal the existing dialog in ARDOUR_UI::get_session_parameters()
3018 _session_dialog->set_provided_session (session_name, session_path);
3019 _session_dialog->response (RESPONSE_NONE);
3020 _session_dialog->hide();
3025 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
3026 /* /path/to/foo => /path/to/foo, foo */
3027 rv = load_session (path, basename_nosuffix (path));
3029 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
3030 rv =load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
3033 // if load_session fails -> pop up SessionDialog.
3035 ARDOUR_COMMAND_LINE::session_name = "";
3037 if (get_session_parameters (true, false)) {
3043 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
3045 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
3047 string session_name;
3048 string session_path;
3049 string template_name;
3051 bool likely_new = false;
3052 bool cancel_not_quit;
3054 /* deal with any existing DIRTY session now, rather than later. don't
3055 * treat a non-dirty session this way, so that it stays visible
3056 * as we bring up the new session dialog.
3059 if (_session && ARDOUR_UI::instance()->video_timeline) {
3060 ARDOUR_UI::instance()->video_timeline->sync_session_state();
3063 /* if there is already a session, relabel the button
3064 on the SessionDialog so that we don't Quit directly
3066 cancel_not_quit = (_session != 0);
3068 if (_session && _session->dirty()) {
3069 if (unload_session (false)) {
3070 /* unload cancelled by user */
3073 ARDOUR_COMMAND_LINE::session_name = "";
3076 if (!load_template.empty()) {
3077 should_be_new = true;
3078 template_name = load_template;
3081 session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3082 session_path = ARDOUR_COMMAND_LINE::session_name;
3084 if (!session_path.empty()) {
3085 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_EXISTS)) {
3086 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_IS_REGULAR)) {
3087 /* session/snapshot file, change path to be dir */
3088 session_path = Glib::path_get_dirname (session_path);
3093 SessionDialog session_dialog (should_be_new, session_name, session_path, load_template, cancel_not_quit);
3095 _session_dialog = &session_dialog;
3098 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
3100 /* if they named a specific statefile, use it, otherwise they are
3101 just giving a session folder, and we want to use it as is
3102 to find the session.
3105 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
3107 if (suffix != string::npos) {
3108 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
3109 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
3110 session_name = Glib::path_get_basename (session_name);
3112 session_path = ARDOUR_COMMAND_LINE::session_name;
3113 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
3118 session_dialog.clear_given ();
3121 if (should_be_new || session_name.empty()) {
3122 /* need the dialog to get info from user */
3124 cerr << "run dialog\n";
3126 switch (session_dialog.run()) {
3127 case RESPONSE_ACCEPT:
3130 /* this is used for async * app->ShouldLoad(). */
3131 continue; // while loop
3134 if (quit_on_cancel) {
3135 // JE - Currently (July 2014) this section can only get reached if the
3136 // user quits from the main 'Session Setup' dialog (i.e. reaching this
3137 // point does NOT indicate an abnormal termination). Therefore, let's
3138 // behave gracefully (i.e. let's do some cleanup) before we call exit()
3140 pthread_cancel_all ();
3148 session_dialog.hide ();
3151 /* if we run the startup dialog again, offer more than just "new session" */
3153 should_be_new = false;
3155 session_name = session_dialog.session_name (likely_new);
3156 session_path = session_dialog.session_folder ();
3162 string::size_type suffix = session_name.find (statefile_suffix);
3164 if (suffix != string::npos) {
3165 session_name = session_name.substr (0, suffix);
3168 /* this shouldn't happen, but we catch it just in case it does */
3170 if (session_name.empty()) {
3174 if (session_dialog.use_session_template()) {
3175 template_name = session_dialog.session_template_name();
3176 _session_is_new = true;
3179 if (session_name[0] == G_DIR_SEPARATOR ||
3180 #ifdef PLATFORM_WINDOWS
3181 (session_name.length() > 3 && session_name[1] == ':' && session_name[2] == G_DIR_SEPARATOR)
3183 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
3184 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)
3189 /* absolute path or cwd-relative path specified for session name: infer session folder
3190 from what was given.
3193 session_path = Glib::path_get_dirname (session_name);
3194 session_name = Glib::path_get_basename (session_name);
3198 session_path = session_dialog.session_folder();
3200 char illegal = Session::session_name_is_legal (session_name);
3203 MessageDialog msg (session_dialog,
3204 string_compose (_("To ensure compatibility with various systems\n"
3205 "session names may not contain a '%1' character"),
3208 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3213 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
3216 if (likely_new && !nsm) {
3218 std::string existing = Glib::build_filename (session_path, session_name);
3220 if (!ask_about_loading_existing_session (existing)) {
3221 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3226 _session_is_new = false;
3231 pop_back_splash (session_dialog);
3232 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
3234 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3238 char illegal = Session::session_name_is_legal(session_name);
3241 pop_back_splash (session_dialog);
3242 MessageDialog msg (session_dialog, string_compose(_("To ensure compatibility with various systems\n"
3243 "session names may not contain a '%1' character"), illegal));
3245 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3249 _session_is_new = true;
3252 if (likely_new && template_name.empty()) {
3254 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3258 ret = load_session (session_path, session_name, template_name);
3261 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
3265 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
3266 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
3270 /* clear this to avoid endless attempts to load the
3274 ARDOUR_COMMAND_LINE::session_name = "";
3278 _session_dialog = NULL;
3284 ARDOUR_UI::close_session()
3286 if (!check_audioengine (_main_window)) {
3290 if (unload_session (true)) {
3294 ARDOUR_COMMAND_LINE::session_name = "";
3296 if (get_session_parameters (true, false)) {
3299 if (splash && splash->is_visible()) {
3300 // in 1 second, hide the splash screen
3301 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
3305 /** @param snap_name Snapshot name (without .ardour suffix).
3306 * @return -2 if the load failed because we are not connected to the AudioEngine.
3309 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
3311 Session *new_session;
3316 unload_status = unload_session ();
3318 if (unload_status < 0) {
3320 } else if (unload_status > 0) {
3326 session_loaded = false;
3328 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
3331 new_session = new Session (*AudioEngine::instance(), path, snap_name, 0, mix_template);
3334 /* this one is special */
3336 catch (AudioEngine::PortRegistrationFailure& err) {
3338 MessageDialog msg (err.what(),
3341 Gtk::BUTTONS_CLOSE);
3343 msg.set_title (_("Port Registration Error"));
3344 msg.set_secondary_text (_("Click the Close button to try again."));
3345 msg.set_position (Gtk::WIN_POS_CENTER);
3346 pop_back_splash (msg);
3349 int response = msg.run ();
3354 case RESPONSE_CANCEL:
3361 catch (SessionException e) {
3362 MessageDialog msg (string_compose(
3363 _("Session \"%1 (snapshot %2)\" did not load successfully: %3"),
3364 path, snap_name, e.what()),
3369 msg.set_title (_("Loading Error"));
3370 msg.set_position (Gtk::WIN_POS_CENTER);
3371 pop_back_splash (msg);
3383 MessageDialog msg (string_compose(
3384 _("Session \"%1 (snapshot %2)\" did not load successfully"),
3390 msg.set_title (_("Loading Error"));
3391 msg.set_position (Gtk::WIN_POS_CENTER);
3392 pop_back_splash (msg);
3404 list<string> const u = new_session->unknown_processors ();
3406 MissingPluginDialog d (_session, u);
3411 if (!new_session->writable()) {
3412 MessageDialog msg (_("This session has been opened in read-only mode.\n\nYou will not be able to record or save."),
3417 msg.set_title (_("Read-only Session"));
3418 msg.set_position (Gtk::WIN_POS_CENTER);
3419 pop_back_splash (msg);
3426 /* Now the session been created, add the transport controls */
3427 new_session->add_controllable(roll_controllable);
3428 new_session->add_controllable(stop_controllable);
3429 new_session->add_controllable(goto_start_controllable);
3430 new_session->add_controllable(goto_end_controllable);
3431 new_session->add_controllable(auto_loop_controllable);
3432 new_session->add_controllable(play_selection_controllable);
3433 new_session->add_controllable(rec_controllable);
3435 set_session (new_session);
3437 session_loaded = true;
3440 _session->set_clean ();
3443 #ifdef WINDOWS_VST_SUPPORT
3444 fst_stop_threading();
3448 Timers::TimerSuspender t;
3452 #ifdef WINDOWS_VST_SUPPORT
3453 fst_start_threading();
3462 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
3464 Session *new_session;
3467 session_loaded = false;
3468 x = unload_session ();
3476 _session_is_new = true;
3479 new_session = new Session (*AudioEngine::instance(), path, snap_name, &bus_profile);
3482 catch (SessionException e) {
3484 MessageDialog msg (string_compose(_("Could not create session in \"%1\": %2"), path, e.what()));
3485 msg.set_title (_("Loading Error"));
3486 msg.set_position (Gtk::WIN_POS_CENTER);
3487 pop_back_splash (msg);
3493 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
3494 msg.set_title (_("Loading Error"));
3495 msg.set_position (Gtk::WIN_POS_CENTER);
3496 pop_back_splash (msg);
3501 /* Give the new session the default GUI state, if such things exist */
3504 n = Config->instant_xml (X_("Editor"));
3506 n->remove_nodes_and_delete ("Selection"); // no not apply selection to new sessions.
3507 new_session->add_instant_xml (*n, false);
3509 n = Config->instant_xml (X_("Mixer"));
3511 new_session->add_instant_xml (*n, false);
3514 /* Put the playhead at 0 and scroll fully left */
3515 n = new_session->instant_xml (X_("Editor"));
3517 n->add_property (X_("playhead"), X_("0"));
3518 n->add_property (X_("left-frame"), X_("0"));
3521 set_session (new_session);
3523 session_loaded = true;
3525 new_session->save_state(new_session->name());
3531 ARDOUR_UI::launch_chat ()
3533 MessageDialog dialog(_("<b>Just ask and wait for an answer.\nIt may take from minutes to hours.</b>"), true);
3535 dialog.set_title (_("About the Chat"));
3536 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."));
3538 switch (dialog.run()) {
3541 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
3542 #elif defined PLATFORM_WINDOWS
3543 open_uri("http://webchat.freenode.net/?channels=ardour-windows");
3545 open_uri("http://webchat.freenode.net/?channels=ardour");
3554 ARDOUR_UI::launch_manual ()
3556 PBD::open_uri (Config->get_tutorial_manual_url());
3560 ARDOUR_UI::launch_reference ()
3562 PBD::open_uri (Config->get_reference_manual_url());
3566 ARDOUR_UI::launch_tracker ()
3568 PBD::open_uri ("http://tracker.ardour.org");
3572 ARDOUR_UI::launch_subscribe ()
3574 PBD::open_uri ("https://community.ardour.org/s/subscribe");
3578 ARDOUR_UI::launch_cheat_sheet ()
3581 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheat_sheet_osx.pdf");
3583 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheatsheet.pdf");
3588 ARDOUR_UI::launch_website ()
3590 PBD::open_uri ("http://ardour.org");
3594 ARDOUR_UI::launch_website_dev ()
3596 PBD::open_uri ("http://ardour.org/development.html");
3600 ARDOUR_UI::launch_forums ()
3602 PBD::open_uri ("https://community.ardour.org/forums");
3606 ARDOUR_UI::launch_howto_report ()
3608 PBD::open_uri ("http://ardour.org/reporting_bugs");
3612 ARDOUR_UI::loading_message (const std::string& msg)
3614 if (ARDOUR_COMMAND_LINE::no_splash) {
3622 splash->message (msg);
3626 ARDOUR_UI::show_splash ()
3630 splash = new Splash;
3640 ARDOUR_UI::hide_splash ()
3647 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title, const bool msg_delete)
3651 removed = rep.paths.size();
3654 MessageDialog msgd (_main_window,
3655 _("No files were ready for clean-up"),
3659 msgd.set_title (_("Clean-up"));
3660 msgd.set_secondary_text (_("If this seems suprising, \n\
3661 check for any existing snapshots.\n\
3662 These may still include regions that\n\
3663 require some unused files to continue to exist."));
3669 ArdourDialog results (_("Clean-up"), true, false);
3671 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
3672 CleanupResultsModelColumns() {
3676 Gtk::TreeModelColumn<std::string> visible_name;
3677 Gtk::TreeModelColumn<std::string> fullpath;
3681 CleanupResultsModelColumns results_columns;
3682 Glib::RefPtr<Gtk::ListStore> results_model;
3683 Gtk::TreeView results_display;
3685 results_model = ListStore::create (results_columns);
3686 results_display.set_model (results_model);
3687 results_display.append_column (list_title, results_columns.visible_name);
3689 results_display.set_name ("CleanupResultsList");
3690 results_display.set_headers_visible (true);
3691 results_display.set_headers_clickable (false);
3692 results_display.set_reorderable (false);
3694 Gtk::ScrolledWindow list_scroller;
3697 Gtk::HBox dhbox; // the hbox for the image and text
3698 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
3699 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
3701 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
3703 const string dead_directory = _session->session_directory().dead_path();
3706 %1 - number of files removed
3707 %2 - location of "dead"
3708 %3 - size of files affected
3709 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
3712 const char* bprefix;
3713 double space_adjusted = 0;
3715 if (rep.space < 1000) {
3717 space_adjusted = rep.space;
3718 } else if (rep.space < 1000000) {
3719 bprefix = _("kilo");
3720 space_adjusted = floorf((float)rep.space / 1000.0);
3721 } else if (rep.space < 1000000 * 1000) {
3722 bprefix = _("mega");
3723 space_adjusted = floorf((float)rep.space / (1000.0 * 1000.0));
3725 bprefix = _("giga");
3726 space_adjusted = floorf((float)rep.space / (1000.0 * 1000 * 1000.0));
3730 txt.set_markup (string_compose (P_("\
3731 The following file was deleted from %2,\n\
3732 releasing %3 %4bytes of disk space", "\
3733 The following %1 files were deleted from %2,\n\
3734 releasing %3 %4bytes of disk space", removed),
3735 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3737 txt.set_markup (string_compose (P_("\
3738 The following file was not in use and \n\
3739 has been moved to: %2\n\n\
3740 After a restart of %5\n\n\
3741 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3742 will release an additional %3 %4bytes of disk space.\n", "\
3743 The following %1 files were not in use and \n\
3744 have been moved to: %2\n\n\
3745 After a restart of %5\n\n\
3746 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3747 will release an additional %3 %4bytes of disk space.\n", removed),
3748 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3751 dhbox.pack_start (*dimage, true, false, 5);
3752 dhbox.pack_start (txt, true, false, 5);
3754 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
3755 TreeModel::Row row = *(results_model->append());
3756 row[results_columns.visible_name] = *i;
3757 row[results_columns.fullpath] = *i;
3760 list_scroller.add (results_display);
3761 list_scroller.set_size_request (-1, 150);
3762 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
3764 dvbox.pack_start (dhbox, true, false, 5);
3765 dvbox.pack_start (list_scroller, true, false, 5);
3766 ddhbox.pack_start (dvbox, true, false, 5);
3768 results.get_vbox()->pack_start (ddhbox, true, false, 5);
3769 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
3770 results.set_default_response (RESPONSE_CLOSE);
3771 results.set_position (Gtk::WIN_POS_MOUSE);
3773 results_display.show();
3774 list_scroller.show();
3781 //results.get_vbox()->show();
3782 results.set_resizable (false);
3789 ARDOUR_UI::cleanup ()
3791 if (_session == 0) {
3792 /* shouldn't happen: menu item is insensitive */
3797 MessageDialog checker (_("Are you sure you want to clean-up?"),
3799 Gtk::MESSAGE_QUESTION,
3802 checker.set_title (_("Clean-up"));
3804 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
3805 ALL undo/redo information will be lost if you clean-up.\n\
3806 Clean-up will move all unused files to a \"dead\" location."));
3808 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3809 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
3810 checker.set_default_response (RESPONSE_CANCEL);
3812 checker.set_name (_("CleanupDialog"));
3813 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3814 checker.set_position (Gtk::WIN_POS_MOUSE);
3816 switch (checker.run()) {
3817 case RESPONSE_ACCEPT:
3823 ARDOUR::CleanupReport rep;
3825 editor->prepare_for_cleanup ();
3827 /* do not allow flush until a session is reloaded */
3829 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3831 act->set_sensitive (false);
3834 if (_session->cleanup_sources (rep)) {
3835 editor->finish_cleanup ();
3839 editor->finish_cleanup ();
3842 display_cleanup_results (rep, _("Cleaned Files"), false);
3846 ARDOUR_UI::flush_trash ()
3848 if (_session == 0) {
3849 /* shouldn't happen: menu item is insensitive */
3853 ARDOUR::CleanupReport rep;
3855 if (_session->cleanup_trash_sources (rep)) {
3859 display_cleanup_results (rep, _("deleted file"), true);
3863 ARDOUR_UI::cleanup_peakfiles ()
3865 if (_session == 0) {
3866 /* shouldn't happen: menu item is insensitive */
3870 if (! _session->can_cleanup_peakfiles ()) {
3874 // get all region-views in this session
3876 TrackViewList empty;
3878 editor->get_regions_after(rs, (framepos_t) 0, empty);
3879 std::list<RegionView*> views = rs.by_layer();
3881 // remove displayed audio-region-views waveforms
3882 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
3883 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
3884 if (!arv) { continue ; }
3885 arv->delete_waves();
3888 // cleanup peak files:
3889 // - stop pending peakfile threads
3890 // - close peakfiles if any
3891 // - remove peak dir in session
3892 // - setup peakfiles (background thread)
3893 _session->cleanup_peakfiles ();
3895 // re-add waves to ARV
3896 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
3897 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
3898 if (!arv) { continue ; }
3899 arv->create_waves();
3904 ARDOUR_UI::setup_order_hint (AddRouteDialog::InsertAt place)
3906 uint32_t order_hint = UINT32_MAX;
3908 if (editor->get_selection().tracks.empty()) {
3913 we want the new routes to have their order keys set starting from
3914 the highest order key in the selection + 1 (if available).
3917 if (place == AddRouteDialog::AfterSelection) {
3918 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.back());
3920 order_hint = rtav->route()->order_key();
3923 } else if (place == AddRouteDialog::BeforeSelection) {
3924 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.front());
3926 order_hint = rtav->route()->order_key();
3928 } else if (place == AddRouteDialog::First) {
3931 /* leave order_hint at UINT32_MAX */
3934 if (order_hint == UINT32_MAX) {
3935 /** AddRouteDialog::Last or selection with first/last not a RouteTimeAxisView
3936 * not setting an order hint will place new routes last.
3941 _session->set_order_hint (order_hint);
3943 /* create a gap in the existing route order keys to accomodate new routes.*/
3944 boost::shared_ptr <RouteList> rd = _session->get_routes();
3945 for (RouteList::iterator ri = rd->begin(); ri != rd->end(); ++ri) {
3946 boost::shared_ptr<Route> rt (*ri);
3948 if (rt->is_monitor()) {
3952 if (rt->order_key () >= order_hint) {
3953 rt->set_order_key (rt->order_key () + add_route_dialog->count());
3959 ARDOUR_UI::start_duplicate_routes ()
3961 if (!duplicate_routes_dialog) {
3962 duplicate_routes_dialog = new DuplicateRouteDialog;
3965 if (duplicate_routes_dialog->restart (_session)) {
3969 duplicate_routes_dialog->present ();
3973 ARDOUR_UI::add_route ()
3981 if (add_route_dialog->is_visible()) {
3982 /* we're already doing this */
3986 ResponseType r = (ResponseType) add_route_dialog->run ();
3988 add_route_dialog->hide();
3991 case RESPONSE_ACCEPT:
3998 if ((count = add_route_dialog->count()) <= 0) {
4002 setup_order_hint(add_route_dialog->insert_at());
4003 string template_path = add_route_dialog->track_template();
4004 DisplaySuspender ds;
4006 if (!template_path.empty()) {
4007 if (add_route_dialog->name_template_is_default()) {
4008 _session->new_route_from_template (count, template_path, string());
4010 _session->new_route_from_template (count, template_path, add_route_dialog->name_template());
4015 ChanCount input_chan= add_route_dialog->channels ();
4016 ChanCount output_chan;
4017 string name_template = add_route_dialog->name_template ();
4018 PluginInfoPtr instrument = add_route_dialog->requested_instrument ();
4019 RouteGroup* route_group = add_route_dialog->route_group ();
4020 AutoConnectOption oac = Config->get_output_auto_connect();
4021 bool strict_io = add_route_dialog->use_strict_io ();
4023 if (oac & AutoConnectMaster) {
4024 output_chan.set (DataType::AUDIO, (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan.n_audio()));
4025 output_chan.set (DataType::MIDI, 0);
4027 output_chan = input_chan;
4030 /* XXX do something with name template */
4032 switch (add_route_dialog->type_wanted()) {
4033 case AddRouteDialog::AudioTrack:
4034 session_add_audio_track (input_chan.n_audio(), output_chan.n_audio(), add_route_dialog->mode(), route_group, count, name_template, strict_io);
4036 case AddRouteDialog::MidiTrack:
4037 session_add_midi_track (route_group, count, name_template, strict_io, instrument);
4039 case AddRouteDialog::MixedTrack:
4040 session_add_mixed_track (input_chan, output_chan, route_group, count, name_template, strict_io, instrument, 0);
4042 case AddRouteDialog::AudioBus:
4043 session_add_audio_bus (input_chan.n_audio(), output_chan.n_audio(), route_group, count, name_template, strict_io);
4045 case AddRouteDialog::MidiBus:
4046 session_add_midi_bus (route_group, count, name_template, strict_io, instrument, 0);
4048 case AddRouteDialog::VCAMaster:
4049 session_add_vca (name_template);
4055 ARDOUR_UI::add_lua_script ()
4061 LuaScriptInfoPtr spi;
4062 ScriptSelector ss ("Add Lua Session Script", LuaScriptInfo::Session);
4063 switch (ss.run ()) {
4064 case Gtk::RESPONSE_ACCEPT:
4072 std::string script = "";
4075 script = Glib::file_get_contents (spi->path);
4076 } catch (Glib::FileError e) {
4077 string msg = string_compose (_("Cannot read session script '%1': %2"), spi->path, e.what());
4078 MessageDialog am (msg);
4083 LuaScriptParamList lsp = LuaScriptParams::script_params (spi, "sess_params");
4084 std::vector<std::string> reg = _session->registered_lua_functions ();
4086 ScriptParameterDialog spd (_("Set Script Parameters"), spi, reg, lsp);
4087 switch (spd.run ()) {
4088 case Gtk::RESPONSE_ACCEPT:
4095 _session->register_lua_function (spd.name(), script, lsp);
4096 } catch (luabridge::LuaException const& e) {
4097 string msg = string_compose (_("Session script '%1' instantiation failed: %2"), spd.name(), e.what ());
4098 MessageDialog am (msg);
4100 } catch (SessionException e) {
4101 string msg = string_compose (_("Loading Session script '%1' failed: %2"), spd.name(), e.what ());
4102 MessageDialog am (msg);
4108 ARDOUR_UI::remove_lua_script ()
4113 if (_session->registered_lua_function_count () == 0) {
4114 string msg = _("There are no active Lua session scripts present in this session.");
4115 MessageDialog am (msg);
4120 std::vector<std::string> reg = _session->registered_lua_functions ();
4121 SessionScriptManager sm ("Remove Lua Session Script", reg);
4122 switch (sm.run ()) {
4123 case Gtk::RESPONSE_ACCEPT:
4129 _session->unregister_lua_function (sm.name());
4130 } catch (luabridge::LuaException const& e) {
4131 string msg = string_compose (_("Session script '%1' removal failed: %2"), sm.name(), e.what ());
4132 MessageDialog am (msg);
4138 ARDOUR_UI::stop_video_server (bool ask_confirm)
4140 if (!video_server_process && ask_confirm) {
4141 warning << string_compose (_("Video-Server was not launched by %1. The request to stop it is ignored."), PROGRAM_NAME) << endmsg;
4143 if (video_server_process) {
4145 ArdourDialog confirm (_("Stop Video-Server"), true);
4146 Label m (_("Do you really want to stop the Video Server?"));
4147 confirm.get_vbox()->pack_start (m, true, true);
4148 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
4149 confirm.add_button (_("Yes, Stop It"), Gtk::RESPONSE_ACCEPT);
4150 confirm.show_all ();
4151 if (confirm.run() == RESPONSE_CANCEL) {
4155 delete video_server_process;
4156 video_server_process =0;
4161 ARDOUR_UI::start_video_server_menu (Gtk::Window* float_window)
4163 ARDOUR_UI::start_video_server( float_window, true);
4167 ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg)
4173 if (ARDOUR_UI::instance()->video_timeline->check_server()) {
4174 if (video_server_process) {
4175 popup_error(_("The Video Server is already started."));
4177 popup_error(_("An external Video Server is configured and can be reached. Not starting a new instance."));
4183 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4185 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4187 VideoServerDialog *video_server_dialog = new VideoServerDialog (_session);
4189 video_server_dialog->set_transient_for (*float_window);
4192 if (!Config->get_show_video_server_dialog() && firsttime < 2) {
4193 video_server_dialog->hide();
4195 ResponseType r = (ResponseType) video_server_dialog->run ();
4196 video_server_dialog->hide();
4197 if (r != RESPONSE_ACCEPT) { return false; }
4198 if (video_server_dialog->show_again()) {
4199 Config->set_show_video_server_dialog(false);
4203 std::string icsd_exec = video_server_dialog->get_exec_path();
4204 std::string icsd_docroot = video_server_dialog->get_docroot();
4205 if (icsd_docroot.empty()) {
4206 #ifndef PLATFORM_WINDOWS
4207 icsd_docroot = X_("/");
4209 icsd_docroot = X_("C:\\");
4214 if (g_lstat (icsd_docroot.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode)) {
4215 warning << _("Specified docroot is not an existing directory.") << endmsg;
4218 #ifndef PLATFORM_WINDOWS
4219 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4220 || (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0 ) {
4221 warning << _("Given Video Server is not an executable file.") << endmsg;
4225 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4226 || (sb.st_mode & (S_IXUSR)) == 0 ) {
4227 warning << _("Given Video Server is not an executable file.") << endmsg;
4233 argp=(char**) calloc(9,sizeof(char*));
4234 argp[0] = strdup(icsd_exec.c_str());
4235 argp[1] = strdup("-P");
4236 argp[2] = (char*) calloc(16,sizeof(char)); snprintf(argp[2], 16, "%s", video_server_dialog->get_listenaddr().c_str());
4237 argp[3] = strdup("-p");
4238 argp[4] = (char*) calloc(6,sizeof(char)); snprintf(argp[4], 6, "%i", video_server_dialog->get_listenport());
4239 argp[5] = strdup("-C");
4240 argp[6] = (char*) calloc(6,sizeof(char)); snprintf(argp[6], 6, "%i", video_server_dialog->get_cachesize());
4241 argp[7] = strdup(icsd_docroot.c_str());
4243 stop_video_server();
4245 if (icsd_docroot == X_("/") || icsd_docroot == X_("C:\\")) {
4246 Config->set_video_advanced_setup(false);
4248 std::ostringstream osstream;
4249 osstream << "http://127.0.0.1:" << video_server_dialog->get_listenport() << "/";
4250 Config->set_video_server_url(osstream.str());
4251 Config->set_video_server_docroot(icsd_docroot);
4252 Config->set_video_advanced_setup(true);
4255 if (video_server_process) {
4256 delete video_server_process;
4259 video_server_process = new ARDOUR::SystemExec(icsd_exec, argp);
4260 if (video_server_process->start()) {
4261 warning << _("Cannot launch the video-server") << endmsg;
4264 int timeout = 120; // 6 sec
4265 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4266 Glib::usleep (50000);
4268 if (--timeout <= 0 || !video_server_process->is_running()) break;
4271 warning << _("Video-server was started but does not respond to requests...") << endmsg;
4273 if (!ARDOUR_UI::instance()->video_timeline->check_server_docroot()) {
4274 delete video_server_process;
4275 video_server_process = 0;
4283 ARDOUR_UI::add_video (Gtk::Window* float_window)
4289 if (!start_video_server(float_window, false)) {
4290 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4295 add_video_dialog->set_transient_for (*float_window);
4298 if (add_video_dialog->is_visible()) {
4299 /* we're already doing this */
4303 ResponseType r = (ResponseType) add_video_dialog->run ();
4304 add_video_dialog->hide();
4305 if (r != RESPONSE_ACCEPT) { return; }
4307 bool local_file, orig_local_file;
4308 std::string path = add_video_dialog->file_name(local_file);
4310 std::string orig_path = path;
4311 orig_local_file = local_file;
4313 bool auto_set_session_fps = add_video_dialog->auto_set_session_fps();
4315 if (local_file && !Glib::file_test(path, Glib::FILE_TEST_EXISTS)) {
4316 warning << string_compose(_("could not open %1"), path) << endmsg;
4319 if (!local_file && path.length() == 0) {
4320 warning << _("no video-file selected") << endmsg;
4324 std::string audio_from_video;
4325 bool detect_ltc = false;
4327 switch (add_video_dialog->import_option()) {
4328 case VTL_IMPORT_TRANSCODE:
4330 TranscodeVideoDialog *transcode_video_dialog;
4331 transcode_video_dialog = new TranscodeVideoDialog (_session, path);
4332 ResponseType r = (ResponseType) transcode_video_dialog->run ();
4333 transcode_video_dialog->hide();
4334 if (r != RESPONSE_ACCEPT) {
4335 delete transcode_video_dialog;
4339 audio_from_video = transcode_video_dialog->get_audiofile();
4341 if (!audio_from_video.empty() && transcode_video_dialog->detect_ltc()) {
4344 else if (!audio_from_video.empty()) {
4345 editor->embed_audio_from_video(
4347 video_timeline->get_offset(),
4348 (transcode_video_dialog->import_option() != VTL_IMPORT_NO_VIDEO)
4351 switch (transcode_video_dialog->import_option()) {
4352 case VTL_IMPORT_TRANSCODED:
4353 path = transcode_video_dialog->get_filename();
4356 case VTL_IMPORT_REFERENCE:
4359 delete transcode_video_dialog;
4362 delete transcode_video_dialog;
4366 case VTL_IMPORT_NONE:
4370 /* strip _session->session_directory().video_path() from video file if possible */
4371 if (local_file && !path.compare(0, _session->session_directory().video_path().size(), _session->session_directory().video_path())) {
4372 path=path.substr(_session->session_directory().video_path().size());
4373 if (path.at(0) == G_DIR_SEPARATOR) {
4374 path=path.substr(1);
4378 video_timeline->set_update_session_fps(auto_set_session_fps);
4380 if (video_timeline->video_file_info(path, local_file)) {
4381 XMLNode* node = new XMLNode(X_("Videotimeline"));
4382 node->add_property (X_("Filename"), path);
4383 node->add_property (X_("AutoFPS"), auto_set_session_fps?X_("1"):X_("0"));
4384 node->add_property (X_("LocalFile"), local_file?X_("1"):X_("0"));
4385 if (orig_local_file) {
4386 node->add_property (X_("OriginalVideoFile"), orig_path);
4388 node->remove_property (X_("OriginalVideoFile"));
4390 _session->add_extra_xml (*node);
4391 _session->set_dirty ();
4393 if (!audio_from_video.empty() && detect_ltc) {
4394 std::vector<LTCFileReader::LTCMap> ltc_seq;
4397 /* TODO ask user about TV standard (LTC alignment if any) */
4398 LTCFileReader ltcr (audio_from_video, video_timeline->get_video_file_fps());
4399 /* TODO ASK user which channel: 0 .. ltcr->channels() - 1 */
4401 ltc_seq = ltcr.read_ltc (/*channel*/ 0, /*max LTC frames to decode*/ 15);
4403 /* TODO seek near end of file, and read LTC until end.
4404 * if it fails to find any LTC frames, scan complete file
4406 * calculate drift of LTC compared to video-duration,
4407 * ask user for reference (timecode from start/mid/end)
4410 // LTCFileReader will have written error messages
4413 ::g_unlink(audio_from_video.c_str());
4415 if (ltc_seq.size() == 0) {
4416 PBD::error << _("No LTC detected, video will not be aligned.") << endmsg;
4418 /* the very first TC in the file is somteimes not aligned properly */
4419 int i = ltc_seq.size() -1;
4420 ARDOUR::frameoffset_t video_start_offset =
4421 _session->nominal_frame_rate() * (ltc_seq[i].timecode_sec - ltc_seq[i].framepos_sec);
4422 PBD::info << string_compose (_("Align video-start to %1 [samples]"), video_start_offset) << endmsg;
4423 video_timeline->set_offset(video_start_offset);
4427 _session->maybe_update_session_range(
4428 std::max(video_timeline->get_offset(), (ARDOUR::frameoffset_t) 0),
4429 std::max(video_timeline->get_offset() + video_timeline->get_duration(), (ARDOUR::frameoffset_t) 0));
4432 if (add_video_dialog->launch_xjadeo() && local_file) {
4433 editor->set_xjadeo_sensitive(true);
4434 editor->toggle_xjadeo_proc(1);
4436 editor->toggle_xjadeo_proc(0);
4438 editor->toggle_ruler_video(true);
4443 ARDOUR_UI::remove_video ()
4445 video_timeline->close_session();
4446 editor->toggle_ruler_video(false);
4449 video_timeline->set_offset_locked(false);
4450 video_timeline->set_offset(0);
4452 /* delete session state */
4453 XMLNode* node = new XMLNode(X_("Videotimeline"));
4454 _session->add_extra_xml(*node);
4455 node = new XMLNode(X_("Videomonitor"));
4456 _session->add_extra_xml(*node);
4457 node = new XMLNode(X_("Videoexport"));
4458 _session->add_extra_xml(*node);
4459 stop_video_server();
4463 ARDOUR_UI::flush_videotimeline_cache (bool localcacheonly)
4465 if (localcacheonly) {
4466 video_timeline->vmon_update();
4468 video_timeline->flush_cache();
4470 editor->queue_visual_videotimeline_update();
4474 ARDOUR_UI::export_video (bool range)
4476 if (ARDOUR::Config->get_show_video_export_info()) {
4477 ExportVideoInfobox infobox (_session);
4478 Gtk::ResponseType rv = (Gtk::ResponseType) infobox.run();
4479 if (infobox.show_again()) {
4480 ARDOUR::Config->set_show_video_export_info(false);
4483 case GTK_RESPONSE_YES:
4484 PBD::open_uri (ARDOUR::Config->get_reference_manual_url() + "/video-timeline/operations/#export");
4490 export_video_dialog->set_session (_session);
4491 export_video_dialog->apply_state(editor->get_selection().time, range);
4492 export_video_dialog->run ();
4493 export_video_dialog->hide ();
4497 ARDOUR_UI::mixer_settings () const
4502 node = _session->instant_xml(X_("Mixer"));
4504 node = Config->instant_xml(X_("Mixer"));
4508 node = new XMLNode (X_("Mixer"));
4515 ARDOUR_UI::main_window_settings () const
4520 node = _session->instant_xml(X_("Main"));
4522 node = Config->instant_xml(X_("Main"));
4526 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4527 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4532 node = new XMLNode (X_("Main"));
4539 ARDOUR_UI::editor_settings () const
4544 node = _session->instant_xml(X_("Editor"));
4546 node = Config->instant_xml(X_("Editor"));
4550 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4551 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4556 node = new XMLNode (X_("Editor"));
4563 ARDOUR_UI::keyboard_settings () const
4567 node = Config->extra_xml(X_("Keyboard"));
4570 node = new XMLNode (X_("Keyboard"));
4577 ARDOUR_UI::create_xrun_marker (framepos_t where)
4580 Location *location = new Location (*_session, where, where, _("xrun"), Location::IsMark);
4581 _session->locations()->add (location);
4586 ARDOUR_UI::halt_on_xrun_message ()
4588 cerr << "HALT on xrun\n";
4589 MessageDialog msg (_main_window, _("Recording was stopped because your system could not keep up."));
4594 ARDOUR_UI::xrun_handler (framepos_t where)
4600 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
4602 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
4603 create_xrun_marker(where);
4606 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
4607 halt_on_xrun_message ();
4612 ARDOUR_UI::disk_overrun_handler ()
4614 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
4616 if (!have_disk_speed_dialog_displayed) {
4617 have_disk_speed_dialog_displayed = true;
4618 MessageDialog* msg = new MessageDialog (_main_window, string_compose (_("\
4619 The disk system on your computer\n\
4620 was not able to keep up with %1.\n\
4622 Specifically, it failed to write data to disk\n\
4623 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
4624 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4630 /* TODO: this is getting elaborate enough to warrant being split into a dedicated class */
4631 static MessageDialog *scan_dlg = NULL;
4632 static ProgressBar *scan_pbar = NULL;
4633 static HBox *scan_tbox = NULL;
4634 static Gtk::Button *scan_timeout_button;
4637 ARDOUR_UI::cancel_plugin_scan ()
4639 PluginManager::instance().cancel_plugin_scan();
4643 ARDOUR_UI::cancel_plugin_timeout ()
4645 PluginManager::instance().cancel_plugin_timeout();
4646 scan_timeout_button->set_sensitive (false);
4650 ARDOUR_UI::plugin_scan_timeout (int timeout)
4652 if (!scan_dlg || !scan_dlg->is_mapped() || !scan_pbar) {
4656 scan_pbar->set_sensitive (false);
4657 scan_timeout_button->set_sensitive (true);
4658 scan_pbar->set_fraction ((float) timeout / (float) Config->get_vst_scan_timeout());
4661 scan_pbar->set_sensitive (false);
4662 scan_timeout_button->set_sensitive (false);
4668 ARDOUR_UI::plugin_scan_dialog (std::string type, std::string plugin, bool can_cancel)
4670 if (type == X_("closeme") && !(scan_dlg && scan_dlg->is_mapped())) {
4674 const bool cancelled = PluginManager::instance().cancelled();
4675 if (type != X_("closeme") && (!UIConfiguration::instance().get_show_plugin_scan_window()) && !_initial_verbose_plugin_scan) {
4676 if (cancelled && scan_dlg->is_mapped()) {
4681 if (cancelled || !can_cancel) {
4686 static Gtk::Button *cancel_button;
4688 scan_dlg = new MessageDialog("", false, MESSAGE_INFO, BUTTONS_NONE); // TODO manage
4689 VBox* vbox = scan_dlg->get_vbox();
4690 vbox->set_size_request(400,-1);
4691 scan_dlg->set_title (_("Scanning for plugins"));
4693 cancel_button = manage(new Gtk::Button(_("Cancel plugin scan")));
4694 cancel_button->set_name ("EditorGTKButton");
4695 cancel_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_scan) );
4696 cancel_button->show();
4698 scan_dlg->get_vbox()->pack_start ( *cancel_button, PACK_SHRINK);
4700 scan_tbox = manage( new HBox() );
4702 scan_timeout_button = manage(new Gtk::Button(_("Stop Timeout")));
4703 scan_timeout_button->set_name ("EditorGTKButton");
4704 scan_timeout_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_timeout) );
4705 scan_timeout_button->show();
4707 scan_pbar = manage(new ProgressBar());
4708 scan_pbar->set_orientation(Gtk::PROGRESS_RIGHT_TO_LEFT);
4709 scan_pbar->set_text(_("Scan Timeout"));
4712 scan_tbox->pack_start (*scan_pbar, PACK_EXPAND_WIDGET, 4);
4713 scan_tbox->pack_start (*scan_timeout_button, PACK_SHRINK, 4);
4715 scan_dlg->get_vbox()->pack_start (*scan_tbox, PACK_SHRINK, 4);
4718 assert(scan_dlg && scan_tbox && cancel_button);
4720 if (type == X_("closeme")) {
4724 scan_dlg->set_message(type + ": " + Glib::path_get_basename(plugin));
4727 if (!can_cancel || !cancelled) {
4728 scan_timeout_button->set_sensitive(false);
4730 cancel_button->set_sensitive(can_cancel && !cancelled);
4736 ARDOUR_UI::gui_idle_handler ()
4739 /* due to idle calls, gtk_events_pending() may always return true */
4740 while (gtk_events_pending() && --timeout) {
4741 gtk_main_iteration ();
4746 ARDOUR_UI::disk_underrun_handler ()
4748 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
4750 if (!have_disk_speed_dialog_displayed) {
4751 have_disk_speed_dialog_displayed = true;
4752 MessageDialog* msg = new MessageDialog (
4753 _main_window, string_compose (_("The disk system on your computer\n\
4754 was not able to keep up with %1.\n\
4756 Specifically, it failed to read data from disk\n\
4757 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
4758 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4764 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
4766 have_disk_speed_dialog_displayed = false;
4771 ARDOUR_UI::session_dialog (std::string msg)
4773 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
4777 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
4784 ARDOUR_UI::pending_state_dialog ()
4786 HBox* hbox = manage (new HBox());
4787 Image* image = manage (new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG));
4788 ArdourDialog dialog (_("Crash Recovery"), true);
4789 Label message (string_compose (_("\
4790 This session appears to have been in the\n\
4791 middle of recording when %1 or\n\
4792 the computer was shutdown.\n\
4794 %1 can recover any captured audio for\n\
4795 you, or it can ignore it. Please decide\n\
4796 what you would like to do.\n"), PROGRAM_NAME));
4797 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4798 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4799 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4800 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4801 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
4802 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
4803 dialog.set_default_response (RESPONSE_ACCEPT);
4804 dialog.set_position (WIN_POS_CENTER);
4809 switch (dialog.run ()) {
4810 case RESPONSE_ACCEPT:
4818 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
4820 HBox* hbox = new HBox();
4821 Image* image = new Image (Stock::DIALOG_WARNING, ICON_SIZE_DIALOG);
4822 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
4823 Label message (string_compose (_("\
4824 This session was created with a sample rate of %1 Hz, but\n\
4825 %2 is currently running at %3 Hz. If you load this session,\n\
4826 audio may be played at the wrong sample rate.\n"), desired, PROGRAM_NAME, actual));
4828 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4829 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4830 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4831 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4832 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
4833 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
4834 dialog.set_default_response (RESPONSE_ACCEPT);
4835 dialog.set_position (WIN_POS_CENTER);
4840 switch (dialog.run()) {
4841 case RESPONSE_ACCEPT:
4851 ARDOUR_UI::sr_mismatch_message (framecnt_t desired, framecnt_t actual)
4853 MessageDialog msg (string_compose (_("\
4854 This session was created with a sample rate of %1 Hz, but\n\
4855 %2 is currently running at %3 Hz.\n\
4856 Audio will be recorded and played at the wrong sample rate.\n\
4857 Re-Configure the Audio Engine in\n\
4858 Menu > Window > Audio/Midi Setup"),
4859 desired, PROGRAM_NAME, actual),
4861 Gtk::MESSAGE_WARNING);
4866 ARDOUR_UI::use_config ()
4868 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
4870 set_transport_controllable_state (*node);
4875 ARDOUR_UI::update_transport_clocks (framepos_t pos)
4877 if (UIConfiguration::instance().get_primary_clock_delta_edit_cursor()) {
4878 primary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
4880 primary_clock->set (pos);
4883 if (UIConfiguration::instance().get_secondary_clock_delta_edit_cursor()) {
4884 secondary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
4886 secondary_clock->set (pos);
4889 if (big_clock_window) {
4890 big_clock->set (pos);
4892 ARDOUR_UI::instance()->video_timeline->manual_seek_video_monitor(pos);
4896 ARDOUR_UI::step_edit_status_change (bool yn)
4898 // XXX should really store pre-step edit status of things
4899 // we make insensitive
4902 rec_button.set_active_state (Gtkmm2ext::ImplicitActive);
4903 rec_button.set_sensitive (false);
4905 rec_button.unset_active_state ();;
4906 rec_button.set_sensitive (true);
4911 ARDOUR_UI::record_state_changed ()
4913 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
4915 if (!_session || !big_clock_window) {
4916 /* why bother - the clock isn't visible */
4920 if (_session->record_status () == Session::Recording && _session->have_rec_enabled_track ()) {
4921 big_clock->set_active (true);
4923 big_clock->set_active (false);
4928 ARDOUR_UI::first_idle ()
4931 _session->allow_auto_play (true);
4935 editor->first_idle();
4938 Keyboard::set_can_save_keybindings (true);
4943 ARDOUR_UI::store_clock_modes ()
4945 XMLNode* node = new XMLNode(X_("ClockModes"));
4947 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
4948 XMLNode* child = new XMLNode (X_("Clock"));
4950 child->add_property (X_("name"), (*x)->name());
4951 child->add_property (X_("mode"), enum_2_string ((*x)->mode()));
4952 child->add_property (X_("on"), ((*x)->off() ? X_("no") : X_("yes")));
4954 node->add_child_nocopy (*child);
4957 _session->add_extra_xml (*node);
4958 _session->set_dirty ();
4961 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
4962 : Controllable (name), ui (u), type(tp)
4968 ARDOUR_UI::TransportControllable::set_value (double val, PBD::Controllable::GroupControlDisposition /*group_override*/)
4971 /* do nothing: these are radio-style actions */
4975 const char *action = 0;
4979 action = X_("Roll");
4982 action = X_("Stop");
4985 action = X_("GotoStart");
4988 action = X_("GotoEnd");
4991 action = X_("Loop");
4994 action = X_("PlaySelection");
4997 action = X_("Record");
5007 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
5015 ARDOUR_UI::TransportControllable::get_value (void) const
5042 ARDOUR_UI::setup_profile ()
5044 if (gdk_screen_width() < 1200 || getenv ("ARDOUR_NARROW_SCREEN")) {
5045 Profile->set_small_screen ();
5048 if (g_getenv ("TRX")) {
5049 Profile->set_trx ();
5052 if (g_getenv ("MIXBUS")) {
5053 Profile->set_mixbus ();
5058 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
5060 MissingFileDialog dialog (s, str, type);
5065 int result = dialog.run ();
5072 return 1; // quit entire session load
5075 result = dialog.get_action ();
5081 ARDOUR_UI::ambiguous_file (std::string file, std::vector<std::string> hits)
5083 AmbiguousFileDialog dialog (file, hits);
5090 return dialog.get_which ();
5093 /** Allocate our thread-local buffers */
5095 ARDOUR_UI::get_process_buffers ()
5097 _process_thread->get_buffers ();
5100 /** Drop our thread-local buffers */
5102 ARDOUR_UI::drop_process_buffers ()
5104 _process_thread->drop_buffers ();
5108 ARDOUR_UI::feedback_detected ()
5110 _feedback_exists = true;
5114 ARDOUR_UI::successful_graph_sort ()
5116 _feedback_exists = false;
5120 ARDOUR_UI::midi_panic ()
5123 _session->midi_panic();
5128 ARDOUR_UI::session_format_mismatch (std::string xml_path, std::string backup_path)
5130 const char* start_big = "<span size=\"x-large\" weight=\"bold\">";
5131 const char* end_big = "</span>";
5132 const char* start_mono = "<tt>";
5133 const char* end_mono = "</tt>";
5135 MessageDialog msg (string_compose (_("%4This is a session from an older version of %3%5\n\n"
5136 "%3 has copied the old session file\n\n%6%1%7\n\nto\n\n%6%2%7\n\n"
5137 "From now on, use the -2000 version with older versions of %3"),
5138 xml_path, backup_path, PROGRAM_NAME,
5140 start_mono, end_mono), true);
5147 ARDOUR_UI::reset_peak_display ()
5149 if (!_session || !_session->master_out() || !editor_meter) return;
5150 editor_meter->clear_meters();
5151 editor_meter_max_peak = -INFINITY;
5152 editor_meter_peak_display.set_active_state ( Gtkmm2ext::Off );
5156 ARDOUR_UI::reset_group_peak_display (RouteGroup* group)
5158 if (!_session || !_session->master_out()) return;
5159 if (group == _session->master_out()->route_group()) {
5160 reset_peak_display ();
5165 ARDOUR_UI::reset_route_peak_display (Route* route)
5167 if (!_session || !_session->master_out()) return;
5168 if (_session->master_out().get() == route) {
5169 reset_peak_display ();
5174 ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate)
5176 audio_midi_setup->set_desired_sample_rate (desired_sample_rate);
5177 audio_midi_setup->set_position (WIN_POS_CENTER);
5179 if (Config->get_try_autostart_engine () || getenv ("TRY_AUTOSTART_ENGINE")) {
5180 audio_midi_setup->try_autostart ();
5181 if (ARDOUR::AudioEngine::instance()->running()) {
5187 int response = audio_midi_setup->run();
5189 case Gtk::RESPONSE_OK:
5190 if (!AudioEngine::instance()->running()) {
5204 ARDOUR_UI::transport_numpad_timeout ()
5206 _numpad_locate_happening = false;
5207 if (_numpad_timeout_connection.connected() )
5208 _numpad_timeout_connection.disconnect();
5213 ARDOUR_UI::transport_numpad_decimal ()
5215 _numpad_timeout_connection.disconnect();
5217 if (_numpad_locate_happening) {
5218 if (editor) editor->goto_nth_marker(_pending_locate_num - 1);
5219 _numpad_locate_happening = false;
5221 _pending_locate_num = 0;
5222 _numpad_locate_happening = true;
5223 _numpad_timeout_connection = Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::transport_numpad_timeout), 2*1000);
5228 ARDOUR_UI::transport_numpad_event (int num)
5230 if ( _numpad_locate_happening ) {
5231 _pending_locate_num = _pending_locate_num*10 + num;
5234 case 0: toggle_roll(false, false); break;
5235 case 1: transport_rewind(1); break;
5236 case 2: transport_forward(1); break;
5237 case 3: transport_record(true); break;
5238 case 4: toggle_session_auto_loop(); break;
5239 case 5: transport_record(false); toggle_session_auto_loop(); break;
5240 case 6: toggle_punch(); break;
5241 case 7: toggle_click(); break;
5242 case 8: toggle_auto_return(); break;
5243 case 9: toggle_follow_edits(); break;
5249 ARDOUR_UI::set_flat_buttons ()
5251 CairoWidget::set_flat_buttons( UIConfiguration::instance().get_flat_buttons() );
5255 ARDOUR_UI::audioengine_became_silent ()
5257 MessageDialog msg (string_compose (_("This is a free/demo copy of %1. It has just switched to silent mode."), PROGRAM_NAME),
5259 Gtk::MESSAGE_WARNING,
5263 msg.set_title (string_compose (_("%1 is now silent"), PROGRAM_NAME));
5265 Gtk::Label pay_label (string_compose (_("Please consider paying for a copy of %1 - you can pay whatever you want."), PROGRAM_NAME));
5266 Gtk::Label subscribe_label (_("Better yet become a subscriber - subscriptions start at US$1 per month."));
5267 Gtk::Button pay_button (_("Pay for a copy (via the web)"));
5268 Gtk::Button subscribe_button (_("Become a subscriber (via the web)"));
5269 Gtk::HBox pay_button_box;
5270 Gtk::HBox subscribe_button_box;
5272 pay_button_box.pack_start (pay_button, true, false);
5273 subscribe_button_box.pack_start (subscribe_button, true, false);
5275 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 */
5277 pay_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://ardour.org/download")));
5278 subscribe_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://community.ardour.org/s/subscribe")));
5280 msg.get_vbox()->pack_start (pay_label);
5281 msg.get_vbox()->pack_start (pay_button_box);
5282 msg.get_vbox()->pack_start (subscribe_label);
5283 msg.get_vbox()->pack_start (subscribe_button_box);
5285 msg.get_vbox()->show_all ();
5287 msg.add_button (_("Remain silent"), Gtk::RESPONSE_CANCEL);
5288 msg.add_button (_("Save and quit"), Gtk::RESPONSE_NO);
5289 msg.add_button (_("Give me more time"), Gtk::RESPONSE_YES);
5294 case Gtk::RESPONSE_YES:
5295 AudioEngine::instance()->reset_silence_countdown ();
5298 case Gtk::RESPONSE_NO:
5300 save_state_canfail ("");
5304 case Gtk::RESPONSE_CANCEL:
5306 /* don't reset, save session and exit */
5312 ARDOUR_UI::hide_application ()
5314 Application::instance ()-> hide ();
5318 ARDOUR_UI::setup_toplevel_window (Gtk::Window& window, const string& name, void* owner)
5320 /* icons, titles, WM stuff */
5322 static list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
5324 if (window_icons.empty()) {
5325 Glib::RefPtr<Gdk::Pixbuf> icon;
5326 if ((icon = ::get_icon (PROGRAM_NAME "-icon_16px")) != 0) {
5327 window_icons.push_back (icon);
5329 if ((icon = ::get_icon (PROGRAM_NAME "-icon_22px")) != 0) {
5330 window_icons.push_back (icon);
5332 if ((icon = ::get_icon (PROGRAM_NAME "-icon_32px")) != 0) {
5333 window_icons.push_back (icon);
5335 if ((icon = ::get_icon (PROGRAM_NAME "-icon_48px")) != 0) {
5336 window_icons.push_back (icon);
5340 if (!window_icons.empty()) {
5341 window.set_default_icon_list (window_icons);
5344 Gtkmm2ext::WindowTitle title (Glib::get_application_name());
5346 if (!name.empty()) {
5350 window.set_title (title.get_string());
5351 window.set_wmclass (string_compose (X_("%1_%1"), downcase (PROGRAM_NAME), downcase (name)), PROGRAM_NAME);
5353 window.set_flags (CAN_FOCUS);
5354 window.add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
5356 /* This is a hack to ensure that GTK-accelerators continue to
5357 * work. Once we switch over to entirely native bindings, this will be
5358 * unnecessary and should be removed
5360 window.add_accel_group (ActionManager::ui_manager->get_accel_group());
5362 window.signal_configure_event().connect (sigc::mem_fun (*this, &ARDOUR_UI::configure_handler));
5363 window.signal_window_state_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::tabbed_window_state_event_handler), owner));
5364 window.signal_key_press_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5365 window.signal_key_release_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5369 ARDOUR_UI::key_event_handler (GdkEventKey* ev, Gtk::Window* event_window)
5371 Gtkmm2ext::Bindings* bindings = 0;
5372 Gtk::Window* window = 0;
5374 /* until we get ardour bindings working, we are not handling key
5378 if (ev->type != GDK_KEY_PRESS) {
5382 if (event_window == &_main_window) {
5384 window = event_window;
5386 /* find current tab contents */
5388 Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page());
5390 /* see if it uses the ardour binding system */
5393 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(w->get_data ("ardour-bindings"));
5396 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("main window key event, bindings = %1, global = %2\n", bindings, &global_bindings));
5400 window = event_window;
5402 /* see if window uses ardour binding system */
5404 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(window->get_data ("ardour-bindings"));
5407 /* An empty binding set is treated as if it doesn't exist */
5409 if (bindings && bindings->empty()) {
5413 return key_press_focus_accelerator_handler (*window, ev, bindings);
5416 static Gtkmm2ext::Bindings*
5417 get_bindings_from_widget_heirarchy (GtkWidget* w)
5422 if ((p = g_object_get_data (G_OBJECT(w), "ardour-bindings")) != 0) {
5425 w = gtk_widget_get_parent (w);
5428 return reinterpret_cast<Gtkmm2ext::Bindings*> (p);
5432 ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev, Gtkmm2ext::Bindings* bindings)
5434 GtkWindow* win = window.gobj();
5435 GtkWidget* focus = gtk_window_get_focus (win);
5436 bool special_handling_of_unmodified_accelerators = false;
5437 const guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK));
5441 /* some widget has keyboard focus */
5443 if (GTK_IS_ENTRY(focus) || Keyboard::some_magic_widget_has_focus()) {
5445 /* A particular kind of focusable widget currently has keyboard
5446 * focus. All unmodified key events should go to that widget
5447 * first and not be used as an accelerator by default
5450 special_handling_of_unmodified_accelerators = true;
5454 Gtkmm2ext::Bindings* focus_bindings = get_bindings_from_widget_heirarchy (focus);
5455 if (focus_bindings) {
5456 bindings = focus_bindings;
5457 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Switch bindings based on focus widget, now using %1\n", bindings->name()));
5462 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",
5465 show_gdk_event_state (ev->state),
5466 special_handling_of_unmodified_accelerators,
5467 Keyboard::some_magic_widget_has_focus(),
5469 (focus ? gtk_widget_get_name (focus) : "no focus widget"),
5470 ((ev->state & mask) ? "yes" : "no"),
5471 window.get_title()));
5473 /* This exists to allow us to override the way GTK handles
5474 key events. The normal sequence is:
5476 a) event is delivered to a GtkWindow
5477 b) accelerators/mnemonics are activated
5478 c) if (b) didn't handle the event, propagate to
5479 the focus widget and/or focus chain
5481 The problem with this is that if the accelerators include
5482 keys without modifiers, such as the space bar or the
5483 letter "e", then pressing the key while typing into
5484 a text entry widget results in the accelerator being
5485 activated, instead of the desired letter appearing
5488 There is no good way of fixing this, but this
5489 represents a compromise. The idea is that
5490 key events involving modifiers (not Shift)
5491 get routed into the activation pathway first, then
5492 get propagated to the focus widget if necessary.
5494 If the key event doesn't involve modifiers,
5495 we deliver to the focus widget first, thus allowing
5496 it to get "normal text" without interference
5499 Of course, this can also be problematic: if there
5500 is a widget with focus, then it will swallow
5501 all "normal text" accelerators.
5505 if (!special_handling_of_unmodified_accelerators || (ev->state & mask)) {
5507 /* no special handling or there are modifiers in effect: accelerate first */
5509 DEBUG_TRACE (DEBUG::Accelerators, "\tactivate, then propagate\n");
5510 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tevent send-event:%1 time:%2 length:%3 name %7 string:%4 hardware_keycode:%5 group:%6\n",
5511 ev->send_event, ev->time, ev->length, ev->string, ev->hardware_keycode, ev->group, gdk_keyval_name (ev->keyval)));
5513 DEBUG_TRACE (DEBUG::Accelerators, "\tsending to window\n");
5514 KeyboardKey k (ev->state, ev->keyval);
5518 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tusing Ardour bindings %1 @ %2 for this event\n", bindings->name(), bindings));
5520 if (bindings->activate (k, Bindings::Press)) {
5521 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5526 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5528 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5529 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5533 DEBUG_TRACE (DEBUG::Accelerators, "\tnot accelerated, now propagate\n");
5535 if (gtk_window_propagate_key_event (win, ev)) {
5536 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate handled\n");
5542 /* no modifiers, propagate first */
5544 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate, then activate\n");
5546 if (gtk_window_propagate_key_event (win, ev)) {
5547 DEBUG_TRACE (DEBUG::Accelerators, "\thandled by propagate\n");
5551 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagation didn't handle, so activate\n");
5552 KeyboardKey k (ev->state, ev->keyval);
5556 DEBUG_TRACE (DEBUG::Accelerators, "\tusing Ardour bindings for this window\n");
5559 if (bindings->activate (k, Bindings::Press)) {
5560 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5566 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5568 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5569 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5574 DEBUG_TRACE (DEBUG::Accelerators, "\tnot handled\n");
5579 ARDOUR_UI::load_bindings ()
5581 if ((global_bindings = Bindings::get_bindings (X_("Global"), global_actions)) == 0) {
5582 error << _("Global keybindings are missing") << endmsg;
5587 ARDOUR_UI::cancel_solo ()
5590 if (_session->soloing()) {
5591 _session->set_solo (_session->get_routes(), false);
5592 } else if (_session->listening()) {
5593 _session->set_listen (_session->get_routes(), false);
5596 _session->clear_all_solo_state (_session->get_routes()); // safeguard, ideally this won't do anything, check the log-window