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/record_enable_control.h"
89 #include "ardour/session_directory.h"
90 #include "ardour/session_route.h"
91 #include "ardour/session_state_utils.h"
92 #include "ardour/session_utils.h"
93 #include "ardour/source_factory.h"
94 #include "ardour/slave.h"
95 #include "ardour/system_exec.h"
96 #include "ardour/track.h"
97 #include "ardour/vca_manager.h"
98 #include "ardour/utils.h"
100 #include "LuaBridge/LuaBridge.h"
102 #ifdef WINDOWS_VST_SUPPORT
105 #ifdef AUDIOUNIT_SUPPORT
106 #include "ardour/audio_unit.h"
109 // fix for OSX (nsm.h has a check function, AU/Apple defines check)
114 #include "timecode/time.h"
116 typedef uint64_t microseconds_t;
121 #include "add_route_dialog.h"
122 #include "ambiguous_file_dialog.h"
123 #include "ardour_ui.h"
124 #include "audio_clock.h"
125 #include "audio_region_view.h"
126 #include "big_clock_window.h"
127 #include "bundle_manager.h"
128 #include "duplicate_routes_dialog.h"
130 #include "engine_dialog.h"
131 #include "export_video_dialog.h"
132 #include "export_video_infobox.h"
133 #include "gain_meter.h"
134 #include "global_port_matrix.h"
135 #include "gui_object.h"
136 #include "gui_thread.h"
137 #include "keyboard.h"
138 #include "keyeditor.h"
139 #include "location_ui.h"
140 #include "lua_script_manager.h"
141 #include "luawindow.h"
142 #include "main_clock.h"
143 #include "missing_file_dialog.h"
144 #include "missing_plugin_dialog.h"
145 #include "mixer_ui.h"
146 #include "meterbridge.h"
147 #include "mouse_cursors.h"
150 #include "pingback.h"
151 #include "processor_box.h"
152 #include "prompter.h"
153 #include "public_editor.h"
154 #include "rc_option_editor.h"
155 #include "route_time_axis.h"
156 #include "route_params_ui.h"
157 #include "save_as_dialog.h"
158 #include "script_selector.h"
159 #include "session_dialog.h"
160 #include "session_metadata_dialog.h"
161 #include "session_option_editor.h"
162 #include "shuttle_control.h"
163 #include "speaker_dialog.h"
166 #include "theme_manager.h"
167 #include "time_axis_view_item.h"
170 #include "video_server_dialog.h"
171 #include "add_video_dialog.h"
172 #include "transcode_video_dialog.h"
176 using namespace ARDOUR;
177 using namespace ARDOUR_UI_UTILS;
179 using namespace Gtkmm2ext;
182 using namespace Editing;
184 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
186 sigc::signal<void, framepos_t, bool, framepos_t> ARDOUR_UI::Clock;
187 sigc::signal<void> ARDOUR_UI::CloseAllDialogs;
190 ask_about_configuration_copy (string const & old_dir, string const & new_dir, int version)
192 MessageDialog msg (string_compose (_("%1 %2.x has discovered configuration files from %1 %3.x.\n\n"
193 "Would you like these files to be copied and used for %1 %2.x?\n\n"
194 "(This will require you to restart %1.)"),
195 PROGRAM_NAME, PROGRAM_VERSION, version),
196 false, /* no markup */
199 true /* modal, though it hardly matters since it is the only window */
202 msg.set_default_response (Gtk::RESPONSE_YES);
205 return (msg.run() == Gtk::RESPONSE_YES);
209 libxml_generic_error_func (void* /* parsing_context*/,
217 vsnprintf (buf, sizeof (buf), msg, ap);
218 error << buf << endmsg;
223 libxml_structured_error_func (void* /* parsing_context*/,
231 replace_all (msg, "\n", "");
234 if (err->file && err->line) {
235 error << X_("XML error: ") << msg << " in " << err->file << " at line " << err->line;
238 error << ':' << err->int2;
243 error << X_("XML error: ") << msg << endmsg;
249 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
250 : Gtkmm2ext::UI (PROGRAM_NAME, X_("gui"), argcp, argvp)
251 , session_loaded (false)
252 , gui_object_state (new GUIObjectState)
253 , primary_clock (new MainClock (X_("primary"), X_("transport"), true ))
254 , secondary_clock (new MainClock (X_("secondary"), X_("secondary"), false))
255 , big_clock (new AudioClock (X_("bigclock"), false, "big", true, true, false, false))
257 , global_actions (X_("global"))
258 , ignore_dual_punch (false)
259 , main_window_visibility (0)
264 , _mixer_on_top (false)
265 , _initial_verbose_plugin_scan (false)
266 , first_time_engine_run (true)
267 , roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll))
268 , stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop))
269 , goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart))
270 , goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd))
271 , auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop))
272 , play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection))
273 , rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable))
274 , auto_return_button (ArdourButton::led_default_elements)
275 , follow_edits_button (ArdourButton::led_default_elements)
276 , auto_input_button (ArdourButton::led_default_elements)
277 , auditioning_alert_button (_("Audition"))
278 , solo_alert_button (_("Solo"))
279 , feedback_alert_button (_("Feedback"))
280 , error_alert_button ( ArdourButton::just_led_default_elements )
282 , editor_meter_peak_display()
283 , _numpad_locate_happening (false)
284 , _session_is_new (false)
285 , last_key_press_time (0)
289 , rc_option_editor (0)
290 , speaker_config_window (X_("speaker-config"), _("Speaker Configuration"))
291 , add_route_dialog (X_("add-routes"), _("Add Tracks/Busses"))
292 , about (X_("about"), _("About"))
293 , location_ui (X_("locations"), _("Locations"))
294 , route_params (X_("inspector"), _("Tracks and Busses"))
295 , audio_midi_setup (X_("audio-midi-setup"), _("Audio/MIDI Setup"))
296 , export_video_dialog (X_("video-export"), _("Video Export Dialog"))
297 , lua_script_window (X_("script-manager"), _("Script Manager"))
298 , session_option_editor (X_("session-options-editor"), _("Properties"), boost::bind (&ARDOUR_UI::create_session_option_editor, this))
299 , add_video_dialog (X_("add-video"), _("Add Video"), boost::bind (&ARDOUR_UI::create_add_video_dialog, this))
300 , bundle_manager (X_("bundle-manager"), _("Bundle Manager"), boost::bind (&ARDOUR_UI::create_bundle_manager, this))
301 , big_clock_window (X_("big-clock"), _("Big Clock"), boost::bind (&ARDOUR_UI::create_big_clock_window, this))
302 , audio_port_matrix (X_("audio-connection-manager"), _("Audio Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::AUDIO))
303 , midi_port_matrix (X_("midi-connection-manager"), _("MIDI Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::MIDI))
304 , key_editor (X_("key-editor"), _("Bindings Editor"), boost::bind (&ARDOUR_UI::create_key_editor, this))
305 , video_server_process (0)
307 , have_configure_timeout (false)
308 , last_configure_time (0)
310 , have_disk_speed_dialog_displayed (false)
311 , _status_bar_visibility (X_("status-bar"))
312 , _feedback_exists (false)
313 , _log_not_acknowledged (LogLevelNone)
314 , duplicate_routes_dialog (0)
315 , editor_visibility_button (S_("Window|Editor"))
316 , mixer_visibility_button (S_("Window|Mixer"))
317 , prefs_visibility_button (S_("Window|Preferences"))
319 Gtkmm2ext::init (localedir);
321 UIConfiguration::instance().post_gui_init ();
323 if (ARDOUR::handle_old_configuration_files (boost::bind (ask_about_configuration_copy, _1, _2, _3))) {
324 MessageDialog msg (string_compose (_("Your configuration files were copied. You can now restart %1."), PROGRAM_NAME), true);
326 /* configuration was modified, exit immediately */
330 if (theArdourUI == 0) {
334 /* track main window visibility */
336 main_window_visibility = new VisibilityTracker (_main_window);
338 /* stop libxml from spewing to stdout/stderr */
340 xmlSetGenericErrorFunc (this, libxml_generic_error_func);
341 xmlSetStructuredErrorFunc (this, libxml_structured_error_func);
343 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::parameter_changed));
344 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
345 UIConfiguration::instance().map_parameters (pc);
347 roll_button.set_controllable (roll_controllable);
348 stop_button.set_controllable (stop_controllable);
349 goto_start_button.set_controllable (goto_start_controllable);
350 goto_end_button.set_controllable (goto_end_controllable);
351 auto_loop_button.set_controllable (auto_loop_controllable);
352 play_selection_button.set_controllable (play_selection_controllable);
353 rec_button.set_controllable (rec_controllable);
355 roll_button.set_name ("transport button");
356 stop_button.set_name ("transport button");
357 goto_start_button.set_name ("transport button");
358 goto_end_button.set_name ("transport button");
359 auto_loop_button.set_name ("transport button");
360 play_selection_button.set_name ("transport button");
361 rec_button.set_name ("transport recenable button");
362 midi_panic_button.set_name ("transport button");
364 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
365 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
367 ARDOUR::Session::VersionMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_format_mismatch, this, _1, _2), gui_context());
369 /* handle dialog requests */
371 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
373 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
375 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
377 /* handle Audio/MIDI setup when session requires it */
379 ARDOUR::Session::AudioEngineSetupRequired.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::do_audio_midi_setup, this, _1));
381 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
383 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
385 /* handle sr mismatch with a dialog - cross-thread from engine */
386 ARDOUR::Session::NotifyAboutSampleRateMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::sr_mismatch_message, this, _1, _2), gui_context ());
388 /* handle requests to quit (coming from JACK session) */
390 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::finish, this), gui_context ());
392 /* tell the user about feedback */
394 ARDOUR::Session::FeedbackDetected.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::feedback_detected, this), gui_context ());
395 ARDOUR::Session::SuccessfulGraphSort.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::successful_graph_sort, this), gui_context ());
397 /* handle requests to deal with missing files */
399 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
401 /* and ambiguous files */
403 ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2));
405 /* also plugin scan messages */
406 ARDOUR::PluginScanMessage.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_dialog, this, _1, _2, _3), gui_context());
407 ARDOUR::PluginScanTimeout.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_timeout, this, _1), gui_context());
409 ARDOUR::GUIIdle.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::gui_idle_handler, this), gui_context());
411 Config->ParameterChanged.connect ( forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::set_flat_buttons, this), gui_context() );
414 /* lets get this party started */
416 setup_gtk_ardour_enums ();
419 SessionEvent::create_per_thread_pool ("GUI", 4096);
421 /* we like keyboards */
423 keyboard = new ArdourKeyboard(*this);
425 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
427 keyboard->set_state (*node, Stateful::loading_state_version);
430 UIConfiguration::instance().reset_dpi ();
432 TimeAxisViewItem::set_constant_heights ();
434 /* Set this up so that our window proxies can register actions */
436 ActionManager::init ();
438 /* The following must happen after ARDOUR::init() so that Config is set up */
440 const XMLNode* ui_xml = Config->extra_xml (X_("UI"));
443 key_editor.set_state (*ui_xml, 0);
444 session_option_editor.set_state (*ui_xml, 0);
445 speaker_config_window.set_state (*ui_xml, 0);
446 about.set_state (*ui_xml, 0);
447 add_route_dialog.set_state (*ui_xml, 0);
448 add_video_dialog.set_state (*ui_xml, 0);
449 route_params.set_state (*ui_xml, 0);
450 bundle_manager.set_state (*ui_xml, 0);
451 location_ui.set_state (*ui_xml, 0);
452 big_clock_window.set_state (*ui_xml, 0);
453 audio_port_matrix.set_state (*ui_xml, 0);
454 midi_port_matrix.set_state (*ui_xml, 0);
455 export_video_dialog.set_state (*ui_xml, 0);
456 lua_script_window.set_state (*ui_xml, 0);
459 /* Separate windows */
461 WM::Manager::instance().register_window (&key_editor);
462 WM::Manager::instance().register_window (&session_option_editor);
463 WM::Manager::instance().register_window (&speaker_config_window);
464 WM::Manager::instance().register_window (&about);
465 WM::Manager::instance().register_window (&add_route_dialog);
466 WM::Manager::instance().register_window (&add_video_dialog);
467 WM::Manager::instance().register_window (&route_params);
468 WM::Manager::instance().register_window (&audio_midi_setup);
469 WM::Manager::instance().register_window (&export_video_dialog);
470 WM::Manager::instance().register_window (&lua_script_window);
471 WM::Manager::instance().register_window (&bundle_manager);
472 WM::Manager::instance().register_window (&location_ui);
473 WM::Manager::instance().register_window (&big_clock_window);
474 WM::Manager::instance().register_window (&audio_port_matrix);
475 WM::Manager::instance().register_window (&midi_port_matrix);
477 /* do not retain position for add route dialog */
478 add_route_dialog.set_state_mask (WindowProxy::Size);
480 /* Trigger setting up the color scheme and loading the GTK RC file */
482 UIConfiguration::instance().load_rc_file (false);
484 _process_thread = new ProcessThread ();
485 _process_thread->init ();
487 UIConfiguration::instance().DPIReset.connect (sigc::mem_fun (*this, &ARDOUR_UI::resize_text_widgets));
492 GlobalPortMatrixWindow*
493 ARDOUR_UI::create_global_port_matrix (ARDOUR::DataType type)
498 return new GlobalPortMatrixWindow (_session, type);
502 ARDOUR_UI::attach_to_engine ()
504 AudioEngine::instance()->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
505 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
509 ARDOUR_UI::engine_stopped ()
511 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
512 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
513 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
514 update_sample_rate (0);
519 ARDOUR_UI::engine_running ()
521 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
522 if (first_time_engine_run) {
524 first_time_engine_run = false;
528 _session->reset_xrun_count ();
530 update_disk_space ();
532 update_xrun_count ();
533 update_sample_rate (AudioEngine::instance()->sample_rate());
534 update_timecode_format ();
535 update_peak_thread_work ();
536 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, true);
537 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, false);
541 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
543 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
544 /* we can't rely on the original string continuing to exist when we are called
545 again in the GUI thread, so make a copy and note that we need to
548 char *copy = strdup (reason);
549 Gtkmm2ext::UI::instance()->call_slot (MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
553 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
554 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
556 update_sample_rate (0);
560 /* if the reason is a non-empty string, it means that the backend was shutdown
561 rather than just Ardour.
564 if (strlen (reason)) {
565 msgstr = string_compose (_("The audio backend was shutdown because:\n\n%1"), reason);
567 msgstr = string_compose (_("\
568 The audio backend has either been shutdown or it\n\
569 disconnected %1 because %1\n\
570 was not fast enough. Try to restart\n\
571 the audio backend and save the session."), PROGRAM_NAME);
574 MessageDialog msg (_main_window, msgstr);
575 pop_back_splash (msg);
579 free (const_cast<char*> (reason));
584 ARDOUR_UI::post_engine ()
586 /* Things to be done once (and once ONLY) after we have a backend running in the AudioEngine
588 #ifdef AUDIOUNIT_SUPPORT
590 if (AUPluginInfo::au_get_crashlog(au_msg)) {
591 popup_error(_("Audio Unit Plugin Scan Failed. Automatic AU scanning has been disabled. Please see the log window for further details."));
592 error << _("Audio Unit Plugin Scan Failed:") << endmsg;
593 info << au_msg << endmsg;
597 ARDOUR::init_post_engine ();
599 /* connect to important signals */
601 AudioEngine::instance()->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
602 AudioEngine::instance()->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
603 AudioEngine::instance()->BufferSizeChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
604 AudioEngine::instance()->Halted.connect_same_thread (halt_connection, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
605 AudioEngine::instance()->BecameSilent.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::audioengine_became_silent, this), gui_context());
607 if (setup_windows ()) {
608 throw failed_constructor ();
611 /* Do this after setup_windows (), as that's when the _status_bar_visibility is created */
612 XMLNode* n = Config->extra_xml (X_("UI"));
614 _status_bar_visibility.set_state (*n);
617 check_memory_locking();
619 /* this is the first point at which all the possible actions are
620 * available, because some of the available actions are dependent on
621 * aspects of the engine/backend.
624 if (ARDOUR_COMMAND_LINE::show_key_actions) {
627 vector<string> paths;
628 vector<string> labels;
629 vector<string> tooltips;
631 vector<Glib::RefPtr<Gtk::Action> > actions;
633 Gtkmm2ext::ActionMap::get_all_actions (paths, labels, tooltips, keys, actions);
635 vector<string>::iterator k;
636 vector<string>::iterator p;
638 for (p = paths.begin(), k = keys.begin(); p != paths.end(); ++k, ++p) {
643 cout << *p << " => " << *k << endl;
647 halt_connection.disconnect ();
648 AudioEngine::instance()->stop ();
652 /* this being a GUI and all, we want peakfiles */
654 AudioFileSource::set_build_peakfiles (true);
655 AudioFileSource::set_build_missing_peakfiles (true);
657 /* set default clock modes */
659 primary_clock->set_mode (AudioClock::Timecode);
660 secondary_clock->set_mode (AudioClock::BBT);
662 /* start the time-of-day-clock */
665 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
666 update_wall_clock ();
667 Glib::signal_timeout().connect_seconds (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 1);
672 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
673 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
674 Config->map_parameters (pc);
676 UIConfiguration::instance().map_parameters (pc);
680 ARDOUR_UI::~ARDOUR_UI ()
682 UIConfiguration::instance().save_state();
686 if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
687 // don't bother at 'real' exit. the OS cleans up for us.
688 delete big_clock; big_clock = 0;
689 delete primary_clock; primary_clock = 0;
690 delete secondary_clock; secondary_clock = 0;
691 delete _process_thread; _process_thread = 0;
692 delete meterbridge; meterbridge = 0;
693 delete luawindow; luawindow = 0;
694 delete editor; editor = 0;
695 delete mixer; mixer = 0;
697 delete gui_object_state; gui_object_state = 0;
698 delete main_window_visibility;
699 FastMeter::flush_pattern_cache ();
700 PixFader::flush_pattern_cache ();
704 /* Small trick to flush main-thread event pool.
705 * Other thread-pools are destroyed at pthread_exit(),
706 * but tmain thread termination is too late to trigger Pool::~Pool()
708 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.
709 delete ev->event_pool();
714 ARDOUR_UI::pop_back_splash (Gtk::Window& win)
716 if (Splash::instance()) {
717 Splash::instance()->pop_back_for (win);
722 ARDOUR_UI::configure_timeout ()
724 if (last_configure_time == 0) {
725 /* no configure events yet */
729 /* force a gap of 0.5 seconds since the last configure event
732 if (get_microseconds() - last_configure_time < 500000) {
735 have_configure_timeout = false;
736 save_ardour_state ();
742 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
744 if (have_configure_timeout) {
745 last_configure_time = get_microseconds();
747 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
748 have_configure_timeout = true;
755 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
757 XMLProperty const * prop;
759 if ((prop = node.property ("roll")) != 0) {
760 roll_controllable->set_id (prop->value());
762 if ((prop = node.property ("stop")) != 0) {
763 stop_controllable->set_id (prop->value());
765 if ((prop = node.property ("goto-start")) != 0) {
766 goto_start_controllable->set_id (prop->value());
768 if ((prop = node.property ("goto-end")) != 0) {
769 goto_end_controllable->set_id (prop->value());
771 if ((prop = node.property ("auto-loop")) != 0) {
772 auto_loop_controllable->set_id (prop->value());
774 if ((prop = node.property ("play-selection")) != 0) {
775 play_selection_controllable->set_id (prop->value());
777 if ((prop = node.property ("rec")) != 0) {
778 rec_controllable->set_id (prop->value());
780 if ((prop = node.property ("shuttle")) != 0) {
781 shuttle_box->controllable()->set_id (prop->value());
786 ARDOUR_UI::get_transport_controllable_state ()
788 XMLNode* node = new XMLNode(X_("TransportControllables"));
791 roll_controllable->id().print (buf, sizeof (buf));
792 node->add_property (X_("roll"), buf);
793 stop_controllable->id().print (buf, sizeof (buf));
794 node->add_property (X_("stop"), buf);
795 goto_start_controllable->id().print (buf, sizeof (buf));
796 node->add_property (X_("goto_start"), buf);
797 goto_end_controllable->id().print (buf, sizeof (buf));
798 node->add_property (X_("goto_end"), buf);
799 auto_loop_controllable->id().print (buf, sizeof (buf));
800 node->add_property (X_("auto_loop"), buf);
801 play_selection_controllable->id().print (buf, sizeof (buf));
802 node->add_property (X_("play_selection"), buf);
803 rec_controllable->id().print (buf, sizeof (buf));
804 node->add_property (X_("rec"), buf);
805 shuttle_box->controllable()->id().print (buf, sizeof (buf));
806 node->add_property (X_("shuttle"), buf);
812 ARDOUR_UI::save_session_at_its_request (std::string snapshot_name)
815 _session->save_state (snapshot_name);
820 ARDOUR_UI::autosave_session ()
822 if (g_main_depth() > 1) {
823 /* inside a recursive main loop,
824 give up because we may not be able to
830 if (!Config->get_periodic_safety_backups()) {
835 _session->maybe_write_autosave();
842 ARDOUR_UI::session_dirty_changed ()
849 ARDOUR_UI::update_autosave ()
851 if (_session && _session->dirty()) {
852 if (_autosave_connection.connected()) {
853 _autosave_connection.disconnect();
856 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
857 Config->get_periodic_safety_backup_interval() * 1000);
860 if (_autosave_connection.connected()) {
861 _autosave_connection.disconnect();
867 ARDOUR_UI::check_announcements ()
870 string _annc_filename;
873 _annc_filename = PROGRAM_NAME "_announcements_osx_";
874 #elif defined PLATFORM_WINDOWS
875 _annc_filename = PROGRAM_NAME "_announcements_windows_";
877 _annc_filename = PROGRAM_NAME "_announcements_linux_";
879 _annc_filename.append (VERSIONSTRING);
881 _announce_string = "";
883 std::string path = Glib::build_filename (user_config_directory(), _annc_filename);
884 FILE* fin = g_fopen (path.c_str(), "rb");
886 while (!feof (fin)) {
889 if ((len = fread (tmp, sizeof(char), 1024, fin)) == 0 || ferror (fin)) {
892 _announce_string.append (tmp, len);
897 pingback (VERSIONSTRING, path);
902 _hide_splash (gpointer arg)
904 ((ARDOUR_UI*)arg)->hide_splash();
909 ARDOUR_UI::starting ()
911 Application* app = Application::instance ();
913 bool brand_new_user = ArdourStartup::required ();
915 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
916 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::load_from_application_api));
918 if (ARDOUR_COMMAND_LINE::check_announcements) {
919 check_announcements ();
924 /* we need to create this early because it may need to set the
925 * audio backend end up.
929 audio_midi_setup.get (true);
931 std::cerr << "audio-midi engine setup failed."<< std::endl;
935 if ((nsm_url = g_getenv ("NSM_URL")) != 0) {
936 nsm = new NSM_Client;
937 if (!nsm->init (nsm_url)) {
938 /* the ardour executable may have different names:
940 * waf's obj.target for distro versions: eg ardour4, ardourvst4
941 * Ardour4, Mixbus3 for bundled versions + full path on OSX & windows
942 * argv[0] does not apply since we need the wrapper-script (not the binary itself)
944 * The wrapper startup script should set the environment variable 'ARDOUR_SELF'
946 const char *process_name = g_getenv ("ARDOUR_SELF");
947 nsm->announce (PROGRAM_NAME, ":dirty:", process_name ? process_name : "ardour4");
950 // wait for announce reply from nsm server
951 for ( i = 0; i < 5000; ++i) {
955 if (nsm->is_active()) {
960 error << _("NSM server did not announce itself") << endmsg;
963 // wait for open command from nsm server
964 for ( i = 0; i < 5000; ++i) {
967 if (nsm->client_id ()) {
973 error << _("NSM: no client ID provided") << endmsg;
977 if (_session && nsm) {
978 _session->set_nsm_state( nsm->is_active() );
980 error << _("NSM: no session created") << endmsg;
984 // nsm requires these actions disabled
985 vector<string> action_names;
986 action_names.push_back("SaveAs");
987 action_names.push_back("Rename");
988 action_names.push_back("New");
989 action_names.push_back("Open");
990 action_names.push_back("Recent");
991 action_names.push_back("Close");
993 for (vector<string>::const_iterator n = action_names.begin(); n != action_names.end(); ++n) {
994 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), (*n).c_str());
996 act->set_sensitive (false);
1003 error << _("NSM: initialization failed") << endmsg;
1009 if (brand_new_user) {
1010 _initial_verbose_plugin_scan = true;
1015 _initial_verbose_plugin_scan = false;
1016 switch (s.response ()) {
1017 case Gtk::RESPONSE_OK:
1024 #ifdef NO_PLUGIN_STATE
1026 ARDOUR::RecentSessions rs;
1027 ARDOUR::read_recent_sessions (rs);
1029 string path = Glib::build_filename (user_config_directory(), ".iknowaboutfreeversion");
1031 if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS) && !rs.empty()) {
1033 /* already used Ardour, have sessions ... warn about plugin state */
1035 ArdourDialog d (_("Free/Demo Version Warning"), true);
1037 Button b (string_compose (_("Subscribe and support development of %1"), PROGRAM_NAME));
1038 CheckButton c (_("Don't warn me about this again"));
1040 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"),
1041 string_compose (_("This is a free/demo version of %1"), PROGRAM_NAME),
1042 _("It will not restore OR save any plugin settings"),
1043 _("If you load an existing session with plugin settings\n"
1044 "they will not be used and will be lost."),
1045 _("To get full access to updates without this limitation\n"
1046 "consider becoming a subscriber for a low cost every month.")));
1047 l.set_justify (JUSTIFY_CENTER);
1049 b.signal_clicked().connect (mem_fun(*this, &ARDOUR_UI::launch_subscribe));
1051 d.get_vbox()->pack_start (l, true, true);
1052 d.get_vbox()->pack_start (b, false, false, 12);
1053 d.get_vbox()->pack_start (c, false, false, 12);
1055 d.add_button (_("Quit now"), RESPONSE_CANCEL);
1056 d.add_button (string_compose (_("Continue using %1"), PROGRAM_NAME), RESPONSE_OK);
1060 c.signal_toggled().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (toggle_file_existence), path)));
1062 if (d.run () != RESPONSE_OK) {
1068 /* go get a session */
1070 const bool new_session_required = (ARDOUR_COMMAND_LINE::new_session || brand_new_user);
1072 if (get_session_parameters (false, new_session_required, ARDOUR_COMMAND_LINE::load_template)) {
1073 std::cerr << "Cannot get session parameters."<< std::endl;
1080 WM::Manager::instance().show_visible ();
1082 /* We have to do this here since goto_editor_window() ends up calling show_all() on the
1083 * editor window, and we may want stuff to be hidden.
1085 _status_bar_visibility.update ();
1087 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
1089 if (splash && splash->is_visible()) {
1090 // in 1 second, hide the splash screen
1091 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
1094 /* all other dialogs are created conditionally */
1100 ARDOUR_UI::check_memory_locking ()
1102 #if defined(__APPLE__) || defined(PLATFORM_WINDOWS)
1103 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
1107 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
1109 if (AudioEngine::instance()->is_realtime() && memory_warning_node == 0) {
1111 struct rlimit limits;
1113 long pages, page_size;
1115 size_t pages_len=sizeof(pages);
1116 if ((page_size = getpagesize()) < 0 ||
1117 sysctlbyname("hw.availpages", &pages, &pages_len, NULL, 0))
1119 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0)
1124 ram = (int64_t) pages * (int64_t) page_size;
1127 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
1131 if (limits.rlim_cur != RLIM_INFINITY) {
1133 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
1137 _("WARNING: Your system has a limit for maximum amount of locked memory. "
1138 "This might cause %1 to run out of memory before your system "
1139 "runs out of memory. \n\n"
1140 "You can view the memory limit with 'ulimit -l', "
1141 "and it is normally controlled by %2"),
1144 X_("/etc/login.conf")
1146 X_(" /etc/security/limits.conf")
1150 msg.set_default_response (RESPONSE_OK);
1152 VBox* vbox = msg.get_vbox();
1154 CheckButton cb (_("Do not show this window again"));
1155 hbox.pack_start (cb, true, false);
1156 vbox->pack_start (hbox);
1161 pop_back_splash (msg);
1165 if (cb.get_active()) {
1166 XMLNode node (X_("no-memory-warning"));
1167 Config->add_instant_xml (node);
1172 #endif // !__APPLE__
1177 ARDOUR_UI::queue_finish ()
1179 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
1183 ARDOUR_UI::idle_finish ()
1186 return false; /* do not call again */
1193 ARDOUR_UI::instance()->video_timeline->sync_session_state();
1195 if (_session->dirty()) {
1196 vector<string> actions;
1197 actions.push_back (_("Don't quit"));
1198 actions.push_back (_("Just quit"));
1199 actions.push_back (_("Save and quit"));
1200 switch (ask_about_saving_session(actions)) {
1205 /* use the default name */
1206 if (save_state_canfail ("")) {
1207 /* failed - don't quit */
1208 MessageDialog msg (_main_window,
1209 string_compose (_("\
1210 %1 was unable to save your session.\n\n\
1211 If you still wish to quit, please use the\n\n\
1212 \"Just quit\" option."), PROGRAM_NAME));
1213 pop_back_splash(msg);
1223 second_connection.disconnect ();
1224 point_one_second_connection.disconnect ();
1225 point_zero_something_second_connection.disconnect();
1226 fps_connection.disconnect();
1229 delete ARDOUR_UI::instance()->video_timeline;
1230 ARDOUR_UI::instance()->video_timeline = NULL;
1231 stop_video_server();
1233 /* Save state before deleting the session, as that causes some
1234 windows to be destroyed before their visible state can be
1237 save_ardour_state ();
1239 close_all_dialogs ();
1242 _session->set_clean ();
1243 _session->remove_pending_capture_state ();
1248 halt_connection.disconnect ();
1249 AudioEngine::instance()->stop ();
1250 #ifdef WINDOWS_VST_SUPPORT
1251 fst_stop_threading();
1257 ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
1259 ArdourDialog window (_("Unsaved Session"));
1260 Gtk::HBox dhbox; // the hbox for the image and text
1261 Gtk::Label prompt_label;
1262 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
1266 assert (actions.size() >= 3);
1268 window.add_button (actions[0], RESPONSE_REJECT);
1269 window.add_button (actions[1], RESPONSE_APPLY);
1270 window.add_button (actions[2], RESPONSE_ACCEPT);
1272 window.set_default_response (RESPONSE_ACCEPT);
1274 Gtk::Button noquit_button (msg);
1275 noquit_button.set_name ("EditorGTKButton");
1279 if (_session->snap_name() == _session->name()) {
1280 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?"),
1281 _session->snap_name());
1283 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?"),
1284 _session->snap_name());
1287 prompt_label.set_text (prompt);
1288 prompt_label.set_name (X_("PrompterLabel"));
1289 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
1291 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
1292 dhbox.set_homogeneous (false);
1293 dhbox.pack_start (*dimage, false, false, 5);
1294 dhbox.pack_start (prompt_label, true, false, 5);
1295 window.get_vbox()->pack_start (dhbox);
1297 window.set_name (_("Prompter"));
1298 window.set_modal (true);
1299 window.set_resizable (false);
1302 prompt_label.show();
1307 ResponseType r = (ResponseType) window.run();
1312 case RESPONSE_ACCEPT: // save and get out of here
1314 case RESPONSE_APPLY: // get out of here
1325 ARDOUR_UI::every_second ()
1328 update_xrun_count ();
1329 update_buffer_load ();
1330 update_disk_space ();
1331 update_timecode_format ();
1332 update_peak_thread_work ();
1334 if (nsm && nsm->is_active ()) {
1337 if (!_was_dirty && _session->dirty ()) {
1341 else if (_was_dirty && !_session->dirty ()){
1349 ARDOUR_UI::every_point_one_seconds ()
1351 // TODO get rid of this..
1352 // ShuttleControl is updated directly via TransportStateChange signal
1356 ARDOUR_UI::every_point_zero_something_seconds ()
1358 // august 2007: actual update frequency: 25Hz (40ms), not 100Hz
1360 if (editor_meter && UIConfiguration::instance().get_show_editor_meter()) {
1361 float mpeak = editor_meter->update_meters();
1362 if (mpeak > editor_meter_max_peak) {
1363 if (mpeak >= UIConfiguration::instance().get_meter_peak()) {
1364 editor_meter_peak_display.set_active_state ( Gtkmm2ext::ExplicitActive );
1371 ARDOUR_UI::set_fps_timeout_connection ()
1373 unsigned int interval = 40;
1374 if (!_session) return;
1375 if (_session->timecode_frames_per_second() != 0) {
1376 /* ideally we'll use a select() to sleep and not accumulate
1377 * idle time to provide a regular periodic signal.
1378 * See linux_vst_gui_support.cc 'elapsed_time_ms'.
1379 * However, that'll require a dedicated thread and cross-thread
1380 * signals to the GUI Thread..
1382 interval = floor(500. /* update twice per FPS, since Glib::signal_timeout is very irregular */
1383 * _session->frame_rate() / _session->nominal_frame_rate()
1384 / _session->timecode_frames_per_second()
1386 #ifdef PLATFORM_WINDOWS
1387 // the smallest windows scheduler time-slice is ~15ms.
1388 // periodic GUI timeouts shorter than that will cause
1389 // WaitForSingleObject to spinlock (100% of one CPU Core)
1390 // and gtk never enters idle mode.
1391 // also changing timeBeginPeriod(1) does not affect that in
1392 // any beneficial way, so we just limit the max rate for now.
1393 interval = std::max(30u, interval); // at most ~33Hz.
1395 interval = std::max(8u, interval); // at most 120Hz.
1398 fps_connection.disconnect();
1399 Timers::set_fps_interval (interval);
1403 ARDOUR_UI::update_sample_rate (framecnt_t)
1407 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
1409 if (!AudioEngine::instance()->connected()) {
1411 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1415 framecnt_t rate = AudioEngine::instance()->sample_rate();
1418 /* no sample rate available */
1419 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1422 if (fmod (rate, 1000.0) != 0.0) {
1423 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
1424 (float) rate / 1000.0f,
1425 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1427 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
1429 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1433 sample_rate_label.set_markup (buf);
1437 ARDOUR_UI::update_format ()
1440 format_label.set_text ("");
1445 s << _("File:") << X_(" <span foreground=\"green\">");
1447 switch (_session->config.get_native_file_header_format ()) {
1479 switch (_session->config.get_native_file_data_format ()) {
1493 format_label.set_markup (s.str ());
1497 ARDOUR_UI::update_xrun_count ()
1501 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1502 should also be changed.
1506 const unsigned int x = _session->get_xrun_count ();
1508 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">>10K</span>"), X_("red"));
1510 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">%u</span>"), x > 0 ? X_("red") : X_("green"), x);
1513 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">?</span>"), X_("yellow"));
1515 xrun_label.set_markup (buf);
1516 set_tip (xrun_label, _("Audio dropouts. Shift+click to reset"));
1520 ARDOUR_UI::update_cpu_load ()
1524 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1525 should also be changed.
1528 double const c = AudioEngine::instance()->get_dsp_load ();
1529 snprintf (buf, sizeof (buf), _("DSP: <span foreground=\"%s\">%5.1f%%</span>"), c >= 90 ? X_("red") : X_("green"), c);
1530 cpu_load_label.set_markup (buf);
1534 ARDOUR_UI::update_peak_thread_work ()
1537 const int c = SourceFactory::peak_work_queue_length ();
1539 snprintf (buf, sizeof (buf), _("PkBld: <span foreground=\"%s\">%d</span>"), c >= 2 ? X_("red") : X_("green"), c);
1540 peak_thread_work_label.set_markup (buf);
1542 peak_thread_work_label.set_markup (X_(""));
1547 ARDOUR_UI::update_buffer_load ()
1551 uint32_t const playback = _session ? _session->playback_load () : 100;
1552 uint32_t const capture = _session ? _session->capture_load () : 100;
1554 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1555 should also be changed.
1561 _("Buffers: <span foreground=\"green\">p:</span><span foreground=\"%s\">%" PRIu32 "%%</span> "
1562 "<span foreground=\"green\">c:</span><span foreground=\"%s\">%" PRIu32 "%%</span>"),
1563 playback <= 5 ? X_("red") : X_("green"),
1565 capture <= 5 ? X_("red") : X_("green"),
1569 buffer_load_label.set_markup (buf);
1571 buffer_load_label.set_text ("");
1576 ARDOUR_UI::count_recenabled_streams (Route& route)
1578 Track* track = dynamic_cast<Track*>(&route);
1579 if (track && track->rec_enable_control()->get_value()) {
1580 rec_enabled_streams += track->n_inputs().n_total();
1585 ARDOUR_UI::update_disk_space()
1587 if (_session == 0) {
1591 boost::optional<framecnt_t> opt_frames = _session->available_capture_duration();
1593 framecnt_t fr = _session->frame_rate();
1596 /* skip update - no SR available */
1601 /* Available space is unknown */
1602 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">Unknown</span>"));
1603 } else if (opt_frames.get_value_or (0) == max_framecnt) {
1604 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">24hrs+</span>"));
1606 rec_enabled_streams = 0;
1607 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams, false);
1609 framecnt_t frames = opt_frames.get_value_or (0);
1611 if (rec_enabled_streams) {
1612 frames /= rec_enabled_streams;
1619 hrs = frames / (fr * 3600);
1622 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">>24 hrs</span>"));
1624 frames -= hrs * fr * 3600;
1625 mins = frames / (fr * 60);
1626 frames -= mins * fr * 60;
1629 bool const low = (hrs == 0 && mins <= 30);
1633 _("Disk: <span foreground=\"%s\">%02dh:%02dm:%02ds</span>"),
1634 low ? X_("red") : X_("green"),
1640 disk_space_label.set_markup (buf);
1644 ARDOUR_UI::update_timecode_format ()
1650 TimecodeSlave* tcslave;
1651 SyncSource sync_src = Config->get_sync_source();
1653 if ((sync_src == LTC || sync_src == MTC) && (tcslave = dynamic_cast<TimecodeSlave*>(_session->slave())) != 0) {
1654 matching = (tcslave->apparent_timecode_format() == _session->config.get_timecode_format());
1659 snprintf (buf, sizeof (buf), S_("Timecode|TC: <span foreground=\"%s\">%s</span>"),
1660 matching ? X_("green") : X_("red"),
1661 Timecode::timecode_format_name (_session->config.get_timecode_format()).c_str());
1663 snprintf (buf, sizeof (buf), "TC: n/a");
1666 timecode_format_label.set_markup (buf);
1670 ARDOUR_UI::update_wall_clock ()
1674 static int last_min = -1;
1677 tm_now = localtime (&now);
1678 if (last_min != tm_now->tm_min) {
1680 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1681 wall_clock_label.set_text (buf);
1682 last_min = tm_now->tm_min;
1689 ARDOUR_UI::open_recent_session ()
1691 bool can_return = (_session != 0);
1693 SessionDialog recent_session_dialog;
1697 ResponseType r = (ResponseType) recent_session_dialog.run ();
1700 case RESPONSE_ACCEPT:
1704 recent_session_dialog.hide();
1711 recent_session_dialog.hide();
1715 std::string path = recent_session_dialog.session_folder();
1716 std::string state = recent_session_dialog.session_name (should_be_new);
1718 if (should_be_new == true) {
1722 _session_is_new = false;
1724 if (load_session (path, state) == 0) {
1730 if (splash && splash->is_visible()) {
1731 // in 1 second, hide the splash screen
1732 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
1737 ARDOUR_UI::check_audioengine (Gtk::Window& parent)
1739 if (!AudioEngine::instance()->connected()) {
1740 MessageDialog msg (parent, string_compose (
1741 _("%1 is not connected to any audio backend.\n"
1742 "You cannot open or close sessions in this condition"),
1744 pop_back_splash (msg);
1752 ARDOUR_UI::open_session ()
1754 if (!check_audioengine (_main_window)) {
1758 /* ardour sessions are folders */
1759 Gtk::FileChooserDialog open_session_selector(_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1760 open_session_selector.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1761 open_session_selector.add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1762 open_session_selector.set_default_response(Gtk::RESPONSE_ACCEPT);
1765 string session_parent_dir = Glib::path_get_dirname(_session->path());
1766 open_session_selector.set_current_folder(session_parent_dir);
1768 open_session_selector.set_current_folder(Config->get_default_session_parent_dir());
1771 Gtkmm2ext::add_volume_shortcuts (open_session_selector);
1773 /* add_shortcut_folder throws an exception if the folder being added already has a shortcut */
1774 string default_session_folder = Config->get_default_session_parent_dir();
1775 open_session_selector.add_shortcut_folder (default_session_folder);
1777 catch (Glib::Error & e) {
1778 std::cerr << "open_session_selector.add_shortcut_folder() threw Glib::Error " << e.what() << std::endl;
1781 FileFilter session_filter;
1782 session_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::statefile_suffix));
1783 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1784 open_session_selector.add_filter (session_filter);
1785 open_session_selector.set_filter (session_filter);
1787 int response = open_session_selector.run();
1788 open_session_selector.hide ();
1790 if (response == Gtk::RESPONSE_CANCEL) {
1794 string session_path = open_session_selector.get_filename();
1798 if (session_path.length() > 0) {
1799 if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1800 _session_is_new = isnew;
1801 load_session (path, name);
1807 ARDOUR_UI::session_add_vca (const string& name_template, uint32_t n)
1813 _session->vca_manager().create_vca (n, name_template);
1817 ARDOUR_UI::session_add_mixed_track (
1818 const ChanCount& input,
1819 const ChanCount& output,
1820 RouteGroup* route_group,
1822 const string& name_template,
1824 PluginInfoPtr instrument,
1825 Plugin::PresetRecord* pset,
1826 ARDOUR::PresentationInfo::order_t order)
1828 list<boost::shared_ptr<MidiTrack> > tracks;
1830 if (_session == 0) {
1831 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1836 tracks = _session->new_midi_track (input, output, instrument, pset, route_group, how_many, name_template, order, ARDOUR::Normal);
1838 if (tracks.size() != how_many) {
1839 error << string_compose(P_("could not create %1 new mixed track", "could not create %1 new mixed tracks", how_many), how_many) << endmsg;
1844 display_insufficient_ports_message ();
1849 for (list<boost::shared_ptr<MidiTrack> >::iterator i = tracks.begin(); i != tracks.end(); ++i) {
1850 (*i)->set_strict_io (true);
1856 ARDOUR_UI::session_add_midi_bus (
1857 RouteGroup* route_group,
1859 const string& name_template,
1861 PluginInfoPtr instrument,
1862 Plugin::PresetRecord* pset,
1863 ARDOUR::PresentationInfo::order_t order)
1867 if (_session == 0) {
1868 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1874 routes = _session->new_midi_route (route_group, how_many, name_template, instrument, pset, PresentationInfo::MidiBus, order);
1875 if (routes.size() != how_many) {
1876 error << string_compose(P_("could not create %1 new Midi Bus", "could not create %1 new Midi Busses", how_many), how_many) << endmsg;
1881 display_insufficient_ports_message ();
1886 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
1887 (*i)->set_strict_io (true);
1893 ARDOUR_UI::session_add_midi_route (
1895 RouteGroup* route_group,
1897 const string& name_template,
1899 PluginInfoPtr instrument,
1900 Plugin::PresetRecord* pset,
1901 ARDOUR::PresentationInfo::order_t order)
1903 ChanCount one_midi_channel;
1904 one_midi_channel.set (DataType::MIDI, 1);
1907 session_add_mixed_track (one_midi_channel, one_midi_channel, route_group, how_many, name_template, strict_io, instrument, pset, order);
1909 session_add_midi_bus (route_group, how_many, name_template, strict_io, instrument, pset, order);
1914 ARDOUR_UI::session_add_audio_route (
1916 int32_t input_channels,
1917 int32_t output_channels,
1918 ARDOUR::TrackMode mode,
1919 RouteGroup* route_group,
1921 string const & name_template,
1923 ARDOUR::PresentationInfo::order_t order)
1925 list<boost::shared_ptr<AudioTrack> > tracks;
1928 if (_session == 0) {
1929 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1935 tracks = _session->new_audio_track (input_channels, output_channels, route_group, how_many, name_template, order, mode);
1937 if (tracks.size() != how_many) {
1938 error << string_compose (P_("could not create %1 new audio track", "could not create %1 new audio tracks", how_many), how_many)
1944 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template, PresentationInfo::AudioBus, order);
1946 if (routes.size() != how_many) {
1947 error << string_compose (P_("could not create %1 new audio bus", "could not create %1 new audio busses", how_many), how_many)
1954 display_insufficient_ports_message ();
1959 for (list<boost::shared_ptr<AudioTrack> >::iterator i = tracks.begin(); i != tracks.end(); ++i) {
1960 (*i)->set_strict_io (true);
1962 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
1963 (*i)->set_strict_io (true);
1969 ARDOUR_UI::display_insufficient_ports_message ()
1971 MessageDialog msg (_main_window,
1972 string_compose (_("There are insufficient ports available\n\
1973 to create a new track or bus.\n\
1974 You should save %1, exit and\n\
1975 restart with more ports."), PROGRAM_NAME));
1976 pop_back_splash (msg);
1981 ARDOUR_UI::transport_goto_start ()
1984 _session->goto_start();
1986 /* force displayed area in editor to start no matter
1987 what "follow playhead" setting is.
1991 editor->center_screen (_session->current_start_frame ());
1997 ARDOUR_UI::transport_goto_zero ()
2000 _session->request_locate (0);
2002 /* force displayed area in editor to start no matter
2003 what "follow playhead" setting is.
2007 editor->reset_x_origin (0);
2013 ARDOUR_UI::transport_goto_wallclock ()
2015 if (_session && editor) {
2022 localtime_r (&now, &tmnow);
2024 framecnt_t frame_rate = _session->frame_rate();
2026 if (frame_rate == 0) {
2027 /* no frame rate available */
2031 frames = tmnow.tm_hour * (60 * 60 * frame_rate);
2032 frames += tmnow.tm_min * (60 * frame_rate);
2033 frames += tmnow.tm_sec * frame_rate;
2035 _session->request_locate (frames, _session->transport_rolling ());
2037 /* force displayed area in editor to start no matter
2038 what "follow playhead" setting is.
2042 editor->center_screen (frames);
2048 ARDOUR_UI::transport_goto_end ()
2051 framepos_t const frame = _session->current_end_frame();
2052 _session->request_locate (frame);
2054 /* force displayed area in editor to start no matter
2055 what "follow playhead" setting is.
2059 editor->center_screen (frame);
2065 ARDOUR_UI::transport_stop ()
2071 if (_session->is_auditioning()) {
2072 _session->cancel_audition ();
2076 _session->request_stop (false, true);
2079 /** Check if any tracks are record enabled. If none are, record enable all of them.
2080 * @return true if track record-enabled status was changed, false otherwise.
2083 ARDOUR_UI::trx_record_enable_all_tracks ()
2089 boost::shared_ptr<RouteList> rl = _session->get_tracks ();
2090 bool none_record_enabled = true;
2092 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
2093 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*r);
2096 if (t->rec_enable_control()->get_value()) {
2097 none_record_enabled = false;
2102 if (none_record_enabled) {
2103 _session->set_controls (route_list_to_control_list (rl, &Stripable::rec_enable_control), 1.0, Controllable::NoGroup);
2106 return none_record_enabled;
2110 ARDOUR_UI::transport_record (bool roll)
2113 switch (_session->record_status()) {
2114 case Session::Disabled:
2115 if (_session->ntracks() == 0) {
2116 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."));
2120 if (Profile->get_trx()) {
2121 roll = trx_record_enable_all_tracks ();
2123 _session->maybe_enable_record ();
2128 case Session::Recording:
2130 _session->request_stop();
2132 _session->disable_record (false, true);
2136 case Session::Enabled:
2137 _session->disable_record (false, true);
2143 ARDOUR_UI::transport_roll ()
2149 if (_session->is_auditioning()) {
2154 if (_session->config.get_external_sync()) {
2155 switch (Config->get_sync_source()) {
2159 /* transport controlled by the master */
2165 bool rolling = _session->transport_rolling();
2167 if (_session->get_play_loop()) {
2169 /* If loop playback is not a mode, then we should cancel
2170 it when this action is requested. If it is a mode
2171 we just leave it in place.
2174 if (!Config->get_loop_is_mode()) {
2175 /* XXX it is not possible to just leave seamless loop and keep
2176 playing at present (nov 4th 2009)
2178 if (!Config->get_seamless_loop()) {
2179 /* stop loop playback and stop rolling */
2180 _session->request_play_loop (false, true);
2181 } else if (rolling) {
2182 /* stop loop playback but keep rolling */
2183 _session->request_play_loop (false, false);
2187 } else if (_session->get_play_range () ) {
2188 /* stop playing a range if we currently are */
2189 _session->request_play_range (0, true);
2193 _session->request_transport_speed (1.0f);
2198 ARDOUR_UI::get_smart_mode() const
2200 return ( editor->get_smart_mode() );
2205 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
2211 if (_session->is_auditioning()) {
2212 _session->cancel_audition ();
2216 if (_session->config.get_external_sync()) {
2217 switch (Config->get_sync_source()) {
2221 /* transport controlled by the master */
2226 bool rolling = _session->transport_rolling();
2227 bool affect_transport = true;
2229 if (rolling && roll_out_of_bounded_mode) {
2230 /* drop out of loop/range playback but leave transport rolling */
2231 if (_session->get_play_loop()) {
2232 if (_session->actively_recording()) {
2234 /* just stop using the loop, then actually stop
2237 _session->request_play_loop (false, affect_transport);
2240 if (Config->get_seamless_loop()) {
2241 /* the disk buffers contain copies of the loop - we can't
2242 just keep playing, so stop the transport. the user
2243 can restart as they wish.
2245 affect_transport = true;
2247 /* disk buffers are normal, so we can keep playing */
2248 affect_transport = false;
2250 _session->request_play_loop (false, affect_transport);
2252 } else if (_session->get_play_range ()) {
2253 affect_transport = false;
2254 _session->request_play_range (0, true);
2258 if (affect_transport) {
2260 _session->request_stop (with_abort, true);
2262 /* the only external sync condition we can be in here
2263 * would be Engine (JACK) sync, in which case we still
2267 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
2268 _session->request_play_range (&editor->get_selection().time, true);
2269 _session->set_requested_return_frame( editor->get_selection().time.front().start ); //force an auto-return here
2271 _session->request_transport_speed (1.0f);
2277 ARDOUR_UI::toggle_session_auto_loop ()
2283 Location * looploc = _session->locations()->auto_loop_location();
2289 if (_session->get_play_loop()) {
2291 /* looping enabled, our job is to disable it */
2293 _session->request_play_loop (false);
2297 /* looping not enabled, our job is to enable it.
2299 loop-is-NOT-mode: this action always starts the transport rolling.
2300 loop-IS-mode: this action simply sets the loop play mechanism, but
2301 does not start transport.
2303 if (Config->get_loop_is_mode()) {
2304 _session->request_play_loop (true, false);
2306 _session->request_play_loop (true, true);
2310 //show the loop markers
2311 looploc->set_hidden (false, this);
2315 ARDOUR_UI::transport_play_selection ()
2321 editor->play_selection ();
2325 ARDOUR_UI::transport_play_preroll ()
2330 editor->play_with_preroll ();
2334 ARDOUR_UI::transport_rewind (int option)
2336 float current_transport_speed;
2339 current_transport_speed = _session->transport_speed();
2341 if (current_transport_speed >= 0.0f) {
2344 _session->request_transport_speed (-1.0f);
2347 _session->request_transport_speed (-4.0f);
2350 _session->request_transport_speed (-0.5f);
2355 _session->request_transport_speed (current_transport_speed * 1.5f);
2361 ARDOUR_UI::transport_forward (int option)
2367 float current_transport_speed = _session->transport_speed();
2369 if (current_transport_speed <= 0.0f) {
2372 _session->request_transport_speed (1.0f);
2375 _session->request_transport_speed (4.0f);
2378 _session->request_transport_speed (0.5f);
2383 _session->request_transport_speed (current_transport_speed * 1.5f);
2388 ARDOUR_UI::toggle_record_enable (uint16_t rid)
2394 boost::shared_ptr<Route> r;
2396 if ((r = _session->get_remote_nth_route (rid)) != 0) {
2398 boost::shared_ptr<Track> t;
2400 if ((t = boost::dynamic_pointer_cast<Track>(r)) != 0) {
2401 t->rec_enable_control()->set_value (!t->rec_enable_control()->get_value(), Controllable::UseGroup);
2407 ARDOUR_UI::map_transport_state ()
2410 auto_loop_button.unset_active_state ();
2411 play_selection_button.unset_active_state ();
2412 roll_button.unset_active_state ();
2413 stop_button.set_active_state (Gtkmm2ext::ExplicitActive);
2417 shuttle_box->map_transport_state ();
2419 float sp = _session->transport_speed();
2425 if (_session->get_play_range()) {
2427 play_selection_button.set_active_state (Gtkmm2ext::ExplicitActive);
2428 roll_button.unset_active_state ();
2429 auto_loop_button.unset_active_state ();
2431 } else if (_session->get_play_loop ()) {
2433 auto_loop_button.set_active (true);
2434 play_selection_button.set_active (false);
2435 if (Config->get_loop_is_mode()) {
2436 roll_button.set_active (true);
2438 roll_button.set_active (false);
2443 roll_button.set_active (true);
2444 play_selection_button.set_active (false);
2445 auto_loop_button.set_active (false);
2448 if (UIConfiguration::instance().get_follow_edits() && !_session->config.get_external_sync()) {
2449 /* light up both roll and play-selection if they are joined */
2450 roll_button.set_active (true);
2451 play_selection_button.set_active (true);
2454 stop_button.set_active (false);
2458 stop_button.set_active (true);
2459 roll_button.set_active (false);
2460 play_selection_button.set_active (false);
2461 if (Config->get_loop_is_mode ()) {
2462 auto_loop_button.set_active (_session->get_play_loop());
2464 auto_loop_button.set_active (false);
2466 update_disk_space ();
2471 ARDOUR_UI::blink_handler (bool blink_on)
2473 transport_rec_enable_blink (blink_on);
2474 solo_blink (blink_on);
2475 sync_blink (blink_on);
2476 audition_blink (blink_on);
2477 feedback_blink (blink_on);
2478 error_blink (blink_on);
2482 ARDOUR_UI::update_clocks ()
2484 if (!_session) return;
2486 if (editor && !editor->dragging_playhead()) {
2487 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD)); /* EMIT_SIGNAL */
2492 ARDOUR_UI::start_clocking ()
2494 if (UIConfiguration::instance().get_super_rapid_clock_update()) {
2495 clock_signal_connection = Timers::fps_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2497 clock_signal_connection = Timers::rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2502 ARDOUR_UI::stop_clocking ()
2504 clock_signal_connection.disconnect ();
2508 ARDOUR_UI::save_as_progress_update (float fraction, int64_t cnt, int64_t total, Gtk::Label* label, Gtk::ProgressBar* bar)
2512 snprintf (buf, sizeof (buf), _("Copied %" PRId64 " of %" PRId64), cnt, total);
2514 label->set_text (buf);
2515 bar->set_fraction (fraction);
2517 /* process events, redraws, etc. */
2519 while (gtk_events_pending()) {
2520 gtk_main_iteration ();
2523 return true; /* continue with save-as */
2527 ARDOUR_UI::save_session_as ()
2533 if (!save_as_dialog) {
2534 save_as_dialog = new SaveAsDialog;
2537 save_as_dialog->set_name (_session->name());
2539 int response = save_as_dialog->run ();
2541 save_as_dialog->hide ();
2544 case Gtk::RESPONSE_OK:
2553 sa.new_parent_folder = save_as_dialog->new_parent_folder ();
2554 sa.new_name = save_as_dialog->new_name ();
2555 sa.switch_to = save_as_dialog->switch_to();
2556 sa.copy_media = save_as_dialog->copy_media();
2557 sa.copy_external = save_as_dialog->copy_external();
2558 sa.include_media = save_as_dialog->include_media ();
2560 /* Only bother with a progress dialog if we're going to copy
2561 media into the save-as target. Without that choice, this
2562 will be very fast because we're only talking about a few kB's to
2563 perhaps a couple of MB's of data.
2566 ArdourDialog progress_dialog (_("Save As"), true);
2568 if (sa.include_media && sa.copy_media) {
2571 Gtk::ProgressBar progress_bar;
2573 progress_dialog.get_vbox()->pack_start (label);
2574 progress_dialog.get_vbox()->pack_start (progress_bar);
2576 progress_bar.show ();
2578 /* this signal will be emitted from within this, the calling thread,
2579 * after every file is copied. It provides information on percentage
2580 * complete (in terms of total data to copy), the number of files
2581 * copied so far, and the total number to copy.
2586 sa.Progress.connect_same_thread (c, boost::bind (&ARDOUR_UI::save_as_progress_update, this, _1, _2, _3, &label, &progress_bar));
2588 progress_dialog.show_all ();
2589 progress_dialog.present ();
2592 if (_session->save_as (sa)) {
2594 MessageDialog msg (string_compose (_("Save As failed: %1"), sa.failure_message));
2598 if (!sa.include_media) {
2599 unload_session (false);
2600 load_session (sa.final_session_folder_name, sa.new_name);
2605 ARDOUR_UI::quick_snapshot_session (bool switch_to_it)
2609 struct tm local_time;
2612 localtime_r (&n, &local_time);
2613 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2615 save_state (timebuf, switch_to_it);
2620 ARDOUR_UI::process_snapshot_session_prompter (ArdourPrompter& prompter, bool switch_to_it)
2624 prompter.get_result (snapname);
2626 bool do_save = (snapname.length() != 0);
2629 char illegal = Session::session_name_is_legal(snapname);
2631 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2632 "snapshot names may not contain a '%1' character"), illegal));
2638 vector<std::string> p;
2639 get_state_files_in_directory (_session->session_directory().root_path(), p);
2640 vector<string> n = get_file_names_no_extension (p);
2642 if (find (n.begin(), n.end(), snapname) != n.end()) {
2644 do_save = overwrite_file_dialog (prompter,
2645 _("Confirm Snapshot Overwrite"),
2646 _("A snapshot already exists with that name. Do you want to overwrite it?"));
2650 save_state (snapname, switch_to_it);
2660 /** Ask the user for the name of a new snapshot and then take it.
2664 ARDOUR_UI::snapshot_session (bool switch_to_it)
2666 ArdourPrompter prompter (true);
2668 prompter.set_name ("Prompter");
2669 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2671 prompter.set_title (_("Snapshot and switch"));
2672 prompter.set_prompt (_("New session name"));
2674 prompter.set_title (_("Take Snapshot"));
2675 prompter.set_prompt (_("Name of new snapshot"));
2679 prompter.set_initial_text (_session->snap_name());
2683 struct tm local_time;
2686 localtime_r (&n, &local_time);
2687 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2688 prompter.set_initial_text (timebuf);
2691 bool finished = false;
2693 switch (prompter.run()) {
2694 case RESPONSE_ACCEPT:
2696 finished = process_snapshot_session_prompter (prompter, switch_to_it);
2707 /** Ask the user for a new session name and then rename the session to it.
2711 ARDOUR_UI::rename_session ()
2717 ArdourPrompter prompter (true);
2720 prompter.set_name ("Prompter");
2721 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2722 prompter.set_title (_("Rename Session"));
2723 prompter.set_prompt (_("New session name"));
2726 switch (prompter.run()) {
2727 case RESPONSE_ACCEPT:
2729 prompter.get_result (name);
2731 bool do_rename = (name.length() != 0);
2734 char illegal = Session::session_name_is_legal (name);
2737 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2738 "session names may not contain a '%1' character"), illegal));
2743 switch (_session->rename (name)) {
2745 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
2746 msg.set_position (WIN_POS_MOUSE);
2754 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
2755 msg.set_position (WIN_POS_MOUSE);
2771 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2773 if (!_session || _session->deletion_in_progress()) {
2777 XMLNode* node = new XMLNode (X_("UI"));
2779 WM::Manager::instance().add_state (*node);
2781 node->add_child_nocopy (gui_object_state->get_state());
2783 _session->add_extra_xml (*node);
2785 if (export_video_dialog) {
2786 _session->add_extra_xml (export_video_dialog->get_state());
2789 save_state_canfail (name, switch_to_it);
2793 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2798 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2803 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2808 ARDOUR_UI::primary_clock_value_changed ()
2811 _session->request_locate (primary_clock->current_time ());
2816 ARDOUR_UI::big_clock_value_changed ()
2819 _session->request_locate (big_clock->current_time ());
2824 ARDOUR_UI::secondary_clock_value_changed ()
2827 _session->request_locate (secondary_clock->current_time ());
2832 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2834 if (_session == 0) {
2838 if (_session->step_editing()) {
2842 Session::RecordState const r = _session->record_status ();
2843 bool const h = _session->have_rec_enabled_track ();
2845 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2847 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2849 rec_button.set_active_state (Gtkmm2ext::Off);
2851 } else if (r == Session::Recording && h) {
2852 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2854 rec_button.unset_active_state ();
2859 ARDOUR_UI::process_save_template_prompter (ArdourPrompter& prompter)
2863 prompter.get_result (name);
2865 if (name.length()) {
2866 int failed = _session->save_template (name);
2868 if (failed == -2) { /* file already exists. */
2869 bool overwrite = overwrite_file_dialog (prompter,
2870 _("Confirm Template Overwrite"),
2871 _("A template already exists with that name. Do you want to overwrite it?"));
2874 _session->save_template (name, true);
2886 ARDOUR_UI::save_template ()
2888 ArdourPrompter prompter (true);
2890 if (!check_audioengine (_main_window)) {
2894 prompter.set_name (X_("Prompter"));
2895 prompter.set_title (_("Save Template"));
2896 prompter.set_prompt (_("Name for template:"));
2897 prompter.set_initial_text(_session->name() + _("-template"));
2898 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2900 bool finished = false;
2902 switch (prompter.run()) {
2903 case RESPONSE_ACCEPT:
2904 finished = process_save_template_prompter (prompter);
2915 ARDOUR_UI::edit_metadata ()
2917 SessionMetadataEditor dialog;
2918 dialog.set_session (_session);
2919 dialog.grab_focus ();
2924 ARDOUR_UI::import_metadata ()
2926 SessionMetadataImporter dialog;
2927 dialog.set_session (_session);
2932 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
2934 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2936 MessageDialog msg (str,
2938 Gtk::MESSAGE_WARNING,
2939 Gtk::BUTTONS_YES_NO,
2943 msg.set_name (X_("OpenExistingDialog"));
2944 msg.set_title (_("Open Existing Session"));
2945 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
2946 msg.set_position (Gtk::WIN_POS_CENTER);
2947 pop_back_splash (msg);
2949 switch (msg.run()) {
2958 ARDOUR_UI::build_session_from_dialog (SessionDialog& sd, const std::string& session_path, const std::string& session_name)
2960 BusProfile bus_profile;
2964 bus_profile.master_out_channels = 2;
2965 bus_profile.input_ac = AutoConnectPhysical;
2966 bus_profile.output_ac = AutoConnectMaster;
2967 bus_profile.requested_physical_in = 0; // use all available
2968 bus_profile.requested_physical_out = 0; // use all available
2972 /* get settings from advanced section of NSD */
2974 if (sd.create_master_bus()) {
2975 bus_profile.master_out_channels = (uint32_t) sd.master_channel_count();
2977 bus_profile.master_out_channels = 0;
2980 if (sd.connect_inputs()) {
2981 bus_profile.input_ac = AutoConnectPhysical;
2983 bus_profile.input_ac = AutoConnectOption (0);
2986 bus_profile.output_ac = AutoConnectOption (0);
2988 if (sd.connect_outputs ()) {
2989 if (sd.connect_outs_to_master()) {
2990 bus_profile.output_ac = AutoConnectMaster;
2991 } else if (sd.connect_outs_to_physical()) {
2992 bus_profile.output_ac = AutoConnectPhysical;
2996 bus_profile.requested_physical_in = (uint32_t) sd.input_limit_count();
2997 bus_profile.requested_physical_out = (uint32_t) sd.output_limit_count();
3000 if (build_session (session_path, session_name, bus_profile)) {
3008 ARDOUR_UI::load_from_application_api (const std::string& path)
3010 ARDOUR_COMMAND_LINE::session_name = path;
3011 /* Cancel SessionDialog if it's visible to make OSX delegates work.
3013 * ARDOUR_UI::starting connects app->ShouldLoad signal and then shows a SessionDialog
3015 * - ShouldLoad does not arrive in time, ARDOUR_COMMAND_LINE::session_name is empty:
3016 * -> ARDOUR_UI::get_session_parameters starts a SessionDialog.
3017 * - ShouldLoad signal arrives, this function is called and sets ARDOUR_COMMAND_LINE::session_name
3018 * -> SessionDialog is not displayed
3021 if (_session_dialog) {
3022 std::string session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3023 std::string session_path = path;
3024 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_REGULAR)) {
3025 session_path = Glib::path_get_dirname (session_path);
3027 // signal the existing dialog in ARDOUR_UI::get_session_parameters()
3028 _session_dialog->set_provided_session (session_name, session_path);
3029 _session_dialog->response (RESPONSE_NONE);
3030 _session_dialog->hide();
3035 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
3036 /* /path/to/foo => /path/to/foo, foo */
3037 rv = load_session (path, basename_nosuffix (path));
3039 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
3040 rv =load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
3043 // if load_session fails -> pop up SessionDialog.
3045 ARDOUR_COMMAND_LINE::session_name = "";
3047 if (get_session_parameters (true, false)) {
3053 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
3055 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
3057 string session_name;
3058 string session_path;
3059 string template_name;
3061 bool likely_new = false;
3062 bool cancel_not_quit;
3064 /* deal with any existing DIRTY session now, rather than later. don't
3065 * treat a non-dirty session this way, so that it stays visible
3066 * as we bring up the new session dialog.
3069 if (_session && ARDOUR_UI::instance()->video_timeline) {
3070 ARDOUR_UI::instance()->video_timeline->sync_session_state();
3073 /* if there is already a session, relabel the button
3074 on the SessionDialog so that we don't Quit directly
3076 cancel_not_quit = (_session != 0);
3078 if (_session && _session->dirty()) {
3079 if (unload_session (false)) {
3080 /* unload cancelled by user */
3083 ARDOUR_COMMAND_LINE::session_name = "";
3086 if (!load_template.empty()) {
3087 should_be_new = true;
3088 template_name = load_template;
3091 session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3092 session_path = ARDOUR_COMMAND_LINE::session_name;
3094 if (!session_path.empty()) {
3095 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_EXISTS)) {
3096 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_IS_REGULAR)) {
3097 /* session/snapshot file, change path to be dir */
3098 session_path = Glib::path_get_dirname (session_path);
3103 SessionDialog session_dialog (should_be_new, session_name, session_path, load_template, cancel_not_quit);
3105 _session_dialog = &session_dialog;
3108 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
3110 /* if they named a specific statefile, use it, otherwise they are
3111 just giving a session folder, and we want to use it as is
3112 to find the session.
3115 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
3117 if (suffix != string::npos) {
3118 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
3119 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
3120 session_name = Glib::path_get_basename (session_name);
3122 session_path = ARDOUR_COMMAND_LINE::session_name;
3123 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
3128 session_dialog.clear_given ();
3131 if (should_be_new || session_name.empty()) {
3132 /* need the dialog to get info from user */
3134 cerr << "run dialog\n";
3136 switch (session_dialog.run()) {
3137 case RESPONSE_ACCEPT:
3140 /* this is used for async * app->ShouldLoad(). */
3141 continue; // while loop
3144 if (quit_on_cancel) {
3145 // JE - Currently (July 2014) this section can only get reached if the
3146 // user quits from the main 'Session Setup' dialog (i.e. reaching this
3147 // point does NOT indicate an abnormal termination). Therefore, let's
3148 // behave gracefully (i.e. let's do some cleanup) before we call exit()
3150 pthread_cancel_all ();
3158 session_dialog.hide ();
3161 /* if we run the startup dialog again, offer more than just "new session" */
3163 should_be_new = false;
3165 session_name = session_dialog.session_name (likely_new);
3166 session_path = session_dialog.session_folder ();
3172 string::size_type suffix = session_name.find (statefile_suffix);
3174 if (suffix != string::npos) {
3175 session_name = session_name.substr (0, suffix);
3178 /* this shouldn't happen, but we catch it just in case it does */
3180 if (session_name.empty()) {
3184 if (session_dialog.use_session_template()) {
3185 template_name = session_dialog.session_template_name();
3186 _session_is_new = true;
3189 if (session_name[0] == G_DIR_SEPARATOR ||
3190 #ifdef PLATFORM_WINDOWS
3191 (session_name.length() > 3 && session_name[1] == ':' && session_name[2] == G_DIR_SEPARATOR)
3193 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
3194 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)
3199 /* absolute path or cwd-relative path specified for session name: infer session folder
3200 from what was given.
3203 session_path = Glib::path_get_dirname (session_name);
3204 session_name = Glib::path_get_basename (session_name);
3208 session_path = session_dialog.session_folder();
3210 char illegal = Session::session_name_is_legal (session_name);
3213 MessageDialog msg (session_dialog,
3214 string_compose (_("To ensure compatibility with various systems\n"
3215 "session names may not contain a '%1' character"),
3218 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3223 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
3226 if (likely_new && !nsm) {
3228 std::string existing = Glib::build_filename (session_path, session_name);
3230 if (!ask_about_loading_existing_session (existing)) {
3231 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3236 _session_is_new = false;
3241 pop_back_splash (session_dialog);
3242 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
3244 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3248 char illegal = Session::session_name_is_legal(session_name);
3251 pop_back_splash (session_dialog);
3252 MessageDialog msg (session_dialog, string_compose(_("To ensure compatibility with various systems\n"
3253 "session names may not contain a '%1' character"), illegal));
3255 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3259 _session_is_new = true;
3262 if (likely_new && template_name.empty()) {
3264 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3268 ret = load_session (session_path, session_name, template_name);
3271 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
3275 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
3276 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
3280 /* clear this to avoid endless attempts to load the
3284 ARDOUR_COMMAND_LINE::session_name = "";
3288 _session_dialog = NULL;
3294 ARDOUR_UI::close_session()
3296 if (!check_audioengine (_main_window)) {
3300 if (unload_session (true)) {
3304 ARDOUR_COMMAND_LINE::session_name = "";
3306 if (get_session_parameters (true, false)) {
3309 if (splash && splash->is_visible()) {
3310 // in 1 second, hide the splash screen
3311 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
3315 /** @param snap_name Snapshot name (without .ardour suffix).
3316 * @return -2 if the load failed because we are not connected to the AudioEngine.
3319 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
3321 Session *new_session;
3326 unload_status = unload_session ();
3328 if (unload_status < 0) {
3330 } else if (unload_status > 0) {
3336 session_loaded = false;
3338 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
3341 new_session = new Session (*AudioEngine::instance(), path, snap_name, 0, mix_template);
3344 /* this one is special */
3346 catch (AudioEngine::PortRegistrationFailure& err) {
3348 MessageDialog msg (err.what(),
3351 Gtk::BUTTONS_CLOSE);
3353 msg.set_title (_("Port Registration Error"));
3354 msg.set_secondary_text (_("Click the Close button to try again."));
3355 msg.set_position (Gtk::WIN_POS_CENTER);
3356 pop_back_splash (msg);
3359 int response = msg.run ();
3364 case RESPONSE_CANCEL:
3371 catch (SessionException e) {
3372 MessageDialog msg (string_compose(
3373 _("Session \"%1 (snapshot %2)\" did not load successfully: %3"),
3374 path, snap_name, e.what()),
3379 msg.set_title (_("Loading Error"));
3380 msg.set_position (Gtk::WIN_POS_CENTER);
3381 pop_back_splash (msg);
3393 MessageDialog msg (string_compose(
3394 _("Session \"%1 (snapshot %2)\" did not load successfully"),
3400 msg.set_title (_("Loading Error"));
3401 msg.set_position (Gtk::WIN_POS_CENTER);
3402 pop_back_splash (msg);
3414 list<string> const u = new_session->unknown_processors ();
3416 MissingPluginDialog d (_session, u);
3421 if (!new_session->writable()) {
3422 MessageDialog msg (_("This session has been opened in read-only mode.\n\nYou will not be able to record or save."),
3427 msg.set_title (_("Read-only Session"));
3428 msg.set_position (Gtk::WIN_POS_CENTER);
3429 pop_back_splash (msg);
3436 /* Now the session been created, add the transport controls */
3437 new_session->add_controllable(roll_controllable);
3438 new_session->add_controllable(stop_controllable);
3439 new_session->add_controllable(goto_start_controllable);
3440 new_session->add_controllable(goto_end_controllable);
3441 new_session->add_controllable(auto_loop_controllable);
3442 new_session->add_controllable(play_selection_controllable);
3443 new_session->add_controllable(rec_controllable);
3445 set_session (new_session);
3447 session_loaded = true;
3450 _session->set_clean ();
3453 #ifdef WINDOWS_VST_SUPPORT
3454 fst_stop_threading();
3458 Timers::TimerSuspender t;
3462 #ifdef WINDOWS_VST_SUPPORT
3463 fst_start_threading();
3472 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
3474 Session *new_session;
3477 session_loaded = false;
3478 x = unload_session ();
3486 _session_is_new = true;
3489 new_session = new Session (*AudioEngine::instance(), path, snap_name, &bus_profile);
3492 catch (SessionException e) {
3494 MessageDialog msg (string_compose(_("Could not create session in \"%1\": %2"), path, e.what()));
3495 msg.set_title (_("Loading Error"));
3496 msg.set_position (Gtk::WIN_POS_CENTER);
3497 pop_back_splash (msg);
3503 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
3504 msg.set_title (_("Loading Error"));
3505 msg.set_position (Gtk::WIN_POS_CENTER);
3506 pop_back_splash (msg);
3511 /* Give the new session the default GUI state, if such things exist */
3514 n = Config->instant_xml (X_("Editor"));
3516 n->remove_nodes_and_delete ("Selection"); // no not apply selection to new sessions.
3517 new_session->add_instant_xml (*n, false);
3519 n = Config->instant_xml (X_("Mixer"));
3521 new_session->add_instant_xml (*n, false);
3524 /* Put the playhead at 0 and scroll fully left */
3525 n = new_session->instant_xml (X_("Editor"));
3527 n->add_property (X_("playhead"), X_("0"));
3528 n->add_property (X_("left-frame"), X_("0"));
3531 set_session (new_session);
3533 session_loaded = true;
3535 new_session->save_state(new_session->name());
3541 ARDOUR_UI::launch_chat ()
3543 MessageDialog dialog(_("<b>Just ask and wait for an answer.\nIt may take from minutes to hours.</b>"), true);
3545 dialog.set_title (_("About the Chat"));
3546 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."));
3548 switch (dialog.run()) {
3551 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
3552 #elif defined PLATFORM_WINDOWS
3553 open_uri("http://webchat.freenode.net/?channels=ardour-windows");
3555 open_uri("http://webchat.freenode.net/?channels=ardour");
3564 ARDOUR_UI::launch_manual ()
3566 PBD::open_uri (Config->get_tutorial_manual_url());
3570 ARDOUR_UI::launch_reference ()
3572 PBD::open_uri (Config->get_reference_manual_url());
3576 ARDOUR_UI::launch_tracker ()
3578 PBD::open_uri ("http://tracker.ardour.org");
3582 ARDOUR_UI::launch_subscribe ()
3584 PBD::open_uri ("https://community.ardour.org/s/subscribe");
3588 ARDOUR_UI::launch_cheat_sheet ()
3591 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheat_sheet_osx.pdf");
3593 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheatsheet.pdf");
3598 ARDOUR_UI::launch_website ()
3600 PBD::open_uri ("http://ardour.org");
3604 ARDOUR_UI::launch_website_dev ()
3606 PBD::open_uri ("http://ardour.org/development.html");
3610 ARDOUR_UI::launch_forums ()
3612 PBD::open_uri ("https://community.ardour.org/forums");
3616 ARDOUR_UI::launch_howto_report ()
3618 PBD::open_uri ("http://ardour.org/reporting_bugs");
3622 ARDOUR_UI::loading_message (const std::string& msg)
3624 if (ARDOUR_COMMAND_LINE::no_splash) {
3632 splash->message (msg);
3636 ARDOUR_UI::show_splash ()
3640 splash = new Splash;
3650 ARDOUR_UI::hide_splash ()
3657 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title, const bool msg_delete)
3661 removed = rep.paths.size();
3664 MessageDialog msgd (_main_window,
3665 _("No files were ready for clean-up"),
3669 msgd.set_title (_("Clean-up"));
3670 msgd.set_secondary_text (_("If this seems suprising, \n\
3671 check for any existing snapshots.\n\
3672 These may still include regions that\n\
3673 require some unused files to continue to exist."));
3679 ArdourDialog results (_("Clean-up"), true, false);
3681 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
3682 CleanupResultsModelColumns() {
3686 Gtk::TreeModelColumn<std::string> visible_name;
3687 Gtk::TreeModelColumn<std::string> fullpath;
3691 CleanupResultsModelColumns results_columns;
3692 Glib::RefPtr<Gtk::ListStore> results_model;
3693 Gtk::TreeView results_display;
3695 results_model = ListStore::create (results_columns);
3696 results_display.set_model (results_model);
3697 results_display.append_column (list_title, results_columns.visible_name);
3699 results_display.set_name ("CleanupResultsList");
3700 results_display.set_headers_visible (true);
3701 results_display.set_headers_clickable (false);
3702 results_display.set_reorderable (false);
3704 Gtk::ScrolledWindow list_scroller;
3707 Gtk::HBox dhbox; // the hbox for the image and text
3708 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
3709 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
3711 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
3713 const string dead_directory = _session->session_directory().dead_path();
3716 %1 - number of files removed
3717 %2 - location of "dead"
3718 %3 - size of files affected
3719 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
3722 const char* bprefix;
3723 double space_adjusted = 0;
3725 if (rep.space < 1000) {
3727 space_adjusted = rep.space;
3728 } else if (rep.space < 1000000) {
3729 bprefix = _("kilo");
3730 space_adjusted = floorf((float)rep.space / 1000.0);
3731 } else if (rep.space < 1000000 * 1000) {
3732 bprefix = _("mega");
3733 space_adjusted = floorf((float)rep.space / (1000.0 * 1000.0));
3735 bprefix = _("giga");
3736 space_adjusted = floorf((float)rep.space / (1000.0 * 1000 * 1000.0));
3740 txt.set_markup (string_compose (P_("\
3741 The following file was deleted from %2,\n\
3742 releasing %3 %4bytes of disk space", "\
3743 The following %1 files were deleted from %2,\n\
3744 releasing %3 %4bytes of disk space", removed),
3745 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3747 txt.set_markup (string_compose (P_("\
3748 The following file was not in use and \n\
3749 has been moved to: %2\n\n\
3750 After a restart of %5\n\n\
3751 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3752 will release an additional %3 %4bytes of disk space.\n", "\
3753 The following %1 files were not in use and \n\
3754 have been moved to: %2\n\n\
3755 After a restart of %5\n\n\
3756 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3757 will release an additional %3 %4bytes of disk space.\n", removed),
3758 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3761 dhbox.pack_start (*dimage, true, false, 5);
3762 dhbox.pack_start (txt, true, false, 5);
3764 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
3765 TreeModel::Row row = *(results_model->append());
3766 row[results_columns.visible_name] = *i;
3767 row[results_columns.fullpath] = *i;
3770 list_scroller.add (results_display);
3771 list_scroller.set_size_request (-1, 150);
3772 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
3774 dvbox.pack_start (dhbox, true, false, 5);
3775 dvbox.pack_start (list_scroller, true, false, 5);
3776 ddhbox.pack_start (dvbox, true, false, 5);
3778 results.get_vbox()->pack_start (ddhbox, true, false, 5);
3779 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
3780 results.set_default_response (RESPONSE_CLOSE);
3781 results.set_position (Gtk::WIN_POS_MOUSE);
3783 results_display.show();
3784 list_scroller.show();
3791 //results.get_vbox()->show();
3792 results.set_resizable (false);
3799 ARDOUR_UI::cleanup ()
3801 if (_session == 0) {
3802 /* shouldn't happen: menu item is insensitive */
3807 MessageDialog checker (_("Are you sure you want to clean-up?"),
3809 Gtk::MESSAGE_QUESTION,
3812 checker.set_title (_("Clean-up"));
3814 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
3815 ALL undo/redo information will be lost if you clean-up.\n\
3816 Clean-up will move all unused files to a \"dead\" location."));
3818 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3819 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
3820 checker.set_default_response (RESPONSE_CANCEL);
3822 checker.set_name (_("CleanupDialog"));
3823 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3824 checker.set_position (Gtk::WIN_POS_MOUSE);
3826 switch (checker.run()) {
3827 case RESPONSE_ACCEPT:
3833 ARDOUR::CleanupReport rep;
3835 editor->prepare_for_cleanup ();
3837 /* do not allow flush until a session is reloaded */
3839 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3841 act->set_sensitive (false);
3844 if (_session->cleanup_sources (rep)) {
3845 editor->finish_cleanup ();
3849 editor->finish_cleanup ();
3852 display_cleanup_results (rep, _("Cleaned Files"), false);
3856 ARDOUR_UI::flush_trash ()
3858 if (_session == 0) {
3859 /* shouldn't happen: menu item is insensitive */
3863 ARDOUR::CleanupReport rep;
3865 if (_session->cleanup_trash_sources (rep)) {
3869 display_cleanup_results (rep, _("deleted file"), true);
3873 ARDOUR_UI::cleanup_peakfiles ()
3875 if (_session == 0) {
3876 /* shouldn't happen: menu item is insensitive */
3880 if (! _session->can_cleanup_peakfiles ()) {
3884 // get all region-views in this session
3886 TrackViewList empty;
3888 editor->get_regions_after(rs, (framepos_t) 0, empty);
3889 std::list<RegionView*> views = rs.by_layer();
3891 // remove displayed audio-region-views waveforms
3892 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
3893 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
3894 if (!arv) { continue ; }
3895 arv->delete_waves();
3898 // cleanup peak files:
3899 // - stop pending peakfile threads
3900 // - close peakfiles if any
3901 // - remove peak dir in session
3902 // - setup peakfiles (background thread)
3903 _session->cleanup_peakfiles ();
3905 // re-add waves to ARV
3906 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
3907 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
3908 if (!arv) { continue ; }
3909 arv->create_waves();
3913 PresentationInfo::order_t
3914 ARDOUR_UI::translate_order (AddRouteDialog::InsertAt place)
3916 if (editor->get_selection().tracks.empty()) {
3917 return PresentationInfo::max_order;
3920 PresentationInfo::order_t order_hint = PresentationInfo::max_order;
3923 we want the new routes to have their order keys set starting from
3924 the highest order key in the selection + 1 (if available).
3927 if (place == AddRouteDialog::AfterSelection) {
3928 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.back());
3930 order_hint = rtav->route()->presentation_info().order();
3933 } else if (place == AddRouteDialog::BeforeSelection) {
3934 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.front());
3936 order_hint = rtav->route()->presentation_info().order();
3938 } else if (place == AddRouteDialog::First) {
3941 /* leave order_hint at max_order */
3948 ARDOUR_UI::start_duplicate_routes ()
3950 if (!duplicate_routes_dialog) {
3951 duplicate_routes_dialog = new DuplicateRouteDialog;
3954 if (duplicate_routes_dialog->restart (_session)) {
3958 duplicate_routes_dialog->present ();
3962 ARDOUR_UI::add_route ()
3970 if (add_route_dialog->is_visible()) {
3971 /* we're already doing this */
3975 ResponseType r = (ResponseType) add_route_dialog->run ();
3977 add_route_dialog->hide();
3980 case RESPONSE_ACCEPT:
3987 if ((count = add_route_dialog->count()) <= 0) {
3991 PresentationInfo::order_t order = translate_order (add_route_dialog->insert_at());
3992 string template_path = add_route_dialog->track_template();
3993 DisplaySuspender ds;
3995 if (!template_path.empty()) {
3996 if (add_route_dialog->name_template_is_default()) {
3997 _session->new_route_from_template (count, template_path, string());
3999 _session->new_route_from_template (count, template_path, add_route_dialog->name_template());
4004 ChanCount input_chan= add_route_dialog->channels ();
4005 ChanCount output_chan;
4006 string name_template = add_route_dialog->name_template ();
4007 PluginInfoPtr instrument = add_route_dialog->requested_instrument ();
4008 RouteGroup* route_group = add_route_dialog->route_group ();
4009 AutoConnectOption oac = Config->get_output_auto_connect();
4010 bool strict_io = add_route_dialog->use_strict_io ();
4012 if (oac & AutoConnectMaster) {
4013 output_chan.set (DataType::AUDIO, (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan.n_audio()));
4014 output_chan.set (DataType::MIDI, 0);
4016 output_chan = input_chan;
4019 /* XXX do something with name template */
4021 switch (add_route_dialog->type_wanted()) {
4022 case AddRouteDialog::AudioTrack:
4023 session_add_audio_track (input_chan.n_audio(), output_chan.n_audio(), add_route_dialog->mode(), route_group, count, name_template, strict_io, order);
4025 case AddRouteDialog::MidiTrack:
4026 session_add_midi_track (route_group, count, name_template, strict_io, instrument, 0, order);
4028 case AddRouteDialog::MixedTrack:
4029 session_add_mixed_track (input_chan, output_chan, route_group, count, name_template, strict_io, instrument, 0, order);
4031 case AddRouteDialog::AudioBus:
4032 session_add_audio_bus (input_chan.n_audio(), output_chan.n_audio(), route_group, count, name_template, strict_io, order);
4034 case AddRouteDialog::MidiBus:
4035 session_add_midi_bus (route_group, count, name_template, strict_io, instrument, 0, order);
4037 case AddRouteDialog::VCAMaster:
4038 session_add_vca (name_template, count);
4044 ARDOUR_UI::add_lua_script ()
4050 LuaScriptInfoPtr spi;
4051 ScriptSelector ss ("Add Lua Session Script", LuaScriptInfo::Session);
4052 switch (ss.run ()) {
4053 case Gtk::RESPONSE_ACCEPT:
4061 std::string script = "";
4064 script = Glib::file_get_contents (spi->path);
4065 } catch (Glib::FileError e) {
4066 string msg = string_compose (_("Cannot read session script '%1': %2"), spi->path, e.what());
4067 MessageDialog am (msg);
4072 LuaScriptParamList lsp = LuaScriptParams::script_params (spi, "sess_params");
4073 std::vector<std::string> reg = _session->registered_lua_functions ();
4075 ScriptParameterDialog spd (_("Set Script Parameters"), spi, reg, lsp);
4076 switch (spd.run ()) {
4077 case Gtk::RESPONSE_ACCEPT:
4084 _session->register_lua_function (spd.name(), script, lsp);
4085 } catch (luabridge::LuaException const& e) {
4086 string msg = string_compose (_("Session script '%1' instantiation failed: %2"), spd.name(), e.what ());
4087 MessageDialog am (msg);
4089 } catch (SessionException e) {
4090 string msg = string_compose (_("Loading Session script '%1' failed: %2"), spd.name(), e.what ());
4091 MessageDialog am (msg);
4097 ARDOUR_UI::remove_lua_script ()
4102 if (_session->registered_lua_function_count () == 0) {
4103 string msg = _("There are no active Lua session scripts present in this session.");
4104 MessageDialog am (msg);
4109 std::vector<std::string> reg = _session->registered_lua_functions ();
4110 SessionScriptManager sm ("Remove Lua Session Script", reg);
4111 switch (sm.run ()) {
4112 case Gtk::RESPONSE_ACCEPT:
4118 _session->unregister_lua_function (sm.name());
4119 } catch (luabridge::LuaException const& e) {
4120 string msg = string_compose (_("Session script '%1' removal failed: %2"), sm.name(), e.what ());
4121 MessageDialog am (msg);
4127 ARDOUR_UI::stop_video_server (bool ask_confirm)
4129 if (!video_server_process && ask_confirm) {
4130 warning << string_compose (_("Video-Server was not launched by %1. The request to stop it is ignored."), PROGRAM_NAME) << endmsg;
4132 if (video_server_process) {
4134 ArdourDialog confirm (_("Stop Video-Server"), true);
4135 Label m (_("Do you really want to stop the Video Server?"));
4136 confirm.get_vbox()->pack_start (m, true, true);
4137 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
4138 confirm.add_button (_("Yes, Stop It"), Gtk::RESPONSE_ACCEPT);
4139 confirm.show_all ();
4140 if (confirm.run() == RESPONSE_CANCEL) {
4144 delete video_server_process;
4145 video_server_process =0;
4150 ARDOUR_UI::start_video_server_menu (Gtk::Window* float_window)
4152 ARDOUR_UI::start_video_server( float_window, true);
4156 ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg)
4162 if (ARDOUR_UI::instance()->video_timeline->check_server()) {
4163 if (video_server_process) {
4164 popup_error(_("The Video Server is already started."));
4166 popup_error(_("An external Video Server is configured and can be reached. Not starting a new instance."));
4172 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4174 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4176 VideoServerDialog *video_server_dialog = new VideoServerDialog (_session);
4178 video_server_dialog->set_transient_for (*float_window);
4181 if (!Config->get_show_video_server_dialog() && firsttime < 2) {
4182 video_server_dialog->hide();
4184 ResponseType r = (ResponseType) video_server_dialog->run ();
4185 video_server_dialog->hide();
4186 if (r != RESPONSE_ACCEPT) { return false; }
4187 if (video_server_dialog->show_again()) {
4188 Config->set_show_video_server_dialog(false);
4192 std::string icsd_exec = video_server_dialog->get_exec_path();
4193 std::string icsd_docroot = video_server_dialog->get_docroot();
4194 if (icsd_docroot.empty()) {
4195 #ifndef PLATFORM_WINDOWS
4196 icsd_docroot = X_("/");
4198 icsd_docroot = X_("C:\\");
4203 if (g_lstat (icsd_docroot.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode)) {
4204 warning << _("Specified docroot is not an existing directory.") << endmsg;
4207 #ifndef PLATFORM_WINDOWS
4208 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4209 || (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0 ) {
4210 warning << _("Given Video Server is not an executable file.") << endmsg;
4214 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4215 || (sb.st_mode & (S_IXUSR)) == 0 ) {
4216 warning << _("Given Video Server is not an executable file.") << endmsg;
4222 argp=(char**) calloc(9,sizeof(char*));
4223 argp[0] = strdup(icsd_exec.c_str());
4224 argp[1] = strdup("-P");
4225 argp[2] = (char*) calloc(16,sizeof(char)); snprintf(argp[2], 16, "%s", video_server_dialog->get_listenaddr().c_str());
4226 argp[3] = strdup("-p");
4227 argp[4] = (char*) calloc(6,sizeof(char)); snprintf(argp[4], 6, "%i", video_server_dialog->get_listenport());
4228 argp[5] = strdup("-C");
4229 argp[6] = (char*) calloc(6,sizeof(char)); snprintf(argp[6], 6, "%i", video_server_dialog->get_cachesize());
4230 argp[7] = strdup(icsd_docroot.c_str());
4232 stop_video_server();
4234 if (icsd_docroot == X_("/") || icsd_docroot == X_("C:\\")) {
4235 Config->set_video_advanced_setup(false);
4237 std::ostringstream osstream;
4238 osstream << "http://127.0.0.1:" << video_server_dialog->get_listenport() << "/";
4239 Config->set_video_server_url(osstream.str());
4240 Config->set_video_server_docroot(icsd_docroot);
4241 Config->set_video_advanced_setup(true);
4244 if (video_server_process) {
4245 delete video_server_process;
4248 video_server_process = new ARDOUR::SystemExec(icsd_exec, argp);
4249 if (video_server_process->start()) {
4250 warning << _("Cannot launch the video-server") << endmsg;
4253 int timeout = 120; // 6 sec
4254 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4255 Glib::usleep (50000);
4257 if (--timeout <= 0 || !video_server_process->is_running()) break;
4260 warning << _("Video-server was started but does not respond to requests...") << endmsg;
4262 if (!ARDOUR_UI::instance()->video_timeline->check_server_docroot()) {
4263 delete video_server_process;
4264 video_server_process = 0;
4272 ARDOUR_UI::add_video (Gtk::Window* float_window)
4278 if (!start_video_server(float_window, false)) {
4279 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4284 add_video_dialog->set_transient_for (*float_window);
4287 if (add_video_dialog->is_visible()) {
4288 /* we're already doing this */
4292 ResponseType r = (ResponseType) add_video_dialog->run ();
4293 add_video_dialog->hide();
4294 if (r != RESPONSE_ACCEPT) { return; }
4296 bool local_file, orig_local_file;
4297 std::string path = add_video_dialog->file_name(local_file);
4299 std::string orig_path = path;
4300 orig_local_file = local_file;
4302 bool auto_set_session_fps = add_video_dialog->auto_set_session_fps();
4304 if (local_file && !Glib::file_test(path, Glib::FILE_TEST_EXISTS)) {
4305 warning << string_compose(_("could not open %1"), path) << endmsg;
4308 if (!local_file && path.length() == 0) {
4309 warning << _("no video-file selected") << endmsg;
4313 std::string audio_from_video;
4314 bool detect_ltc = false;
4316 switch (add_video_dialog->import_option()) {
4317 case VTL_IMPORT_TRANSCODE:
4319 TranscodeVideoDialog *transcode_video_dialog;
4320 transcode_video_dialog = new TranscodeVideoDialog (_session, path);
4321 ResponseType r = (ResponseType) transcode_video_dialog->run ();
4322 transcode_video_dialog->hide();
4323 if (r != RESPONSE_ACCEPT) {
4324 delete transcode_video_dialog;
4328 audio_from_video = transcode_video_dialog->get_audiofile();
4330 if (!audio_from_video.empty() && transcode_video_dialog->detect_ltc()) {
4333 else if (!audio_from_video.empty()) {
4334 editor->embed_audio_from_video(
4336 video_timeline->get_offset(),
4337 (transcode_video_dialog->import_option() != VTL_IMPORT_NO_VIDEO)
4340 switch (transcode_video_dialog->import_option()) {
4341 case VTL_IMPORT_TRANSCODED:
4342 path = transcode_video_dialog->get_filename();
4345 case VTL_IMPORT_REFERENCE:
4348 delete transcode_video_dialog;
4351 delete transcode_video_dialog;
4355 case VTL_IMPORT_NONE:
4359 /* strip _session->session_directory().video_path() from video file if possible */
4360 if (local_file && !path.compare(0, _session->session_directory().video_path().size(), _session->session_directory().video_path())) {
4361 path=path.substr(_session->session_directory().video_path().size());
4362 if (path.at(0) == G_DIR_SEPARATOR) {
4363 path=path.substr(1);
4367 video_timeline->set_update_session_fps(auto_set_session_fps);
4369 if (video_timeline->video_file_info(path, local_file)) {
4370 XMLNode* node = new XMLNode(X_("Videotimeline"));
4371 node->add_property (X_("Filename"), path);
4372 node->add_property (X_("AutoFPS"), auto_set_session_fps?X_("1"):X_("0"));
4373 node->add_property (X_("LocalFile"), local_file?X_("1"):X_("0"));
4374 if (orig_local_file) {
4375 node->add_property (X_("OriginalVideoFile"), orig_path);
4377 node->remove_property (X_("OriginalVideoFile"));
4379 _session->add_extra_xml (*node);
4380 _session->set_dirty ();
4382 if (!audio_from_video.empty() && detect_ltc) {
4383 std::vector<LTCFileReader::LTCMap> ltc_seq;
4386 /* TODO ask user about TV standard (LTC alignment if any) */
4387 LTCFileReader ltcr (audio_from_video, video_timeline->get_video_file_fps());
4388 /* TODO ASK user which channel: 0 .. ltcr->channels() - 1 */
4390 ltc_seq = ltcr.read_ltc (/*channel*/ 0, /*max LTC frames to decode*/ 15);
4392 /* TODO seek near end of file, and read LTC until end.
4393 * if it fails to find any LTC frames, scan complete file
4395 * calculate drift of LTC compared to video-duration,
4396 * ask user for reference (timecode from start/mid/end)
4399 // LTCFileReader will have written error messages
4402 ::g_unlink(audio_from_video.c_str());
4404 if (ltc_seq.size() == 0) {
4405 PBD::error << _("No LTC detected, video will not be aligned.") << endmsg;
4407 /* the very first TC in the file is somteimes not aligned properly */
4408 int i = ltc_seq.size() -1;
4409 ARDOUR::frameoffset_t video_start_offset =
4410 _session->nominal_frame_rate() * (ltc_seq[i].timecode_sec - ltc_seq[i].framepos_sec);
4411 PBD::info << string_compose (_("Align video-start to %1 [samples]"), video_start_offset) << endmsg;
4412 video_timeline->set_offset(video_start_offset);
4416 _session->maybe_update_session_range(
4417 std::max(video_timeline->get_offset(), (ARDOUR::frameoffset_t) 0),
4418 std::max(video_timeline->get_offset() + video_timeline->get_duration(), (ARDOUR::frameoffset_t) 0));
4421 if (add_video_dialog->launch_xjadeo() && local_file) {
4422 editor->set_xjadeo_sensitive(true);
4423 editor->toggle_xjadeo_proc(1);
4425 editor->toggle_xjadeo_proc(0);
4427 editor->toggle_ruler_video(true);
4432 ARDOUR_UI::remove_video ()
4434 video_timeline->close_session();
4435 editor->toggle_ruler_video(false);
4438 video_timeline->set_offset_locked(false);
4439 video_timeline->set_offset(0);
4441 /* delete session state */
4442 XMLNode* node = new XMLNode(X_("Videotimeline"));
4443 _session->add_extra_xml(*node);
4444 node = new XMLNode(X_("Videomonitor"));
4445 _session->add_extra_xml(*node);
4446 node = new XMLNode(X_("Videoexport"));
4447 _session->add_extra_xml(*node);
4448 stop_video_server();
4452 ARDOUR_UI::flush_videotimeline_cache (bool localcacheonly)
4454 if (localcacheonly) {
4455 video_timeline->vmon_update();
4457 video_timeline->flush_cache();
4459 editor->queue_visual_videotimeline_update();
4463 ARDOUR_UI::export_video (bool range)
4465 if (ARDOUR::Config->get_show_video_export_info()) {
4466 ExportVideoInfobox infobox (_session);
4467 Gtk::ResponseType rv = (Gtk::ResponseType) infobox.run();
4468 if (infobox.show_again()) {
4469 ARDOUR::Config->set_show_video_export_info(false);
4472 case GTK_RESPONSE_YES:
4473 PBD::open_uri (ARDOUR::Config->get_reference_manual_url() + "/video-timeline/operations/#export");
4479 export_video_dialog->set_session (_session);
4480 export_video_dialog->apply_state(editor->get_selection().time, range);
4481 export_video_dialog->run ();
4482 export_video_dialog->hide ();
4486 ARDOUR_UI::mixer_settings () const
4491 node = _session->instant_xml(X_("Mixer"));
4493 node = Config->instant_xml(X_("Mixer"));
4497 node = new XMLNode (X_("Mixer"));
4504 ARDOUR_UI::main_window_settings () const
4509 node = _session->instant_xml(X_("Main"));
4511 node = Config->instant_xml(X_("Main"));
4515 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4516 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4521 node = new XMLNode (X_("Main"));
4528 ARDOUR_UI::editor_settings () const
4533 node = _session->instant_xml(X_("Editor"));
4535 node = Config->instant_xml(X_("Editor"));
4539 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4540 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4545 node = new XMLNode (X_("Editor"));
4552 ARDOUR_UI::keyboard_settings () const
4556 node = Config->extra_xml(X_("Keyboard"));
4559 node = new XMLNode (X_("Keyboard"));
4566 ARDOUR_UI::create_xrun_marker (framepos_t where)
4569 Location *location = new Location (*_session, where, where, _("xrun"), Location::IsMark);
4570 _session->locations()->add (location);
4575 ARDOUR_UI::halt_on_xrun_message ()
4577 cerr << "HALT on xrun\n";
4578 MessageDialog msg (_main_window, _("Recording was stopped because your system could not keep up."));
4583 ARDOUR_UI::xrun_handler (framepos_t where)
4589 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
4591 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
4592 create_xrun_marker(where);
4595 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
4596 halt_on_xrun_message ();
4601 ARDOUR_UI::disk_overrun_handler ()
4603 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
4605 if (!have_disk_speed_dialog_displayed) {
4606 have_disk_speed_dialog_displayed = true;
4607 MessageDialog* msg = new MessageDialog (_main_window, string_compose (_("\
4608 The disk system on your computer\n\
4609 was not able to keep up with %1.\n\
4611 Specifically, it failed to write data to disk\n\
4612 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
4613 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4619 /* TODO: this is getting elaborate enough to warrant being split into a dedicated class */
4620 static MessageDialog *scan_dlg = NULL;
4621 static ProgressBar *scan_pbar = NULL;
4622 static HBox *scan_tbox = NULL;
4623 static Gtk::Button *scan_timeout_button;
4626 ARDOUR_UI::cancel_plugin_scan ()
4628 PluginManager::instance().cancel_plugin_scan();
4632 ARDOUR_UI::cancel_plugin_timeout ()
4634 PluginManager::instance().cancel_plugin_timeout();
4635 scan_timeout_button->set_sensitive (false);
4639 ARDOUR_UI::plugin_scan_timeout (int timeout)
4641 if (!scan_dlg || !scan_dlg->is_mapped() || !scan_pbar) {
4645 scan_pbar->set_sensitive (false);
4646 scan_timeout_button->set_sensitive (true);
4647 scan_pbar->set_fraction ((float) timeout / (float) Config->get_vst_scan_timeout());
4650 scan_pbar->set_sensitive (false);
4651 scan_timeout_button->set_sensitive (false);
4657 ARDOUR_UI::plugin_scan_dialog (std::string type, std::string plugin, bool can_cancel)
4659 if (type == X_("closeme") && !(scan_dlg && scan_dlg->is_mapped())) {
4663 const bool cancelled = PluginManager::instance().cancelled();
4664 if (type != X_("closeme") && (!UIConfiguration::instance().get_show_plugin_scan_window()) && !_initial_verbose_plugin_scan) {
4665 if (cancelled && scan_dlg->is_mapped()) {
4670 if (cancelled || !can_cancel) {
4675 static Gtk::Button *cancel_button;
4677 scan_dlg = new MessageDialog("", false, MESSAGE_INFO, BUTTONS_NONE); // TODO manage
4678 VBox* vbox = scan_dlg->get_vbox();
4679 vbox->set_size_request(400,-1);
4680 scan_dlg->set_title (_("Scanning for plugins"));
4682 cancel_button = manage(new Gtk::Button(_("Cancel plugin scan")));
4683 cancel_button->set_name ("EditorGTKButton");
4684 cancel_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_scan) );
4685 cancel_button->show();
4687 scan_dlg->get_vbox()->pack_start ( *cancel_button, PACK_SHRINK);
4689 scan_tbox = manage( new HBox() );
4691 scan_timeout_button = manage(new Gtk::Button(_("Stop Timeout")));
4692 scan_timeout_button->set_name ("EditorGTKButton");
4693 scan_timeout_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_timeout) );
4694 scan_timeout_button->show();
4696 scan_pbar = manage(new ProgressBar());
4697 scan_pbar->set_orientation(Gtk::PROGRESS_RIGHT_TO_LEFT);
4698 scan_pbar->set_text(_("Scan Timeout"));
4701 scan_tbox->pack_start (*scan_pbar, PACK_EXPAND_WIDGET, 4);
4702 scan_tbox->pack_start (*scan_timeout_button, PACK_SHRINK, 4);
4704 scan_dlg->get_vbox()->pack_start (*scan_tbox, PACK_SHRINK, 4);
4707 assert(scan_dlg && scan_tbox && cancel_button);
4709 if (type == X_("closeme")) {
4713 scan_dlg->set_message(type + ": " + Glib::path_get_basename(plugin));
4716 if (!can_cancel || !cancelled) {
4717 scan_timeout_button->set_sensitive(false);
4719 cancel_button->set_sensitive(can_cancel && !cancelled);
4725 ARDOUR_UI::gui_idle_handler ()
4728 /* due to idle calls, gtk_events_pending() may always return true */
4729 while (gtk_events_pending() && --timeout) {
4730 gtk_main_iteration ();
4735 ARDOUR_UI::disk_underrun_handler ()
4737 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
4739 if (!have_disk_speed_dialog_displayed) {
4740 have_disk_speed_dialog_displayed = true;
4741 MessageDialog* msg = new MessageDialog (
4742 _main_window, string_compose (_("The disk system on your computer\n\
4743 was not able to keep up with %1.\n\
4745 Specifically, it failed to read data from disk\n\
4746 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
4747 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4753 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
4755 have_disk_speed_dialog_displayed = false;
4760 ARDOUR_UI::session_dialog (std::string msg)
4762 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
4766 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
4773 ARDOUR_UI::pending_state_dialog ()
4775 HBox* hbox = manage (new HBox());
4776 Image* image = manage (new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG));
4777 ArdourDialog dialog (_("Crash Recovery"), true);
4778 Label message (string_compose (_("\
4779 This session appears to have been in the\n\
4780 middle of recording when %1 or\n\
4781 the computer was shutdown.\n\
4783 %1 can recover any captured audio for\n\
4784 you, or it can ignore it. Please decide\n\
4785 what you would like to do.\n"), PROGRAM_NAME));
4786 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4787 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4788 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4789 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4790 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
4791 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
4792 dialog.set_default_response (RESPONSE_ACCEPT);
4793 dialog.set_position (WIN_POS_CENTER);
4798 switch (dialog.run ()) {
4799 case RESPONSE_ACCEPT:
4807 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
4809 HBox* hbox = new HBox();
4810 Image* image = new Image (Stock::DIALOG_WARNING, ICON_SIZE_DIALOG);
4811 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
4812 Label message (string_compose (_("\
4813 This session was created with a sample rate of %1 Hz, but\n\
4814 %2 is currently running at %3 Hz. If you load this session,\n\
4815 audio may be played at the wrong sample rate.\n"), desired, PROGRAM_NAME, actual));
4817 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4818 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4819 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4820 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4821 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
4822 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
4823 dialog.set_default_response (RESPONSE_ACCEPT);
4824 dialog.set_position (WIN_POS_CENTER);
4829 switch (dialog.run()) {
4830 case RESPONSE_ACCEPT:
4840 ARDOUR_UI::sr_mismatch_message (framecnt_t desired, framecnt_t actual)
4842 MessageDialog msg (string_compose (_("\
4843 This session was created with a sample rate of %1 Hz, but\n\
4844 %2 is currently running at %3 Hz.\n\
4845 Audio will be recorded and played at the wrong sample rate.\n\
4846 Re-Configure the Audio Engine in\n\
4847 Menu > Window > Audio/Midi Setup"),
4848 desired, PROGRAM_NAME, actual),
4850 Gtk::MESSAGE_WARNING);
4855 ARDOUR_UI::use_config ()
4857 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
4859 set_transport_controllable_state (*node);
4864 ARDOUR_UI::update_transport_clocks (framepos_t pos)
4866 if (UIConfiguration::instance().get_primary_clock_delta_edit_cursor()) {
4867 primary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
4869 primary_clock->set (pos);
4872 if (UIConfiguration::instance().get_secondary_clock_delta_edit_cursor()) {
4873 secondary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
4875 secondary_clock->set (pos);
4878 if (big_clock_window) {
4879 big_clock->set (pos);
4881 ARDOUR_UI::instance()->video_timeline->manual_seek_video_monitor(pos);
4885 ARDOUR_UI::step_edit_status_change (bool yn)
4887 // XXX should really store pre-step edit status of things
4888 // we make insensitive
4891 rec_button.set_active_state (Gtkmm2ext::ImplicitActive);
4892 rec_button.set_sensitive (false);
4894 rec_button.unset_active_state ();;
4895 rec_button.set_sensitive (true);
4900 ARDOUR_UI::record_state_changed ()
4902 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
4904 if (!_session || !big_clock_window) {
4905 /* why bother - the clock isn't visible */
4909 if (_session->record_status () == Session::Recording && _session->have_rec_enabled_track ()) {
4910 big_clock->set_active (true);
4912 big_clock->set_active (false);
4917 ARDOUR_UI::first_idle ()
4920 _session->allow_auto_play (true);
4924 editor->first_idle();
4927 Keyboard::set_can_save_keybindings (true);
4932 ARDOUR_UI::store_clock_modes ()
4934 XMLNode* node = new XMLNode(X_("ClockModes"));
4936 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
4937 XMLNode* child = new XMLNode (X_("Clock"));
4939 child->add_property (X_("name"), (*x)->name());
4940 child->add_property (X_("mode"), enum_2_string ((*x)->mode()));
4941 child->add_property (X_("on"), ((*x)->off() ? X_("no") : X_("yes")));
4943 node->add_child_nocopy (*child);
4946 _session->add_extra_xml (*node);
4947 _session->set_dirty ();
4950 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
4951 : Controllable (name), ui (u), type(tp)
4957 ARDOUR_UI::TransportControllable::set_value (double val, PBD::Controllable::GroupControlDisposition /*group_override*/)
4960 /* do nothing: these are radio-style actions */
4964 const char *action = 0;
4968 action = X_("Roll");
4971 action = X_("Stop");
4974 action = X_("GotoStart");
4977 action = X_("GotoEnd");
4980 action = X_("Loop");
4983 action = X_("PlaySelection");
4986 action = X_("Record");
4996 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
5004 ARDOUR_UI::TransportControllable::get_value (void) const
5031 ARDOUR_UI::setup_profile ()
5033 if (gdk_screen_width() < 1200 || getenv ("ARDOUR_NARROW_SCREEN")) {
5034 Profile->set_small_screen ();
5037 if (g_getenv ("TRX")) {
5038 Profile->set_trx ();
5041 if (g_getenv ("MIXBUS")) {
5042 Profile->set_mixbus ();
5047 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
5049 MissingFileDialog dialog (s, str, type);
5054 int result = dialog.run ();
5061 return 1; // quit entire session load
5064 result = dialog.get_action ();
5070 ARDOUR_UI::ambiguous_file (std::string file, std::vector<std::string> hits)
5072 AmbiguousFileDialog dialog (file, hits);
5079 return dialog.get_which ();
5082 /** Allocate our thread-local buffers */
5084 ARDOUR_UI::get_process_buffers ()
5086 _process_thread->get_buffers ();
5089 /** Drop our thread-local buffers */
5091 ARDOUR_UI::drop_process_buffers ()
5093 _process_thread->drop_buffers ();
5097 ARDOUR_UI::feedback_detected ()
5099 _feedback_exists = true;
5103 ARDOUR_UI::successful_graph_sort ()
5105 _feedback_exists = false;
5109 ARDOUR_UI::midi_panic ()
5112 _session->midi_panic();
5117 ARDOUR_UI::session_format_mismatch (std::string xml_path, std::string backup_path)
5119 const char* start_big = "<span size=\"x-large\" weight=\"bold\">";
5120 const char* end_big = "</span>";
5121 const char* start_mono = "<tt>";
5122 const char* end_mono = "</tt>";
5124 MessageDialog msg (string_compose (_("%4This is a session from an older version of %3%5\n\n"
5125 "%3 has copied the old session file\n\n%6%1%7\n\nto\n\n%6%2%7\n\n"
5126 "From now on, use the backup copy with older versions of %3"),
5127 xml_path, backup_path, PROGRAM_NAME,
5129 start_mono, end_mono), true);
5136 ARDOUR_UI::reset_peak_display ()
5138 if (!_session || !_session->master_out() || !editor_meter) return;
5139 editor_meter->clear_meters();
5140 editor_meter_max_peak = -INFINITY;
5141 editor_meter_peak_display.set_active_state ( Gtkmm2ext::Off );
5145 ARDOUR_UI::reset_group_peak_display (RouteGroup* group)
5147 if (!_session || !_session->master_out()) return;
5148 if (group == _session->master_out()->route_group()) {
5149 reset_peak_display ();
5154 ARDOUR_UI::reset_route_peak_display (Route* route)
5156 if (!_session || !_session->master_out()) return;
5157 if (_session->master_out().get() == route) {
5158 reset_peak_display ();
5163 ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate)
5165 audio_midi_setup->set_desired_sample_rate (desired_sample_rate);
5166 audio_midi_setup->set_position (WIN_POS_CENTER);
5168 if (Config->get_try_autostart_engine () || getenv ("TRY_AUTOSTART_ENGINE")) {
5169 audio_midi_setup->try_autostart ();
5170 if (ARDOUR::AudioEngine::instance()->running()) {
5176 int response = audio_midi_setup->run();
5178 case Gtk::RESPONSE_OK:
5179 if (!AudioEngine::instance()->running()) {
5193 ARDOUR_UI::transport_numpad_timeout ()
5195 _numpad_locate_happening = false;
5196 if (_numpad_timeout_connection.connected() )
5197 _numpad_timeout_connection.disconnect();
5202 ARDOUR_UI::transport_numpad_decimal ()
5204 _numpad_timeout_connection.disconnect();
5206 if (_numpad_locate_happening) {
5207 if (editor) editor->goto_nth_marker(_pending_locate_num - 1);
5208 _numpad_locate_happening = false;
5210 _pending_locate_num = 0;
5211 _numpad_locate_happening = true;
5212 _numpad_timeout_connection = Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::transport_numpad_timeout), 2*1000);
5217 ARDOUR_UI::transport_numpad_event (int num)
5219 if ( _numpad_locate_happening ) {
5220 _pending_locate_num = _pending_locate_num*10 + num;
5223 case 0: toggle_roll(false, false); break;
5224 case 1: transport_rewind(1); break;
5225 case 2: transport_forward(1); break;
5226 case 3: transport_record(true); break;
5227 case 4: toggle_session_auto_loop(); break;
5228 case 5: transport_record(false); toggle_session_auto_loop(); break;
5229 case 6: toggle_punch(); break;
5230 case 7: toggle_click(); break;
5231 case 8: toggle_auto_return(); break;
5232 case 9: toggle_follow_edits(); break;
5238 ARDOUR_UI::set_flat_buttons ()
5240 CairoWidget::set_flat_buttons( UIConfiguration::instance().get_flat_buttons() );
5244 ARDOUR_UI::audioengine_became_silent ()
5246 MessageDialog msg (string_compose (_("This is a free/demo copy of %1. It has just switched to silent mode."), PROGRAM_NAME),
5248 Gtk::MESSAGE_WARNING,
5252 msg.set_title (string_compose (_("%1 is now silent"), PROGRAM_NAME));
5254 Gtk::Label pay_label (string_compose (_("Please consider paying for a copy of %1 - you can pay whatever you want."), PROGRAM_NAME));
5255 Gtk::Label subscribe_label (_("Better yet become a subscriber - subscriptions start at US$1 per month."));
5256 Gtk::Button pay_button (_("Pay for a copy (via the web)"));
5257 Gtk::Button subscribe_button (_("Become a subscriber (via the web)"));
5258 Gtk::HBox pay_button_box;
5259 Gtk::HBox subscribe_button_box;
5261 pay_button_box.pack_start (pay_button, true, false);
5262 subscribe_button_box.pack_start (subscribe_button, true, false);
5264 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 */
5266 pay_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://ardour.org/download")));
5267 subscribe_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://community.ardour.org/s/subscribe")));
5269 msg.get_vbox()->pack_start (pay_label);
5270 msg.get_vbox()->pack_start (pay_button_box);
5271 msg.get_vbox()->pack_start (subscribe_label);
5272 msg.get_vbox()->pack_start (subscribe_button_box);
5274 msg.get_vbox()->show_all ();
5276 msg.add_button (_("Remain silent"), Gtk::RESPONSE_CANCEL);
5277 msg.add_button (_("Save and quit"), Gtk::RESPONSE_NO);
5278 msg.add_button (_("Give me more time"), Gtk::RESPONSE_YES);
5283 case Gtk::RESPONSE_YES:
5284 AudioEngine::instance()->reset_silence_countdown ();
5287 case Gtk::RESPONSE_NO:
5289 save_state_canfail ("");
5293 case Gtk::RESPONSE_CANCEL:
5295 /* don't reset, save session and exit */
5301 ARDOUR_UI::hide_application ()
5303 Application::instance ()-> hide ();
5307 ARDOUR_UI::setup_toplevel_window (Gtk::Window& window, const string& name, void* owner)
5309 /* icons, titles, WM stuff */
5311 static list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
5313 if (window_icons.empty()) {
5314 Glib::RefPtr<Gdk::Pixbuf> icon;
5315 if ((icon = ::get_icon (PROGRAM_NAME "-icon_16px")) != 0) {
5316 window_icons.push_back (icon);
5318 if ((icon = ::get_icon (PROGRAM_NAME "-icon_22px")) != 0) {
5319 window_icons.push_back (icon);
5321 if ((icon = ::get_icon (PROGRAM_NAME "-icon_32px")) != 0) {
5322 window_icons.push_back (icon);
5324 if ((icon = ::get_icon (PROGRAM_NAME "-icon_48px")) != 0) {
5325 window_icons.push_back (icon);
5329 if (!window_icons.empty()) {
5330 window.set_default_icon_list (window_icons);
5333 Gtkmm2ext::WindowTitle title (Glib::get_application_name());
5335 if (!name.empty()) {
5339 window.set_title (title.get_string());
5340 window.set_wmclass (string_compose (X_("%1_%1"), downcase (PROGRAM_NAME), downcase (name)), PROGRAM_NAME);
5342 window.set_flags (CAN_FOCUS);
5343 window.add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
5345 /* This is a hack to ensure that GTK-accelerators continue to
5346 * work. Once we switch over to entirely native bindings, this will be
5347 * unnecessary and should be removed
5349 window.add_accel_group (ActionManager::ui_manager->get_accel_group());
5351 window.signal_configure_event().connect (sigc::mem_fun (*this, &ARDOUR_UI::configure_handler));
5352 window.signal_window_state_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::tabbed_window_state_event_handler), owner));
5353 window.signal_key_press_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5354 window.signal_key_release_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5358 ARDOUR_UI::key_event_handler (GdkEventKey* ev, Gtk::Window* event_window)
5360 Gtkmm2ext::Bindings* bindings = 0;
5361 Gtk::Window* window = 0;
5363 /* until we get ardour bindings working, we are not handling key
5367 if (ev->type != GDK_KEY_PRESS) {
5371 if (event_window == &_main_window) {
5373 window = event_window;
5375 /* find current tab contents */
5377 Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page());
5379 /* see if it uses the ardour binding system */
5382 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(w->get_data ("ardour-bindings"));
5385 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("main window key event, bindings = %1, global = %2\n", bindings, &global_bindings));
5389 window = event_window;
5391 /* see if window uses ardour binding system */
5393 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(window->get_data ("ardour-bindings"));
5396 /* An empty binding set is treated as if it doesn't exist */
5398 if (bindings && bindings->empty()) {
5402 return key_press_focus_accelerator_handler (*window, ev, bindings);
5405 static Gtkmm2ext::Bindings*
5406 get_bindings_from_widget_heirarchy (GtkWidget* w)
5411 if ((p = g_object_get_data (G_OBJECT(w), "ardour-bindings")) != 0) {
5414 w = gtk_widget_get_parent (w);
5417 return reinterpret_cast<Gtkmm2ext::Bindings*> (p);
5421 ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev, Gtkmm2ext::Bindings* bindings)
5423 GtkWindow* win = window.gobj();
5424 GtkWidget* focus = gtk_window_get_focus (win);
5425 bool special_handling_of_unmodified_accelerators = false;
5426 const guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK));
5430 /* some widget has keyboard focus */
5432 if (GTK_IS_ENTRY(focus) || Keyboard::some_magic_widget_has_focus()) {
5434 /* A particular kind of focusable widget currently has keyboard
5435 * focus. All unmodified key events should go to that widget
5436 * first and not be used as an accelerator by default
5439 special_handling_of_unmodified_accelerators = true;
5443 Gtkmm2ext::Bindings* focus_bindings = get_bindings_from_widget_heirarchy (focus);
5444 if (focus_bindings) {
5445 bindings = focus_bindings;
5446 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Switch bindings based on focus widget, now using %1\n", bindings->name()));
5451 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",
5454 show_gdk_event_state (ev->state),
5455 special_handling_of_unmodified_accelerators,
5456 Keyboard::some_magic_widget_has_focus(),
5458 (focus ? gtk_widget_get_name (focus) : "no focus widget"),
5459 ((ev->state & mask) ? "yes" : "no"),
5460 window.get_title()));
5462 /* This exists to allow us to override the way GTK handles
5463 key events. The normal sequence is:
5465 a) event is delivered to a GtkWindow
5466 b) accelerators/mnemonics are activated
5467 c) if (b) didn't handle the event, propagate to
5468 the focus widget and/or focus chain
5470 The problem with this is that if the accelerators include
5471 keys without modifiers, such as the space bar or the
5472 letter "e", then pressing the key while typing into
5473 a text entry widget results in the accelerator being
5474 activated, instead of the desired letter appearing
5477 There is no good way of fixing this, but this
5478 represents a compromise. The idea is that
5479 key events involving modifiers (not Shift)
5480 get routed into the activation pathway first, then
5481 get propagated to the focus widget if necessary.
5483 If the key event doesn't involve modifiers,
5484 we deliver to the focus widget first, thus allowing
5485 it to get "normal text" without interference
5488 Of course, this can also be problematic: if there
5489 is a widget with focus, then it will swallow
5490 all "normal text" accelerators.
5494 if (!special_handling_of_unmodified_accelerators || (ev->state & mask)) {
5496 /* no special handling or there are modifiers in effect: accelerate first */
5498 DEBUG_TRACE (DEBUG::Accelerators, "\tactivate, then propagate\n");
5499 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tevent send-event:%1 time:%2 length:%3 name %7 string:%4 hardware_keycode:%5 group:%6\n",
5500 ev->send_event, ev->time, ev->length, ev->string, ev->hardware_keycode, ev->group, gdk_keyval_name (ev->keyval)));
5502 DEBUG_TRACE (DEBUG::Accelerators, "\tsending to window\n");
5503 KeyboardKey k (ev->state, ev->keyval);
5507 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tusing Ardour bindings %1 @ %2 for this event\n", bindings->name(), bindings));
5509 if (bindings->activate (k, Bindings::Press)) {
5510 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5515 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5517 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5518 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5522 DEBUG_TRACE (DEBUG::Accelerators, "\tnot accelerated, now propagate\n");
5524 if (gtk_window_propagate_key_event (win, ev)) {
5525 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate handled\n");
5531 /* no modifiers, propagate first */
5533 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate, then activate\n");
5535 if (gtk_window_propagate_key_event (win, ev)) {
5536 DEBUG_TRACE (DEBUG::Accelerators, "\thandled by propagate\n");
5540 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagation didn't handle, so activate\n");
5541 KeyboardKey k (ev->state, ev->keyval);
5545 DEBUG_TRACE (DEBUG::Accelerators, "\tusing Ardour bindings for this window\n");
5548 if (bindings->activate (k, Bindings::Press)) {
5549 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5555 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5557 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5558 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5563 DEBUG_TRACE (DEBUG::Accelerators, "\tnot handled\n");
5568 ARDOUR_UI::load_bindings ()
5570 if ((global_bindings = Bindings::get_bindings (X_("Global"), global_actions)) == 0) {
5571 error << _("Global keybindings are missing") << endmsg;
5576 ARDOUR_UI::cancel_solo ()
5580 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_control), 0.0, Controllable::NoGroup);
5582 _session->clear_all_solo_state (_session->get_routes()); // safeguard, ideally this won't do anything, check the log-window