2 Copyright (C) 1999-2013 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include "gtk2ardour-config.h"
22 #include "gtk2ardour-version.h"
32 #ifndef PLATFORM_WINDOWS
33 #include <sys/resource.h>
43 #include "pbd/gstdio_compat.h"
45 #include <gtkmm/messagedialog.h>
46 #include <gtkmm/accelmap.h>
48 #include "pbd/error.h"
49 #include "pbd/basename.h"
50 #include "pbd/compose.h"
51 #include "pbd/convert.h"
52 #include "pbd/failed_constructor.h"
53 #include "pbd/enumwriter.h"
54 #include "pbd/memento_command.h"
55 #include "pbd/openuri.h"
56 #include "pbd/stl_delete.h"
57 #include "pbd/file_utils.h"
58 #include "pbd/localtime_r.h"
59 #include "pbd/pthread_utils.h"
60 #include "pbd/replace_all.h"
61 #include "pbd/xml++.h"
63 #include "gtkmm2ext/application.h"
64 #include "gtkmm2ext/bindings.h"
65 #include "gtkmm2ext/gtk_ui.h"
66 #include "gtkmm2ext/utils.h"
67 #include "gtkmm2ext/click_box.h"
68 #include "gtkmm2ext/fastmeter.h"
69 #include "gtkmm2ext/popup.h"
70 #include "gtkmm2ext/window_title.h"
72 #include "ardour/ardour.h"
73 #include "ardour/audio_backend.h"
74 #include "ardour/audio_track.h"
75 #include "ardour/audioengine.h"
76 #include "ardour/audiofilesource.h"
77 #include "ardour/automation_watch.h"
78 #include "ardour/diskstream.h"
79 #include "ardour/filename_extensions.h"
80 #include "ardour/filesystem_paths.h"
81 #include "ardour/ltc_file_reader.h"
82 #include "ardour/midi_track.h"
83 #include "ardour/port.h"
84 #include "ardour/plugin_manager.h"
85 #include "ardour/process_thread.h"
86 #include "ardour/profile.h"
87 #include "ardour/recent_sessions.h"
88 #include "ardour/session_directory.h"
89 #include "ardour/session_route.h"
90 #include "ardour/session_state_utils.h"
91 #include "ardour/session_utils.h"
92 #include "ardour/source_factory.h"
93 #include "ardour/slave.h"
94 #include "ardour/system_exec.h"
96 #include "LuaBridge/LuaBridge.h"
98 #ifdef WINDOWS_VST_SUPPORT
101 #ifdef AUDIOUNIT_SUPPORT
102 #include "ardour/audio_unit.h"
105 // fix for OSX (nsm.h has a check function, AU/Apple defines check)
110 #include "timecode/time.h"
112 typedef uint64_t microseconds_t;
117 #include "add_route_dialog.h"
118 #include "ambiguous_file_dialog.h"
119 #include "ardour_ui.h"
120 #include "audio_clock.h"
121 #include "audio_region_view.h"
122 #include "big_clock_window.h"
123 #include "bundle_manager.h"
124 #include "duplicate_routes_dialog.h"
126 #include "engine_dialog.h"
127 #include "export_video_dialog.h"
128 #include "export_video_infobox.h"
129 #include "gain_meter.h"
130 #include "global_port_matrix.h"
131 #include "gui_object.h"
132 #include "gui_thread.h"
133 #include "keyboard.h"
134 #include "keyeditor.h"
135 #include "location_ui.h"
136 #include "lua_script_manager.h"
137 #include "luawindow.h"
138 #include "main_clock.h"
139 #include "missing_file_dialog.h"
140 #include "missing_plugin_dialog.h"
141 #include "mixer_ui.h"
142 #include "meterbridge.h"
143 #include "mouse_cursors.h"
146 #include "pingback.h"
147 #include "processor_box.h"
148 #include "prompter.h"
149 #include "public_editor.h"
150 #include "rc_option_editor.h"
151 #include "route_time_axis.h"
152 #include "route_params_ui.h"
153 #include "save_as_dialog.h"
154 #include "script_selector.h"
155 #include "session_dialog.h"
156 #include "session_metadata_dialog.h"
157 #include "session_option_editor.h"
158 #include "shuttle_control.h"
159 #include "speaker_dialog.h"
162 #include "theme_manager.h"
163 #include "time_axis_view_item.h"
166 #include "video_server_dialog.h"
167 #include "add_video_dialog.h"
168 #include "transcode_video_dialog.h"
172 using namespace ARDOUR;
173 using namespace ARDOUR_UI_UTILS;
175 using namespace Gtkmm2ext;
178 using namespace Editing;
180 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
182 sigc::signal<void, framepos_t, bool, framepos_t> ARDOUR_UI::Clock;
183 sigc::signal<void> ARDOUR_UI::CloseAllDialogs;
186 ask_about_configuration_copy (string const & old_dir, string const & new_dir, int version)
188 MessageDialog msg (string_compose (_("%1 %2.x has discovered configuration files from %1 %3.x.\n\n"
189 "Would you like these files to be copied and used for %1 %2.x?\n\n"
190 "(This will require you to restart %1.)"),
191 PROGRAM_NAME, PROGRAM_VERSION, version),
192 false, /* no markup */
195 true /* modal, though it hardly matters since it is the only window */
198 msg.set_default_response (Gtk::RESPONSE_YES);
201 return (msg.run() == Gtk::RESPONSE_YES);
205 libxml_generic_error_func (void* /* parsing_context*/,
213 vsnprintf (buf, sizeof (buf), msg, ap);
214 error << buf << endmsg;
219 libxml_structured_error_func (void* /* parsing_context*/,
227 replace_all (msg, "\n", "");
230 if (err->file && err->line) {
231 error << X_("XML error: ") << msg << " in " << err->file << " at line " << err->line;
234 error << ':' << err->int2;
239 error << X_("XML error: ") << msg << endmsg;
245 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
246 : Gtkmm2ext::UI (PROGRAM_NAME, X_("gui"), argcp, argvp)
247 , session_loaded (false)
248 , gui_object_state (new GUIObjectState)
249 , primary_clock (new MainClock (X_("primary"), X_("transport"), true ))
250 , secondary_clock (new MainClock (X_("secondary"), X_("secondary"), false))
251 , big_clock (new AudioClock (X_("bigclock"), false, "big", true, true, false, false))
253 , global_actions (X_("global"))
254 , ignore_dual_punch (false)
255 , main_window_visibility (0)
261 , _mixer_on_top (false)
262 , _initial_verbose_plugin_scan (false)
263 , first_time_engine_run (true)
264 , roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll))
265 , stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop))
266 , goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart))
267 , goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd))
268 , auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop))
269 , play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection))
270 , rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable))
271 , auto_return_button (ArdourButton::led_default_elements)
272 , follow_edits_button (ArdourButton::led_default_elements)
273 , auto_input_button (ArdourButton::led_default_elements)
274 , auditioning_alert_button (_("Audition"))
275 , solo_alert_button (_("Solo"))
276 , feedback_alert_button (_("Feedback"))
277 , error_alert_button ( ArdourButton::just_led_default_elements )
279 , editor_meter_peak_display()
280 , _numpad_locate_happening (false)
281 , _session_is_new (false)
282 , last_key_press_time (0)
286 , rc_option_editor (0)
287 , speaker_config_window (X_("speaker-config"), _("Speaker Configuration"))
288 , add_route_dialog (X_("add-routes"), _("Add Tracks/Busses"))
289 , about (X_("about"), _("About"))
290 , location_ui (X_("locations"), _("Locations"))
291 , route_params (X_("inspector"), _("Tracks and Busses"))
292 , audio_midi_setup (X_("audio-midi-setup"), _("Audio/MIDI Setup"))
293 , export_video_dialog (X_("video-export"), _("Video Export Dialog"))
294 , lua_script_window (X_("script-manager"), _("Script Manager"))
295 , session_option_editor (X_("session-options-editor"), _("Properties"), boost::bind (&ARDOUR_UI::create_session_option_editor, this))
296 , add_video_dialog (X_("add-video"), _("Add Video"), boost::bind (&ARDOUR_UI::create_add_video_dialog, this))
297 , bundle_manager (X_("bundle-manager"), _("Bundle Manager"), boost::bind (&ARDOUR_UI::create_bundle_manager, this))
298 , big_clock_window (X_("big-clock"), _("Big Clock"), boost::bind (&ARDOUR_UI::create_big_clock_window, this))
299 , audio_port_matrix (X_("audio-connection-manager"), _("Audio Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::AUDIO))
300 , midi_port_matrix (X_("midi-connection-manager"), _("MIDI Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::MIDI))
301 , key_editor (X_("key-editor"), _("Bindings Editor"), boost::bind (&ARDOUR_UI::create_key_editor, this))
302 , video_server_process (0)
304 , have_configure_timeout (false)
305 , last_configure_time (0)
307 , have_disk_speed_dialog_displayed (false)
308 , _status_bar_visibility (X_("status-bar"))
309 , _feedback_exists (false)
310 , _log_not_acknowledged (LogLevelNone)
311 , duplicate_routes_dialog (0)
312 , editor_visibility_button (S_("Window|Editor"))
313 , mixer_visibility_button (S_("Window|Mixer"))
314 , prefs_visibility_button (S_("Window|Preferences"))
315 , masters_visibility_button (S_("Windows|Masters"))
317 Gtkmm2ext::init (localedir);
319 UIConfiguration::instance().post_gui_init ();
321 if (ARDOUR::handle_old_configuration_files (boost::bind (ask_about_configuration_copy, _1, _2, _3))) {
322 MessageDialog msg (string_compose (_("Your configuration files were copied. You can now restart %1."), PROGRAM_NAME), true);
324 /* configuration was modified, exit immediately */
328 if (theArdourUI == 0) {
332 /* track main window visibility */
334 main_window_visibility = new VisibilityTracker (_main_window);
336 /* stop libxml from spewing to stdout/stderr */
338 xmlSetGenericErrorFunc (this, libxml_generic_error_func);
339 xmlSetStructuredErrorFunc (this, libxml_structured_error_func);
341 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::parameter_changed));
342 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
343 UIConfiguration::instance().map_parameters (pc);
345 roll_button.set_controllable (roll_controllable);
346 stop_button.set_controllable (stop_controllable);
347 goto_start_button.set_controllable (goto_start_controllable);
348 goto_end_button.set_controllable (goto_end_controllable);
349 auto_loop_button.set_controllable (auto_loop_controllable);
350 play_selection_button.set_controllable (play_selection_controllable);
351 rec_button.set_controllable (rec_controllable);
353 roll_button.set_name ("transport button");
354 stop_button.set_name ("transport button");
355 goto_start_button.set_name ("transport button");
356 goto_end_button.set_name ("transport button");
357 auto_loop_button.set_name ("transport button");
358 play_selection_button.set_name ("transport button");
359 rec_button.set_name ("transport recenable button");
360 midi_panic_button.set_name ("transport button");
362 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
363 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
365 ARDOUR::Session::VersionMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_format_mismatch, this, _1, _2), gui_context());
367 /* handle dialog requests */
369 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
371 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
373 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
375 /* handle Audio/MIDI setup when session requires it */
377 ARDOUR::Session::AudioEngineSetupRequired.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::do_audio_midi_setup, this, _1));
379 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
381 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
383 /* handle sr mismatch with a dialog - cross-thread from engine */
384 ARDOUR::Session::NotifyAboutSampleRateMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::sr_mismatch_message, this, _1, _2), gui_context ());
386 /* handle requests to quit (coming from JACK session) */
388 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::finish, this), gui_context ());
390 /* tell the user about feedback */
392 ARDOUR::Session::FeedbackDetected.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::feedback_detected, this), gui_context ());
393 ARDOUR::Session::SuccessfulGraphSort.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::successful_graph_sort, this), gui_context ());
395 /* handle requests to deal with missing files */
397 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
399 /* and ambiguous files */
401 ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2));
403 /* also plugin scan messages */
404 ARDOUR::PluginScanMessage.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_dialog, this, _1, _2, _3), gui_context());
405 ARDOUR::PluginScanTimeout.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_timeout, this, _1), gui_context());
407 ARDOUR::GUIIdle.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::gui_idle_handler, this), gui_context());
409 Config->ParameterChanged.connect ( forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::set_flat_buttons, this), gui_context() );
412 /* lets get this party started */
414 setup_gtk_ardour_enums ();
417 SessionEvent::create_per_thread_pool ("GUI", 4096);
419 /* we like keyboards */
421 keyboard = new ArdourKeyboard(*this);
423 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
425 keyboard->set_state (*node, Stateful::loading_state_version);
428 UIConfiguration::instance().reset_dpi ();
430 TimeAxisViewItem::set_constant_heights ();
432 /* Set this up so that our window proxies can register actions */
434 ActionManager::init ();
436 /* The following must happen after ARDOUR::init() so that Config is set up */
438 const XMLNode* ui_xml = Config->extra_xml (X_("UI"));
441 key_editor.set_state (*ui_xml, 0);
442 session_option_editor.set_state (*ui_xml, 0);
443 speaker_config_window.set_state (*ui_xml, 0);
444 about.set_state (*ui_xml, 0);
445 add_route_dialog.set_state (*ui_xml, 0);
446 add_video_dialog.set_state (*ui_xml, 0);
447 route_params.set_state (*ui_xml, 0);
448 bundle_manager.set_state (*ui_xml, 0);
449 location_ui.set_state (*ui_xml, 0);
450 big_clock_window.set_state (*ui_xml, 0);
451 audio_port_matrix.set_state (*ui_xml, 0);
452 midi_port_matrix.set_state (*ui_xml, 0);
453 export_video_dialog.set_state (*ui_xml, 0);
454 lua_script_window.set_state (*ui_xml, 0);
457 /* Separate windows */
459 WM::Manager::instance().register_window (&key_editor);
460 WM::Manager::instance().register_window (&session_option_editor);
461 WM::Manager::instance().register_window (&speaker_config_window);
462 WM::Manager::instance().register_window (&about);
463 WM::Manager::instance().register_window (&add_route_dialog);
464 WM::Manager::instance().register_window (&add_video_dialog);
465 WM::Manager::instance().register_window (&route_params);
466 WM::Manager::instance().register_window (&audio_midi_setup);
467 WM::Manager::instance().register_window (&export_video_dialog);
468 WM::Manager::instance().register_window (&lua_script_window);
469 WM::Manager::instance().register_window (&bundle_manager);
470 WM::Manager::instance().register_window (&location_ui);
471 WM::Manager::instance().register_window (&big_clock_window);
472 WM::Manager::instance().register_window (&audio_port_matrix);
473 WM::Manager::instance().register_window (&midi_port_matrix);
475 /* Trigger setting up the color scheme and loading the GTK RC file */
477 UIConfiguration::instance().load_rc_file (false);
479 _process_thread = new ProcessThread ();
480 _process_thread->init ();
482 UIConfiguration::instance().DPIReset.connect (sigc::mem_fun (*this, &ARDOUR_UI::resize_text_widgets));
487 GlobalPortMatrixWindow*
488 ARDOUR_UI::create_global_port_matrix (ARDOUR::DataType type)
493 return new GlobalPortMatrixWindow (_session, type);
497 ARDOUR_UI::attach_to_engine ()
499 AudioEngine::instance()->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
500 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
504 ARDOUR_UI::engine_stopped ()
506 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
507 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
508 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
509 update_sample_rate (0);
514 ARDOUR_UI::engine_running ()
516 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
517 if (first_time_engine_run) {
519 first_time_engine_run = false;
523 _session->reset_xrun_count ();
525 update_disk_space ();
527 update_xrun_count ();
528 update_sample_rate (AudioEngine::instance()->sample_rate());
529 update_timecode_format ();
530 update_peak_thread_work ();
531 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, true);
532 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, false);
536 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
538 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
539 /* we can't rely on the original string continuing to exist when we are called
540 again in the GUI thread, so make a copy and note that we need to
543 char *copy = strdup (reason);
544 Gtkmm2ext::UI::instance()->call_slot (MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
548 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
549 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
551 update_sample_rate (0);
555 /* if the reason is a non-empty string, it means that the backend was shutdown
556 rather than just Ardour.
559 if (strlen (reason)) {
560 msgstr = string_compose (_("The audio backend was shutdown because:\n\n%1"), reason);
562 msgstr = string_compose (_("\
563 The audio backend has either been shutdown or it\n\
564 disconnected %1 because %1\n\
565 was not fast enough. Try to restart\n\
566 the audio backend and save the session."), PROGRAM_NAME);
569 MessageDialog msg (_main_window, msgstr);
570 pop_back_splash (msg);
574 free (const_cast<char*> (reason));
579 ARDOUR_UI::post_engine ()
581 /* Things to be done once (and once ONLY) after we have a backend running in the AudioEngine
583 #ifdef AUDIOUNIT_SUPPORT
585 if (AUPluginInfo::au_get_crashlog(au_msg)) {
586 popup_error(_("Audio Unit Plugin Scan Failed. Automatic AU scanning has been disabled. Please see the log window for further details."));
587 error << _("Audio Unit Plugin Scan Failed:") << endmsg;
588 info << au_msg << endmsg;
592 ARDOUR::init_post_engine ();
594 /* connect to important signals */
596 AudioEngine::instance()->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
597 AudioEngine::instance()->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
598 AudioEngine::instance()->BufferSizeChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
599 AudioEngine::instance()->Halted.connect_same_thread (halt_connection, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
600 AudioEngine::instance()->BecameSilent.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::audioengine_became_silent, this), gui_context());
602 if (setup_windows ()) {
603 throw failed_constructor ();
606 /* Do this after setup_windows (), as that's when the _status_bar_visibility is created */
607 XMLNode* n = Config->extra_xml (X_("UI"));
609 _status_bar_visibility.set_state (*n);
612 check_memory_locking();
614 /* this is the first point at which all the possible actions are
615 * available, because some of the available actions are dependent on
616 * aspects of the engine/backend.
619 if (ARDOUR_COMMAND_LINE::show_key_actions) {
622 vector<string> paths;
623 vector<string> labels;
624 vector<string> tooltips;
626 vector<Glib::RefPtr<Gtk::Action> > actions;
628 Gtkmm2ext::ActionMap::get_all_actions (paths, labels, tooltips, keys, actions);
630 vector<string>::iterator k;
631 vector<string>::iterator p;
633 for (p = paths.begin(), k = keys.begin(); p != paths.end(); ++k, ++p) {
638 cout << *p << " => " << *k << endl;
642 halt_connection.disconnect ();
643 AudioEngine::instance()->stop ();
647 /* this being a GUI and all, we want peakfiles */
649 AudioFileSource::set_build_peakfiles (true);
650 AudioFileSource::set_build_missing_peakfiles (true);
652 /* set default clock modes */
654 primary_clock->set_mode (AudioClock::Timecode);
655 secondary_clock->set_mode (AudioClock::BBT);
657 /* start the time-of-day-clock */
660 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
661 update_wall_clock ();
662 Glib::signal_timeout().connect_seconds (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 1);
667 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
668 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
669 Config->map_parameters (pc);
671 UIConfiguration::instance().map_parameters (pc);
675 ARDOUR_UI::~ARDOUR_UI ()
677 UIConfiguration::instance().save_state();
681 if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
682 // don't bother at 'real' exit. the OS cleans up for us.
683 delete big_clock; big_clock = 0;
684 delete primary_clock; primary_clock = 0;
685 delete secondary_clock; secondary_clock = 0;
686 delete _process_thread; _process_thread = 0;
687 delete meterbridge; meterbridge = 0;
688 delete luawindow; luawindow = 0;
689 delete editor; editor = 0;
690 delete mixer; mixer = 0;
692 delete gui_object_state; gui_object_state = 0;
693 delete main_window_visibility;
694 FastMeter::flush_pattern_cache ();
695 PixFader::flush_pattern_cache ();
699 /* Small trick to flush main-thread event pool.
700 * Other thread-pools are destroyed at pthread_exit(),
701 * but tmain thread termination is too late to trigger Pool::~Pool()
703 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.
704 delete ev->event_pool();
709 ARDOUR_UI::pop_back_splash (Gtk::Window& win)
711 if (Splash::instance()) {
712 Splash::instance()->pop_back_for (win);
717 ARDOUR_UI::configure_timeout ()
719 if (last_configure_time == 0) {
720 /* no configure events yet */
724 /* force a gap of 0.5 seconds since the last configure event
727 if (get_microseconds() - last_configure_time < 500000) {
730 have_configure_timeout = false;
731 save_ardour_state ();
737 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
739 if (have_configure_timeout) {
740 last_configure_time = get_microseconds();
742 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
743 have_configure_timeout = true;
750 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
752 XMLProperty const * prop;
754 if ((prop = node.property ("roll")) != 0) {
755 roll_controllable->set_id (prop->value());
757 if ((prop = node.property ("stop")) != 0) {
758 stop_controllable->set_id (prop->value());
760 if ((prop = node.property ("goto-start")) != 0) {
761 goto_start_controllable->set_id (prop->value());
763 if ((prop = node.property ("goto-end")) != 0) {
764 goto_end_controllable->set_id (prop->value());
766 if ((prop = node.property ("auto-loop")) != 0) {
767 auto_loop_controllable->set_id (prop->value());
769 if ((prop = node.property ("play-selection")) != 0) {
770 play_selection_controllable->set_id (prop->value());
772 if ((prop = node.property ("rec")) != 0) {
773 rec_controllable->set_id (prop->value());
775 if ((prop = node.property ("shuttle")) != 0) {
776 shuttle_box->controllable()->set_id (prop->value());
781 ARDOUR_UI::get_transport_controllable_state ()
783 XMLNode* node = new XMLNode(X_("TransportControllables"));
786 roll_controllable->id().print (buf, sizeof (buf));
787 node->add_property (X_("roll"), buf);
788 stop_controllable->id().print (buf, sizeof (buf));
789 node->add_property (X_("stop"), buf);
790 goto_start_controllable->id().print (buf, sizeof (buf));
791 node->add_property (X_("goto_start"), buf);
792 goto_end_controllable->id().print (buf, sizeof (buf));
793 node->add_property (X_("goto_end"), buf);
794 auto_loop_controllable->id().print (buf, sizeof (buf));
795 node->add_property (X_("auto_loop"), buf);
796 play_selection_controllable->id().print (buf, sizeof (buf));
797 node->add_property (X_("play_selection"), buf);
798 rec_controllable->id().print (buf, sizeof (buf));
799 node->add_property (X_("rec"), buf);
800 shuttle_box->controllable()->id().print (buf, sizeof (buf));
801 node->add_property (X_("shuttle"), buf);
807 ARDOUR_UI::save_session_at_its_request (std::string snapshot_name)
810 _session->save_state (snapshot_name);
815 ARDOUR_UI::autosave_session ()
817 if (g_main_depth() > 1) {
818 /* inside a recursive main loop,
819 give up because we may not be able to
825 if (!Config->get_periodic_safety_backups()) {
830 _session->maybe_write_autosave();
837 ARDOUR_UI::session_dirty_changed ()
844 ARDOUR_UI::update_autosave ()
846 if (_session && _session->dirty()) {
847 if (_autosave_connection.connected()) {
848 _autosave_connection.disconnect();
851 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
852 Config->get_periodic_safety_backup_interval() * 1000);
855 if (_autosave_connection.connected()) {
856 _autosave_connection.disconnect();
862 ARDOUR_UI::check_announcements ()
865 string _annc_filename;
868 _annc_filename = PROGRAM_NAME "_announcements_osx_";
869 #elif defined PLATFORM_WINDOWS
870 _annc_filename = PROGRAM_NAME "_announcements_windows_";
872 _annc_filename = PROGRAM_NAME "_announcements_linux_";
874 _annc_filename.append (VERSIONSTRING);
876 _announce_string = "";
878 std::string path = Glib::build_filename (user_config_directory(), _annc_filename);
879 FILE* fin = g_fopen (path.c_str(), "rb");
881 while (!feof (fin)) {
884 if ((len = fread (tmp, sizeof(char), 1024, fin)) == 0 || ferror (fin)) {
887 _announce_string.append (tmp, len);
892 pingback (VERSIONSTRING, path);
897 _hide_splash (gpointer arg)
899 ((ARDOUR_UI*)arg)->hide_splash();
904 ARDOUR_UI::starting ()
906 Application* app = Application::instance ();
908 bool brand_new_user = ArdourStartup::required ();
910 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
911 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::load_from_application_api));
913 if (ARDOUR_COMMAND_LINE::check_announcements) {
914 check_announcements ();
919 /* we need to create this early because it may need to set the
920 * audio backend end up.
924 audio_midi_setup.get (true);
926 std::cerr << "audio-midi engine setup failed."<< std::endl;
930 if ((nsm_url = g_getenv ("NSM_URL")) != 0) {
931 nsm = new NSM_Client;
932 if (!nsm->init (nsm_url)) {
933 /* the ardour executable may have different names:
935 * waf's obj.target for distro versions: eg ardour4, ardourvst4
936 * Ardour4, Mixbus3 for bundled versions + full path on OSX & windows
937 * argv[0] does not apply since we need the wrapper-script (not the binary itself)
939 * The wrapper startup script should set the environment variable 'ARDOUR_SELF'
941 const char *process_name = g_getenv ("ARDOUR_SELF");
942 nsm->announce (PROGRAM_NAME, ":dirty:", process_name ? process_name : "ardour4");
945 // wait for announce reply from nsm server
946 for ( i = 0; i < 5000; ++i) {
950 if (nsm->is_active()) {
955 error << _("NSM server did not announce itself") << endmsg;
958 // wait for open command from nsm server
959 for ( i = 0; i < 5000; ++i) {
962 if (nsm->client_id ()) {
968 error << _("NSM: no client ID provided") << endmsg;
972 if (_session && nsm) {
973 _session->set_nsm_state( nsm->is_active() );
975 error << _("NSM: no session created") << endmsg;
979 // nsm requires these actions disabled
980 vector<string> action_names;
981 action_names.push_back("SaveAs");
982 action_names.push_back("Rename");
983 action_names.push_back("New");
984 action_names.push_back("Open");
985 action_names.push_back("Recent");
986 action_names.push_back("Close");
988 for (vector<string>::const_iterator n = action_names.begin(); n != action_names.end(); ++n) {
989 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), (*n).c_str());
991 act->set_sensitive (false);
998 error << _("NSM: initialization failed") << endmsg;
1004 if (brand_new_user) {
1005 _initial_verbose_plugin_scan = true;
1010 _initial_verbose_plugin_scan = false;
1011 switch (s.response ()) {
1012 case Gtk::RESPONSE_OK:
1019 #ifdef NO_PLUGIN_STATE
1021 ARDOUR::RecentSessions rs;
1022 ARDOUR::read_recent_sessions (rs);
1024 string path = Glib::build_filename (user_config_directory(), ".iknowaboutfreeversion");
1026 if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS) && !rs.empty()) {
1028 /* already used Ardour, have sessions ... warn about plugin state */
1030 ArdourDialog d (_("Free/Demo Version Warning"), true);
1032 Button b (string_compose (_("Subscribe and support development of %1"), PROGRAM_NAME));
1033 CheckButton c (_("Don't warn me about this again"));
1035 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"),
1036 string_compose (_("This is a free/demo version of %1"), PROGRAM_NAME),
1037 _("It will not restore OR save any plugin settings"),
1038 _("If you load an existing session with plugin settings\n"
1039 "they will not be used and will be lost."),
1040 _("To get full access to updates without this limitation\n"
1041 "consider becoming a subscriber for a low cost every month.")));
1042 l.set_justify (JUSTIFY_CENTER);
1044 b.signal_clicked().connect (mem_fun(*this, &ARDOUR_UI::launch_subscribe));
1046 d.get_vbox()->pack_start (l, true, true);
1047 d.get_vbox()->pack_start (b, false, false, 12);
1048 d.get_vbox()->pack_start (c, false, false, 12);
1050 d.add_button (_("Quit now"), RESPONSE_CANCEL);
1051 d.add_button (string_compose (_("Continue using %1"), PROGRAM_NAME), RESPONSE_OK);
1055 c.signal_toggled().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (toggle_file_existence), path)));
1057 if (d.run () != RESPONSE_OK) {
1063 /* go get a session */
1065 const bool new_session_required = (ARDOUR_COMMAND_LINE::new_session || brand_new_user);
1067 if (get_session_parameters (false, new_session_required, ARDOUR_COMMAND_LINE::load_template)) {
1068 std::cerr << "Cannot get session parameters."<< std::endl;
1075 WM::Manager::instance().show_visible ();
1077 /* We have to do this here since goto_editor_window() ends up calling show_all() on the
1078 * editor window, and we may want stuff to be hidden.
1080 _status_bar_visibility.update ();
1082 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
1084 if (splash && splash->is_visible()) {
1085 // in 1 second, hide the splash screen
1086 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
1089 /* all other dialogs are created conditionally */
1095 ARDOUR_UI::check_memory_locking ()
1097 #if defined(__APPLE__) || defined(PLATFORM_WINDOWS)
1098 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
1102 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
1104 if (AudioEngine::instance()->is_realtime() && memory_warning_node == 0) {
1106 struct rlimit limits;
1108 long pages, page_size;
1110 size_t pages_len=sizeof(pages);
1111 if ((page_size = getpagesize()) < 0 ||
1112 sysctlbyname("hw.availpages", &pages, &pages_len, NULL, 0))
1114 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0)
1119 ram = (int64_t) pages * (int64_t) page_size;
1122 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
1126 if (limits.rlim_cur != RLIM_INFINITY) {
1128 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
1132 _("WARNING: Your system has a limit for maximum amount of locked memory. "
1133 "This might cause %1 to run out of memory before your system "
1134 "runs out of memory. \n\n"
1135 "You can view the memory limit with 'ulimit -l', "
1136 "and it is normally controlled by %2"),
1139 X_("/etc/login.conf")
1141 X_(" /etc/security/limits.conf")
1145 msg.set_default_response (RESPONSE_OK);
1147 VBox* vbox = msg.get_vbox();
1149 CheckButton cb (_("Do not show this window again"));
1150 hbox.pack_start (cb, true, false);
1151 vbox->pack_start (hbox);
1156 pop_back_splash (msg);
1160 if (cb.get_active()) {
1161 XMLNode node (X_("no-memory-warning"));
1162 Config->add_instant_xml (node);
1167 #endif // !__APPLE__
1172 ARDOUR_UI::queue_finish ()
1174 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
1178 ARDOUR_UI::idle_finish ()
1181 return false; /* do not call again */
1188 ARDOUR_UI::instance()->video_timeline->sync_session_state();
1190 if (_session->dirty()) {
1191 vector<string> actions;
1192 actions.push_back (_("Don't quit"));
1193 actions.push_back (_("Just quit"));
1194 actions.push_back (_("Save and quit"));
1195 switch (ask_about_saving_session(actions)) {
1200 /* use the default name */
1201 if (save_state_canfail ("")) {
1202 /* failed - don't quit */
1203 MessageDialog msg (_main_window,
1204 string_compose (_("\
1205 %1 was unable to save your session.\n\n\
1206 If you still wish to quit, please use the\n\n\
1207 \"Just quit\" option."), PROGRAM_NAME));
1208 pop_back_splash(msg);
1218 second_connection.disconnect ();
1219 point_one_second_connection.disconnect ();
1220 point_zero_something_second_connection.disconnect();
1221 fps_connection.disconnect();
1224 delete ARDOUR_UI::instance()->video_timeline;
1225 ARDOUR_UI::instance()->video_timeline = NULL;
1226 stop_video_server();
1228 /* Save state before deleting the session, as that causes some
1229 windows to be destroyed before their visible state can be
1232 save_ardour_state ();
1234 close_all_dialogs ();
1237 _session->set_clean ();
1238 _session->remove_pending_capture_state ();
1243 halt_connection.disconnect ();
1244 AudioEngine::instance()->stop ();
1245 #ifdef WINDOWS_VST_SUPPORT
1246 fst_stop_threading();
1252 ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
1254 ArdourDialog window (_("Unsaved Session"));
1255 Gtk::HBox dhbox; // the hbox for the image and text
1256 Gtk::Label prompt_label;
1257 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
1261 assert (actions.size() >= 3);
1263 window.add_button (actions[0], RESPONSE_REJECT);
1264 window.add_button (actions[1], RESPONSE_APPLY);
1265 window.add_button (actions[2], RESPONSE_ACCEPT);
1267 window.set_default_response (RESPONSE_ACCEPT);
1269 Gtk::Button noquit_button (msg);
1270 noquit_button.set_name ("EditorGTKButton");
1274 if (_session->snap_name() == _session->name()) {
1275 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?"),
1276 _session->snap_name());
1278 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?"),
1279 _session->snap_name());
1282 prompt_label.set_text (prompt);
1283 prompt_label.set_name (X_("PrompterLabel"));
1284 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
1286 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
1287 dhbox.set_homogeneous (false);
1288 dhbox.pack_start (*dimage, false, false, 5);
1289 dhbox.pack_start (prompt_label, true, false, 5);
1290 window.get_vbox()->pack_start (dhbox);
1292 window.set_name (_("Prompter"));
1293 window.set_modal (true);
1294 window.set_resizable (false);
1297 prompt_label.show();
1302 ResponseType r = (ResponseType) window.run();
1307 case RESPONSE_ACCEPT: // save and get out of here
1309 case RESPONSE_APPLY: // get out of here
1320 ARDOUR_UI::every_second ()
1323 update_xrun_count ();
1324 update_buffer_load ();
1325 update_disk_space ();
1326 update_timecode_format ();
1327 update_peak_thread_work ();
1329 if (nsm && nsm->is_active ()) {
1332 if (!_was_dirty && _session->dirty ()) {
1336 else if (_was_dirty && !_session->dirty ()){
1344 ARDOUR_UI::every_point_one_seconds ()
1346 // TODO get rid of this..
1347 // ShuttleControl is updated directly via TransportStateChange signal
1351 ARDOUR_UI::every_point_zero_something_seconds ()
1353 // august 2007: actual update frequency: 25Hz (40ms), not 100Hz
1355 if (editor_meter && UIConfiguration::instance().get_show_editor_meter()) {
1356 float mpeak = editor_meter->update_meters();
1357 if (mpeak > editor_meter_max_peak) {
1358 if (mpeak >= UIConfiguration::instance().get_meter_peak()) {
1359 editor_meter_peak_display.set_active_state ( Gtkmm2ext::ExplicitActive );
1366 ARDOUR_UI::set_fps_timeout_connection ()
1368 unsigned int interval = 40;
1369 if (!_session) return;
1370 if (_session->timecode_frames_per_second() != 0) {
1371 /* ideally we'll use a select() to sleep and not accumulate
1372 * idle time to provide a regular periodic signal.
1373 * See linux_vst_gui_support.cc 'elapsed_time_ms'.
1374 * However, that'll require a dedicated thread and cross-thread
1375 * signals to the GUI Thread..
1377 interval = floor(500. /* update twice per FPS, since Glib::signal_timeout is very irregular */
1378 * _session->frame_rate() / _session->nominal_frame_rate()
1379 / _session->timecode_frames_per_second()
1381 #ifdef PLATFORM_WINDOWS
1382 // the smallest windows scheduler time-slice is ~15ms.
1383 // periodic GUI timeouts shorter than that will cause
1384 // WaitForSingleObject to spinlock (100% of one CPU Core)
1385 // and gtk never enters idle mode.
1386 // also changing timeBeginPeriod(1) does not affect that in
1387 // any beneficial way, so we just limit the max rate for now.
1388 interval = std::max(30u, interval); // at most ~33Hz.
1390 interval = std::max(8u, interval); // at most 120Hz.
1393 fps_connection.disconnect();
1394 Timers::set_fps_interval (interval);
1398 ARDOUR_UI::update_sample_rate (framecnt_t)
1402 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
1404 if (!AudioEngine::instance()->connected()) {
1406 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1410 framecnt_t rate = AudioEngine::instance()->sample_rate();
1413 /* no sample rate available */
1414 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1417 if (fmod (rate, 1000.0) != 0.0) {
1418 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
1419 (float) rate / 1000.0f,
1420 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1422 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
1424 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1428 sample_rate_label.set_markup (buf);
1432 ARDOUR_UI::update_format ()
1435 format_label.set_text ("");
1440 s << _("File:") << X_(" <span foreground=\"green\">");
1442 switch (_session->config.get_native_file_header_format ()) {
1474 switch (_session->config.get_native_file_data_format ()) {
1488 format_label.set_markup (s.str ());
1492 ARDOUR_UI::update_xrun_count ()
1496 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1497 should also be changed.
1501 const unsigned int x = _session->get_xrun_count ();
1503 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">>10K</span>"), X_("red"));
1505 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">%u</span>"), x > 0 ? X_("red") : X_("green"), x);
1508 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">?</span>"), X_("yellow"));
1510 xrun_label.set_markup (buf);
1511 set_tip (xrun_label, _("Audio dropouts. Shift+click to reset"));
1515 ARDOUR_UI::update_cpu_load ()
1519 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1520 should also be changed.
1523 double const c = AudioEngine::instance()->get_dsp_load ();
1524 snprintf (buf, sizeof (buf), _("DSP: <span foreground=\"%s\">%5.1f%%</span>"), c >= 90 ? X_("red") : X_("green"), c);
1525 cpu_load_label.set_markup (buf);
1529 ARDOUR_UI::update_peak_thread_work ()
1532 const int c = SourceFactory::peak_work_queue_length ();
1534 snprintf (buf, sizeof (buf), _("PkBld: <span foreground=\"%s\">%d</span>"), c >= 2 ? X_("red") : X_("green"), c);
1535 peak_thread_work_label.set_markup (buf);
1537 peak_thread_work_label.set_markup (X_(""));
1542 ARDOUR_UI::update_buffer_load ()
1546 uint32_t const playback = _session ? _session->playback_load () : 100;
1547 uint32_t const capture = _session ? _session->capture_load () : 100;
1549 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1550 should also be changed.
1556 _("Buffers: <span foreground=\"green\">p:</span><span foreground=\"%s\">%" PRIu32 "%%</span> "
1557 "<span foreground=\"green\">c:</span><span foreground=\"%s\">%" PRIu32 "%%</span>"),
1558 playback <= 5 ? X_("red") : X_("green"),
1560 capture <= 5 ? X_("red") : X_("green"),
1564 buffer_load_label.set_markup (buf);
1566 buffer_load_label.set_text ("");
1571 ARDOUR_UI::count_recenabled_streams (Route& route)
1573 Track* track = dynamic_cast<Track*>(&route);
1574 if (track && track->record_enabled()) {
1575 rec_enabled_streams += track->n_inputs().n_total();
1580 ARDOUR_UI::update_disk_space()
1582 if (_session == 0) {
1586 boost::optional<framecnt_t> opt_frames = _session->available_capture_duration();
1588 framecnt_t fr = _session->frame_rate();
1591 /* skip update - no SR available */
1596 /* Available space is unknown */
1597 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">Unknown</span>"));
1598 } else if (opt_frames.get_value_or (0) == max_framecnt) {
1599 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">24hrs+</span>"));
1601 rec_enabled_streams = 0;
1602 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams, false);
1604 framecnt_t frames = opt_frames.get_value_or (0);
1606 if (rec_enabled_streams) {
1607 frames /= rec_enabled_streams;
1614 hrs = frames / (fr * 3600);
1617 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">>24 hrs</span>"));
1619 frames -= hrs * fr * 3600;
1620 mins = frames / (fr * 60);
1621 frames -= mins * fr * 60;
1624 bool const low = (hrs == 0 && mins <= 30);
1628 _("Disk: <span foreground=\"%s\">%02dh:%02dm:%02ds</span>"),
1629 low ? X_("red") : X_("green"),
1635 disk_space_label.set_markup (buf);
1639 ARDOUR_UI::update_timecode_format ()
1645 TimecodeSlave* tcslave;
1646 SyncSource sync_src = Config->get_sync_source();
1648 if ((sync_src == LTC || sync_src == MTC) && (tcslave = dynamic_cast<TimecodeSlave*>(_session->slave())) != 0) {
1649 matching = (tcslave->apparent_timecode_format() == _session->config.get_timecode_format());
1654 snprintf (buf, sizeof (buf), S_("Timecode|TC: <span foreground=\"%s\">%s</span>"),
1655 matching ? X_("green") : X_("red"),
1656 Timecode::timecode_format_name (_session->config.get_timecode_format()).c_str());
1658 snprintf (buf, sizeof (buf), "TC: n/a");
1661 timecode_format_label.set_markup (buf);
1665 ARDOUR_UI::update_wall_clock ()
1669 static int last_min = -1;
1672 tm_now = localtime (&now);
1673 if (last_min != tm_now->tm_min) {
1675 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1676 wall_clock_label.set_text (buf);
1677 last_min = tm_now->tm_min;
1684 ARDOUR_UI::open_recent_session ()
1686 bool can_return = (_session != 0);
1688 SessionDialog recent_session_dialog;
1692 ResponseType r = (ResponseType) recent_session_dialog.run ();
1695 case RESPONSE_ACCEPT:
1699 recent_session_dialog.hide();
1706 recent_session_dialog.hide();
1710 std::string path = recent_session_dialog.session_folder();
1711 std::string state = recent_session_dialog.session_name (should_be_new);
1713 if (should_be_new == true) {
1717 _session_is_new = false;
1719 if (load_session (path, state) == 0) {
1725 if (splash && splash->is_visible()) {
1726 // in 1 second, hide the splash screen
1727 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
1732 ARDOUR_UI::check_audioengine (Gtk::Window& parent)
1734 if (!AudioEngine::instance()->connected()) {
1735 MessageDialog msg (parent, string_compose (
1736 _("%1 is not connected to any audio backend.\n"
1737 "You cannot open or close sessions in this condition"),
1739 pop_back_splash (msg);
1747 ARDOUR_UI::open_session ()
1749 if (!check_audioengine (_main_window)) {
1753 /* ardour sessions are folders */
1754 Gtk::FileChooserDialog open_session_selector(_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1755 open_session_selector.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1756 open_session_selector.add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1757 open_session_selector.set_default_response(Gtk::RESPONSE_ACCEPT);
1760 string session_parent_dir = Glib::path_get_dirname(_session->path());
1761 open_session_selector.set_current_folder(session_parent_dir);
1763 open_session_selector.set_current_folder(Config->get_default_session_parent_dir());
1766 Gtkmm2ext::add_volume_shortcuts (open_session_selector);
1768 /* add_shortcut_folder throws an exception if the folder being added already has a shortcut */
1769 string default_session_folder = Config->get_default_session_parent_dir();
1770 open_session_selector.add_shortcut_folder (default_session_folder);
1772 catch (Glib::Error & e) {
1773 std::cerr << "open_session_selector.add_shortcut_folder() threw Glib::Error " << e.what() << std::endl;
1776 FileFilter session_filter;
1777 session_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::statefile_suffix));
1778 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1779 open_session_selector.add_filter (session_filter);
1780 open_session_selector.set_filter (session_filter);
1782 int response = open_session_selector.run();
1783 open_session_selector.hide ();
1785 if (response == Gtk::RESPONSE_CANCEL) {
1789 string session_path = open_session_selector.get_filename();
1793 if (session_path.length() > 0) {
1794 if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1795 _session_is_new = isnew;
1796 load_session (path, name);
1802 ARDOUR_UI::session_add_mixed_track (
1803 const ChanCount& input,
1804 const ChanCount& output,
1805 RouteGroup* route_group,
1807 const string& name_template,
1809 PluginInfoPtr instrument,
1810 Plugin::PresetRecord* pset)
1812 list<boost::shared_ptr<MidiTrack> > tracks;
1814 if (_session == 0) {
1815 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1820 tracks = _session->new_midi_track (input, output, instrument, ARDOUR::Normal, route_group, how_many, name_template, pset);
1822 if (tracks.size() != how_many) {
1823 error << string_compose(P_("could not create %1 new mixed track", "could not create %1 new mixed tracks", how_many), how_many) << endmsg;
1828 display_insufficient_ports_message ();
1833 for (list<boost::shared_ptr<MidiTrack> >::iterator i = tracks.begin(); i != tracks.end(); ++i) {
1834 (*i)->set_strict_io (true);
1840 ARDOUR_UI::session_add_midi_bus (
1841 RouteGroup* route_group,
1843 const string& name_template,
1845 PluginInfoPtr instrument,
1846 Plugin::PresetRecord* pset)
1850 if (_session == 0) {
1851 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1856 routes = _session->new_midi_route (route_group, how_many, name_template, instrument, pset);
1857 if (routes.size() != how_many) {
1858 error << string_compose(P_("could not create %1 new Midi Bus", "could not create %1 new Midi Busses", how_many), how_many) << endmsg;
1863 display_insufficient_ports_message ();
1868 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
1869 (*i)->set_strict_io (true);
1875 ARDOUR_UI::session_add_midi_route (
1877 RouteGroup* route_group,
1879 const string& name_template,
1881 PluginInfoPtr instrument,
1882 Plugin::PresetRecord* pset)
1884 ChanCount one_midi_channel;
1885 one_midi_channel.set (DataType::MIDI, 1);
1888 session_add_mixed_track (one_midi_channel, one_midi_channel, route_group, how_many, name_template, strict_io, instrument, pset);
1890 session_add_midi_bus (route_group, how_many, name_template, strict_io, instrument, pset);
1895 ARDOUR_UI::session_add_audio_route (
1897 int32_t input_channels,
1898 int32_t output_channels,
1899 ARDOUR::TrackMode mode,
1900 RouteGroup* route_group,
1902 string const & name_template,
1906 list<boost::shared_ptr<AudioTrack> > tracks;
1909 if (_session == 0) {
1910 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1916 tracks = _session->new_audio_track (input_channels, output_channels, mode, route_group, how_many, name_template);
1918 if (tracks.size() != how_many) {
1919 error << string_compose (P_("could not create %1 new audio track", "could not create %1 new audio tracks", how_many), how_many)
1925 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template);
1927 if (routes.size() != how_many) {
1928 error << string_compose (P_("could not create %1 new audio bus", "could not create %1 new audio busses", how_many), how_many)
1935 display_insufficient_ports_message ();
1940 for (list<boost::shared_ptr<AudioTrack> >::iterator i = tracks.begin(); i != tracks.end(); ++i) {
1941 (*i)->set_strict_io (true);
1943 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
1944 (*i)->set_strict_io (true);
1950 ARDOUR_UI::display_insufficient_ports_message ()
1952 MessageDialog msg (_main_window,
1953 string_compose (_("There are insufficient ports available\n\
1954 to create a new track or bus.\n\
1955 You should save %1, exit and\n\
1956 restart with more ports."), PROGRAM_NAME));
1957 pop_back_splash (msg);
1962 ARDOUR_UI::transport_goto_start ()
1965 _session->goto_start();
1967 /* force displayed area in editor to start no matter
1968 what "follow playhead" setting is.
1972 editor->center_screen (_session->current_start_frame ());
1978 ARDOUR_UI::transport_goto_zero ()
1981 _session->request_locate (0);
1983 /* force displayed area in editor to start no matter
1984 what "follow playhead" setting is.
1988 editor->reset_x_origin (0);
1994 ARDOUR_UI::transport_goto_wallclock ()
1996 if (_session && editor) {
2003 localtime_r (&now, &tmnow);
2005 framecnt_t frame_rate = _session->frame_rate();
2007 if (frame_rate == 0) {
2008 /* no frame rate available */
2012 frames = tmnow.tm_hour * (60 * 60 * frame_rate);
2013 frames += tmnow.tm_min * (60 * frame_rate);
2014 frames += tmnow.tm_sec * frame_rate;
2016 _session->request_locate (frames, _session->transport_rolling ());
2018 /* force displayed area in editor to start no matter
2019 what "follow playhead" setting is.
2023 editor->center_screen (frames);
2029 ARDOUR_UI::transport_goto_end ()
2032 framepos_t const frame = _session->current_end_frame();
2033 _session->request_locate (frame);
2035 /* force displayed area in editor to start no matter
2036 what "follow playhead" setting is.
2040 editor->center_screen (frame);
2046 ARDOUR_UI::transport_stop ()
2052 if (_session->is_auditioning()) {
2053 _session->cancel_audition ();
2057 _session->request_stop (false, true);
2060 /** Check if any tracks are record enabled. If none are, record enable all of them.
2061 * @return true if track record-enabled status was changed, false otherwise.
2064 ARDOUR_UI::trx_record_enable_all_tracks ()
2070 boost::shared_ptr<RouteList> rl = _session->get_tracks ();
2071 bool none_record_enabled = true;
2073 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
2074 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*r);
2077 if (t->record_enabled()) {
2078 none_record_enabled = false;
2083 if (none_record_enabled) {
2084 _session->set_record_enabled (rl, true, Session::rt_cleanup);
2087 return none_record_enabled;
2091 ARDOUR_UI::transport_record (bool roll)
2094 switch (_session->record_status()) {
2095 case Session::Disabled:
2096 if (_session->ntracks() == 0) {
2097 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."));
2101 if (Profile->get_trx()) {
2102 roll = trx_record_enable_all_tracks ();
2104 _session->maybe_enable_record ();
2109 case Session::Recording:
2111 _session->request_stop();
2113 _session->disable_record (false, true);
2117 case Session::Enabled:
2118 _session->disable_record (false, true);
2124 ARDOUR_UI::transport_roll ()
2130 if (_session->is_auditioning()) {
2135 if (_session->config.get_external_sync()) {
2136 switch (Config->get_sync_source()) {
2140 /* transport controlled by the master */
2146 bool rolling = _session->transport_rolling();
2148 if (_session->get_play_loop()) {
2150 /* If loop playback is not a mode, then we should cancel
2151 it when this action is requested. If it is a mode
2152 we just leave it in place.
2155 if (!Config->get_loop_is_mode()) {
2156 /* XXX it is not possible to just leave seamless loop and keep
2157 playing at present (nov 4th 2009)
2159 if (!Config->get_seamless_loop()) {
2160 /* stop loop playback and stop rolling */
2161 _session->request_play_loop (false, true);
2162 } else if (rolling) {
2163 /* stop loop playback but keep rolling */
2164 _session->request_play_loop (false, false);
2168 } else if (_session->get_play_range () ) {
2169 /* stop playing a range if we currently are */
2170 _session->request_play_range (0, true);
2174 _session->request_transport_speed (1.0f);
2179 ARDOUR_UI::get_smart_mode() const
2181 return ( editor->get_smart_mode() );
2186 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
2192 if (_session->is_auditioning()) {
2193 _session->cancel_audition ();
2197 if (_session->config.get_external_sync()) {
2198 switch (Config->get_sync_source()) {
2202 /* transport controlled by the master */
2207 bool rolling = _session->transport_rolling();
2208 bool affect_transport = true;
2210 if (rolling && roll_out_of_bounded_mode) {
2211 /* drop out of loop/range playback but leave transport rolling */
2212 if (_session->get_play_loop()) {
2213 if (_session->actively_recording()) {
2215 /* just stop using the loop, then actually stop
2218 _session->request_play_loop (false, affect_transport);
2221 if (Config->get_seamless_loop()) {
2222 /* the disk buffers contain copies of the loop - we can't
2223 just keep playing, so stop the transport. the user
2224 can restart as they wish.
2226 affect_transport = true;
2228 /* disk buffers are normal, so we can keep playing */
2229 affect_transport = false;
2231 _session->request_play_loop (false, affect_transport);
2233 } else if (_session->get_play_range ()) {
2234 affect_transport = false;
2235 _session->request_play_range (0, true);
2239 if (affect_transport) {
2241 _session->request_stop (with_abort, true);
2243 /* the only external sync condition we can be in here
2244 * would be Engine (JACK) sync, in which case we still
2248 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
2249 _session->request_play_range (&editor->get_selection().time, true);
2250 _session->set_requested_return_frame( editor->get_selection().time.front().start ); //force an auto-return here
2252 _session->request_transport_speed (1.0f);
2258 ARDOUR_UI::toggle_session_auto_loop ()
2264 Location * looploc = _session->locations()->auto_loop_location();
2270 if (_session->get_play_loop()) {
2272 /* looping enabled, our job is to disable it */
2274 _session->request_play_loop (false);
2278 /* looping not enabled, our job is to enable it.
2280 loop-is-NOT-mode: this action always starts the transport rolling.
2281 loop-IS-mode: this action simply sets the loop play mechanism, but
2282 does not start transport.
2284 if (Config->get_loop_is_mode()) {
2285 _session->request_play_loop (true, false);
2287 _session->request_play_loop (true, true);
2291 //show the loop markers
2292 looploc->set_hidden (false, this);
2296 ARDOUR_UI::transport_play_selection ()
2302 editor->play_selection ();
2306 ARDOUR_UI::transport_play_preroll ()
2311 editor->play_with_preroll ();
2315 ARDOUR_UI::transport_rewind (int option)
2317 float current_transport_speed;
2320 current_transport_speed = _session->transport_speed();
2322 if (current_transport_speed >= 0.0f) {
2325 _session->request_transport_speed (-1.0f);
2328 _session->request_transport_speed (-4.0f);
2331 _session->request_transport_speed (-0.5f);
2336 _session->request_transport_speed (current_transport_speed * 1.5f);
2342 ARDOUR_UI::transport_forward (int option)
2348 float current_transport_speed = _session->transport_speed();
2350 if (current_transport_speed <= 0.0f) {
2353 _session->request_transport_speed (1.0f);
2356 _session->request_transport_speed (4.0f);
2359 _session->request_transport_speed (0.5f);
2364 _session->request_transport_speed (current_transport_speed * 1.5f);
2369 ARDOUR_UI::toggle_record_enable (uint32_t rid)
2375 boost::shared_ptr<Route> r;
2377 if ((r = _session->route_by_remote_id (rid)) != 0) {
2379 boost::shared_ptr<Track> t;
2381 if ((t = boost::dynamic_pointer_cast<Track>(r)) != 0) {
2382 t->set_record_enabled (!t->record_enabled(), Controllable::UseGroup);
2388 ARDOUR_UI::map_transport_state ()
2391 auto_loop_button.unset_active_state ();
2392 play_selection_button.unset_active_state ();
2393 roll_button.unset_active_state ();
2394 stop_button.set_active_state (Gtkmm2ext::ExplicitActive);
2398 shuttle_box->map_transport_state ();
2400 float sp = _session->transport_speed();
2406 if (_session->get_play_range()) {
2408 play_selection_button.set_active_state (Gtkmm2ext::ExplicitActive);
2409 roll_button.unset_active_state ();
2410 auto_loop_button.unset_active_state ();
2412 } else if (_session->get_play_loop ()) {
2414 auto_loop_button.set_active (true);
2415 play_selection_button.set_active (false);
2416 if (Config->get_loop_is_mode()) {
2417 roll_button.set_active (true);
2419 roll_button.set_active (false);
2424 roll_button.set_active (true);
2425 play_selection_button.set_active (false);
2426 auto_loop_button.set_active (false);
2429 if (UIConfiguration::instance().get_follow_edits() && !_session->config.get_external_sync()) {
2430 /* light up both roll and play-selection if they are joined */
2431 roll_button.set_active (true);
2432 play_selection_button.set_active (true);
2435 stop_button.set_active (false);
2439 stop_button.set_active (true);
2440 roll_button.set_active (false);
2441 play_selection_button.set_active (false);
2442 if (Config->get_loop_is_mode ()) {
2443 auto_loop_button.set_active (_session->get_play_loop());
2445 auto_loop_button.set_active (false);
2447 update_disk_space ();
2452 ARDOUR_UI::blink_handler (bool blink_on)
2454 transport_rec_enable_blink (blink_on);
2455 solo_blink (blink_on);
2456 sync_blink (blink_on);
2457 audition_blink (blink_on);
2458 feedback_blink (blink_on);
2459 error_blink (blink_on);
2463 ARDOUR_UI::update_clocks ()
2465 if (!_session) return;
2467 if (editor && !editor->dragging_playhead()) {
2468 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD)); /* EMIT_SIGNAL */
2473 ARDOUR_UI::start_clocking ()
2475 if (UIConfiguration::instance().get_super_rapid_clock_update()) {
2476 clock_signal_connection = Timers::fps_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2478 clock_signal_connection = Timers::rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2483 ARDOUR_UI::stop_clocking ()
2485 clock_signal_connection.disconnect ();
2489 ARDOUR_UI::save_as_progress_update (float fraction, int64_t cnt, int64_t total, Gtk::Label* label, Gtk::ProgressBar* bar)
2493 snprintf (buf, sizeof (buf), _("Copied %" PRId64 " of %" PRId64), cnt, total);
2495 label->set_text (buf);
2496 bar->set_fraction (fraction);
2498 /* process events, redraws, etc. */
2500 while (gtk_events_pending()) {
2501 gtk_main_iteration ();
2504 return true; /* continue with save-as */
2508 ARDOUR_UI::save_session_as ()
2514 if (!save_as_dialog) {
2515 save_as_dialog = new SaveAsDialog;
2518 save_as_dialog->set_name (_session->name());
2520 int response = save_as_dialog->run ();
2522 save_as_dialog->hide ();
2525 case Gtk::RESPONSE_OK:
2534 sa.new_parent_folder = save_as_dialog->new_parent_folder ();
2535 sa.new_name = save_as_dialog->new_name ();
2536 sa.switch_to = save_as_dialog->switch_to();
2537 sa.copy_media = save_as_dialog->copy_media();
2538 sa.copy_external = save_as_dialog->copy_external();
2539 sa.include_media = save_as_dialog->include_media ();
2541 /* Only bother with a progress dialog if we're going to copy
2542 media into the save-as target. Without that choice, this
2543 will be very fast because we're only talking about a few kB's to
2544 perhaps a couple of MB's of data.
2547 ArdourDialog progress_dialog (_("Save As"), true);
2549 if (sa.include_media && sa.copy_media) {
2552 Gtk::ProgressBar progress_bar;
2554 progress_dialog.get_vbox()->pack_start (label);
2555 progress_dialog.get_vbox()->pack_start (progress_bar);
2557 progress_bar.show ();
2559 /* this signal will be emitted from within this, the calling thread,
2560 * after every file is copied. It provides information on percentage
2561 * complete (in terms of total data to copy), the number of files
2562 * copied so far, and the total number to copy.
2567 sa.Progress.connect_same_thread (c, boost::bind (&ARDOUR_UI::save_as_progress_update, this, _1, _2, _3, &label, &progress_bar));
2569 progress_dialog.show_all ();
2570 progress_dialog.present ();
2573 if (_session->save_as (sa)) {
2575 MessageDialog msg (string_compose (_("Save As failed: %1"), sa.failure_message));
2579 if (!sa.include_media) {
2580 unload_session (false);
2581 load_session (sa.final_session_folder_name, sa.new_name);
2586 ARDOUR_UI::quick_snapshot_session (bool switch_to_it)
2590 struct tm local_time;
2593 localtime_r (&n, &local_time);
2594 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2596 save_state (timebuf, switch_to_it);
2601 ARDOUR_UI::process_snapshot_session_prompter (ArdourPrompter& prompter, bool switch_to_it)
2605 prompter.get_result (snapname);
2607 bool do_save = (snapname.length() != 0);
2610 char illegal = Session::session_name_is_legal(snapname);
2612 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2613 "snapshot names may not contain a '%1' character"), illegal));
2619 vector<std::string> p;
2620 get_state_files_in_directory (_session->session_directory().root_path(), p);
2621 vector<string> n = get_file_names_no_extension (p);
2623 if (find (n.begin(), n.end(), snapname) != n.end()) {
2625 do_save = overwrite_file_dialog (prompter,
2626 _("Confirm Snapshot Overwrite"),
2627 _("A snapshot already exists with that name. Do you want to overwrite it?"));
2631 save_state (snapname, switch_to_it);
2641 /** Ask the user for the name of a new snapshot and then take it.
2645 ARDOUR_UI::snapshot_session (bool switch_to_it)
2647 ArdourPrompter prompter (true);
2649 prompter.set_name ("Prompter");
2650 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2652 prompter.set_title (_("Snapshot and switch"));
2653 prompter.set_prompt (_("New session name"));
2655 prompter.set_title (_("Take Snapshot"));
2656 prompter.set_prompt (_("Name of new snapshot"));
2660 prompter.set_initial_text (_session->snap_name());
2664 struct tm local_time;
2667 localtime_r (&n, &local_time);
2668 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2669 prompter.set_initial_text (timebuf);
2672 bool finished = false;
2674 switch (prompter.run()) {
2675 case RESPONSE_ACCEPT:
2677 finished = process_snapshot_session_prompter (prompter, switch_to_it);
2688 /** Ask the user for a new session name and then rename the session to it.
2692 ARDOUR_UI::rename_session ()
2698 ArdourPrompter prompter (true);
2701 prompter.set_name ("Prompter");
2702 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2703 prompter.set_title (_("Rename Session"));
2704 prompter.set_prompt (_("New session name"));
2707 switch (prompter.run()) {
2708 case RESPONSE_ACCEPT:
2710 prompter.get_result (name);
2712 bool do_rename = (name.length() != 0);
2715 char illegal = Session::session_name_is_legal (name);
2718 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2719 "session names may not contain a '%1' character"), illegal));
2724 switch (_session->rename (name)) {
2726 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
2727 msg.set_position (WIN_POS_MOUSE);
2735 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
2736 msg.set_position (WIN_POS_MOUSE);
2752 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2754 if (!_session || _session->deletion_in_progress()) {
2758 XMLNode* node = new XMLNode (X_("UI"));
2760 WM::Manager::instance().add_state (*node);
2762 node->add_child_nocopy (gui_object_state->get_state());
2764 _session->add_extra_xml (*node);
2766 if (export_video_dialog) {
2767 _session->add_extra_xml (export_video_dialog->get_state());
2770 save_state_canfail (name, switch_to_it);
2774 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2779 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2784 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2789 ARDOUR_UI::primary_clock_value_changed ()
2792 _session->request_locate (primary_clock->current_time ());
2797 ARDOUR_UI::big_clock_value_changed ()
2800 _session->request_locate (big_clock->current_time ());
2805 ARDOUR_UI::secondary_clock_value_changed ()
2808 _session->request_locate (secondary_clock->current_time ());
2813 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2815 if (_session == 0) {
2819 if (_session->step_editing()) {
2823 Session::RecordState const r = _session->record_status ();
2824 bool const h = _session->have_rec_enabled_track ();
2826 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2828 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2830 rec_button.set_active_state (Gtkmm2ext::Off);
2832 } else if (r == Session::Recording && h) {
2833 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2835 rec_button.unset_active_state ();
2840 ARDOUR_UI::process_save_template_prompter (ArdourPrompter& prompter)
2844 prompter.get_result (name);
2846 if (name.length()) {
2847 int failed = _session->save_template (name);
2849 if (failed == -2) { /* file already exists. */
2850 bool overwrite = overwrite_file_dialog (prompter,
2851 _("Confirm Template Overwrite"),
2852 _("A template already exists with that name. Do you want to overwrite it?"));
2855 _session->save_template (name, true);
2867 ARDOUR_UI::save_template ()
2869 ArdourPrompter prompter (true);
2871 if (!check_audioengine (_main_window)) {
2875 prompter.set_name (X_("Prompter"));
2876 prompter.set_title (_("Save Template"));
2877 prompter.set_prompt (_("Name for template:"));
2878 prompter.set_initial_text(_session->name() + _("-template"));
2879 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2881 bool finished = false;
2883 switch (prompter.run()) {
2884 case RESPONSE_ACCEPT:
2885 finished = process_save_template_prompter (prompter);
2896 ARDOUR_UI::edit_metadata ()
2898 SessionMetadataEditor dialog;
2899 dialog.set_session (_session);
2900 dialog.grab_focus ();
2905 ARDOUR_UI::import_metadata ()
2907 SessionMetadataImporter dialog;
2908 dialog.set_session (_session);
2913 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
2915 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2917 MessageDialog msg (str,
2919 Gtk::MESSAGE_WARNING,
2920 Gtk::BUTTONS_YES_NO,
2924 msg.set_name (X_("OpenExistingDialog"));
2925 msg.set_title (_("Open Existing Session"));
2926 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
2927 msg.set_position (Gtk::WIN_POS_CENTER);
2928 pop_back_splash (msg);
2930 switch (msg.run()) {
2939 ARDOUR_UI::build_session_from_dialog (SessionDialog& sd, const std::string& session_path, const std::string& session_name)
2941 BusProfile bus_profile;
2945 bus_profile.master_out_channels = 2;
2946 bus_profile.input_ac = AutoConnectPhysical;
2947 bus_profile.output_ac = AutoConnectMaster;
2948 bus_profile.requested_physical_in = 0; // use all available
2949 bus_profile.requested_physical_out = 0; // use all available
2953 /* get settings from advanced section of NSD */
2955 if (sd.create_master_bus()) {
2956 bus_profile.master_out_channels = (uint32_t) sd.master_channel_count();
2958 bus_profile.master_out_channels = 0;
2961 if (sd.connect_inputs()) {
2962 bus_profile.input_ac = AutoConnectPhysical;
2964 bus_profile.input_ac = AutoConnectOption (0);
2967 bus_profile.output_ac = AutoConnectOption (0);
2969 if (sd.connect_outputs ()) {
2970 if (sd.connect_outs_to_master()) {
2971 bus_profile.output_ac = AutoConnectMaster;
2972 } else if (sd.connect_outs_to_physical()) {
2973 bus_profile.output_ac = AutoConnectPhysical;
2977 bus_profile.requested_physical_in = (uint32_t) sd.input_limit_count();
2978 bus_profile.requested_physical_out = (uint32_t) sd.output_limit_count();
2981 if (build_session (session_path, session_name, bus_profile)) {
2989 ARDOUR_UI::load_from_application_api (const std::string& path)
2991 ARDOUR_COMMAND_LINE::session_name = path;
2992 /* Cancel SessionDialog if it's visible to make OSX delegates work.
2994 * ARDOUR_UI::starting connects app->ShouldLoad signal and then shows a SessionDialog
2996 * - ShouldLoad does not arrive in time, ARDOUR_COMMAND_LINE::session_name is empty:
2997 * -> ARDOUR_UI::get_session_parameters starts a SessionDialog.
2998 * - ShouldLoad signal arrives, this function is called and sets ARDOUR_COMMAND_LINE::session_name
2999 * -> SessionDialog is not displayed
3002 if (_session_dialog) {
3003 std::string session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3004 std::string session_path = path;
3005 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_REGULAR)) {
3006 session_path = Glib::path_get_dirname (session_path);
3008 // signal the existing dialog in ARDOUR_UI::get_session_parameters()
3009 _session_dialog->set_provided_session (session_name, session_path);
3010 _session_dialog->response (RESPONSE_NONE);
3011 _session_dialog->hide();
3016 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
3017 /* /path/to/foo => /path/to/foo, foo */
3018 rv = load_session (path, basename_nosuffix (path));
3020 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
3021 rv =load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
3024 // if load_session fails -> pop up SessionDialog.
3026 ARDOUR_COMMAND_LINE::session_name = "";
3028 if (get_session_parameters (true, false)) {
3034 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
3036 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
3038 string session_name;
3039 string session_path;
3040 string template_name;
3042 bool likely_new = false;
3043 bool cancel_not_quit;
3045 /* deal with any existing DIRTY session now, rather than later. don't
3046 * treat a non-dirty session this way, so that it stays visible
3047 * as we bring up the new session dialog.
3050 if (_session && ARDOUR_UI::instance()->video_timeline) {
3051 ARDOUR_UI::instance()->video_timeline->sync_session_state();
3054 /* if there is already a session, relabel the button
3055 on the SessionDialog so that we don't Quit directly
3057 cancel_not_quit = (_session != 0);
3059 if (_session && _session->dirty()) {
3060 if (unload_session (false)) {
3061 /* unload cancelled by user */
3064 ARDOUR_COMMAND_LINE::session_name = "";
3067 if (!load_template.empty()) {
3068 should_be_new = true;
3069 template_name = load_template;
3072 session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3073 session_path = ARDOUR_COMMAND_LINE::session_name;
3075 if (!session_path.empty()) {
3076 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_EXISTS)) {
3077 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_IS_REGULAR)) {
3078 /* session/snapshot file, change path to be dir */
3079 session_path = Glib::path_get_dirname (session_path);
3084 SessionDialog session_dialog (should_be_new, session_name, session_path, load_template, cancel_not_quit);
3086 _session_dialog = &session_dialog;
3089 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
3091 /* if they named a specific statefile, use it, otherwise they are
3092 just giving a session folder, and we want to use it as is
3093 to find the session.
3096 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
3098 if (suffix != string::npos) {
3099 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
3100 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
3101 session_name = Glib::path_get_basename (session_name);
3103 session_path = ARDOUR_COMMAND_LINE::session_name;
3104 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
3109 session_dialog.clear_given ();
3112 if (should_be_new || session_name.empty()) {
3113 /* need the dialog to get info from user */
3115 cerr << "run dialog\n";
3117 switch (session_dialog.run()) {
3118 case RESPONSE_ACCEPT:
3121 /* this is used for async * app->ShouldLoad(). */
3122 continue; // while loop
3125 if (quit_on_cancel) {
3126 // JE - Currently (July 2014) this section can only get reached if the
3127 // user quits from the main 'Session Setup' dialog (i.e. reaching this
3128 // point does NOT indicate an abnormal termination). Therefore, let's
3129 // behave gracefully (i.e. let's do some cleanup) before we call exit()
3131 pthread_cancel_all ();
3139 session_dialog.hide ();
3142 /* if we run the startup dialog again, offer more than just "new session" */
3144 should_be_new = false;
3146 session_name = session_dialog.session_name (likely_new);
3147 session_path = session_dialog.session_folder ();
3153 string::size_type suffix = session_name.find (statefile_suffix);
3155 if (suffix != string::npos) {
3156 session_name = session_name.substr (0, suffix);
3159 /* this shouldn't happen, but we catch it just in case it does */
3161 if (session_name.empty()) {
3165 if (session_dialog.use_session_template()) {
3166 template_name = session_dialog.session_template_name();
3167 _session_is_new = true;
3170 if (session_name[0] == G_DIR_SEPARATOR ||
3171 #ifdef PLATFORM_WINDOWS
3172 (session_name.length() > 3 && session_name[1] == ':' && session_name[2] == G_DIR_SEPARATOR)
3174 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
3175 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)
3180 /* absolute path or cwd-relative path specified for session name: infer session folder
3181 from what was given.
3184 session_path = Glib::path_get_dirname (session_name);
3185 session_name = Glib::path_get_basename (session_name);
3189 session_path = session_dialog.session_folder();
3191 char illegal = Session::session_name_is_legal (session_name);
3194 MessageDialog msg (session_dialog,
3195 string_compose (_("To ensure compatibility with various systems\n"
3196 "session names may not contain a '%1' character"),
3199 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3204 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
3207 if (likely_new && !nsm) {
3209 std::string existing = Glib::build_filename (session_path, session_name);
3211 if (!ask_about_loading_existing_session (existing)) {
3212 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3217 _session_is_new = false;
3222 pop_back_splash (session_dialog);
3223 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
3225 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3229 char illegal = Session::session_name_is_legal(session_name);
3232 pop_back_splash (session_dialog);
3233 MessageDialog msg (session_dialog, string_compose(_("To ensure compatibility with various systems\n"
3234 "session names may not contain a '%1' character"), illegal));
3236 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3240 _session_is_new = true;
3243 if (likely_new && template_name.empty()) {
3245 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3249 ret = load_session (session_path, session_name, template_name);
3252 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
3256 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
3257 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
3261 /* clear this to avoid endless attempts to load the
3265 ARDOUR_COMMAND_LINE::session_name = "";
3269 _session_dialog = NULL;
3275 ARDOUR_UI::close_session()
3277 if (!check_audioengine (_main_window)) {
3281 if (unload_session (true)) {
3285 ARDOUR_COMMAND_LINE::session_name = "";
3287 if (get_session_parameters (true, false)) {
3290 if (splash && splash->is_visible()) {
3291 // in 1 second, hide the splash screen
3292 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
3296 /** @param snap_name Snapshot name (without .ardour suffix).
3297 * @return -2 if the load failed because we are not connected to the AudioEngine.
3300 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
3302 Session *new_session;
3307 unload_status = unload_session ();
3309 if (unload_status < 0) {
3311 } else if (unload_status > 0) {
3317 session_loaded = false;
3319 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
3322 new_session = new Session (*AudioEngine::instance(), path, snap_name, 0, mix_template);
3325 /* this one is special */
3327 catch (AudioEngine::PortRegistrationFailure& err) {
3329 MessageDialog msg (err.what(),
3332 Gtk::BUTTONS_CLOSE);
3334 msg.set_title (_("Port Registration Error"));
3335 msg.set_secondary_text (_("Click the Close button to try again."));
3336 msg.set_position (Gtk::WIN_POS_CENTER);
3337 pop_back_splash (msg);
3340 int response = msg.run ();
3345 case RESPONSE_CANCEL:
3352 catch (SessionException e) {
3353 MessageDialog msg (string_compose(
3354 _("Session \"%1 (snapshot %2)\" did not load successfully: %3"),
3355 path, snap_name, e.what()),
3360 msg.set_title (_("Loading Error"));
3361 msg.set_position (Gtk::WIN_POS_CENTER);
3362 pop_back_splash (msg);
3374 MessageDialog msg (string_compose(
3375 _("Session \"%1 (snapshot %2)\" did not load successfully"),
3381 msg.set_title (_("Loading Error"));
3382 msg.set_position (Gtk::WIN_POS_CENTER);
3383 pop_back_splash (msg);
3395 list<string> const u = new_session->unknown_processors ();
3397 MissingPluginDialog d (_session, u);
3402 if (!new_session->writable()) {
3403 MessageDialog msg (_("This session has been opened in read-only mode.\n\nYou will not be able to record or save."),
3408 msg.set_title (_("Read-only Session"));
3409 msg.set_position (Gtk::WIN_POS_CENTER);
3410 pop_back_splash (msg);
3417 /* Now the session been created, add the transport controls */
3418 new_session->add_controllable(roll_controllable);
3419 new_session->add_controllable(stop_controllable);
3420 new_session->add_controllable(goto_start_controllable);
3421 new_session->add_controllable(goto_end_controllable);
3422 new_session->add_controllable(auto_loop_controllable);
3423 new_session->add_controllable(play_selection_controllable);
3424 new_session->add_controllable(rec_controllable);
3426 set_session (new_session);
3428 session_loaded = true;
3431 _session->set_clean ();
3434 #ifdef WINDOWS_VST_SUPPORT
3435 fst_stop_threading();
3439 Timers::TimerSuspender t;
3443 #ifdef WINDOWS_VST_SUPPORT
3444 fst_start_threading();
3453 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
3455 Session *new_session;
3458 session_loaded = false;
3459 x = unload_session ();
3467 _session_is_new = true;
3470 new_session = new Session (*AudioEngine::instance(), path, snap_name, &bus_profile);
3473 catch (SessionException e) {
3475 MessageDialog msg (string_compose(_("Could not create session in \"%1\": %2"), path, e.what()));
3476 msg.set_title (_("Loading Error"));
3477 msg.set_position (Gtk::WIN_POS_CENTER);
3478 pop_back_splash (msg);
3484 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
3485 msg.set_title (_("Loading Error"));
3486 msg.set_position (Gtk::WIN_POS_CENTER);
3487 pop_back_splash (msg);
3492 /* Give the new session the default GUI state, if such things exist */
3495 n = Config->instant_xml (X_("Editor"));
3497 n->remove_nodes_and_delete ("Selection"); // no not apply selection to new sessions.
3498 new_session->add_instant_xml (*n, false);
3500 n = Config->instant_xml (X_("Mixer"));
3502 new_session->add_instant_xml (*n, false);
3505 /* Put the playhead at 0 and scroll fully left */
3506 n = new_session->instant_xml (X_("Editor"));
3508 n->add_property (X_("playhead"), X_("0"));
3509 n->add_property (X_("left-frame"), X_("0"));
3512 set_session (new_session);
3514 session_loaded = true;
3516 new_session->save_state(new_session->name());
3522 ARDOUR_UI::launch_chat ()
3524 MessageDialog dialog(_("<b>Just ask and wait for an answer.\nIt may take from minutes to hours.</b>"), true);
3526 dialog.set_title (_("About the Chat"));
3527 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."));
3529 switch (dialog.run()) {
3532 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
3533 #elif defined PLATFORM_WINDOWS
3534 open_uri("http://webchat.freenode.net/?channels=ardour-windows");
3536 open_uri("http://webchat.freenode.net/?channels=ardour");
3545 ARDOUR_UI::launch_manual ()
3547 PBD::open_uri (Config->get_tutorial_manual_url());
3551 ARDOUR_UI::launch_reference ()
3553 PBD::open_uri (Config->get_reference_manual_url());
3557 ARDOUR_UI::launch_tracker ()
3559 PBD::open_uri ("http://tracker.ardour.org");
3563 ARDOUR_UI::launch_subscribe ()
3565 PBD::open_uri ("https://community.ardour.org/s/subscribe");
3569 ARDOUR_UI::launch_cheat_sheet ()
3572 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheat_sheet_osx.pdf");
3574 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheatsheet.pdf");
3579 ARDOUR_UI::launch_website ()
3581 PBD::open_uri ("http://ardour.org");
3585 ARDOUR_UI::launch_website_dev ()
3587 PBD::open_uri ("http://ardour.org/development.html");
3591 ARDOUR_UI::launch_forums ()
3593 PBD::open_uri ("https://community.ardour.org/forums");
3597 ARDOUR_UI::launch_howto_report ()
3599 PBD::open_uri ("http://ardour.org/reporting_bugs");
3603 ARDOUR_UI::loading_message (const std::string& msg)
3605 if (ARDOUR_COMMAND_LINE::no_splash) {
3613 splash->message (msg);
3617 ARDOUR_UI::show_splash ()
3621 splash = new Splash;
3631 ARDOUR_UI::hide_splash ()
3638 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title, const bool msg_delete)
3642 removed = rep.paths.size();
3645 MessageDialog msgd (_main_window,
3646 _("No files were ready for clean-up"),
3650 msgd.set_title (_("Clean-up"));
3651 msgd.set_secondary_text (_("If this seems suprising, \n\
3652 check for any existing snapshots.\n\
3653 These may still include regions that\n\
3654 require some unused files to continue to exist."));
3660 ArdourDialog results (_("Clean-up"), true, false);
3662 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
3663 CleanupResultsModelColumns() {
3667 Gtk::TreeModelColumn<std::string> visible_name;
3668 Gtk::TreeModelColumn<std::string> fullpath;
3672 CleanupResultsModelColumns results_columns;
3673 Glib::RefPtr<Gtk::ListStore> results_model;
3674 Gtk::TreeView results_display;
3676 results_model = ListStore::create (results_columns);
3677 results_display.set_model (results_model);
3678 results_display.append_column (list_title, results_columns.visible_name);
3680 results_display.set_name ("CleanupResultsList");
3681 results_display.set_headers_visible (true);
3682 results_display.set_headers_clickable (false);
3683 results_display.set_reorderable (false);
3685 Gtk::ScrolledWindow list_scroller;
3688 Gtk::HBox dhbox; // the hbox for the image and text
3689 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
3690 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
3692 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
3694 const string dead_directory = _session->session_directory().dead_path();
3697 %1 - number of files removed
3698 %2 - location of "dead"
3699 %3 - size of files affected
3700 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
3703 const char* bprefix;
3704 double space_adjusted = 0;
3706 if (rep.space < 1000) {
3708 space_adjusted = rep.space;
3709 } else if (rep.space < 1000000) {
3710 bprefix = _("kilo");
3711 space_adjusted = floorf((float)rep.space / 1000.0);
3712 } else if (rep.space < 1000000 * 1000) {
3713 bprefix = _("mega");
3714 space_adjusted = floorf((float)rep.space / (1000.0 * 1000.0));
3716 bprefix = _("giga");
3717 space_adjusted = floorf((float)rep.space / (1000.0 * 1000 * 1000.0));
3721 txt.set_markup (string_compose (P_("\
3722 The following file was deleted from %2,\n\
3723 releasing %3 %4bytes of disk space", "\
3724 The following %1 files were deleted from %2,\n\
3725 releasing %3 %4bytes of disk space", removed),
3726 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3728 txt.set_markup (string_compose (P_("\
3729 The following file was not in use and \n\
3730 has been moved to: %2\n\n\
3731 After a restart of %5\n\n\
3732 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3733 will release an additional %3 %4bytes of disk space.\n", "\
3734 The following %1 files were not in use and \n\
3735 have been moved to: %2\n\n\
3736 After a restart of %5\n\n\
3737 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3738 will release an additional %3 %4bytes of disk space.\n", removed),
3739 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3742 dhbox.pack_start (*dimage, true, false, 5);
3743 dhbox.pack_start (txt, true, false, 5);
3745 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
3746 TreeModel::Row row = *(results_model->append());
3747 row[results_columns.visible_name] = *i;
3748 row[results_columns.fullpath] = *i;
3751 list_scroller.add (results_display);
3752 list_scroller.set_size_request (-1, 150);
3753 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
3755 dvbox.pack_start (dhbox, true, false, 5);
3756 dvbox.pack_start (list_scroller, true, false, 5);
3757 ddhbox.pack_start (dvbox, true, false, 5);
3759 results.get_vbox()->pack_start (ddhbox, true, false, 5);
3760 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
3761 results.set_default_response (RESPONSE_CLOSE);
3762 results.set_position (Gtk::WIN_POS_MOUSE);
3764 results_display.show();
3765 list_scroller.show();
3772 //results.get_vbox()->show();
3773 results.set_resizable (false);
3780 ARDOUR_UI::cleanup ()
3782 if (_session == 0) {
3783 /* shouldn't happen: menu item is insensitive */
3788 MessageDialog checker (_("Are you sure you want to clean-up?"),
3790 Gtk::MESSAGE_QUESTION,
3793 checker.set_title (_("Clean-up"));
3795 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
3796 ALL undo/redo information will be lost if you clean-up.\n\
3797 Clean-up will move all unused files to a \"dead\" location."));
3799 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3800 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
3801 checker.set_default_response (RESPONSE_CANCEL);
3803 checker.set_name (_("CleanupDialog"));
3804 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3805 checker.set_position (Gtk::WIN_POS_MOUSE);
3807 switch (checker.run()) {
3808 case RESPONSE_ACCEPT:
3814 ARDOUR::CleanupReport rep;
3816 editor->prepare_for_cleanup ();
3818 /* do not allow flush until a session is reloaded */
3820 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3822 act->set_sensitive (false);
3825 if (_session->cleanup_sources (rep)) {
3826 editor->finish_cleanup ();
3830 editor->finish_cleanup ();
3833 display_cleanup_results (rep, _("Cleaned Files"), false);
3837 ARDOUR_UI::flush_trash ()
3839 if (_session == 0) {
3840 /* shouldn't happen: menu item is insensitive */
3844 ARDOUR::CleanupReport rep;
3846 if (_session->cleanup_trash_sources (rep)) {
3850 display_cleanup_results (rep, _("deleted file"), true);
3854 ARDOUR_UI::cleanup_peakfiles ()
3856 if (_session == 0) {
3857 /* shouldn't happen: menu item is insensitive */
3861 if (! _session->can_cleanup_peakfiles ()) {
3865 // get all region-views in this session
3867 TrackViewList empty;
3869 editor->get_regions_after(rs, (framepos_t) 0, empty);
3870 std::list<RegionView*> views = rs.by_layer();
3872 // remove displayed audio-region-views waveforms
3873 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
3874 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
3875 if (!arv) { continue ; }
3876 arv->delete_waves();
3879 // cleanup peak files:
3880 // - stop pending peakfile threads
3881 // - close peakfiles if any
3882 // - remove peak dir in session
3883 // - setup peakfiles (background thread)
3884 _session->cleanup_peakfiles ();
3886 // re-add waves to ARV
3887 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
3888 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
3889 if (!arv) { continue ; }
3890 arv->create_waves();
3895 ARDOUR_UI::setup_order_hint (AddRouteDialog::InsertAt place)
3897 uint32_t order_hint = UINT32_MAX;
3899 if (editor->get_selection().tracks.empty()) {
3904 we want the new routes to have their order keys set starting from
3905 the highest order key in the selection + 1 (if available).
3908 if (place == AddRouteDialog::AfterSelection) {
3909 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.back());
3911 order_hint = rtav->route()->order_key();
3914 } else if (place == AddRouteDialog::BeforeSelection) {
3915 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.front());
3917 order_hint = rtav->route()->order_key();
3919 } else if (place == AddRouteDialog::First) {
3922 /* leave order_hint at UINT32_MAX */
3925 if (order_hint == UINT32_MAX) {
3926 /** AddRouteDialog::Last or selection with first/last not a RouteTimeAxisView
3927 * not setting an order hint will place new routes last.
3932 _session->set_order_hint (order_hint);
3934 /* create a gap in the existing route order keys to accomodate new routes.*/
3935 boost::shared_ptr <RouteList> rd = _session->get_routes();
3936 for (RouteList::iterator ri = rd->begin(); ri != rd->end(); ++ri) {
3937 boost::shared_ptr<Route> rt (*ri);
3939 if (rt->is_monitor()) {
3943 if (rt->order_key () >= order_hint) {
3944 rt->set_order_key (rt->order_key () + add_route_dialog->count());
3950 ARDOUR_UI::start_duplicate_routes ()
3952 if (!duplicate_routes_dialog) {
3953 duplicate_routes_dialog = new DuplicateRouteDialog;
3956 if (duplicate_routes_dialog->restart (_session)) {
3960 duplicate_routes_dialog->present ();
3964 ARDOUR_UI::add_route ()
3972 if (add_route_dialog->is_visible()) {
3973 /* we're already doing this */
3977 ResponseType r = (ResponseType) add_route_dialog->run ();
3979 add_route_dialog->hide();
3982 case RESPONSE_ACCEPT:
3989 if ((count = add_route_dialog->count()) <= 0) {
3993 setup_order_hint(add_route_dialog->insert_at());
3994 string template_path = add_route_dialog->track_template();
3995 DisplaySuspender ds;
3997 if (!template_path.empty()) {
3998 if (add_route_dialog->name_template_is_default()) {
3999 _session->new_route_from_template (count, template_path, string());
4001 _session->new_route_from_template (count, template_path, add_route_dialog->name_template());
4006 ChanCount input_chan= add_route_dialog->channels ();
4007 ChanCount output_chan;
4008 string name_template = add_route_dialog->name_template ();
4009 PluginInfoPtr instrument = add_route_dialog->requested_instrument ();
4010 RouteGroup* route_group = add_route_dialog->route_group ();
4011 AutoConnectOption oac = Config->get_output_auto_connect();
4012 bool strict_io = add_route_dialog->use_strict_io ();
4014 if (oac & AutoConnectMaster) {
4015 output_chan.set (DataType::AUDIO, (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan.n_audio()));
4016 output_chan.set (DataType::MIDI, 0);
4018 output_chan = input_chan;
4021 /* XXX do something with name template */
4023 switch (add_route_dialog->type_wanted()) {
4024 case AddRouteDialog::AudioTrack:
4025 session_add_audio_track (input_chan.n_audio(), output_chan.n_audio(), add_route_dialog->mode(), route_group, count, name_template, strict_io);
4027 case AddRouteDialog::MidiTrack:
4028 session_add_midi_track (route_group, count, name_template, strict_io, instrument);
4030 case AddRouteDialog::MixedTrack:
4031 session_add_mixed_track (input_chan, output_chan, route_group, count, name_template, strict_io, instrument, 0);
4033 case AddRouteDialog::AudioBus:
4034 session_add_audio_bus (input_chan.n_audio(), output_chan.n_audio(), route_group, count, name_template, strict_io);
4036 case AddRouteDialog::MidiBus:
4037 session_add_midi_bus (route_group, count, name_template, strict_io, instrument, 0);
4043 ARDOUR_UI::add_lua_script ()
4049 LuaScriptInfoPtr spi;
4050 ScriptSelector ss ("Add Lua Session Script", LuaScriptInfo::Session);
4051 switch (ss.run ()) {
4052 case Gtk::RESPONSE_ACCEPT:
4060 std::string script = "";
4063 script = Glib::file_get_contents (spi->path);
4064 } catch (Glib::FileError e) {
4065 string msg = string_compose (_("Cannot read session script '%1': %2"), spi->path, e.what());
4066 MessageDialog am (msg);
4071 LuaScriptParamList lsp = LuaScriptParams::script_params (spi, "sess_params");
4072 std::vector<std::string> reg = _session->registered_lua_functions ();
4074 ScriptParameterDialog spd (_("Set Script Parameters"), spi, reg, lsp);
4075 switch (spd.run ()) {
4076 case Gtk::RESPONSE_ACCEPT:
4083 _session->register_lua_function (spd.name(), script, lsp);
4084 } catch (luabridge::LuaException const& e) {
4085 string msg = string_compose (_("Session script '%1' instantiation failed: %2"), spd.name(), e.what ());
4086 MessageDialog am (msg);
4088 } catch (SessionException e) {
4089 string msg = string_compose (_("Loading Session script '%1' failed: %2"), spd.name(), e.what ());
4090 MessageDialog am (msg);
4096 ARDOUR_UI::remove_lua_script ()
4101 if (_session->registered_lua_function_count () == 0) {
4102 string msg = _("There are no active Lua session scripts present in this session.");
4103 MessageDialog am (msg);
4108 std::vector<std::string> reg = _session->registered_lua_functions ();
4109 SessionScriptManager sm ("Remove Lua Session Script", reg);
4110 switch (sm.run ()) {
4111 case Gtk::RESPONSE_ACCEPT:
4117 _session->unregister_lua_function (sm.name());
4118 } catch (luabridge::LuaException const& e) {
4119 string msg = string_compose (_("Session script '%1' removal failed: %2"), sm.name(), e.what ());
4120 MessageDialog am (msg);
4126 ARDOUR_UI::stop_video_server (bool ask_confirm)
4128 if (!video_server_process && ask_confirm) {
4129 warning << string_compose (_("Video-Server was not launched by %1. The request to stop it is ignored."), PROGRAM_NAME) << endmsg;
4131 if (video_server_process) {
4133 ArdourDialog confirm (_("Stop Video-Server"), true);
4134 Label m (_("Do you really want to stop the Video Server?"));
4135 confirm.get_vbox()->pack_start (m, true, true);
4136 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
4137 confirm.add_button (_("Yes, Stop It"), Gtk::RESPONSE_ACCEPT);
4138 confirm.show_all ();
4139 if (confirm.run() == RESPONSE_CANCEL) {
4143 delete video_server_process;
4144 video_server_process =0;
4149 ARDOUR_UI::start_video_server_menu (Gtk::Window* float_window)
4151 ARDOUR_UI::start_video_server( float_window, true);
4155 ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg)
4161 if (ARDOUR_UI::instance()->video_timeline->check_server()) {
4162 if (video_server_process) {
4163 popup_error(_("The Video Server is already started."));
4165 popup_error(_("An external Video Server is configured and can be reached. Not starting a new instance."));
4171 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4173 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4175 VideoServerDialog *video_server_dialog = new VideoServerDialog (_session);
4177 video_server_dialog->set_transient_for (*float_window);
4180 if (!Config->get_show_video_server_dialog() && firsttime < 2) {
4181 video_server_dialog->hide();
4183 ResponseType r = (ResponseType) video_server_dialog->run ();
4184 video_server_dialog->hide();
4185 if (r != RESPONSE_ACCEPT) { return false; }
4186 if (video_server_dialog->show_again()) {
4187 Config->set_show_video_server_dialog(false);
4191 std::string icsd_exec = video_server_dialog->get_exec_path();
4192 std::string icsd_docroot = video_server_dialog->get_docroot();
4193 if (icsd_docroot.empty()) {
4194 #ifndef PLATFORM_WINDOWS
4195 icsd_docroot = X_("/");
4197 icsd_docroot = X_("C:\\");
4202 if (g_lstat (icsd_docroot.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode)) {
4203 warning << _("Specified docroot is not an existing directory.") << endmsg;
4206 #ifndef PLATFORM_WINDOWS
4207 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4208 || (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0 ) {
4209 warning << _("Given Video Server is not an executable file.") << endmsg;
4213 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4214 || (sb.st_mode & (S_IXUSR)) == 0 ) {
4215 warning << _("Given Video Server is not an executable file.") << endmsg;
4221 argp=(char**) calloc(9,sizeof(char*));
4222 argp[0] = strdup(icsd_exec.c_str());
4223 argp[1] = strdup("-P");
4224 argp[2] = (char*) calloc(16,sizeof(char)); snprintf(argp[2], 16, "%s", video_server_dialog->get_listenaddr().c_str());
4225 argp[3] = strdup("-p");
4226 argp[4] = (char*) calloc(6,sizeof(char)); snprintf(argp[4], 6, "%i", video_server_dialog->get_listenport());
4227 argp[5] = strdup("-C");
4228 argp[6] = (char*) calloc(6,sizeof(char)); snprintf(argp[6], 6, "%i", video_server_dialog->get_cachesize());
4229 argp[7] = strdup(icsd_docroot.c_str());
4231 stop_video_server();
4233 if (icsd_docroot == X_("/") || icsd_docroot == X_("C:\\")) {
4234 Config->set_video_advanced_setup(false);
4236 std::ostringstream osstream;
4237 osstream << "http://127.0.0.1:" << video_server_dialog->get_listenport() << "/";
4238 Config->set_video_server_url(osstream.str());
4239 Config->set_video_server_docroot(icsd_docroot);
4240 Config->set_video_advanced_setup(true);
4243 if (video_server_process) {
4244 delete video_server_process;
4247 video_server_process = new ARDOUR::SystemExec(icsd_exec, argp);
4248 if (video_server_process->start()) {
4249 warning << _("Cannot launch the video-server") << endmsg;
4252 int timeout = 120; // 6 sec
4253 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4254 Glib::usleep (50000);
4256 if (--timeout <= 0 || !video_server_process->is_running()) break;
4259 warning << _("Video-server was started but does not respond to requests...") << endmsg;
4261 if (!ARDOUR_UI::instance()->video_timeline->check_server_docroot()) {
4262 delete video_server_process;
4263 video_server_process = 0;
4271 ARDOUR_UI::add_video (Gtk::Window* float_window)
4277 if (!start_video_server(float_window, false)) {
4278 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4283 add_video_dialog->set_transient_for (*float_window);
4286 if (add_video_dialog->is_visible()) {
4287 /* we're already doing this */
4291 ResponseType r = (ResponseType) add_video_dialog->run ();
4292 add_video_dialog->hide();
4293 if (r != RESPONSE_ACCEPT) { return; }
4295 bool local_file, orig_local_file;
4296 std::string path = add_video_dialog->file_name(local_file);
4298 std::string orig_path = path;
4299 orig_local_file = local_file;
4301 bool auto_set_session_fps = add_video_dialog->auto_set_session_fps();
4303 if (local_file && !Glib::file_test(path, Glib::FILE_TEST_EXISTS)) {
4304 warning << string_compose(_("could not open %1"), path) << endmsg;
4307 if (!local_file && path.length() == 0) {
4308 warning << _("no video-file selected") << endmsg;
4312 std::string audio_from_video;
4313 bool detect_ltc = false;
4315 switch (add_video_dialog->import_option()) {
4316 case VTL_IMPORT_TRANSCODE:
4318 TranscodeVideoDialog *transcode_video_dialog;
4319 transcode_video_dialog = new TranscodeVideoDialog (_session, path);
4320 ResponseType r = (ResponseType) transcode_video_dialog->run ();
4321 transcode_video_dialog->hide();
4322 if (r != RESPONSE_ACCEPT) {
4323 delete transcode_video_dialog;
4327 audio_from_video = transcode_video_dialog->get_audiofile();
4329 if (!audio_from_video.empty() && transcode_video_dialog->detect_ltc()) {
4332 else if (!audio_from_video.empty()) {
4333 editor->embed_audio_from_video(
4335 video_timeline->get_offset(),
4336 (transcode_video_dialog->import_option() != VTL_IMPORT_NO_VIDEO)
4339 switch (transcode_video_dialog->import_option()) {
4340 case VTL_IMPORT_TRANSCODED:
4341 path = transcode_video_dialog->get_filename();
4344 case VTL_IMPORT_REFERENCE:
4347 delete transcode_video_dialog;
4350 delete transcode_video_dialog;
4354 case VTL_IMPORT_NONE:
4358 /* strip _session->session_directory().video_path() from video file if possible */
4359 if (local_file && !path.compare(0, _session->session_directory().video_path().size(), _session->session_directory().video_path())) {
4360 path=path.substr(_session->session_directory().video_path().size());
4361 if (path.at(0) == G_DIR_SEPARATOR) {
4362 path=path.substr(1);
4366 video_timeline->set_update_session_fps(auto_set_session_fps);
4368 if (video_timeline->video_file_info(path, local_file)) {
4369 XMLNode* node = new XMLNode(X_("Videotimeline"));
4370 node->add_property (X_("Filename"), path);
4371 node->add_property (X_("AutoFPS"), auto_set_session_fps?X_("1"):X_("0"));
4372 node->add_property (X_("LocalFile"), local_file?X_("1"):X_("0"));
4373 if (orig_local_file) {
4374 node->add_property (X_("OriginalVideoFile"), orig_path);
4376 node->remove_property (X_("OriginalVideoFile"));
4378 _session->add_extra_xml (*node);
4379 _session->set_dirty ();
4381 if (!audio_from_video.empty() && detect_ltc) {
4382 std::vector<LTCFileReader::LTCMap> ltc_seq;
4385 /* TODO ask user about TV standard (LTC alignment if any) */
4386 LTCFileReader ltcr (audio_from_video, video_timeline->get_video_file_fps());
4387 /* TODO ASK user which channel: 0 .. ltcr->channels() - 1 */
4389 ltc_seq = ltcr.read_ltc (/*channel*/ 0, /*max LTC frames to decode*/ 15);
4391 /* TODO seek near end of file, and read LTC until end.
4392 * if it fails to find any LTC frames, scan complete file
4394 * calculate drift of LTC compared to video-duration,
4395 * ask user for reference (timecode from start/mid/end)
4398 // LTCFileReader will have written error messages
4401 ::g_unlink(audio_from_video.c_str());
4403 if (ltc_seq.size() == 0) {
4404 PBD::error << _("No LTC detected, video will not be aligned.") << endmsg;
4406 /* the very first TC in the file is somteimes not aligned properly */
4407 int i = ltc_seq.size() -1;
4408 ARDOUR::frameoffset_t video_start_offset =
4409 _session->nominal_frame_rate() * (ltc_seq[i].timecode_sec - ltc_seq[i].framepos_sec);
4410 PBD::info << string_compose (_("Align video-start to %1 [samples]"), video_start_offset) << endmsg;
4411 video_timeline->set_offset(video_start_offset);
4415 _session->maybe_update_session_range(
4416 std::max(video_timeline->get_offset(), (ARDOUR::frameoffset_t) 0),
4417 std::max(video_timeline->get_offset() + video_timeline->get_duration(), (ARDOUR::frameoffset_t) 0));
4420 if (add_video_dialog->launch_xjadeo() && local_file) {
4421 editor->set_xjadeo_sensitive(true);
4422 editor->toggle_xjadeo_proc(1);
4424 editor->toggle_xjadeo_proc(0);
4426 editor->toggle_ruler_video(true);
4431 ARDOUR_UI::remove_video ()
4433 video_timeline->close_session();
4434 editor->toggle_ruler_video(false);
4437 video_timeline->set_offset_locked(false);
4438 video_timeline->set_offset(0);
4440 /* delete session state */
4441 XMLNode* node = new XMLNode(X_("Videotimeline"));
4442 _session->add_extra_xml(*node);
4443 node = new XMLNode(X_("Videomonitor"));
4444 _session->add_extra_xml(*node);
4445 node = new XMLNode(X_("Videoexport"));
4446 _session->add_extra_xml(*node);
4447 stop_video_server();
4451 ARDOUR_UI::flush_videotimeline_cache (bool localcacheonly)
4453 if (localcacheonly) {
4454 video_timeline->vmon_update();
4456 video_timeline->flush_cache();
4458 editor->queue_visual_videotimeline_update();
4462 ARDOUR_UI::export_video (bool range)
4464 if (ARDOUR::Config->get_show_video_export_info()) {
4465 ExportVideoInfobox infobox (_session);
4466 Gtk::ResponseType rv = (Gtk::ResponseType) infobox.run();
4467 if (infobox.show_again()) {
4468 ARDOUR::Config->set_show_video_export_info(false);
4471 case GTK_RESPONSE_YES:
4472 PBD::open_uri (ARDOUR::Config->get_reference_manual_url() + "/video-timeline/operations/#export");
4478 export_video_dialog->set_session (_session);
4479 export_video_dialog->apply_state(editor->get_selection().time, range);
4480 export_video_dialog->run ();
4481 export_video_dialog->hide ();
4485 ARDOUR_UI::mixer_settings () const
4490 node = _session->instant_xml(X_("Mixer"));
4492 node = Config->instant_xml(X_("Mixer"));
4496 node = new XMLNode (X_("Mixer"));
4503 ARDOUR_UI::main_window_settings () const
4508 node = _session->instant_xml(X_("Main"));
4510 node = Config->instant_xml(X_("Main"));
4514 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4515 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4520 node = new XMLNode (X_("Main"));
4527 ARDOUR_UI::editor_settings () const
4532 node = _session->instant_xml(X_("Editor"));
4534 node = Config->instant_xml(X_("Editor"));
4538 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4539 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4544 node = new XMLNode (X_("Editor"));
4551 ARDOUR_UI::keyboard_settings () const
4555 node = Config->extra_xml(X_("Keyboard"));
4558 node = new XMLNode (X_("Keyboard"));
4565 ARDOUR_UI::create_xrun_marker (framepos_t where)
4568 Location *location = new Location (*_session, where, where, _("xrun"), Location::IsMark);
4569 _session->locations()->add (location);
4574 ARDOUR_UI::halt_on_xrun_message ()
4576 cerr << "HALT on xrun\n";
4577 MessageDialog msg (_main_window, _("Recording was stopped because your system could not keep up."));
4582 ARDOUR_UI::xrun_handler (framepos_t where)
4588 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
4590 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
4591 create_xrun_marker(where);
4594 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
4595 halt_on_xrun_message ();
4600 ARDOUR_UI::disk_overrun_handler ()
4602 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
4604 if (!have_disk_speed_dialog_displayed) {
4605 have_disk_speed_dialog_displayed = true;
4606 MessageDialog* msg = new MessageDialog (_main_window, string_compose (_("\
4607 The disk system on your computer\n\
4608 was not able to keep up with %1.\n\
4610 Specifically, it failed to write data to disk\n\
4611 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
4612 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4618 /* TODO: this is getting elaborate enough to warrant being split into a dedicated class */
4619 static MessageDialog *scan_dlg = NULL;
4620 static ProgressBar *scan_pbar = NULL;
4621 static HBox *scan_tbox = NULL;
4622 static Gtk::Button *scan_timeout_button;
4625 ARDOUR_UI::cancel_plugin_scan ()
4627 PluginManager::instance().cancel_plugin_scan();
4631 ARDOUR_UI::cancel_plugin_timeout ()
4633 PluginManager::instance().cancel_plugin_timeout();
4634 scan_timeout_button->set_sensitive (false);
4638 ARDOUR_UI::plugin_scan_timeout (int timeout)
4640 if (!scan_dlg || !scan_dlg->is_mapped() || !scan_pbar) {
4644 scan_pbar->set_sensitive (false);
4645 scan_timeout_button->set_sensitive (true);
4646 scan_pbar->set_fraction ((float) timeout / (float) Config->get_vst_scan_timeout());
4649 scan_pbar->set_sensitive (false);
4650 scan_timeout_button->set_sensitive (false);
4656 ARDOUR_UI::plugin_scan_dialog (std::string type, std::string plugin, bool can_cancel)
4658 if (type == X_("closeme") && !(scan_dlg && scan_dlg->is_mapped())) {
4662 const bool cancelled = PluginManager::instance().cancelled();
4663 if (type != X_("closeme") && (!UIConfiguration::instance().get_show_plugin_scan_window()) && !_initial_verbose_plugin_scan) {
4664 if (cancelled && scan_dlg->is_mapped()) {
4669 if (cancelled || !can_cancel) {
4674 static Gtk::Button *cancel_button;
4676 scan_dlg = new MessageDialog("", false, MESSAGE_INFO, BUTTONS_NONE); // TODO manage
4677 VBox* vbox = scan_dlg->get_vbox();
4678 vbox->set_size_request(400,-1);
4679 scan_dlg->set_title (_("Scanning for plugins"));
4681 cancel_button = manage(new Gtk::Button(_("Cancel plugin scan")));
4682 cancel_button->set_name ("EditorGTKButton");
4683 cancel_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_scan) );
4684 cancel_button->show();
4686 scan_dlg->get_vbox()->pack_start ( *cancel_button, PACK_SHRINK);
4688 scan_tbox = manage( new HBox() );
4690 scan_timeout_button = manage(new Gtk::Button(_("Stop Timeout")));
4691 scan_timeout_button->set_name ("EditorGTKButton");
4692 scan_timeout_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_timeout) );
4693 scan_timeout_button->show();
4695 scan_pbar = manage(new ProgressBar());
4696 scan_pbar->set_orientation(Gtk::PROGRESS_RIGHT_TO_LEFT);
4697 scan_pbar->set_text(_("Scan Timeout"));
4700 scan_tbox->pack_start (*scan_pbar, PACK_EXPAND_WIDGET, 4);
4701 scan_tbox->pack_start (*scan_timeout_button, PACK_SHRINK, 4);
4703 scan_dlg->get_vbox()->pack_start (*scan_tbox, PACK_SHRINK, 4);
4706 assert(scan_dlg && scan_tbox && cancel_button);
4708 if (type == X_("closeme")) {
4712 scan_dlg->set_message(type + ": " + Glib::path_get_basename(plugin));
4715 if (!can_cancel || !cancelled) {
4716 scan_timeout_button->set_sensitive(false);
4718 cancel_button->set_sensitive(can_cancel && !cancelled);
4724 ARDOUR_UI::gui_idle_handler ()
4727 /* due to idle calls, gtk_events_pending() may always return true */
4728 while (gtk_events_pending() && --timeout) {
4729 gtk_main_iteration ();
4734 ARDOUR_UI::disk_underrun_handler ()
4736 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
4738 if (!have_disk_speed_dialog_displayed) {
4739 have_disk_speed_dialog_displayed = true;
4740 MessageDialog* msg = new MessageDialog (
4741 _main_window, string_compose (_("The disk system on your computer\n\
4742 was not able to keep up with %1.\n\
4744 Specifically, it failed to read data from disk\n\
4745 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
4746 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4752 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
4754 have_disk_speed_dialog_displayed = false;
4759 ARDOUR_UI::session_dialog (std::string msg)
4761 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
4765 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
4772 ARDOUR_UI::pending_state_dialog ()
4774 HBox* hbox = manage (new HBox());
4775 Image* image = manage (new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG));
4776 ArdourDialog dialog (_("Crash Recovery"), true);
4777 Label message (string_compose (_("\
4778 This session appears to have been in the\n\
4779 middle of recording when %1 or\n\
4780 the computer was shutdown.\n\
4782 %1 can recover any captured audio for\n\
4783 you, or it can ignore it. Please decide\n\
4784 what you would like to do.\n"), PROGRAM_NAME));
4785 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4786 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4787 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4788 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4789 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
4790 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
4791 dialog.set_default_response (RESPONSE_ACCEPT);
4792 dialog.set_position (WIN_POS_CENTER);
4797 switch (dialog.run ()) {
4798 case RESPONSE_ACCEPT:
4806 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
4808 HBox* hbox = new HBox();
4809 Image* image = new Image (Stock::DIALOG_WARNING, ICON_SIZE_DIALOG);
4810 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
4811 Label message (string_compose (_("\
4812 This session was created with a sample rate of %1 Hz, but\n\
4813 %2 is currently running at %3 Hz. If you load this session,\n\
4814 audio may be played at the wrong sample rate.\n"), desired, PROGRAM_NAME, actual));
4816 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4817 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4818 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4819 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4820 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
4821 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
4822 dialog.set_default_response (RESPONSE_ACCEPT);
4823 dialog.set_position (WIN_POS_CENTER);
4828 switch (dialog.run()) {
4829 case RESPONSE_ACCEPT:
4839 ARDOUR_UI::sr_mismatch_message (framecnt_t desired, framecnt_t actual)
4841 MessageDialog msg (string_compose (_("\
4842 This session was created with a sample rate of %1 Hz, but\n\
4843 %2 is currently running at %3 Hz.\n\
4844 Audio will be recorded and played at the wrong sample rate.\n\
4845 Re-Configure the Audio Engine in\n\
4846 Menu > Window > Audio/Midi Setup"),
4847 desired, PROGRAM_NAME, actual),
4849 Gtk::MESSAGE_WARNING);
4854 ARDOUR_UI::use_config ()
4856 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
4858 set_transport_controllable_state (*node);
4863 ARDOUR_UI::update_transport_clocks (framepos_t pos)
4865 if (UIConfiguration::instance().get_primary_clock_delta_edit_cursor()) {
4866 primary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
4868 primary_clock->set (pos);
4871 if (UIConfiguration::instance().get_secondary_clock_delta_edit_cursor()) {
4872 secondary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
4874 secondary_clock->set (pos);
4877 if (big_clock_window) {
4878 big_clock->set (pos);
4880 ARDOUR_UI::instance()->video_timeline->manual_seek_video_monitor(pos);
4884 ARDOUR_UI::step_edit_status_change (bool yn)
4886 // XXX should really store pre-step edit status of things
4887 // we make insensitive
4890 rec_button.set_active_state (Gtkmm2ext::ImplicitActive);
4891 rec_button.set_sensitive (false);
4893 rec_button.unset_active_state ();;
4894 rec_button.set_sensitive (true);
4899 ARDOUR_UI::record_state_changed ()
4901 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
4903 if (!_session || !big_clock_window) {
4904 /* why bother - the clock isn't visible */
4908 if (_session->record_status () == Session::Recording && _session->have_rec_enabled_track ()) {
4909 big_clock->set_active (true);
4911 big_clock->set_active (false);
4916 ARDOUR_UI::first_idle ()
4919 _session->allow_auto_play (true);
4923 editor->first_idle();
4926 Keyboard::set_can_save_keybindings (true);
4931 ARDOUR_UI::store_clock_modes ()
4933 XMLNode* node = new XMLNode(X_("ClockModes"));
4935 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
4936 XMLNode* child = new XMLNode (X_("Clock"));
4938 child->add_property (X_("name"), (*x)->name());
4939 child->add_property (X_("mode"), enum_2_string ((*x)->mode()));
4940 child->add_property (X_("on"), ((*x)->off() ? X_("no") : X_("yes")));
4942 node->add_child_nocopy (*child);
4945 _session->add_extra_xml (*node);
4946 _session->set_dirty ();
4949 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
4950 : Controllable (name), ui (u), type(tp)
4956 ARDOUR_UI::TransportControllable::set_value (double val, PBD::Controllable::GroupControlDisposition /*group_override*/)
4959 /* do nothing: these are radio-style actions */
4963 const char *action = 0;
4967 action = X_("Roll");
4970 action = X_("Stop");
4973 action = X_("GotoStart");
4976 action = X_("GotoEnd");
4979 action = X_("Loop");
4982 action = X_("PlaySelection");
4985 action = X_("Record");
4995 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
5003 ARDOUR_UI::TransportControllable::get_value (void) const
5030 ARDOUR_UI::setup_profile ()
5032 if (gdk_screen_width() < 1200 || getenv ("ARDOUR_NARROW_SCREEN")) {
5033 Profile->set_small_screen ();
5036 if (g_getenv ("TRX")) {
5037 Profile->set_trx ();
5040 if (g_getenv ("MIXBUS")) {
5041 Profile->set_mixbus ();
5046 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
5048 MissingFileDialog dialog (s, str, type);
5053 int result = dialog.run ();
5060 return 1; // quit entire session load
5063 result = dialog.get_action ();
5069 ARDOUR_UI::ambiguous_file (std::string file, std::vector<std::string> hits)
5071 AmbiguousFileDialog dialog (file, hits);
5078 return dialog.get_which ();
5081 /** Allocate our thread-local buffers */
5083 ARDOUR_UI::get_process_buffers ()
5085 _process_thread->get_buffers ();
5088 /** Drop our thread-local buffers */
5090 ARDOUR_UI::drop_process_buffers ()
5092 _process_thread->drop_buffers ();
5096 ARDOUR_UI::feedback_detected ()
5098 _feedback_exists = true;
5102 ARDOUR_UI::successful_graph_sort ()
5104 _feedback_exists = false;
5108 ARDOUR_UI::midi_panic ()
5111 _session->midi_panic();
5116 ARDOUR_UI::session_format_mismatch (std::string xml_path, std::string backup_path)
5118 const char* start_big = "<span size=\"x-large\" weight=\"bold\">";
5119 const char* end_big = "</span>";
5120 const char* start_mono = "<tt>";
5121 const char* end_mono = "</tt>";
5123 MessageDialog msg (string_compose (_("%4This is a session from an older version of %3%5\n\n"
5124 "%3 has copied the old session file\n\n%6%1%7\n\nto\n\n%6%2%7\n\n"
5125 "From now on, use the -2000 version with older versions of %3"),
5126 xml_path, backup_path, PROGRAM_NAME,
5128 start_mono, end_mono), true);
5135 ARDOUR_UI::reset_peak_display ()
5137 if (!_session || !_session->master_out() || !editor_meter) return;
5138 editor_meter->clear_meters();
5139 editor_meter_max_peak = -INFINITY;
5140 editor_meter_peak_display.set_active_state ( Gtkmm2ext::Off );
5144 ARDOUR_UI::reset_group_peak_display (RouteGroup* group)
5146 if (!_session || !_session->master_out()) return;
5147 if (group == _session->master_out()->route_group()) {
5148 reset_peak_display ();
5153 ARDOUR_UI::reset_route_peak_display (Route* route)
5155 if (!_session || !_session->master_out()) return;
5156 if (_session->master_out().get() == route) {
5157 reset_peak_display ();
5162 ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate)
5164 audio_midi_setup->set_desired_sample_rate (desired_sample_rate);
5165 audio_midi_setup->set_position (WIN_POS_CENTER);
5167 if (Config->get_try_autostart_engine () || getenv ("TRY_AUTOSTART_ENGINE")) {
5168 audio_midi_setup->try_autostart ();
5169 if (ARDOUR::AudioEngine::instance()->running()) {
5175 int response = audio_midi_setup->run();
5177 case Gtk::RESPONSE_OK:
5178 if (!AudioEngine::instance()->running()) {
5192 ARDOUR_UI::transport_numpad_timeout ()
5194 _numpad_locate_happening = false;
5195 if (_numpad_timeout_connection.connected() )
5196 _numpad_timeout_connection.disconnect();
5201 ARDOUR_UI::transport_numpad_decimal ()
5203 _numpad_timeout_connection.disconnect();
5205 if (_numpad_locate_happening) {
5206 if (editor) editor->goto_nth_marker(_pending_locate_num - 1);
5207 _numpad_locate_happening = false;
5209 _pending_locate_num = 0;
5210 _numpad_locate_happening = true;
5211 _numpad_timeout_connection = Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::transport_numpad_timeout), 2*1000);
5216 ARDOUR_UI::transport_numpad_event (int num)
5218 if ( _numpad_locate_happening ) {
5219 _pending_locate_num = _pending_locate_num*10 + num;
5222 case 0: toggle_roll(false, false); break;
5223 case 1: transport_rewind(1); break;
5224 case 2: transport_forward(1); break;
5225 case 3: transport_record(true); break;
5226 case 4: toggle_session_auto_loop(); break;
5227 case 5: transport_record(false); toggle_session_auto_loop(); break;
5228 case 6: toggle_punch(); break;
5229 case 7: toggle_click(); break;
5230 case 8: toggle_auto_return(); break;
5231 case 9: toggle_follow_edits(); break;
5237 ARDOUR_UI::set_flat_buttons ()
5239 CairoWidget::set_flat_buttons( UIConfiguration::instance().get_flat_buttons() );
5243 ARDOUR_UI::audioengine_became_silent ()
5245 MessageDialog msg (string_compose (_("This is a free/demo copy of %1. It has just switched to silent mode."), PROGRAM_NAME),
5247 Gtk::MESSAGE_WARNING,
5251 msg.set_title (string_compose (_("%1 is now silent"), PROGRAM_NAME));
5253 Gtk::Label pay_label (string_compose (_("Please consider paying for a copy of %1 - you can pay whatever you want."), PROGRAM_NAME));
5254 Gtk::Label subscribe_label (_("Better yet become a subscriber - subscriptions start at US$1 per month."));
5255 Gtk::Button pay_button (_("Pay for a copy (via the web)"));
5256 Gtk::Button subscribe_button (_("Become a subscriber (via the web)"));
5257 Gtk::HBox pay_button_box;
5258 Gtk::HBox subscribe_button_box;
5260 pay_button_box.pack_start (pay_button, true, false);
5261 subscribe_button_box.pack_start (subscribe_button, true, false);
5263 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 */
5265 pay_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://ardour.org/download")));
5266 subscribe_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://community.ardour.org/s/subscribe")));
5268 msg.get_vbox()->pack_start (pay_label);
5269 msg.get_vbox()->pack_start (pay_button_box);
5270 msg.get_vbox()->pack_start (subscribe_label);
5271 msg.get_vbox()->pack_start (subscribe_button_box);
5273 msg.get_vbox()->show_all ();
5275 msg.add_button (_("Remain silent"), Gtk::RESPONSE_CANCEL);
5276 msg.add_button (_("Save and quit"), Gtk::RESPONSE_NO);
5277 msg.add_button (_("Give me more time"), Gtk::RESPONSE_YES);
5282 case Gtk::RESPONSE_YES:
5283 AudioEngine::instance()->reset_silence_countdown ();
5286 case Gtk::RESPONSE_NO:
5288 save_state_canfail ("");
5292 case Gtk::RESPONSE_CANCEL:
5294 /* don't reset, save session and exit */
5300 ARDOUR_UI::hide_application ()
5302 Application::instance ()-> hide ();
5306 ARDOUR_UI::setup_toplevel_window (Gtk::Window& window, const string& name, void* owner)
5308 /* icons, titles, WM stuff */
5310 static list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
5312 if (window_icons.empty()) {
5313 Glib::RefPtr<Gdk::Pixbuf> icon;
5314 if ((icon = ::get_icon (PROGRAM_NAME "-icon_16px")) != 0) {
5315 window_icons.push_back (icon);
5317 if ((icon = ::get_icon (PROGRAM_NAME "-icon_22px")) != 0) {
5318 window_icons.push_back (icon);
5320 if ((icon = ::get_icon (PROGRAM_NAME "-icon_32px")) != 0) {
5321 window_icons.push_back (icon);
5323 if ((icon = ::get_icon (PROGRAM_NAME "-icon_48px")) != 0) {
5324 window_icons.push_back (icon);
5328 if (!window_icons.empty()) {
5329 window.set_default_icon_list (window_icons);
5332 Gtkmm2ext::WindowTitle title (Glib::get_application_name());
5334 if (!name.empty()) {
5338 window.set_title (title.get_string());
5339 window.set_wmclass (string_compose (X_("%1_%1"), downcase (PROGRAM_NAME), downcase (name)), PROGRAM_NAME);
5341 window.set_flags (CAN_FOCUS);
5342 window.add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
5344 /* This is a hack to ensure that GTK-accelerators continue to
5345 * work. Once we switch over to entirely native bindings, this will be
5346 * unnecessary and should be removed
5348 window.add_accel_group (ActionManager::ui_manager->get_accel_group());
5350 window.signal_configure_event().connect (sigc::mem_fun (*this, &ARDOUR_UI::configure_handler));
5351 window.signal_window_state_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::tabbed_window_state_event_handler), owner));
5352 window.signal_key_press_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5353 window.signal_key_release_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5357 ARDOUR_UI::key_event_handler (GdkEventKey* ev, Gtk::Window* event_window)
5359 Gtkmm2ext::Bindings* bindings = 0;
5360 Gtk::Window* window = 0;
5362 /* until we get ardour bindings working, we are not handling key
5366 if (ev->type != GDK_KEY_PRESS) {
5370 if (event_window == &_main_window) {
5372 window = event_window;
5374 /* find current tab contents */
5376 Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page());
5378 /* see if it uses the ardour binding system */
5381 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(w->get_data ("ardour-bindings"));
5384 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("main window key event, bindings = %1, global = %2\n", bindings, &global_bindings));
5388 window = event_window;
5390 /* see if window uses ardour binding system */
5392 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(window->get_data ("ardour-bindings"));
5395 /* An empty binding set is treated as if it doesn't exist */
5397 if (bindings && bindings->empty()) {
5401 return key_press_focus_accelerator_handler (*window, ev, bindings);
5404 static Gtkmm2ext::Bindings*
5405 get_bindings_from_widget_heirarchy (GtkWidget* w)
5410 if ((p = g_object_get_data (G_OBJECT(w), "ardour-bindings")) != 0) {
5413 w = gtk_widget_get_parent (w);
5416 return reinterpret_cast<Gtkmm2ext::Bindings*> (p);
5420 ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev, Gtkmm2ext::Bindings* bindings)
5422 GtkWindow* win = window.gobj();
5423 GtkWidget* focus = gtk_window_get_focus (win);
5424 bool special_handling_of_unmodified_accelerators = false;
5425 const guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK));
5429 /* some widget has keyboard focus */
5431 if (GTK_IS_ENTRY(focus) || Keyboard::some_magic_widget_has_focus()) {
5433 /* A particular kind of focusable widget currently has keyboard
5434 * focus. All unmodified key events should go to that widget
5435 * first and not be used as an accelerator by default
5438 special_handling_of_unmodified_accelerators = true;
5442 Gtkmm2ext::Bindings* focus_bindings = get_bindings_from_widget_heirarchy (focus);
5443 if (focus_bindings) {
5444 bindings = focus_bindings;
5445 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Switch bindings based on focus widget, now using %1\n", bindings->name()));
5450 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",
5453 show_gdk_event_state (ev->state),
5454 special_handling_of_unmodified_accelerators,
5455 Keyboard::some_magic_widget_has_focus(),
5457 (focus ? gtk_widget_get_name (focus) : "no focus widget"),
5458 ((ev->state & mask) ? "yes" : "no"),
5459 window.get_title()));
5461 /* This exists to allow us to override the way GTK handles
5462 key events. The normal sequence is:
5464 a) event is delivered to a GtkWindow
5465 b) accelerators/mnemonics are activated
5466 c) if (b) didn't handle the event, propagate to
5467 the focus widget and/or focus chain
5469 The problem with this is that if the accelerators include
5470 keys without modifiers, such as the space bar or the
5471 letter "e", then pressing the key while typing into
5472 a text entry widget results in the accelerator being
5473 activated, instead of the desired letter appearing
5476 There is no good way of fixing this, but this
5477 represents a compromise. The idea is that
5478 key events involving modifiers (not Shift)
5479 get routed into the activation pathway first, then
5480 get propagated to the focus widget if necessary.
5482 If the key event doesn't involve modifiers,
5483 we deliver to the focus widget first, thus allowing
5484 it to get "normal text" without interference
5487 Of course, this can also be problematic: if there
5488 is a widget with focus, then it will swallow
5489 all "normal text" accelerators.
5493 if (!special_handling_of_unmodified_accelerators || (ev->state & mask)) {
5495 /* no special handling or there are modifiers in effect: accelerate first */
5497 DEBUG_TRACE (DEBUG::Accelerators, "\tactivate, then propagate\n");
5498 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tevent send-event:%1 time:%2 length:%3 name %7 string:%4 hardware_keycode:%5 group:%6\n",
5499 ev->send_event, ev->time, ev->length, ev->string, ev->hardware_keycode, ev->group, gdk_keyval_name (ev->keyval)));
5501 DEBUG_TRACE (DEBUG::Accelerators, "\tsending to window\n");
5502 KeyboardKey k (ev->state, ev->keyval);
5506 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tusing Ardour bindings %1 @ %2 for this event\n", bindings->name(), bindings));
5508 if (bindings->activate (k, Bindings::Press)) {
5509 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5514 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5516 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5517 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5521 DEBUG_TRACE (DEBUG::Accelerators, "\tnot accelerated, now propagate\n");
5523 if (gtk_window_propagate_key_event (win, ev)) {
5524 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate handled\n");
5530 /* no modifiers, propagate first */
5532 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate, then activate\n");
5534 if (gtk_window_propagate_key_event (win, ev)) {
5535 DEBUG_TRACE (DEBUG::Accelerators, "\thandled by propagate\n");
5539 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagation didn't handle, so activate\n");
5540 KeyboardKey k (ev->state, ev->keyval);
5544 DEBUG_TRACE (DEBUG::Accelerators, "\tusing Ardour bindings for this window\n");
5547 if (bindings->activate (k, Bindings::Press)) {
5548 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5554 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5556 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5557 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5562 DEBUG_TRACE (DEBUG::Accelerators, "\tnot handled\n");
5567 ARDOUR_UI::load_bindings ()
5569 if ((global_bindings = Bindings::get_bindings (X_("Global"), global_actions)) == 0) {
5570 error << _("Global keybindings are missing") << endmsg;
5575 ARDOUR_UI::cancel_solo ()
5578 if (_session->soloing()) {
5579 _session->set_solo (_session->get_routes(), false);
5580 } else if (_session->listening()) {
5581 _session->set_listen (_session->get_routes(), false);
5584 _session->clear_all_solo_state (_session->get_routes()); // safeguard, ideally this won't do anything, check the log-window