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>
37 #include <sys/types.h>
38 #include <sys/sysctl.h>
48 #include "pbd/gstdio_compat.h"
50 #include <gtkmm/messagedialog.h>
51 #include <gtkmm/accelmap.h>
52 #include <gtkmm/stock.h>
54 #include "pbd/error.h"
55 #include "pbd/basename.h"
56 #include "pbd/compose.h"
57 #include "pbd/convert.h"
58 #include "pbd/failed_constructor.h"
59 #include "pbd/enumwriter.h"
60 #include "pbd/memento_command.h"
61 #include "pbd/openuri.h"
62 #include "pbd/stl_delete.h"
63 #include "pbd/file_utils.h"
64 #include "pbd/localtime_r.h"
65 #include "pbd/pthread_utils.h"
66 #include "pbd/replace_all.h"
67 #include "pbd/xml++.h"
69 #include "gtkmm2ext/application.h"
70 #include "gtkmm2ext/bindings.h"
71 #include "gtkmm2ext/gtk_ui.h"
72 #include "gtkmm2ext/utils.h"
73 #include "gtkmm2ext/click_box.h"
74 #include "gtkmm2ext/fastmeter.h"
75 #include "gtkmm2ext/popup.h"
76 #include "gtkmm2ext/window_title.h"
78 #include "ardour/ardour.h"
79 #include "ardour/audio_backend.h"
80 #include "ardour/audio_track.h"
81 #include "ardour/audioengine.h"
82 #include "ardour/audiofilesource.h"
83 #include "ardour/automation_watch.h"
84 #include "ardour/diskstream.h"
85 #include "ardour/filename_extensions.h"
86 #include "ardour/filesystem_paths.h"
87 #include "ardour/ltc_file_reader.h"
88 #include "ardour/midi_track.h"
89 #include "ardour/port.h"
90 #include "ardour/plugin_manager.h"
91 #include "ardour/process_thread.h"
92 #include "ardour/profile.h"
93 #include "ardour/recent_sessions.h"
94 #include "ardour/record_enable_control.h"
95 #include "ardour/session_directory.h"
96 #include "ardour/session_route.h"
97 #include "ardour/session_state_utils.h"
98 #include "ardour/session_utils.h"
99 #include "ardour/source_factory.h"
100 #include "ardour/slave.h"
101 #include "ardour/system_exec.h"
102 #include "ardour/track.h"
103 #include "ardour/vca_manager.h"
104 #include "ardour/utils.h"
106 #include "LuaBridge/LuaBridge.h"
108 #ifdef WINDOWS_VST_SUPPORT
111 #ifdef AUDIOUNIT_SUPPORT
112 #include "ardour/audio_unit.h"
115 // fix for OSX (nsm.h has a check function, AU/Apple defines check)
120 #include "timecode/time.h"
122 typedef uint64_t microseconds_t;
127 #include "add_route_dialog.h"
128 #include "ambiguous_file_dialog.h"
129 #include "ardour_ui.h"
130 #include "audio_clock.h"
131 #include "audio_region_view.h"
132 #include "big_clock_window.h"
133 #include "bundle_manager.h"
134 #include "duplicate_routes_dialog.h"
136 #include "engine_dialog.h"
137 #include "export_video_dialog.h"
138 #include "export_video_infobox.h"
139 #include "gain_meter.h"
140 #include "global_port_matrix.h"
141 #include "gui_object.h"
142 #include "gui_thread.h"
143 #include "keyboard.h"
144 #include "keyeditor.h"
145 #include "location_ui.h"
146 #include "lua_script_manager.h"
147 #include "luawindow.h"
148 #include "main_clock.h"
149 #include "missing_file_dialog.h"
150 #include "missing_plugin_dialog.h"
151 #include "mixer_ui.h"
152 #include "meterbridge.h"
153 #include "mouse_cursors.h"
156 #include "pingback.h"
157 #include "processor_box.h"
158 #include "prompter.h"
159 #include "public_editor.h"
160 #include "rc_option_editor.h"
161 #include "route_time_axis.h"
162 #include "route_params_ui.h"
163 #include "save_as_dialog.h"
164 #include "script_selector.h"
165 #include "session_dialog.h"
166 #include "session_metadata_dialog.h"
167 #include "session_option_editor.h"
168 #include "shuttle_control.h"
169 #include "speaker_dialog.h"
172 #include "theme_manager.h"
173 #include "time_axis_view_item.h"
176 #include "video_server_dialog.h"
177 #include "add_video_dialog.h"
178 #include "transcode_video_dialog.h"
182 using namespace ARDOUR;
183 using namespace ARDOUR_UI_UTILS;
185 using namespace Gtkmm2ext;
188 using namespace Editing;
190 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
192 sigc::signal<void, framepos_t, bool, framepos_t> ARDOUR_UI::Clock;
193 sigc::signal<void> ARDOUR_UI::CloseAllDialogs;
196 ask_about_configuration_copy (string const & old_dir, string const & new_dir, int version)
198 MessageDialog msg (string_compose (_("%1 %2.x has discovered configuration files from %1 %3.x.\n\n"
199 "Would you like these files to be copied and used for %1 %2.x?\n\n"
200 "(This will require you to restart %1.)"),
201 PROGRAM_NAME, PROGRAM_VERSION, version),
202 false, /* no markup */
205 true /* modal, though it hardly matters since it is the only window */
208 msg.set_default_response (Gtk::RESPONSE_YES);
211 return (msg.run() == Gtk::RESPONSE_YES);
215 libxml_generic_error_func (void* /* parsing_context*/,
223 vsnprintf (buf, sizeof (buf), msg, ap);
224 error << buf << endmsg;
229 libxml_structured_error_func (void* /* parsing_context*/,
237 replace_all (msg, "\n", "");
240 if (err->file && err->line) {
241 error << X_("XML error: ") << msg << " in " << err->file << " at line " << err->line;
244 error << ':' << err->int2;
249 error << X_("XML error: ") << msg << endmsg;
255 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
256 : Gtkmm2ext::UI (PROGRAM_NAME, X_("gui"), argcp, argvp)
257 , session_loaded (false)
258 , gui_object_state (new GUIObjectState)
259 , primary_clock (new MainClock (X_("primary"), X_("transport"), true ))
260 , secondary_clock (new MainClock (X_("secondary"), X_("secondary"), false))
261 , big_clock (new AudioClock (X_("bigclock"), false, "big", true, true, false, false))
263 , global_actions (X_("global"))
264 , ignore_dual_punch (false)
265 , main_window_visibility (0)
270 , _mixer_on_top (false)
271 , _initial_verbose_plugin_scan (false)
272 , first_time_engine_run (true)
273 , roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll))
274 , stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop))
275 , goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart))
276 , goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd))
277 , auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop))
278 , play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection))
279 , rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable))
280 , auto_return_button (ArdourButton::led_default_elements)
281 , follow_edits_button (ArdourButton::led_default_elements)
282 , auto_input_button (ArdourButton::led_default_elements)
283 , auditioning_alert_button (_("Audition"))
284 , solo_alert_button (_("Solo"))
285 , feedback_alert_button (_("Feedback"))
286 , error_alert_button ( ArdourButton::just_led_default_elements )
288 , editor_meter_peak_display()
289 , _numpad_locate_happening (false)
290 , _session_is_new (false)
291 , last_key_press_time (0)
295 , rc_option_editor (0)
296 , speaker_config_window (X_("speaker-config"), _("Speaker Configuration"))
297 , add_route_dialog (X_("add-routes"), _("Add Tracks/Busses"))
298 , about (X_("about"), _("About"))
299 , location_ui (X_("locations"), S_("Ranges|Locations"))
300 , route_params (X_("inspector"), _("Tracks and Busses"))
301 , audio_midi_setup (X_("audio-midi-setup"), _("Audio/MIDI Setup"))
302 , export_video_dialog (X_("video-export"), _("Video Export Dialog"))
303 , lua_script_window (X_("script-manager"), _("Script Manager"))
304 , session_option_editor (X_("session-options-editor"), _("Properties"), boost::bind (&ARDOUR_UI::create_session_option_editor, this))
305 , add_video_dialog (X_("add-video"), _("Add Video"), boost::bind (&ARDOUR_UI::create_add_video_dialog, this))
306 , bundle_manager (X_("bundle-manager"), _("Bundle Manager"), boost::bind (&ARDOUR_UI::create_bundle_manager, this))
307 , big_clock_window (X_("big-clock"), _("Big Clock"), boost::bind (&ARDOUR_UI::create_big_clock_window, this))
308 , audio_port_matrix (X_("audio-connection-manager"), _("Audio Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::AUDIO))
309 , midi_port_matrix (X_("midi-connection-manager"), _("MIDI Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::MIDI))
310 , key_editor (X_("key-editor"), _("Bindings Editor"), boost::bind (&ARDOUR_UI::create_key_editor, this))
311 , video_server_process (0)
313 , have_configure_timeout (false)
314 , last_configure_time (0)
316 , have_disk_speed_dialog_displayed (false)
317 , _status_bar_visibility (X_("status-bar"))
318 , _feedback_exists (false)
319 , _log_not_acknowledged (LogLevelNone)
320 , duplicate_routes_dialog (0)
321 , editor_visibility_button (S_("Window|Editor"))
322 , mixer_visibility_button (S_("Window|Mixer"))
323 , prefs_visibility_button (S_("Window|Preferences"))
325 Gtkmm2ext::init (localedir);
327 UIConfiguration::instance().post_gui_init ();
329 if (ARDOUR::handle_old_configuration_files (boost::bind (ask_about_configuration_copy, _1, _2, _3))) {
330 MessageDialog msg (string_compose (_("Your configuration files were copied. You can now restart %1."), PROGRAM_NAME), true);
332 /* configuration was modified, exit immediately */
337 if (string (VERSIONSTRING).find (".pre") != string::npos) {
338 /* check this is not being run from ./ardev etc. */
339 if (!running_from_source_tree ()) {
340 pre_release_dialog ();
344 if (theArdourUI == 0) {
348 /* track main window visibility */
350 main_window_visibility = new VisibilityTracker (_main_window);
352 /* stop libxml from spewing to stdout/stderr */
354 xmlSetGenericErrorFunc (this, libxml_generic_error_func);
355 xmlSetStructuredErrorFunc (this, libxml_structured_error_func);
357 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::parameter_changed));
358 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
359 UIConfiguration::instance().map_parameters (pc);
361 roll_button.set_controllable (roll_controllable);
362 stop_button.set_controllable (stop_controllable);
363 goto_start_button.set_controllable (goto_start_controllable);
364 goto_end_button.set_controllable (goto_end_controllable);
365 auto_loop_button.set_controllable (auto_loop_controllable);
366 play_selection_button.set_controllable (play_selection_controllable);
367 rec_button.set_controllable (rec_controllable);
369 roll_button.set_name ("transport button");
370 stop_button.set_name ("transport button");
371 goto_start_button.set_name ("transport button");
372 goto_end_button.set_name ("transport button");
373 auto_loop_button.set_name ("transport button");
374 play_selection_button.set_name ("transport button");
375 rec_button.set_name ("transport recenable button");
376 midi_panic_button.set_name ("transport button");
378 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
379 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
381 ARDOUR::Session::VersionMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_format_mismatch, this, _1, _2), gui_context());
383 /* handle dialog requests */
385 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
387 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
389 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
391 /* handle Audio/MIDI setup when session requires it */
393 ARDOUR::Session::AudioEngineSetupRequired.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::do_audio_midi_setup, this, _1));
395 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
397 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
399 /* handle sr mismatch with a dialog - cross-thread from engine */
400 ARDOUR::Session::NotifyAboutSampleRateMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::sr_mismatch_message, this, _1, _2), gui_context ());
402 /* handle requests to quit (coming from JACK session) */
404 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::finish, this), gui_context ());
406 /* tell the user about feedback */
408 ARDOUR::Session::FeedbackDetected.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::feedback_detected, this), gui_context ());
409 ARDOUR::Session::SuccessfulGraphSort.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::successful_graph_sort, this), gui_context ());
411 /* handle requests to deal with missing files */
413 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
415 /* and ambiguous files */
417 ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2));
419 /* also plugin scan messages */
420 ARDOUR::PluginScanMessage.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_dialog, this, _1, _2, _3), gui_context());
421 ARDOUR::PluginScanTimeout.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_timeout, this, _1), gui_context());
423 ARDOUR::GUIIdle.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::gui_idle_handler, this), gui_context());
425 Config->ParameterChanged.connect ( forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::set_flat_buttons, this), gui_context() );
428 /* lets get this party started */
430 setup_gtk_ardour_enums ();
433 SessionEvent::create_per_thread_pool ("GUI", 4096);
435 /* we like keyboards */
437 keyboard = new ArdourKeyboard(*this);
439 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
441 keyboard->set_state (*node, Stateful::loading_state_version);
444 UIConfiguration::instance().reset_dpi ();
446 TimeAxisViewItem::set_constant_heights ();
448 /* Set this up so that our window proxies can register actions */
450 ActionManager::init ();
452 /* The following must happen after ARDOUR::init() so that Config is set up */
454 const XMLNode* ui_xml = Config->extra_xml (X_("UI"));
457 key_editor.set_state (*ui_xml, 0);
458 session_option_editor.set_state (*ui_xml, 0);
459 speaker_config_window.set_state (*ui_xml, 0);
460 about.set_state (*ui_xml, 0);
461 add_route_dialog.set_state (*ui_xml, 0);
462 add_video_dialog.set_state (*ui_xml, 0);
463 route_params.set_state (*ui_xml, 0);
464 bundle_manager.set_state (*ui_xml, 0);
465 location_ui.set_state (*ui_xml, 0);
466 big_clock_window.set_state (*ui_xml, 0);
467 audio_port_matrix.set_state (*ui_xml, 0);
468 midi_port_matrix.set_state (*ui_xml, 0);
469 export_video_dialog.set_state (*ui_xml, 0);
470 lua_script_window.set_state (*ui_xml, 0);
473 /* Separate windows */
475 WM::Manager::instance().register_window (&key_editor);
476 WM::Manager::instance().register_window (&session_option_editor);
477 WM::Manager::instance().register_window (&speaker_config_window);
478 WM::Manager::instance().register_window (&about);
479 WM::Manager::instance().register_window (&add_route_dialog);
480 WM::Manager::instance().register_window (&add_video_dialog);
481 WM::Manager::instance().register_window (&route_params);
482 WM::Manager::instance().register_window (&audio_midi_setup);
483 WM::Manager::instance().register_window (&export_video_dialog);
484 WM::Manager::instance().register_window (&lua_script_window);
485 WM::Manager::instance().register_window (&bundle_manager);
486 WM::Manager::instance().register_window (&location_ui);
487 WM::Manager::instance().register_window (&big_clock_window);
488 WM::Manager::instance().register_window (&audio_port_matrix);
489 WM::Manager::instance().register_window (&midi_port_matrix);
491 /* do not retain position for add route dialog */
492 add_route_dialog.set_state_mask (WindowProxy::Size);
494 /* Trigger setting up the color scheme and loading the GTK RC file */
496 UIConfiguration::instance().load_rc_file (false);
498 _process_thread = new ProcessThread ();
499 _process_thread->init ();
501 UIConfiguration::instance().DPIReset.connect (sigc::mem_fun (*this, &ARDOUR_UI::resize_text_widgets));
507 ARDOUR_UI::pre_release_dialog ()
509 ArdourDialog d (_("Pre-Release Warning"), true, false);
510 d.add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
512 Label* label = manage (new Label);
513 label->set_markup (string_compose (_("<b>Welcome to this pre-release build of %1 %2</b>\n\n\
514 There are still several issues and bugs to be worked on,\n\
515 as well as general workflow improvements, before this can be considered\n\
516 release software. So, a few guidelines:\n\
518 1) Please do <b>NOT</b> use this software with the expectation that it is stable or reliable\n\
519 though it may be so, depending on your workflow.\n\
520 2) Please wait for a helpful writeup of new features.\n\
521 3) <b>Please do NOT use the forums at ardour.org to report issues</b>.\n\
522 4) Please <b>DO</b> use the bugtracker at http://tracker.ardour.org/ to report issues\n\
523 making sure to note the product version number as 5.0-pre.\n\
524 5) Please <b>DO</b> use the ardour-users mailing list to discuss ideas and pass on comments.\n\
525 6) Please <b>DO</b> join us on IRC for real time discussions about %1 %2. You\n\
526 can get there directly from within the program via the Help->Chat menu option.\n\
528 Full information on all the above can be found on the support page at\n\
530 http://ardour.org/support\n\
531 "), PROGRAM_NAME, VERSIONSTRING));
533 d.get_vbox()->set_border_width (12);
534 d.get_vbox()->pack_start (*label, false, false, 12);
535 d.get_vbox()->show_all ();
540 GlobalPortMatrixWindow*
541 ARDOUR_UI::create_global_port_matrix (ARDOUR::DataType type)
546 return new GlobalPortMatrixWindow (_session, type);
550 ARDOUR_UI::attach_to_engine ()
552 AudioEngine::instance()->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
553 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
557 ARDOUR_UI::engine_stopped ()
559 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
560 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
561 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
562 update_sample_rate (0);
567 ARDOUR_UI::engine_running ()
569 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
570 if (first_time_engine_run) {
572 first_time_engine_run = false;
576 _session->reset_xrun_count ();
578 update_disk_space ();
580 update_xrun_count ();
581 update_sample_rate (AudioEngine::instance()->sample_rate());
582 update_timecode_format ();
583 update_peak_thread_work ();
584 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, true);
585 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, false);
589 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
591 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
592 /* we can't rely on the original string continuing to exist when we are called
593 again in the GUI thread, so make a copy and note that we need to
596 char *copy = strdup (reason);
597 Gtkmm2ext::UI::instance()->call_slot (MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
601 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
602 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
604 update_sample_rate (0);
608 /* if the reason is a non-empty string, it means that the backend was shutdown
609 rather than just Ardour.
612 if (strlen (reason)) {
613 msgstr = string_compose (_("The audio backend was shutdown because:\n\n%1"), reason);
615 msgstr = string_compose (_("\
616 The audio backend has either been shutdown or it\n\
617 disconnected %1 because %1\n\
618 was not fast enough. Try to restart\n\
619 the audio backend and save the session."), PROGRAM_NAME);
622 MessageDialog msg (_main_window, msgstr);
623 pop_back_splash (msg);
627 free (const_cast<char*> (reason));
632 ARDOUR_UI::post_engine ()
634 /* Things to be done once (and once ONLY) after we have a backend running in the AudioEngine
636 #ifdef AUDIOUNIT_SUPPORT
638 if (AUPluginInfo::au_get_crashlog(au_msg)) {
639 popup_error(_("Audio Unit Plugin Scan Failed. Automatic AU scanning has been disabled. Please see the log window for further details."));
640 error << _("Audio Unit Plugin Scan Failed:") << endmsg;
641 info << au_msg << endmsg;
645 ARDOUR::init_post_engine ();
647 /* connect to important signals */
649 AudioEngine::instance()->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
650 AudioEngine::instance()->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
651 AudioEngine::instance()->BufferSizeChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
652 AudioEngine::instance()->Halted.connect_same_thread (halt_connection, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
653 AudioEngine::instance()->BecameSilent.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::audioengine_became_silent, this), gui_context());
655 if (setup_windows ()) {
656 throw failed_constructor ();
659 /* Do this after setup_windows (), as that's when the _status_bar_visibility is created */
660 XMLNode* n = Config->extra_xml (X_("UI"));
662 _status_bar_visibility.set_state (*n);
665 check_memory_locking();
667 /* this is the first point at which all the possible actions are
668 * available, because some of the available actions are dependent on
669 * aspects of the engine/backend.
672 if (ARDOUR_COMMAND_LINE::show_key_actions) {
675 vector<string> paths;
676 vector<string> labels;
677 vector<string> tooltips;
679 vector<Glib::RefPtr<Gtk::Action> > actions;
681 Gtkmm2ext::ActionMap::get_all_actions (paths, labels, tooltips, keys, actions);
683 vector<string>::iterator k;
684 vector<string>::iterator p;
686 for (p = paths.begin(), k = keys.begin(); p != paths.end(); ++k, ++p) {
691 cout << *p << " => " << *k << endl;
695 halt_connection.disconnect ();
696 AudioEngine::instance()->stop ();
700 /* this being a GUI and all, we want peakfiles */
702 AudioFileSource::set_build_peakfiles (true);
703 AudioFileSource::set_build_missing_peakfiles (true);
705 /* set default clock modes */
707 primary_clock->set_mode (AudioClock::Timecode);
708 secondary_clock->set_mode (AudioClock::BBT);
710 /* start the time-of-day-clock */
713 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
714 update_wall_clock ();
715 Glib::signal_timeout().connect_seconds (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 1);
720 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
721 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
722 Config->map_parameters (pc);
724 UIConfiguration::instance().map_parameters (pc);
728 ARDOUR_UI::~ARDOUR_UI ()
730 UIConfiguration::instance().save_state();
734 if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
735 // don't bother at 'real' exit. the OS cleans up for us.
736 delete big_clock; big_clock = 0;
737 delete primary_clock; primary_clock = 0;
738 delete secondary_clock; secondary_clock = 0;
739 delete _process_thread; _process_thread = 0;
740 delete meterbridge; meterbridge = 0;
741 delete luawindow; luawindow = 0;
742 delete editor; editor = 0;
743 delete mixer; mixer = 0;
745 delete gui_object_state; gui_object_state = 0;
746 delete main_window_visibility;
747 FastMeter::flush_pattern_cache ();
748 PixFader::flush_pattern_cache ();
752 /* Small trick to flush main-thread event pool.
753 * Other thread-pools are destroyed at pthread_exit(),
754 * but tmain thread termination is too late to trigger Pool::~Pool()
756 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.
757 delete ev->event_pool();
762 ARDOUR_UI::pop_back_splash (Gtk::Window& win)
764 if (Splash::instance()) {
765 Splash::instance()->pop_back_for (win);
770 ARDOUR_UI::configure_timeout ()
772 if (last_configure_time == 0) {
773 /* no configure events yet */
777 /* force a gap of 0.5 seconds since the last configure event
780 if (get_microseconds() - last_configure_time < 500000) {
783 have_configure_timeout = false;
784 save_ardour_state ();
790 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
792 if (have_configure_timeout) {
793 last_configure_time = get_microseconds();
795 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
796 have_configure_timeout = true;
803 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
805 XMLProperty const * prop;
807 if ((prop = node.property ("roll")) != 0) {
808 roll_controllable->set_id (prop->value());
810 if ((prop = node.property ("stop")) != 0) {
811 stop_controllable->set_id (prop->value());
813 if ((prop = node.property ("goto-start")) != 0) {
814 goto_start_controllable->set_id (prop->value());
816 if ((prop = node.property ("goto-end")) != 0) {
817 goto_end_controllable->set_id (prop->value());
819 if ((prop = node.property ("auto-loop")) != 0) {
820 auto_loop_controllable->set_id (prop->value());
822 if ((prop = node.property ("play-selection")) != 0) {
823 play_selection_controllable->set_id (prop->value());
825 if ((prop = node.property ("rec")) != 0) {
826 rec_controllable->set_id (prop->value());
828 if ((prop = node.property ("shuttle")) != 0) {
829 shuttle_box->controllable()->set_id (prop->value());
834 ARDOUR_UI::get_transport_controllable_state ()
836 XMLNode* node = new XMLNode(X_("TransportControllables"));
839 roll_controllable->id().print (buf, sizeof (buf));
840 node->add_property (X_("roll"), buf);
841 stop_controllable->id().print (buf, sizeof (buf));
842 node->add_property (X_("stop"), buf);
843 goto_start_controllable->id().print (buf, sizeof (buf));
844 node->add_property (X_("goto_start"), buf);
845 goto_end_controllable->id().print (buf, sizeof (buf));
846 node->add_property (X_("goto_end"), buf);
847 auto_loop_controllable->id().print (buf, sizeof (buf));
848 node->add_property (X_("auto_loop"), buf);
849 play_selection_controllable->id().print (buf, sizeof (buf));
850 node->add_property (X_("play_selection"), buf);
851 rec_controllable->id().print (buf, sizeof (buf));
852 node->add_property (X_("rec"), buf);
853 shuttle_box->controllable()->id().print (buf, sizeof (buf));
854 node->add_property (X_("shuttle"), buf);
860 ARDOUR_UI::save_session_at_its_request (std::string snapshot_name)
863 _session->save_state (snapshot_name);
868 ARDOUR_UI::autosave_session ()
870 if (g_main_depth() > 1) {
871 /* inside a recursive main loop,
872 give up because we may not be able to
878 if (!Config->get_periodic_safety_backups()) {
883 _session->maybe_write_autosave();
890 ARDOUR_UI::session_dirty_changed ()
897 ARDOUR_UI::update_autosave ()
899 if (_session && _session->dirty()) {
900 if (_autosave_connection.connected()) {
901 _autosave_connection.disconnect();
904 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
905 Config->get_periodic_safety_backup_interval() * 1000);
908 if (_autosave_connection.connected()) {
909 _autosave_connection.disconnect();
915 ARDOUR_UI::check_announcements ()
918 string _annc_filename;
921 _annc_filename = PROGRAM_NAME "_announcements_osx_";
922 #elif defined PLATFORM_WINDOWS
923 _annc_filename = PROGRAM_NAME "_announcements_windows_";
925 _annc_filename = PROGRAM_NAME "_announcements_linux_";
927 _annc_filename.append (VERSIONSTRING);
929 _announce_string = "";
931 std::string path = Glib::build_filename (user_config_directory(), _annc_filename);
932 FILE* fin = g_fopen (path.c_str(), "rb");
934 while (!feof (fin)) {
937 if ((len = fread (tmp, sizeof(char), 1024, fin)) == 0 || ferror (fin)) {
940 _announce_string.append (tmp, len);
945 pingback (VERSIONSTRING, path);
950 _hide_splash (gpointer arg)
952 ((ARDOUR_UI*)arg)->hide_splash();
957 ARDOUR_UI::starting ()
959 Application* app = Application::instance ();
961 bool brand_new_user = ArdourStartup::required ();
963 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
964 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::load_from_application_api));
966 if (ARDOUR_COMMAND_LINE::check_announcements) {
967 check_announcements ();
972 /* we need to create this early because it may need to set the
973 * audio backend end up.
977 audio_midi_setup.get (true);
979 std::cerr << "audio-midi engine setup failed."<< std::endl;
983 if ((nsm_url = g_getenv ("NSM_URL")) != 0) {
984 nsm = new NSM_Client;
985 if (!nsm->init (nsm_url)) {
986 /* the ardour executable may have different names:
988 * waf's obj.target for distro versions: eg ardour4, ardourvst4
989 * Ardour4, Mixbus3 for bundled versions + full path on OSX & windows
990 * argv[0] does not apply since we need the wrapper-script (not the binary itself)
992 * The wrapper startup script should set the environment variable 'ARDOUR_SELF'
994 const char *process_name = g_getenv ("ARDOUR_SELF");
995 nsm->announce (PROGRAM_NAME, ":dirty:", process_name ? process_name : "ardour4");
998 // wait for announce reply from nsm server
999 for ( i = 0; i < 5000; ++i) {
1003 if (nsm->is_active()) {
1008 error << _("NSM server did not announce itself") << endmsg;
1011 // wait for open command from nsm server
1012 for ( i = 0; i < 5000; ++i) {
1014 Glib::usleep (1000);
1015 if (nsm->client_id ()) {
1021 error << _("NSM: no client ID provided") << endmsg;
1025 if (_session && nsm) {
1026 _session->set_nsm_state( nsm->is_active() );
1028 error << _("NSM: no session created") << endmsg;
1032 // nsm requires these actions disabled
1033 vector<string> action_names;
1034 action_names.push_back("SaveAs");
1035 action_names.push_back("Rename");
1036 action_names.push_back("New");
1037 action_names.push_back("Open");
1038 action_names.push_back("Recent");
1039 action_names.push_back("Close");
1041 for (vector<string>::const_iterator n = action_names.begin(); n != action_names.end(); ++n) {
1042 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), (*n).c_str());
1044 act->set_sensitive (false);
1051 error << _("NSM: initialization failed") << endmsg;
1057 if (brand_new_user) {
1058 _initial_verbose_plugin_scan = true;
1063 _initial_verbose_plugin_scan = false;
1064 switch (s.response ()) {
1065 case Gtk::RESPONSE_OK:
1072 #ifdef NO_PLUGIN_STATE
1074 ARDOUR::RecentSessions rs;
1075 ARDOUR::read_recent_sessions (rs);
1077 string path = Glib::build_filename (user_config_directory(), ".iknowaboutfreeversion");
1079 if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS) && !rs.empty()) {
1081 /* already used Ardour, have sessions ... warn about plugin state */
1083 ArdourDialog d (_("Free/Demo Version Warning"), true);
1085 Button b (string_compose (_("Subscribe and support development of %1"), PROGRAM_NAME));
1086 CheckButton c (_("Don't warn me about this again"));
1088 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"),
1089 string_compose (_("This is a free/demo version of %1"), PROGRAM_NAME),
1090 _("It will not restore OR save any plugin settings"),
1091 _("If you load an existing session with plugin settings\n"
1092 "they will not be used and will be lost."),
1093 _("To get full access to updates without this limitation\n"
1094 "consider becoming a subscriber for a low cost every month.")));
1095 l.set_justify (JUSTIFY_CENTER);
1097 b.signal_clicked().connect (mem_fun(*this, &ARDOUR_UI::launch_subscribe));
1099 d.get_vbox()->pack_start (l, true, true);
1100 d.get_vbox()->pack_start (b, false, false, 12);
1101 d.get_vbox()->pack_start (c, false, false, 12);
1103 d.add_button (_("Quit now"), RESPONSE_CANCEL);
1104 d.add_button (string_compose (_("Continue using %1"), PROGRAM_NAME), RESPONSE_OK);
1108 c.signal_toggled().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (toggle_file_existence), path)));
1110 if (d.run () != RESPONSE_OK) {
1116 /* go get a session */
1118 const bool new_session_required = (ARDOUR_COMMAND_LINE::new_session || brand_new_user);
1120 if (get_session_parameters (false, new_session_required, ARDOUR_COMMAND_LINE::load_template)) {
1121 std::cerr << "Cannot get session parameters."<< std::endl;
1128 WM::Manager::instance().show_visible ();
1130 /* We have to do this here since goto_editor_window() ends up calling show_all() on the
1131 * editor window, and we may want stuff to be hidden.
1133 _status_bar_visibility.update ();
1135 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
1137 if (splash && splash->is_visible()) {
1138 // in 1 second, hide the splash screen
1139 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
1142 /* all other dialogs are created conditionally */
1148 ARDOUR_UI::check_memory_locking ()
1150 #if defined(__APPLE__) || defined(PLATFORM_WINDOWS)
1151 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
1155 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
1157 if (AudioEngine::instance()->is_realtime() && memory_warning_node == 0) {
1159 struct rlimit limits;
1161 long pages, page_size;
1163 size_t pages_len=sizeof(pages);
1164 if ((page_size = getpagesize()) < 0 ||
1165 sysctlbyname("hw.availpages", &pages, &pages_len, NULL, 0))
1167 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0)
1172 ram = (int64_t) pages * (int64_t) page_size;
1175 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
1179 if (limits.rlim_cur != RLIM_INFINITY) {
1181 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
1185 _("WARNING: Your system has a limit for maximum amount of locked memory. "
1186 "This might cause %1 to run out of memory before your system "
1187 "runs out of memory. \n\n"
1188 "You can view the memory limit with 'ulimit -l', "
1189 "and it is normally controlled by %2"),
1192 X_("/etc/login.conf")
1194 X_(" /etc/security/limits.conf")
1198 msg.set_default_response (RESPONSE_OK);
1200 VBox* vbox = msg.get_vbox();
1202 CheckButton cb (_("Do not show this window again"));
1203 hbox.pack_start (cb, true, false);
1204 vbox->pack_start (hbox);
1209 pop_back_splash (msg);
1213 if (cb.get_active()) {
1214 XMLNode node (X_("no-memory-warning"));
1215 Config->add_instant_xml (node);
1220 #endif // !__APPLE__
1225 ARDOUR_UI::queue_finish ()
1227 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
1231 ARDOUR_UI::idle_finish ()
1234 return false; /* do not call again */
1241 ARDOUR_UI::instance()->video_timeline->sync_session_state();
1243 if (_session->dirty()) {
1244 vector<string> actions;
1245 actions.push_back (_("Don't quit"));
1246 actions.push_back (_("Just quit"));
1247 actions.push_back (_("Save and quit"));
1248 switch (ask_about_saving_session(actions)) {
1253 /* use the default name */
1254 if (save_state_canfail ("")) {
1255 /* failed - don't quit */
1256 MessageDialog msg (_main_window,
1257 string_compose (_("\
1258 %1 was unable to save your session.\n\n\
1259 If you still wish to quit, please use the\n\n\
1260 \"Just quit\" option."), PROGRAM_NAME));
1261 pop_back_splash(msg);
1271 second_connection.disconnect ();
1272 point_one_second_connection.disconnect ();
1273 point_zero_something_second_connection.disconnect();
1274 fps_connection.disconnect();
1277 delete ARDOUR_UI::instance()->video_timeline;
1278 ARDOUR_UI::instance()->video_timeline = NULL;
1279 stop_video_server();
1281 /* Save state before deleting the session, as that causes some
1282 windows to be destroyed before their visible state can be
1285 save_ardour_state ();
1287 close_all_dialogs ();
1290 _session->set_clean ();
1291 _session->remove_pending_capture_state ();
1296 halt_connection.disconnect ();
1297 AudioEngine::instance()->stop ();
1298 #ifdef WINDOWS_VST_SUPPORT
1299 fst_stop_threading();
1305 ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
1307 ArdourDialog window (_("Unsaved Session"));
1308 Gtk::HBox dhbox; // the hbox for the image and text
1309 Gtk::Label prompt_label;
1310 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
1314 assert (actions.size() >= 3);
1316 window.add_button (actions[0], RESPONSE_REJECT);
1317 window.add_button (actions[1], RESPONSE_APPLY);
1318 window.add_button (actions[2], RESPONSE_ACCEPT);
1320 window.set_default_response (RESPONSE_ACCEPT);
1322 Gtk::Button noquit_button (msg);
1323 noquit_button.set_name ("EditorGTKButton");
1327 if (_session->snap_name() == _session->name()) {
1328 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?"),
1329 _session->snap_name());
1331 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?"),
1332 _session->snap_name());
1335 prompt_label.set_text (prompt);
1336 prompt_label.set_name (X_("PrompterLabel"));
1337 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
1339 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
1340 dhbox.set_homogeneous (false);
1341 dhbox.pack_start (*dimage, false, false, 5);
1342 dhbox.pack_start (prompt_label, true, false, 5);
1343 window.get_vbox()->pack_start (dhbox);
1345 window.set_name (_("Prompter"));
1346 window.set_modal (true);
1347 window.set_resizable (false);
1350 prompt_label.show();
1355 ResponseType r = (ResponseType) window.run();
1360 case RESPONSE_ACCEPT: // save and get out of here
1362 case RESPONSE_APPLY: // get out of here
1373 ARDOUR_UI::every_second ()
1376 update_xrun_count ();
1377 update_buffer_load ();
1378 update_disk_space ();
1379 update_timecode_format ();
1380 update_peak_thread_work ();
1382 if (nsm && nsm->is_active ()) {
1385 if (!_was_dirty && _session->dirty ()) {
1389 else if (_was_dirty && !_session->dirty ()){
1397 ARDOUR_UI::every_point_one_seconds ()
1399 // TODO get rid of this..
1400 // ShuttleControl is updated directly via TransportStateChange signal
1404 ARDOUR_UI::every_point_zero_something_seconds ()
1406 // august 2007: actual update frequency: 25Hz (40ms), not 100Hz
1408 if (editor_meter && UIConfiguration::instance().get_show_editor_meter()) {
1409 float mpeak = editor_meter->update_meters();
1410 if (mpeak > editor_meter_max_peak) {
1411 if (mpeak >= UIConfiguration::instance().get_meter_peak()) {
1412 editor_meter_peak_display.set_active_state ( Gtkmm2ext::ExplicitActive );
1419 ARDOUR_UI::set_fps_timeout_connection ()
1421 unsigned int interval = 40;
1422 if (!_session) return;
1423 if (_session->timecode_frames_per_second() != 0) {
1424 /* ideally we'll use a select() to sleep and not accumulate
1425 * idle time to provide a regular periodic signal.
1426 * See linux_vst_gui_support.cc 'elapsed_time_ms'.
1427 * However, that'll require a dedicated thread and cross-thread
1428 * signals to the GUI Thread..
1430 interval = floor(500. /* update twice per FPS, since Glib::signal_timeout is very irregular */
1431 * _session->frame_rate() / _session->nominal_frame_rate()
1432 / _session->timecode_frames_per_second()
1434 #ifdef PLATFORM_WINDOWS
1435 // the smallest windows scheduler time-slice is ~15ms.
1436 // periodic GUI timeouts shorter than that will cause
1437 // WaitForSingleObject to spinlock (100% of one CPU Core)
1438 // and gtk never enters idle mode.
1439 // also changing timeBeginPeriod(1) does not affect that in
1440 // any beneficial way, so we just limit the max rate for now.
1441 interval = std::max(30u, interval); // at most ~33Hz.
1443 interval = std::max(8u, interval); // at most 120Hz.
1446 fps_connection.disconnect();
1447 Timers::set_fps_interval (interval);
1451 ARDOUR_UI::update_sample_rate (framecnt_t)
1455 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
1457 if (!AudioEngine::instance()->connected()) {
1459 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1463 framecnt_t rate = AudioEngine::instance()->sample_rate();
1466 /* no sample rate available */
1467 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1470 if (fmod (rate, 1000.0) != 0.0) {
1471 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
1472 (float) rate / 1000.0f,
1473 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1475 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
1477 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1481 sample_rate_label.set_markup (buf);
1485 ARDOUR_UI::update_format ()
1488 format_label.set_text ("");
1493 s << _("File:") << X_(" <span foreground=\"green\">");
1495 switch (_session->config.get_native_file_header_format ()) {
1527 switch (_session->config.get_native_file_data_format ()) {
1541 format_label.set_markup (s.str ());
1545 ARDOUR_UI::update_xrun_count ()
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.
1554 const unsigned int x = _session->get_xrun_count ();
1556 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">>10K</span>"), X_("red"));
1558 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">%u</span>"), x > 0 ? X_("red") : X_("green"), x);
1561 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">?</span>"), X_("yellow"));
1563 xrun_label.set_markup (buf);
1564 set_tip (xrun_label, _("Audio dropouts. Shift+click to reset"));
1568 ARDOUR_UI::update_cpu_load ()
1572 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1573 should also be changed.
1576 double const c = AudioEngine::instance()->get_dsp_load ();
1577 snprintf (buf, sizeof (buf), _("DSP: <span foreground=\"%s\">%5.1f%%</span>"), c >= 90 ? X_("red") : X_("green"), c);
1578 cpu_load_label.set_markup (buf);
1582 ARDOUR_UI::update_peak_thread_work ()
1585 const int c = SourceFactory::peak_work_queue_length ();
1587 snprintf (buf, sizeof (buf), _("PkBld: <span foreground=\"%s\">%d</span>"), c >= 2 ? X_("red") : X_("green"), c);
1588 peak_thread_work_label.set_markup (buf);
1590 peak_thread_work_label.set_markup (X_(""));
1595 ARDOUR_UI::update_buffer_load ()
1599 uint32_t const playback = _session ? _session->playback_load () : 100;
1600 uint32_t const capture = _session ? _session->capture_load () : 100;
1602 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1603 should also be changed.
1609 _("Buffers: <span foreground=\"green\">p:</span><span foreground=\"%s\">%" PRIu32 "%%</span> "
1610 "<span foreground=\"green\">c:</span><span foreground=\"%s\">%" PRIu32 "%%</span>"),
1611 playback <= 5 ? X_("red") : X_("green"),
1613 capture <= 5 ? X_("red") : X_("green"),
1617 buffer_load_label.set_markup (buf);
1619 buffer_load_label.set_text ("");
1624 ARDOUR_UI::count_recenabled_streams (Route& route)
1626 Track* track = dynamic_cast<Track*>(&route);
1627 if (track && track->rec_enable_control()->get_value()) {
1628 rec_enabled_streams += track->n_inputs().n_total();
1633 ARDOUR_UI::update_disk_space()
1635 if (_session == 0) {
1639 boost::optional<framecnt_t> opt_frames = _session->available_capture_duration();
1641 framecnt_t fr = _session->frame_rate();
1644 /* skip update - no SR available */
1649 /* Available space is unknown */
1650 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">Unknown</span>"));
1651 } else if (opt_frames.get_value_or (0) == max_framecnt) {
1652 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">24hrs+</span>"));
1654 rec_enabled_streams = 0;
1655 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams, false);
1657 framecnt_t frames = opt_frames.get_value_or (0);
1659 if (rec_enabled_streams) {
1660 frames /= rec_enabled_streams;
1667 hrs = frames / (fr * 3600);
1670 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">>24 hrs</span>"));
1672 frames -= hrs * fr * 3600;
1673 mins = frames / (fr * 60);
1674 frames -= mins * fr * 60;
1677 bool const low = (hrs == 0 && mins <= 30);
1681 _("Disk: <span foreground=\"%s\">%02dh:%02dm:%02ds</span>"),
1682 low ? X_("red") : X_("green"),
1688 disk_space_label.set_markup (buf);
1692 ARDOUR_UI::update_timecode_format ()
1698 TimecodeSlave* tcslave;
1699 SyncSource sync_src = Config->get_sync_source();
1701 if ((sync_src == LTC || sync_src == MTC) && (tcslave = dynamic_cast<TimecodeSlave*>(_session->slave())) != 0) {
1702 matching = (tcslave->apparent_timecode_format() == _session->config.get_timecode_format());
1707 snprintf (buf, sizeof (buf), S_("Timecode|TC: <span foreground=\"%s\">%s</span>"),
1708 matching ? X_("green") : X_("red"),
1709 Timecode::timecode_format_name (_session->config.get_timecode_format()).c_str());
1711 snprintf (buf, sizeof (buf), "TC: n/a");
1714 timecode_format_label.set_markup (buf);
1718 ARDOUR_UI::update_wall_clock ()
1722 static int last_min = -1;
1725 tm_now = localtime (&now);
1726 if (last_min != tm_now->tm_min) {
1728 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1729 wall_clock_label.set_text (buf);
1730 last_min = tm_now->tm_min;
1737 ARDOUR_UI::open_recent_session ()
1739 bool can_return = (_session != 0);
1741 SessionDialog recent_session_dialog;
1745 ResponseType r = (ResponseType) recent_session_dialog.run ();
1748 case RESPONSE_ACCEPT:
1752 recent_session_dialog.hide();
1759 recent_session_dialog.hide();
1763 std::string path = recent_session_dialog.session_folder();
1764 std::string state = recent_session_dialog.session_name (should_be_new);
1766 if (should_be_new == true) {
1770 _session_is_new = false;
1772 if (load_session (path, state) == 0) {
1778 if (splash && splash->is_visible()) {
1779 // in 1 second, hide the splash screen
1780 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
1785 ARDOUR_UI::check_audioengine (Gtk::Window& parent)
1787 if (!AudioEngine::instance()->connected()) {
1788 MessageDialog msg (parent, string_compose (
1789 _("%1 is not connected to any audio backend.\n"
1790 "You cannot open or close sessions in this condition"),
1792 pop_back_splash (msg);
1800 ARDOUR_UI::open_session ()
1802 if (!check_audioengine (_main_window)) {
1806 /* ardour sessions are folders */
1807 Gtk::FileChooserDialog open_session_selector(_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1808 open_session_selector.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1809 open_session_selector.add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1810 open_session_selector.set_default_response(Gtk::RESPONSE_ACCEPT);
1813 string session_parent_dir = Glib::path_get_dirname(_session->path());
1814 open_session_selector.set_current_folder(session_parent_dir);
1816 open_session_selector.set_current_folder(Config->get_default_session_parent_dir());
1819 Gtkmm2ext::add_volume_shortcuts (open_session_selector);
1821 /* add_shortcut_folder throws an exception if the folder being added already has a shortcut */
1822 string default_session_folder = Config->get_default_session_parent_dir();
1823 open_session_selector.add_shortcut_folder (default_session_folder);
1825 catch (Glib::Error & e) {
1826 std::cerr << "open_session_selector.add_shortcut_folder() threw Glib::Error " << e.what() << std::endl;
1829 FileFilter session_filter;
1830 session_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::statefile_suffix));
1831 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1832 open_session_selector.add_filter (session_filter);
1833 open_session_selector.set_filter (session_filter);
1835 int response = open_session_selector.run();
1836 open_session_selector.hide ();
1838 if (response == Gtk::RESPONSE_CANCEL) {
1842 string session_path = open_session_selector.get_filename();
1846 if (session_path.length() > 0) {
1847 if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1848 _session_is_new = isnew;
1849 load_session (path, name);
1855 ARDOUR_UI::session_add_vca (const string& name_template, uint32_t n)
1861 _session->vca_manager().create_vca (n, name_template);
1865 ARDOUR_UI::session_add_mixed_track (
1866 const ChanCount& input,
1867 const ChanCount& output,
1868 RouteGroup* route_group,
1870 const string& name_template,
1872 PluginInfoPtr instrument,
1873 Plugin::PresetRecord* pset,
1874 ARDOUR::PresentationInfo::order_t order)
1876 list<boost::shared_ptr<MidiTrack> > tracks;
1878 if (_session == 0) {
1879 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1884 tracks = _session->new_midi_track (input, output, instrument, pset, route_group, how_many, name_template, order, ARDOUR::Normal);
1886 if (tracks.size() != how_many) {
1887 error << string_compose(P_("could not create %1 new mixed track", "could not create %1 new mixed tracks", how_many), how_many) << endmsg;
1892 display_insufficient_ports_message ();
1897 for (list<boost::shared_ptr<MidiTrack> >::iterator i = tracks.begin(); i != tracks.end(); ++i) {
1898 (*i)->set_strict_io (true);
1904 ARDOUR_UI::session_add_midi_bus (
1905 RouteGroup* route_group,
1907 const string& name_template,
1909 PluginInfoPtr instrument,
1910 Plugin::PresetRecord* pset,
1911 ARDOUR::PresentationInfo::order_t order)
1915 if (_session == 0) {
1916 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1922 routes = _session->new_midi_route (route_group, how_many, name_template, instrument, pset, PresentationInfo::MidiBus, order);
1923 if (routes.size() != how_many) {
1924 error << string_compose(P_("could not create %1 new Midi Bus", "could not create %1 new Midi Busses", how_many), how_many) << endmsg;
1929 display_insufficient_ports_message ();
1934 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
1935 (*i)->set_strict_io (true);
1941 ARDOUR_UI::session_add_midi_route (
1943 RouteGroup* route_group,
1945 const string& name_template,
1947 PluginInfoPtr instrument,
1948 Plugin::PresetRecord* pset,
1949 ARDOUR::PresentationInfo::order_t order)
1951 ChanCount one_midi_channel;
1952 one_midi_channel.set (DataType::MIDI, 1);
1955 session_add_mixed_track (one_midi_channel, one_midi_channel, route_group, how_many, name_template, strict_io, instrument, pset, order);
1957 session_add_midi_bus (route_group, how_many, name_template, strict_io, instrument, pset, order);
1962 ARDOUR_UI::session_add_audio_route (
1964 int32_t input_channels,
1965 int32_t output_channels,
1966 ARDOUR::TrackMode mode,
1967 RouteGroup* route_group,
1969 string const & name_template,
1971 ARDOUR::PresentationInfo::order_t order)
1973 list<boost::shared_ptr<AudioTrack> > tracks;
1976 if (_session == 0) {
1977 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1983 tracks = _session->new_audio_track (input_channels, output_channels, route_group, how_many, name_template, order, mode);
1985 if (tracks.size() != how_many) {
1986 error << string_compose (P_("could not create %1 new audio track", "could not create %1 new audio tracks", how_many), how_many)
1992 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template, PresentationInfo::AudioBus, order);
1994 if (routes.size() != how_many) {
1995 error << string_compose (P_("could not create %1 new audio bus", "could not create %1 new audio busses", how_many), how_many)
2002 display_insufficient_ports_message ();
2007 for (list<boost::shared_ptr<AudioTrack> >::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2008 (*i)->set_strict_io (true);
2010 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
2011 (*i)->set_strict_io (true);
2017 ARDOUR_UI::display_insufficient_ports_message ()
2019 MessageDialog msg (_main_window,
2020 string_compose (_("There are insufficient ports available\n\
2021 to create a new track or bus.\n\
2022 You should save %1, exit and\n\
2023 restart with more ports."), PROGRAM_NAME));
2024 pop_back_splash (msg);
2029 ARDOUR_UI::transport_goto_start ()
2032 _session->goto_start();
2034 /* force displayed area in editor to start no matter
2035 what "follow playhead" setting is.
2039 editor->center_screen (_session->current_start_frame ());
2045 ARDOUR_UI::transport_goto_zero ()
2048 _session->request_locate (0);
2050 /* force displayed area in editor to start no matter
2051 what "follow playhead" setting is.
2055 editor->reset_x_origin (0);
2061 ARDOUR_UI::transport_goto_wallclock ()
2063 if (_session && editor) {
2070 localtime_r (&now, &tmnow);
2072 framecnt_t frame_rate = _session->frame_rate();
2074 if (frame_rate == 0) {
2075 /* no frame rate available */
2079 frames = tmnow.tm_hour * (60 * 60 * frame_rate);
2080 frames += tmnow.tm_min * (60 * frame_rate);
2081 frames += tmnow.tm_sec * frame_rate;
2083 _session->request_locate (frames, _session->transport_rolling ());
2085 /* force displayed area in editor to start no matter
2086 what "follow playhead" setting is.
2090 editor->center_screen (frames);
2096 ARDOUR_UI::transport_goto_end ()
2099 framepos_t const frame = _session->current_end_frame();
2100 _session->request_locate (frame);
2102 /* force displayed area in editor to start no matter
2103 what "follow playhead" setting is.
2107 editor->center_screen (frame);
2113 ARDOUR_UI::transport_stop ()
2119 if (_session->is_auditioning()) {
2120 _session->cancel_audition ();
2124 _session->request_stop (false, true);
2127 /** Check if any tracks are record enabled. If none are, record enable all of them.
2128 * @return true if track record-enabled status was changed, false otherwise.
2131 ARDOUR_UI::trx_record_enable_all_tracks ()
2137 boost::shared_ptr<RouteList> rl = _session->get_tracks ();
2138 bool none_record_enabled = true;
2140 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
2141 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*r);
2144 if (t->rec_enable_control()->get_value()) {
2145 none_record_enabled = false;
2150 if (none_record_enabled) {
2151 _session->set_controls (route_list_to_control_list (rl, &Stripable::rec_enable_control), 1.0, Controllable::NoGroup);
2154 return none_record_enabled;
2158 ARDOUR_UI::transport_record (bool roll)
2161 switch (_session->record_status()) {
2162 case Session::Disabled:
2163 if (_session->ntracks() == 0) {
2164 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."));
2168 if (Profile->get_trx()) {
2169 roll = trx_record_enable_all_tracks ();
2171 _session->maybe_enable_record ();
2176 case Session::Recording:
2178 _session->request_stop();
2180 _session->disable_record (false, true);
2184 case Session::Enabled:
2185 _session->disable_record (false, true);
2191 ARDOUR_UI::transport_roll ()
2197 if (_session->is_auditioning()) {
2202 if (_session->config.get_external_sync()) {
2203 switch (Config->get_sync_source()) {
2207 /* transport controlled by the master */
2213 bool rolling = _session->transport_rolling();
2215 if (_session->get_play_loop()) {
2217 /* If loop playback is not a mode, then we should cancel
2218 it when this action is requested. If it is a mode
2219 we just leave it in place.
2222 if (!Config->get_loop_is_mode()) {
2223 /* XXX it is not possible to just leave seamless loop and keep
2224 playing at present (nov 4th 2009)
2226 if (!Config->get_seamless_loop()) {
2227 /* stop loop playback and stop rolling */
2228 _session->request_play_loop (false, true);
2229 } else if (rolling) {
2230 /* stop loop playback but keep rolling */
2231 _session->request_play_loop (false, false);
2235 } else if (_session->get_play_range () ) {
2236 /* stop playing a range if we currently are */
2237 _session->request_play_range (0, true);
2241 _session->request_transport_speed (1.0f);
2246 ARDOUR_UI::get_smart_mode() const
2248 return ( editor->get_smart_mode() );
2253 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
2259 if (_session->is_auditioning()) {
2260 _session->cancel_audition ();
2264 if (_session->config.get_external_sync()) {
2265 switch (Config->get_sync_source()) {
2269 /* transport controlled by the master */
2274 bool rolling = _session->transport_rolling();
2275 bool affect_transport = true;
2277 if (rolling && roll_out_of_bounded_mode) {
2278 /* drop out of loop/range playback but leave transport rolling */
2279 if (_session->get_play_loop()) {
2280 if (_session->actively_recording()) {
2282 /* just stop using the loop, then actually stop
2285 _session->request_play_loop (false, affect_transport);
2288 if (Config->get_seamless_loop()) {
2289 /* the disk buffers contain copies of the loop - we can't
2290 just keep playing, so stop the transport. the user
2291 can restart as they wish.
2293 affect_transport = true;
2295 /* disk buffers are normal, so we can keep playing */
2296 affect_transport = false;
2298 _session->request_play_loop (false, affect_transport);
2300 } else if (_session->get_play_range ()) {
2301 affect_transport = false;
2302 _session->request_play_range (0, true);
2306 if (affect_transport) {
2308 _session->request_stop (with_abort, true);
2310 /* the only external sync condition we can be in here
2311 * would be Engine (JACK) sync, in which case we still
2315 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
2316 _session->request_play_range (&editor->get_selection().time, true);
2317 _session->set_requested_return_frame( editor->get_selection().time.front().start ); //force an auto-return here
2319 _session->request_transport_speed (1.0f);
2325 ARDOUR_UI::toggle_session_auto_loop ()
2331 Location * looploc = _session->locations()->auto_loop_location();
2337 if (_session->get_play_loop()) {
2339 /* looping enabled, our job is to disable it */
2341 _session->request_play_loop (false);
2345 /* looping not enabled, our job is to enable it.
2347 loop-is-NOT-mode: this action always starts the transport rolling.
2348 loop-IS-mode: this action simply sets the loop play mechanism, but
2349 does not start transport.
2351 if (Config->get_loop_is_mode()) {
2352 _session->request_play_loop (true, false);
2354 _session->request_play_loop (true, true);
2358 //show the loop markers
2359 looploc->set_hidden (false, this);
2363 ARDOUR_UI::transport_play_selection ()
2369 editor->play_selection ();
2373 ARDOUR_UI::transport_play_preroll ()
2378 editor->play_with_preroll ();
2382 ARDOUR_UI::transport_rewind (int option)
2384 float current_transport_speed;
2387 current_transport_speed = _session->transport_speed();
2389 if (current_transport_speed >= 0.0f) {
2392 _session->request_transport_speed (-1.0f);
2395 _session->request_transport_speed (-4.0f);
2398 _session->request_transport_speed (-0.5f);
2403 _session->request_transport_speed (current_transport_speed * 1.5f);
2409 ARDOUR_UI::transport_forward (int option)
2415 float current_transport_speed = _session->transport_speed();
2417 if (current_transport_speed <= 0.0f) {
2420 _session->request_transport_speed (1.0f);
2423 _session->request_transport_speed (4.0f);
2426 _session->request_transport_speed (0.5f);
2431 _session->request_transport_speed (current_transport_speed * 1.5f);
2436 ARDOUR_UI::toggle_record_enable (uint16_t rid)
2442 boost::shared_ptr<Route> r;
2444 if ((r = _session->get_remote_nth_route (rid)) != 0) {
2446 boost::shared_ptr<Track> t;
2448 if ((t = boost::dynamic_pointer_cast<Track>(r)) != 0) {
2449 t->rec_enable_control()->set_value (!t->rec_enable_control()->get_value(), Controllable::UseGroup);
2455 ARDOUR_UI::map_transport_state ()
2458 auto_loop_button.unset_active_state ();
2459 play_selection_button.unset_active_state ();
2460 roll_button.unset_active_state ();
2461 stop_button.set_active_state (Gtkmm2ext::ExplicitActive);
2465 shuttle_box->map_transport_state ();
2467 float sp = _session->transport_speed();
2473 if (_session->get_play_range()) {
2475 play_selection_button.set_active_state (Gtkmm2ext::ExplicitActive);
2476 roll_button.unset_active_state ();
2477 auto_loop_button.unset_active_state ();
2479 } else if (_session->get_play_loop ()) {
2481 auto_loop_button.set_active (true);
2482 play_selection_button.set_active (false);
2483 if (Config->get_loop_is_mode()) {
2484 roll_button.set_active (true);
2486 roll_button.set_active (false);
2491 roll_button.set_active (true);
2492 play_selection_button.set_active (false);
2493 auto_loop_button.set_active (false);
2496 if (UIConfiguration::instance().get_follow_edits() && !_session->config.get_external_sync()) {
2497 /* light up both roll and play-selection if they are joined */
2498 roll_button.set_active (true);
2499 play_selection_button.set_active (true);
2502 stop_button.set_active (false);
2506 stop_button.set_active (true);
2507 roll_button.set_active (false);
2508 play_selection_button.set_active (false);
2509 if (Config->get_loop_is_mode ()) {
2510 auto_loop_button.set_active (_session->get_play_loop());
2512 auto_loop_button.set_active (false);
2514 update_disk_space ();
2519 ARDOUR_UI::blink_handler (bool blink_on)
2521 transport_rec_enable_blink (blink_on);
2522 solo_blink (blink_on);
2523 sync_blink (blink_on);
2524 audition_blink (blink_on);
2525 feedback_blink (blink_on);
2526 error_blink (blink_on);
2530 ARDOUR_UI::update_clocks ()
2532 if (!_session) return;
2534 if (editor && !editor->dragging_playhead()) {
2535 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD)); /* EMIT_SIGNAL */
2540 ARDOUR_UI::start_clocking ()
2542 if (UIConfiguration::instance().get_super_rapid_clock_update()) {
2543 clock_signal_connection = Timers::fps_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2545 clock_signal_connection = Timers::rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2550 ARDOUR_UI::stop_clocking ()
2552 clock_signal_connection.disconnect ();
2556 ARDOUR_UI::save_as_progress_update (float fraction, int64_t cnt, int64_t total, Gtk::Label* label, Gtk::ProgressBar* bar)
2560 snprintf (buf, sizeof (buf), _("Copied %" PRId64 " of %" PRId64), cnt, total);
2562 label->set_text (buf);
2563 bar->set_fraction (fraction);
2565 /* process events, redraws, etc. */
2567 while (gtk_events_pending()) {
2568 gtk_main_iteration ();
2571 return true; /* continue with save-as */
2575 ARDOUR_UI::save_session_as ()
2581 if (!save_as_dialog) {
2582 save_as_dialog = new SaveAsDialog;
2585 save_as_dialog->set_name (_session->name());
2587 int response = save_as_dialog->run ();
2589 save_as_dialog->hide ();
2592 case Gtk::RESPONSE_OK:
2601 sa.new_parent_folder = save_as_dialog->new_parent_folder ();
2602 sa.new_name = save_as_dialog->new_name ();
2603 sa.switch_to = save_as_dialog->switch_to();
2604 sa.copy_media = save_as_dialog->copy_media();
2605 sa.copy_external = save_as_dialog->copy_external();
2606 sa.include_media = save_as_dialog->include_media ();
2608 /* Only bother with a progress dialog if we're going to copy
2609 media into the save-as target. Without that choice, this
2610 will be very fast because we're only talking about a few kB's to
2611 perhaps a couple of MB's of data.
2614 ArdourDialog progress_dialog (_("Save As"), true);
2616 if (sa.include_media && sa.copy_media) {
2619 Gtk::ProgressBar progress_bar;
2621 progress_dialog.get_vbox()->pack_start (label);
2622 progress_dialog.get_vbox()->pack_start (progress_bar);
2624 progress_bar.show ();
2626 /* this signal will be emitted from within this, the calling thread,
2627 * after every file is copied. It provides information on percentage
2628 * complete (in terms of total data to copy), the number of files
2629 * copied so far, and the total number to copy.
2634 sa.Progress.connect_same_thread (c, boost::bind (&ARDOUR_UI::save_as_progress_update, this, _1, _2, _3, &label, &progress_bar));
2636 progress_dialog.show_all ();
2637 progress_dialog.present ();
2640 if (_session->save_as (sa)) {
2642 MessageDialog msg (string_compose (_("Save As failed: %1"), sa.failure_message));
2646 if (!sa.include_media) {
2647 unload_session (false);
2648 load_session (sa.final_session_folder_name, sa.new_name);
2653 ARDOUR_UI::quick_snapshot_session (bool switch_to_it)
2657 struct tm local_time;
2660 localtime_r (&n, &local_time);
2661 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2663 save_state (timebuf, switch_to_it);
2668 ARDOUR_UI::process_snapshot_session_prompter (ArdourPrompter& prompter, bool switch_to_it)
2672 prompter.get_result (snapname);
2674 bool do_save = (snapname.length() != 0);
2677 char illegal = Session::session_name_is_legal(snapname);
2679 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2680 "snapshot names may not contain a '%1' character"), illegal));
2686 vector<std::string> p;
2687 get_state_files_in_directory (_session->session_directory().root_path(), p);
2688 vector<string> n = get_file_names_no_extension (p);
2690 if (find (n.begin(), n.end(), snapname) != n.end()) {
2692 do_save = overwrite_file_dialog (prompter,
2693 _("Confirm Snapshot Overwrite"),
2694 _("A snapshot already exists with that name. Do you want to overwrite it?"));
2698 save_state (snapname, switch_to_it);
2708 /** Ask the user for the name of a new snapshot and then take it.
2712 ARDOUR_UI::snapshot_session (bool switch_to_it)
2714 ArdourPrompter prompter (true);
2716 prompter.set_name ("Prompter");
2717 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2719 prompter.set_title (_("Snapshot and switch"));
2720 prompter.set_prompt (_("New session name"));
2722 prompter.set_title (_("Take Snapshot"));
2723 prompter.set_prompt (_("Name of new snapshot"));
2727 prompter.set_initial_text (_session->snap_name());
2731 struct tm local_time;
2734 localtime_r (&n, &local_time);
2735 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2736 prompter.set_initial_text (timebuf);
2739 bool finished = false;
2741 switch (prompter.run()) {
2742 case RESPONSE_ACCEPT:
2744 finished = process_snapshot_session_prompter (prompter, switch_to_it);
2755 /** Ask the user for a new session name and then rename the session to it.
2759 ARDOUR_UI::rename_session ()
2765 ArdourPrompter prompter (true);
2768 prompter.set_name ("Prompter");
2769 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2770 prompter.set_title (_("Rename Session"));
2771 prompter.set_prompt (_("New session name"));
2774 switch (prompter.run()) {
2775 case RESPONSE_ACCEPT:
2777 prompter.get_result (name);
2779 bool do_rename = (name.length() != 0);
2782 char illegal = Session::session_name_is_legal (name);
2785 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2786 "session names may not contain a '%1' character"), illegal));
2791 switch (_session->rename (name)) {
2793 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
2794 msg.set_position (WIN_POS_MOUSE);
2802 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
2803 msg.set_position (WIN_POS_MOUSE);
2819 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2821 if (!_session || _session->deletion_in_progress()) {
2825 XMLNode* node = new XMLNode (X_("UI"));
2827 WM::Manager::instance().add_state (*node);
2829 node->add_child_nocopy (gui_object_state->get_state());
2831 _session->add_extra_xml (*node);
2833 if (export_video_dialog) {
2834 _session->add_extra_xml (export_video_dialog->get_state());
2837 save_state_canfail (name, switch_to_it);
2841 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2846 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2851 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2856 ARDOUR_UI::primary_clock_value_changed ()
2859 _session->request_locate (primary_clock->current_time ());
2864 ARDOUR_UI::big_clock_value_changed ()
2867 _session->request_locate (big_clock->current_time ());
2872 ARDOUR_UI::secondary_clock_value_changed ()
2875 _session->request_locate (secondary_clock->current_time ());
2880 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2882 if (_session == 0) {
2886 if (_session->step_editing()) {
2890 Session::RecordState const r = _session->record_status ();
2891 bool const h = _session->have_rec_enabled_track ();
2893 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2895 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2897 rec_button.set_active_state (Gtkmm2ext::Off);
2899 } else if (r == Session::Recording && h) {
2900 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2902 rec_button.unset_active_state ();
2907 ARDOUR_UI::process_save_template_prompter (ArdourPrompter& prompter)
2911 prompter.get_result (name);
2913 if (name.length()) {
2914 int failed = _session->save_template (name);
2916 if (failed == -2) { /* file already exists. */
2917 bool overwrite = overwrite_file_dialog (prompter,
2918 _("Confirm Template Overwrite"),
2919 _("A template already exists with that name. Do you want to overwrite it?"));
2922 _session->save_template (name, true);
2934 ARDOUR_UI::save_template ()
2936 ArdourPrompter prompter (true);
2938 if (!check_audioengine (_main_window)) {
2942 prompter.set_name (X_("Prompter"));
2943 prompter.set_title (_("Save Template"));
2944 prompter.set_prompt (_("Name for template:"));
2945 prompter.set_initial_text(_session->name() + _("-template"));
2946 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2948 bool finished = false;
2950 switch (prompter.run()) {
2951 case RESPONSE_ACCEPT:
2952 finished = process_save_template_prompter (prompter);
2963 ARDOUR_UI::edit_metadata ()
2965 SessionMetadataEditor dialog;
2966 dialog.set_session (_session);
2967 dialog.grab_focus ();
2972 ARDOUR_UI::import_metadata ()
2974 SessionMetadataImporter dialog;
2975 dialog.set_session (_session);
2980 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
2982 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2984 MessageDialog msg (str,
2986 Gtk::MESSAGE_WARNING,
2987 Gtk::BUTTONS_YES_NO,
2991 msg.set_name (X_("OpenExistingDialog"));
2992 msg.set_title (_("Open Existing Session"));
2993 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
2994 msg.set_position (Gtk::WIN_POS_CENTER);
2995 pop_back_splash (msg);
2997 switch (msg.run()) {
3006 ARDOUR_UI::build_session_from_dialog (SessionDialog& sd, const std::string& session_path, const std::string& session_name)
3008 BusProfile bus_profile;
3012 bus_profile.master_out_channels = 2;
3013 bus_profile.input_ac = AutoConnectPhysical;
3014 bus_profile.output_ac = AutoConnectMaster;
3015 bus_profile.requested_physical_in = 0; // use all available
3016 bus_profile.requested_physical_out = 0; // use all available
3020 /* get settings from advanced section of NSD */
3022 if (sd.create_master_bus()) {
3023 bus_profile.master_out_channels = (uint32_t) sd.master_channel_count();
3025 bus_profile.master_out_channels = 0;
3028 if (sd.connect_inputs()) {
3029 bus_profile.input_ac = AutoConnectPhysical;
3031 bus_profile.input_ac = AutoConnectOption (0);
3034 bus_profile.output_ac = AutoConnectOption (0);
3036 if (sd.connect_outputs ()) {
3037 if (sd.connect_outs_to_master()) {
3038 bus_profile.output_ac = AutoConnectMaster;
3039 } else if (sd.connect_outs_to_physical()) {
3040 bus_profile.output_ac = AutoConnectPhysical;
3044 bus_profile.requested_physical_in = (uint32_t) sd.input_limit_count();
3045 bus_profile.requested_physical_out = (uint32_t) sd.output_limit_count();
3048 if (build_session (session_path, session_name, bus_profile)) {
3056 ARDOUR_UI::load_from_application_api (const std::string& path)
3058 ARDOUR_COMMAND_LINE::session_name = path;
3059 /* Cancel SessionDialog if it's visible to make OSX delegates work.
3061 * ARDOUR_UI::starting connects app->ShouldLoad signal and then shows a SessionDialog
3063 * - ShouldLoad does not arrive in time, ARDOUR_COMMAND_LINE::session_name is empty:
3064 * -> ARDOUR_UI::get_session_parameters starts a SessionDialog.
3065 * - ShouldLoad signal arrives, this function is called and sets ARDOUR_COMMAND_LINE::session_name
3066 * -> SessionDialog is not displayed
3069 if (_session_dialog) {
3070 std::string session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3071 std::string session_path = path;
3072 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_REGULAR)) {
3073 session_path = Glib::path_get_dirname (session_path);
3075 // signal the existing dialog in ARDOUR_UI::get_session_parameters()
3076 _session_dialog->set_provided_session (session_name, session_path);
3077 _session_dialog->response (RESPONSE_NONE);
3078 _session_dialog->hide();
3083 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
3084 /* /path/to/foo => /path/to/foo, foo */
3085 rv = load_session (path, basename_nosuffix (path));
3087 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
3088 rv =load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
3091 // if load_session fails -> pop up SessionDialog.
3093 ARDOUR_COMMAND_LINE::session_name = "";
3095 if (get_session_parameters (true, false)) {
3101 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
3103 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
3105 string session_name;
3106 string session_path;
3107 string template_name;
3109 bool likely_new = false;
3110 bool cancel_not_quit;
3112 /* deal with any existing DIRTY session now, rather than later. don't
3113 * treat a non-dirty session this way, so that it stays visible
3114 * as we bring up the new session dialog.
3117 if (_session && ARDOUR_UI::instance()->video_timeline) {
3118 ARDOUR_UI::instance()->video_timeline->sync_session_state();
3121 /* if there is already a session, relabel the button
3122 on the SessionDialog so that we don't Quit directly
3124 cancel_not_quit = (_session != 0);
3126 if (_session && _session->dirty()) {
3127 if (unload_session (false)) {
3128 /* unload cancelled by user */
3131 ARDOUR_COMMAND_LINE::session_name = "";
3134 if (!load_template.empty()) {
3135 should_be_new = true;
3136 template_name = load_template;
3139 session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3140 session_path = ARDOUR_COMMAND_LINE::session_name;
3142 if (!session_path.empty()) {
3143 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_EXISTS)) {
3144 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_IS_REGULAR)) {
3145 /* session/snapshot file, change path to be dir */
3146 session_path = Glib::path_get_dirname (session_path);
3151 SessionDialog session_dialog (should_be_new, session_name, session_path, load_template, cancel_not_quit);
3153 _session_dialog = &session_dialog;
3156 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
3158 /* if they named a specific statefile, use it, otherwise they are
3159 just giving a session folder, and we want to use it as is
3160 to find the session.
3163 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
3165 if (suffix != string::npos) {
3166 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
3167 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
3168 session_name = Glib::path_get_basename (session_name);
3170 session_path = ARDOUR_COMMAND_LINE::session_name;
3171 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
3176 session_dialog.clear_given ();
3179 if (should_be_new || session_name.empty()) {
3180 /* need the dialog to get info from user */
3182 cerr << "run dialog\n";
3184 switch (session_dialog.run()) {
3185 case RESPONSE_ACCEPT:
3188 /* this is used for async * app->ShouldLoad(). */
3189 continue; // while loop
3192 if (quit_on_cancel) {
3193 // JE - Currently (July 2014) this section can only get reached if the
3194 // user quits from the main 'Session Setup' dialog (i.e. reaching this
3195 // point does NOT indicate an abnormal termination). Therefore, let's
3196 // behave gracefully (i.e. let's do some cleanup) before we call exit()
3198 pthread_cancel_all ();
3206 session_dialog.hide ();
3209 /* if we run the startup dialog again, offer more than just "new session" */
3211 should_be_new = false;
3213 session_name = session_dialog.session_name (likely_new);
3214 session_path = session_dialog.session_folder ();
3220 string::size_type suffix = session_name.find (statefile_suffix);
3222 if (suffix != string::npos) {
3223 session_name = session_name.substr (0, suffix);
3226 /* this shouldn't happen, but we catch it just in case it does */
3228 if (session_name.empty()) {
3232 if (session_dialog.use_session_template()) {
3233 template_name = session_dialog.session_template_name();
3234 _session_is_new = true;
3237 if (session_name[0] == G_DIR_SEPARATOR ||
3238 #ifdef PLATFORM_WINDOWS
3239 (session_name.length() > 3 && session_name[1] == ':' && session_name[2] == G_DIR_SEPARATOR)
3241 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
3242 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)
3247 /* absolute path or cwd-relative path specified for session name: infer session folder
3248 from what was given.
3251 session_path = Glib::path_get_dirname (session_name);
3252 session_name = Glib::path_get_basename (session_name);
3256 session_path = session_dialog.session_folder();
3258 char illegal = Session::session_name_is_legal (session_name);
3261 MessageDialog msg (session_dialog,
3262 string_compose (_("To ensure compatibility with various systems\n"
3263 "session names may not contain a '%1' character"),
3266 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3271 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
3274 if (likely_new && !nsm) {
3276 std::string existing = Glib::build_filename (session_path, session_name);
3278 if (!ask_about_loading_existing_session (existing)) {
3279 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3284 _session_is_new = false;
3289 pop_back_splash (session_dialog);
3290 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
3292 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3296 char illegal = Session::session_name_is_legal(session_name);
3299 pop_back_splash (session_dialog);
3300 MessageDialog msg (session_dialog, string_compose(_("To ensure compatibility with various systems\n"
3301 "session names may not contain a '%1' character"), illegal));
3303 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3307 _session_is_new = true;
3310 if (likely_new && template_name.empty()) {
3312 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3316 ret = load_session (session_path, session_name, template_name);
3319 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
3323 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
3324 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
3328 /* clear this to avoid endless attempts to load the
3332 ARDOUR_COMMAND_LINE::session_name = "";
3336 _session_dialog = NULL;
3342 ARDOUR_UI::close_session()
3344 if (!check_audioengine (_main_window)) {
3348 if (unload_session (true)) {
3352 ARDOUR_COMMAND_LINE::session_name = "";
3354 if (get_session_parameters (true, false)) {
3357 if (splash && splash->is_visible()) {
3358 // in 1 second, hide the splash screen
3359 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
3363 /** @param snap_name Snapshot name (without .ardour suffix).
3364 * @return -2 if the load failed because we are not connected to the AudioEngine.
3367 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
3369 Session *new_session;
3374 unload_status = unload_session ();
3376 if (unload_status < 0) {
3378 } else if (unload_status > 0) {
3384 session_loaded = false;
3386 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
3389 new_session = new Session (*AudioEngine::instance(), path, snap_name, 0, mix_template);
3392 /* this one is special */
3394 catch (AudioEngine::PortRegistrationFailure& err) {
3396 MessageDialog msg (err.what(),
3399 Gtk::BUTTONS_CLOSE);
3401 msg.set_title (_("Port Registration Error"));
3402 msg.set_secondary_text (_("Click the Close button to try again."));
3403 msg.set_position (Gtk::WIN_POS_CENTER);
3404 pop_back_splash (msg);
3407 int response = msg.run ();
3412 case RESPONSE_CANCEL:
3419 catch (SessionException e) {
3420 MessageDialog msg (string_compose(
3421 _("Session \"%1 (snapshot %2)\" did not load successfully: %3"),
3422 path, snap_name, e.what()),
3427 msg.set_title (_("Loading Error"));
3428 msg.set_position (Gtk::WIN_POS_CENTER);
3429 pop_back_splash (msg);
3441 MessageDialog msg (string_compose(
3442 _("Session \"%1 (snapshot %2)\" did not load successfully"),
3448 msg.set_title (_("Loading Error"));
3449 msg.set_position (Gtk::WIN_POS_CENTER);
3450 pop_back_splash (msg);
3462 list<string> const u = new_session->unknown_processors ();
3464 MissingPluginDialog d (_session, u);
3469 if (!new_session->writable()) {
3470 MessageDialog msg (_("This session has been opened in read-only mode.\n\nYou will not be able to record or save."),
3475 msg.set_title (_("Read-only Session"));
3476 msg.set_position (Gtk::WIN_POS_CENTER);
3477 pop_back_splash (msg);
3484 /* Now the session been created, add the transport controls */
3485 new_session->add_controllable(roll_controllable);
3486 new_session->add_controllable(stop_controllable);
3487 new_session->add_controllable(goto_start_controllable);
3488 new_session->add_controllable(goto_end_controllable);
3489 new_session->add_controllable(auto_loop_controllable);
3490 new_session->add_controllable(play_selection_controllable);
3491 new_session->add_controllable(rec_controllable);
3493 set_session (new_session);
3495 session_loaded = true;
3498 _session->set_clean ();
3501 #ifdef WINDOWS_VST_SUPPORT
3502 fst_stop_threading();
3506 Timers::TimerSuspender t;
3510 #ifdef WINDOWS_VST_SUPPORT
3511 fst_start_threading();
3520 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
3522 Session *new_session;
3525 session_loaded = false;
3526 x = unload_session ();
3534 _session_is_new = true;
3537 new_session = new Session (*AudioEngine::instance(), path, snap_name, &bus_profile);
3540 catch (SessionException e) {
3542 MessageDialog msg (string_compose(_("Could not create session in \"%1\": %2"), path, e.what()));
3543 msg.set_title (_("Loading Error"));
3544 msg.set_position (Gtk::WIN_POS_CENTER);
3545 pop_back_splash (msg);
3551 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
3552 msg.set_title (_("Loading Error"));
3553 msg.set_position (Gtk::WIN_POS_CENTER);
3554 pop_back_splash (msg);
3559 /* Give the new session the default GUI state, if such things exist */
3562 n = Config->instant_xml (X_("Editor"));
3564 n->remove_nodes_and_delete ("Selection"); // no not apply selection to new sessions.
3565 new_session->add_instant_xml (*n, false);
3567 n = Config->instant_xml (X_("Mixer"));
3569 new_session->add_instant_xml (*n, false);
3572 /* Put the playhead at 0 and scroll fully left */
3573 n = new_session->instant_xml (X_("Editor"));
3575 n->add_property (X_("playhead"), X_("0"));
3576 n->add_property (X_("left-frame"), X_("0"));
3579 set_session (new_session);
3581 session_loaded = true;
3583 new_session->save_state(new_session->name());
3589 ARDOUR_UI::launch_chat ()
3591 MessageDialog dialog(_("<b>Just ask and wait for an answer.\nIt may take from minutes to hours.</b>"), true);
3593 dialog.set_title (_("About the Chat"));
3594 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."));
3596 switch (dialog.run()) {
3599 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
3600 #elif defined PLATFORM_WINDOWS
3601 open_uri("http://webchat.freenode.net/?channels=ardour-windows");
3603 open_uri("http://webchat.freenode.net/?channels=ardour");
3612 ARDOUR_UI::launch_manual ()
3614 PBD::open_uri (Config->get_tutorial_manual_url());
3618 ARDOUR_UI::launch_reference ()
3620 PBD::open_uri (Config->get_reference_manual_url());
3624 ARDOUR_UI::launch_tracker ()
3626 PBD::open_uri ("http://tracker.ardour.org");
3630 ARDOUR_UI::launch_subscribe ()
3632 PBD::open_uri ("https://community.ardour.org/s/subscribe");
3636 ARDOUR_UI::launch_cheat_sheet ()
3639 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheat_sheet_osx.pdf");
3641 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheatsheet.pdf");
3646 ARDOUR_UI::launch_website ()
3648 PBD::open_uri ("http://ardour.org");
3652 ARDOUR_UI::launch_website_dev ()
3654 PBD::open_uri ("http://ardour.org/development.html");
3658 ARDOUR_UI::launch_forums ()
3660 PBD::open_uri ("https://community.ardour.org/forums");
3664 ARDOUR_UI::launch_howto_report ()
3666 PBD::open_uri ("http://ardour.org/reporting_bugs");
3670 ARDOUR_UI::loading_message (const std::string& msg)
3672 if (ARDOUR_COMMAND_LINE::no_splash) {
3680 splash->message (msg);
3684 ARDOUR_UI::show_splash ()
3688 splash = new Splash;
3698 ARDOUR_UI::hide_splash ()
3705 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title, const bool msg_delete)
3709 removed = rep.paths.size();
3712 MessageDialog msgd (_main_window,
3713 _("No files were ready for clean-up"),
3717 msgd.set_title (_("Clean-up"));
3718 msgd.set_secondary_text (_("If this seems suprising, \n\
3719 check for any existing snapshots.\n\
3720 These may still include regions that\n\
3721 require some unused files to continue to exist."));
3727 ArdourDialog results (_("Clean-up"), true, false);
3729 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
3730 CleanupResultsModelColumns() {
3734 Gtk::TreeModelColumn<std::string> visible_name;
3735 Gtk::TreeModelColumn<std::string> fullpath;
3739 CleanupResultsModelColumns results_columns;
3740 Glib::RefPtr<Gtk::ListStore> results_model;
3741 Gtk::TreeView results_display;
3743 results_model = ListStore::create (results_columns);
3744 results_display.set_model (results_model);
3745 results_display.append_column (list_title, results_columns.visible_name);
3747 results_display.set_name ("CleanupResultsList");
3748 results_display.set_headers_visible (true);
3749 results_display.set_headers_clickable (false);
3750 results_display.set_reorderable (false);
3752 Gtk::ScrolledWindow list_scroller;
3755 Gtk::HBox dhbox; // the hbox for the image and text
3756 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
3757 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
3759 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
3761 const string dead_directory = _session->session_directory().dead_path();
3764 %1 - number of files removed
3765 %2 - location of "dead"
3766 %3 - size of files affected
3767 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
3770 const char* bprefix;
3771 double space_adjusted = 0;
3773 if (rep.space < 1000) {
3775 space_adjusted = rep.space;
3776 } else if (rep.space < 1000000) {
3777 bprefix = _("kilo");
3778 space_adjusted = floorf((float)rep.space / 1000.0);
3779 } else if (rep.space < 1000000 * 1000) {
3780 bprefix = _("mega");
3781 space_adjusted = floorf((float)rep.space / (1000.0 * 1000.0));
3783 bprefix = _("giga");
3784 space_adjusted = floorf((float)rep.space / (1000.0 * 1000 * 1000.0));
3788 txt.set_markup (string_compose (P_("\
3789 The following file was deleted from %2,\n\
3790 releasing %3 %4bytes of disk space", "\
3791 The following %1 files were deleted from %2,\n\
3792 releasing %3 %4bytes of disk space", removed),
3793 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3795 txt.set_markup (string_compose (P_("\
3796 The following file was not in use and \n\
3797 has been moved to: %2\n\n\
3798 After a restart of %5\n\n\
3799 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3800 will release an additional %3 %4bytes of disk space.\n", "\
3801 The following %1 files were not in use and \n\
3802 have been moved to: %2\n\n\
3803 After a restart of %5\n\n\
3804 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3805 will release an additional %3 %4bytes of disk space.\n", removed),
3806 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3809 dhbox.pack_start (*dimage, true, false, 5);
3810 dhbox.pack_start (txt, true, false, 5);
3812 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
3813 TreeModel::Row row = *(results_model->append());
3814 row[results_columns.visible_name] = *i;
3815 row[results_columns.fullpath] = *i;
3818 list_scroller.add (results_display);
3819 list_scroller.set_size_request (-1, 150);
3820 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
3822 dvbox.pack_start (dhbox, true, false, 5);
3823 dvbox.pack_start (list_scroller, true, false, 5);
3824 ddhbox.pack_start (dvbox, true, false, 5);
3826 results.get_vbox()->pack_start (ddhbox, true, false, 5);
3827 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
3828 results.set_default_response (RESPONSE_CLOSE);
3829 results.set_position (Gtk::WIN_POS_MOUSE);
3831 results_display.show();
3832 list_scroller.show();
3839 //results.get_vbox()->show();
3840 results.set_resizable (false);
3847 ARDOUR_UI::cleanup ()
3849 if (_session == 0) {
3850 /* shouldn't happen: menu item is insensitive */
3855 MessageDialog checker (_("Are you sure you want to clean-up?"),
3857 Gtk::MESSAGE_QUESTION,
3860 checker.set_title (_("Clean-up"));
3862 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
3863 ALL undo/redo information will be lost if you clean-up.\n\
3864 Clean-up will move all unused files to a \"dead\" location."));
3866 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3867 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
3868 checker.set_default_response (RESPONSE_CANCEL);
3870 checker.set_name (_("CleanupDialog"));
3871 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3872 checker.set_position (Gtk::WIN_POS_MOUSE);
3874 switch (checker.run()) {
3875 case RESPONSE_ACCEPT:
3881 ARDOUR::CleanupReport rep;
3883 editor->prepare_for_cleanup ();
3885 /* do not allow flush until a session is reloaded */
3887 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3889 act->set_sensitive (false);
3892 if (_session->cleanup_sources (rep)) {
3893 editor->finish_cleanup ();
3897 editor->finish_cleanup ();
3900 display_cleanup_results (rep, _("Cleaned Files"), false);
3904 ARDOUR_UI::flush_trash ()
3906 if (_session == 0) {
3907 /* shouldn't happen: menu item is insensitive */
3911 ARDOUR::CleanupReport rep;
3913 if (_session->cleanup_trash_sources (rep)) {
3917 display_cleanup_results (rep, _("deleted file"), true);
3921 ARDOUR_UI::cleanup_peakfiles ()
3923 if (_session == 0) {
3924 /* shouldn't happen: menu item is insensitive */
3928 if (! _session->can_cleanup_peakfiles ()) {
3932 // get all region-views in this session
3934 TrackViewList empty;
3936 editor->get_regions_after(rs, (framepos_t) 0, empty);
3937 std::list<RegionView*> views = rs.by_layer();
3939 // remove displayed audio-region-views waveforms
3940 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
3941 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
3942 if (!arv) { continue ; }
3943 arv->delete_waves();
3946 // cleanup peak files:
3947 // - stop pending peakfile threads
3948 // - close peakfiles if any
3949 // - remove peak dir in session
3950 // - setup peakfiles (background thread)
3951 _session->cleanup_peakfiles ();
3953 // re-add waves to ARV
3954 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
3955 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
3956 if (!arv) { continue ; }
3957 arv->create_waves();
3961 PresentationInfo::order_t
3962 ARDOUR_UI::translate_order (AddRouteDialog::InsertAt place)
3964 if (editor->get_selection().tracks.empty()) {
3965 return PresentationInfo::max_order;
3968 PresentationInfo::order_t order_hint = PresentationInfo::max_order;
3971 we want the new routes to have their order keys set starting from
3972 the highest order key in the selection + 1 (if available).
3975 if (place == AddRouteDialog::AfterSelection) {
3976 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.back());
3978 order_hint = rtav->route()->presentation_info().order();
3981 } else if (place == AddRouteDialog::BeforeSelection) {
3982 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.front());
3984 order_hint = rtav->route()->presentation_info().order();
3986 } else if (place == AddRouteDialog::First) {
3989 /* leave order_hint at max_order */
3996 ARDOUR_UI::start_duplicate_routes ()
3998 if (!duplicate_routes_dialog) {
3999 duplicate_routes_dialog = new DuplicateRouteDialog;
4002 if (duplicate_routes_dialog->restart (_session)) {
4006 duplicate_routes_dialog->present ();
4010 ARDOUR_UI::add_route ()
4012 if (!add_route_dialog.get (false)) {
4013 add_route_dialog->signal_response().connect (sigc::mem_fun (*this, &ARDOUR_UI::add_route_dialog_finished));
4020 if (add_route_dialog->is_visible()) {
4021 /* we're already doing this */
4025 add_route_dialog->set_position (WIN_POS_MOUSE);
4026 add_route_dialog->present();
4030 ARDOUR_UI::add_route_dialog_finished (int r)
4034 add_route_dialog->hide();
4037 case RESPONSE_ACCEPT:
4044 if ((count = add_route_dialog->count()) <= 0) {
4048 PresentationInfo::order_t order = translate_order (add_route_dialog->insert_at());
4049 string template_path = add_route_dialog->track_template();
4050 DisplaySuspender ds;
4052 if (!template_path.empty()) {
4053 if (add_route_dialog->name_template_is_default()) {
4054 _session->new_route_from_template (count, template_path, string());
4056 _session->new_route_from_template (count, template_path, add_route_dialog->name_template());
4061 ChanCount input_chan= add_route_dialog->channels ();
4062 ChanCount output_chan;
4063 string name_template = add_route_dialog->name_template ();
4064 PluginInfoPtr instrument = add_route_dialog->requested_instrument ();
4065 RouteGroup* route_group = add_route_dialog->route_group ();
4066 AutoConnectOption oac = Config->get_output_auto_connect();
4067 bool strict_io = add_route_dialog->use_strict_io ();
4069 if (oac & AutoConnectMaster) {
4070 output_chan.set (DataType::AUDIO, (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan.n_audio()));
4071 output_chan.set (DataType::MIDI, 0);
4073 output_chan = input_chan;
4076 /* XXX do something with name template */
4078 switch (add_route_dialog->type_wanted()) {
4079 case AddRouteDialog::AudioTrack:
4080 session_add_audio_track (input_chan.n_audio(), output_chan.n_audio(), add_route_dialog->mode(), route_group, count, name_template, strict_io, order);
4082 case AddRouteDialog::MidiTrack:
4083 session_add_midi_track (route_group, count, name_template, strict_io, instrument, 0, order);
4085 case AddRouteDialog::MixedTrack:
4086 session_add_mixed_track (input_chan, output_chan, route_group, count, name_template, strict_io, instrument, 0, order);
4088 case AddRouteDialog::AudioBus:
4089 session_add_audio_bus (input_chan.n_audio(), output_chan.n_audio(), route_group, count, name_template, strict_io, order);
4091 case AddRouteDialog::MidiBus:
4092 session_add_midi_bus (route_group, count, name_template, strict_io, instrument, 0, order);
4094 case AddRouteDialog::VCAMaster:
4095 session_add_vca (name_template, count);
4101 ARDOUR_UI::add_lua_script ()
4107 LuaScriptInfoPtr spi;
4108 ScriptSelector ss ("Add Lua Session Script", LuaScriptInfo::Session);
4109 switch (ss.run ()) {
4110 case Gtk::RESPONSE_ACCEPT:
4118 std::string script = "";
4121 script = Glib::file_get_contents (spi->path);
4122 } catch (Glib::FileError e) {
4123 string msg = string_compose (_("Cannot read session script '%1': %2"), spi->path, e.what());
4124 MessageDialog am (msg);
4129 LuaScriptParamList lsp = LuaScriptParams::script_params (spi, "sess_params");
4130 std::vector<std::string> reg = _session->registered_lua_functions ();
4132 ScriptParameterDialog spd (_("Set Script Parameters"), spi, reg, lsp);
4133 switch (spd.run ()) {
4134 case Gtk::RESPONSE_ACCEPT:
4141 _session->register_lua_function (spd.name(), script, lsp);
4142 } catch (luabridge::LuaException const& e) {
4143 string msg = string_compose (_("Session script '%1' instantiation failed: %2"), spd.name(), e.what ());
4144 MessageDialog am (msg);
4146 } catch (SessionException e) {
4147 string msg = string_compose (_("Loading Session script '%1' failed: %2"), spd.name(), e.what ());
4148 MessageDialog am (msg);
4154 ARDOUR_UI::remove_lua_script ()
4159 if (_session->registered_lua_function_count () == 0) {
4160 string msg = _("There are no active Lua session scripts present in this session.");
4161 MessageDialog am (msg);
4166 std::vector<std::string> reg = _session->registered_lua_functions ();
4167 SessionScriptManager sm ("Remove Lua Session Script", reg);
4168 switch (sm.run ()) {
4169 case Gtk::RESPONSE_ACCEPT:
4175 _session->unregister_lua_function (sm.name());
4176 } catch (luabridge::LuaException const& e) {
4177 string msg = string_compose (_("Session script '%1' removal failed: %2"), sm.name(), e.what ());
4178 MessageDialog am (msg);
4184 ARDOUR_UI::stop_video_server (bool ask_confirm)
4186 if (!video_server_process && ask_confirm) {
4187 warning << string_compose (_("Video-Server was not launched by %1. The request to stop it is ignored."), PROGRAM_NAME) << endmsg;
4189 if (video_server_process) {
4191 ArdourDialog confirm (_("Stop Video-Server"), true);
4192 Label m (_("Do you really want to stop the Video Server?"));
4193 confirm.get_vbox()->pack_start (m, true, true);
4194 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
4195 confirm.add_button (_("Yes, Stop It"), Gtk::RESPONSE_ACCEPT);
4196 confirm.show_all ();
4197 if (confirm.run() == RESPONSE_CANCEL) {
4201 delete video_server_process;
4202 video_server_process =0;
4207 ARDOUR_UI::start_video_server_menu (Gtk::Window* float_window)
4209 ARDOUR_UI::start_video_server( float_window, true);
4213 ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg)
4219 if (ARDOUR_UI::instance()->video_timeline->check_server()) {
4220 if (video_server_process) {
4221 popup_error(_("The Video Server is already started."));
4223 popup_error(_("An external Video Server is configured and can be reached. Not starting a new instance."));
4229 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4231 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4233 VideoServerDialog *video_server_dialog = new VideoServerDialog (_session);
4235 video_server_dialog->set_transient_for (*float_window);
4238 if (!Config->get_show_video_server_dialog() && firsttime < 2) {
4239 video_server_dialog->hide();
4241 ResponseType r = (ResponseType) video_server_dialog->run ();
4242 video_server_dialog->hide();
4243 if (r != RESPONSE_ACCEPT) { return false; }
4244 if (video_server_dialog->show_again()) {
4245 Config->set_show_video_server_dialog(false);
4249 std::string icsd_exec = video_server_dialog->get_exec_path();
4250 std::string icsd_docroot = video_server_dialog->get_docroot();
4251 if (icsd_docroot.empty()) {
4252 #ifndef PLATFORM_WINDOWS
4253 icsd_docroot = X_("/");
4255 icsd_docroot = X_("C:\\");
4260 if (g_lstat (icsd_docroot.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode)) {
4261 warning << _("Specified docroot is not an existing directory.") << endmsg;
4264 #ifndef PLATFORM_WINDOWS
4265 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4266 || (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0 ) {
4267 warning << _("Given Video Server is not an executable file.") << endmsg;
4271 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4272 || (sb.st_mode & (S_IXUSR)) == 0 ) {
4273 warning << _("Given Video Server is not an executable file.") << endmsg;
4279 argp=(char**) calloc(9,sizeof(char*));
4280 argp[0] = strdup(icsd_exec.c_str());
4281 argp[1] = strdup("-P");
4282 argp[2] = (char*) calloc(16,sizeof(char)); snprintf(argp[2], 16, "%s", video_server_dialog->get_listenaddr().c_str());
4283 argp[3] = strdup("-p");
4284 argp[4] = (char*) calloc(6,sizeof(char)); snprintf(argp[4], 6, "%i", video_server_dialog->get_listenport());
4285 argp[5] = strdup("-C");
4286 argp[6] = (char*) calloc(6,sizeof(char)); snprintf(argp[6], 6, "%i", video_server_dialog->get_cachesize());
4287 argp[7] = strdup(icsd_docroot.c_str());
4289 stop_video_server();
4291 if (icsd_docroot == X_("/") || icsd_docroot == X_("C:\\")) {
4292 Config->set_video_advanced_setup(false);
4294 std::ostringstream osstream;
4295 osstream << "http://127.0.0.1:" << video_server_dialog->get_listenport() << "/";
4296 Config->set_video_server_url(osstream.str());
4297 Config->set_video_server_docroot(icsd_docroot);
4298 Config->set_video_advanced_setup(true);
4301 if (video_server_process) {
4302 delete video_server_process;
4305 video_server_process = new ARDOUR::SystemExec(icsd_exec, argp);
4306 if (video_server_process->start()) {
4307 warning << _("Cannot launch the video-server") << endmsg;
4310 int timeout = 120; // 6 sec
4311 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4312 Glib::usleep (50000);
4314 if (--timeout <= 0 || !video_server_process->is_running()) break;
4317 warning << _("Video-server was started but does not respond to requests...") << endmsg;
4319 if (!ARDOUR_UI::instance()->video_timeline->check_server_docroot()) {
4320 delete video_server_process;
4321 video_server_process = 0;
4329 ARDOUR_UI::add_video (Gtk::Window* float_window)
4335 if (!start_video_server(float_window, false)) {
4336 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4341 add_video_dialog->set_transient_for (*float_window);
4344 if (add_video_dialog->is_visible()) {
4345 /* we're already doing this */
4349 ResponseType r = (ResponseType) add_video_dialog->run ();
4350 add_video_dialog->hide();
4351 if (r != RESPONSE_ACCEPT) { return; }
4353 bool local_file, orig_local_file;
4354 std::string path = add_video_dialog->file_name(local_file);
4356 std::string orig_path = path;
4357 orig_local_file = local_file;
4359 bool auto_set_session_fps = add_video_dialog->auto_set_session_fps();
4361 if (local_file && !Glib::file_test(path, Glib::FILE_TEST_EXISTS)) {
4362 warning << string_compose(_("could not open %1"), path) << endmsg;
4365 if (!local_file && path.length() == 0) {
4366 warning << _("no video-file selected") << endmsg;
4370 std::string audio_from_video;
4371 bool detect_ltc = false;
4373 switch (add_video_dialog->import_option()) {
4374 case VTL_IMPORT_TRANSCODE:
4376 TranscodeVideoDialog *transcode_video_dialog;
4377 transcode_video_dialog = new TranscodeVideoDialog (_session, path);
4378 ResponseType r = (ResponseType) transcode_video_dialog->run ();
4379 transcode_video_dialog->hide();
4380 if (r != RESPONSE_ACCEPT) {
4381 delete transcode_video_dialog;
4385 audio_from_video = transcode_video_dialog->get_audiofile();
4387 if (!audio_from_video.empty() && transcode_video_dialog->detect_ltc()) {
4390 else if (!audio_from_video.empty()) {
4391 editor->embed_audio_from_video(
4393 video_timeline->get_offset(),
4394 (transcode_video_dialog->import_option() != VTL_IMPORT_NO_VIDEO)
4397 switch (transcode_video_dialog->import_option()) {
4398 case VTL_IMPORT_TRANSCODED:
4399 path = transcode_video_dialog->get_filename();
4402 case VTL_IMPORT_REFERENCE:
4405 delete transcode_video_dialog;
4408 delete transcode_video_dialog;
4412 case VTL_IMPORT_NONE:
4416 /* strip _session->session_directory().video_path() from video file if possible */
4417 if (local_file && !path.compare(0, _session->session_directory().video_path().size(), _session->session_directory().video_path())) {
4418 path=path.substr(_session->session_directory().video_path().size());
4419 if (path.at(0) == G_DIR_SEPARATOR) {
4420 path=path.substr(1);
4424 video_timeline->set_update_session_fps(auto_set_session_fps);
4426 if (video_timeline->video_file_info(path, local_file)) {
4427 XMLNode* node = new XMLNode(X_("Videotimeline"));
4428 node->add_property (X_("Filename"), path);
4429 node->add_property (X_("AutoFPS"), auto_set_session_fps?X_("1"):X_("0"));
4430 node->add_property (X_("LocalFile"), local_file?X_("1"):X_("0"));
4431 if (orig_local_file) {
4432 node->add_property (X_("OriginalVideoFile"), orig_path);
4434 node->remove_property (X_("OriginalVideoFile"));
4436 _session->add_extra_xml (*node);
4437 _session->set_dirty ();
4439 if (!audio_from_video.empty() && detect_ltc) {
4440 std::vector<LTCFileReader::LTCMap> ltc_seq;
4443 /* TODO ask user about TV standard (LTC alignment if any) */
4444 LTCFileReader ltcr (audio_from_video, video_timeline->get_video_file_fps());
4445 /* TODO ASK user which channel: 0 .. ltcr->channels() - 1 */
4447 ltc_seq = ltcr.read_ltc (/*channel*/ 0, /*max LTC frames to decode*/ 15);
4449 /* TODO seek near end of file, and read LTC until end.
4450 * if it fails to find any LTC frames, scan complete file
4452 * calculate drift of LTC compared to video-duration,
4453 * ask user for reference (timecode from start/mid/end)
4456 // LTCFileReader will have written error messages
4459 ::g_unlink(audio_from_video.c_str());
4461 if (ltc_seq.size() == 0) {
4462 PBD::error << _("No LTC detected, video will not be aligned.") << endmsg;
4464 /* the very first TC in the file is somteimes not aligned properly */
4465 int i = ltc_seq.size() -1;
4466 ARDOUR::frameoffset_t video_start_offset =
4467 _session->nominal_frame_rate() * (ltc_seq[i].timecode_sec - ltc_seq[i].framepos_sec);
4468 PBD::info << string_compose (_("Align video-start to %1 [samples]"), video_start_offset) << endmsg;
4469 video_timeline->set_offset(video_start_offset);
4473 _session->maybe_update_session_range(
4474 std::max(video_timeline->get_offset(), (ARDOUR::frameoffset_t) 0),
4475 std::max(video_timeline->get_offset() + video_timeline->get_duration(), (ARDOUR::frameoffset_t) 0));
4478 if (add_video_dialog->launch_xjadeo() && local_file) {
4479 editor->set_xjadeo_sensitive(true);
4480 editor->toggle_xjadeo_proc(1);
4482 editor->toggle_xjadeo_proc(0);
4484 editor->toggle_ruler_video(true);
4489 ARDOUR_UI::remove_video ()
4491 video_timeline->close_session();
4492 editor->toggle_ruler_video(false);
4495 video_timeline->set_offset_locked(false);
4496 video_timeline->set_offset(0);
4498 /* delete session state */
4499 XMLNode* node = new XMLNode(X_("Videotimeline"));
4500 _session->add_extra_xml(*node);
4501 node = new XMLNode(X_("Videomonitor"));
4502 _session->add_extra_xml(*node);
4503 node = new XMLNode(X_("Videoexport"));
4504 _session->add_extra_xml(*node);
4505 stop_video_server();
4509 ARDOUR_UI::flush_videotimeline_cache (bool localcacheonly)
4511 if (localcacheonly) {
4512 video_timeline->vmon_update();
4514 video_timeline->flush_cache();
4516 editor->queue_visual_videotimeline_update();
4520 ARDOUR_UI::export_video (bool range)
4522 if (ARDOUR::Config->get_show_video_export_info()) {
4523 ExportVideoInfobox infobox (_session);
4524 Gtk::ResponseType rv = (Gtk::ResponseType) infobox.run();
4525 if (infobox.show_again()) {
4526 ARDOUR::Config->set_show_video_export_info(false);
4529 case GTK_RESPONSE_YES:
4530 PBD::open_uri (ARDOUR::Config->get_reference_manual_url() + "/video-timeline/operations/#export");
4536 export_video_dialog->set_session (_session);
4537 export_video_dialog->apply_state(editor->get_selection().time, range);
4538 export_video_dialog->run ();
4539 export_video_dialog->hide ();
4543 ARDOUR_UI::mixer_settings () const
4548 node = _session->instant_xml(X_("Mixer"));
4550 node = Config->instant_xml(X_("Mixer"));
4554 node = new XMLNode (X_("Mixer"));
4561 ARDOUR_UI::main_window_settings () const
4566 node = _session->instant_xml(X_("Main"));
4568 node = Config->instant_xml(X_("Main"));
4572 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4573 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4578 node = new XMLNode (X_("Main"));
4585 ARDOUR_UI::editor_settings () const
4590 node = _session->instant_xml(X_("Editor"));
4592 node = Config->instant_xml(X_("Editor"));
4596 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4597 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4602 node = new XMLNode (X_("Editor"));
4609 ARDOUR_UI::keyboard_settings () const
4613 node = Config->extra_xml(X_("Keyboard"));
4616 node = new XMLNode (X_("Keyboard"));
4623 ARDOUR_UI::create_xrun_marker (framepos_t where)
4626 Location *location = new Location (*_session, where, where, _("xrun"), Location::IsMark);
4627 _session->locations()->add (location);
4632 ARDOUR_UI::halt_on_xrun_message ()
4634 cerr << "HALT on xrun\n";
4635 MessageDialog msg (_main_window, _("Recording was stopped because your system could not keep up."));
4640 ARDOUR_UI::xrun_handler (framepos_t where)
4646 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
4648 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
4649 create_xrun_marker(where);
4652 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
4653 halt_on_xrun_message ();
4658 ARDOUR_UI::disk_overrun_handler ()
4660 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
4662 if (!have_disk_speed_dialog_displayed) {
4663 have_disk_speed_dialog_displayed = true;
4664 MessageDialog* msg = new MessageDialog (_main_window, string_compose (_("\
4665 The disk system on your computer\n\
4666 was not able to keep up with %1.\n\
4668 Specifically, it failed to write data to disk\n\
4669 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
4670 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4676 /* TODO: this is getting elaborate enough to warrant being split into a dedicated class */
4677 static MessageDialog *scan_dlg = NULL;
4678 static ProgressBar *scan_pbar = NULL;
4679 static HBox *scan_tbox = NULL;
4680 static Gtk::Button *scan_timeout_button;
4683 ARDOUR_UI::cancel_plugin_scan ()
4685 PluginManager::instance().cancel_plugin_scan();
4689 ARDOUR_UI::cancel_plugin_timeout ()
4691 PluginManager::instance().cancel_plugin_timeout();
4692 scan_timeout_button->set_sensitive (false);
4696 ARDOUR_UI::plugin_scan_timeout (int timeout)
4698 if (!scan_dlg || !scan_dlg->is_mapped() || !scan_pbar) {
4702 scan_pbar->set_sensitive (false);
4703 scan_timeout_button->set_sensitive (true);
4704 scan_pbar->set_fraction ((float) timeout / (float) Config->get_vst_scan_timeout());
4707 scan_pbar->set_sensitive (false);
4708 scan_timeout_button->set_sensitive (false);
4714 ARDOUR_UI::plugin_scan_dialog (std::string type, std::string plugin, bool can_cancel)
4716 if (type == X_("closeme") && !(scan_dlg && scan_dlg->is_mapped())) {
4720 const bool cancelled = PluginManager::instance().cancelled();
4721 if (type != X_("closeme") && (!UIConfiguration::instance().get_show_plugin_scan_window()) && !_initial_verbose_plugin_scan) {
4722 if (cancelled && scan_dlg->is_mapped()) {
4727 if (cancelled || !can_cancel) {
4732 static Gtk::Button *cancel_button;
4734 scan_dlg = new MessageDialog("", false, MESSAGE_INFO, BUTTONS_NONE); // TODO manage
4735 VBox* vbox = scan_dlg->get_vbox();
4736 vbox->set_size_request(400,-1);
4737 scan_dlg->set_title (_("Scanning for plugins"));
4739 cancel_button = manage(new Gtk::Button(_("Cancel plugin scan")));
4740 cancel_button->set_name ("EditorGTKButton");
4741 cancel_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_scan) );
4742 cancel_button->show();
4744 scan_dlg->get_vbox()->pack_start ( *cancel_button, PACK_SHRINK);
4746 scan_tbox = manage( new HBox() );
4748 scan_timeout_button = manage(new Gtk::Button(_("Stop Timeout")));
4749 scan_timeout_button->set_name ("EditorGTKButton");
4750 scan_timeout_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_timeout) );
4751 scan_timeout_button->show();
4753 scan_pbar = manage(new ProgressBar());
4754 scan_pbar->set_orientation(Gtk::PROGRESS_RIGHT_TO_LEFT);
4755 scan_pbar->set_text(_("Scan Timeout"));
4758 scan_tbox->pack_start (*scan_pbar, PACK_EXPAND_WIDGET, 4);
4759 scan_tbox->pack_start (*scan_timeout_button, PACK_SHRINK, 4);
4761 scan_dlg->get_vbox()->pack_start (*scan_tbox, PACK_SHRINK, 4);
4764 assert(scan_dlg && scan_tbox && cancel_button);
4766 if (type == X_("closeme")) {
4770 scan_dlg->set_message(type + ": " + Glib::path_get_basename(plugin));
4773 if (!can_cancel || !cancelled) {
4774 scan_timeout_button->set_sensitive(false);
4776 cancel_button->set_sensitive(can_cancel && !cancelled);
4782 ARDOUR_UI::gui_idle_handler ()
4785 /* due to idle calls, gtk_events_pending() may always return true */
4786 while (gtk_events_pending() && --timeout) {
4787 gtk_main_iteration ();
4792 ARDOUR_UI::disk_underrun_handler ()
4794 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
4796 if (!have_disk_speed_dialog_displayed) {
4797 have_disk_speed_dialog_displayed = true;
4798 MessageDialog* msg = new MessageDialog (
4799 _main_window, string_compose (_("The disk system on your computer\n\
4800 was not able to keep up with %1.\n\
4802 Specifically, it failed to read data from disk\n\
4803 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
4804 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4810 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
4812 have_disk_speed_dialog_displayed = false;
4817 ARDOUR_UI::session_dialog (std::string msg)
4819 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
4823 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
4830 ARDOUR_UI::pending_state_dialog ()
4832 HBox* hbox = manage (new HBox());
4833 Image* image = manage (new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG));
4834 ArdourDialog dialog (_("Crash Recovery"), true);
4835 Label message (string_compose (_("\
4836 This session appears to have been in the\n\
4837 middle of recording when %1 or\n\
4838 the computer was shutdown.\n\
4840 %1 can recover any captured audio for\n\
4841 you, or it can ignore it. Please decide\n\
4842 what you would like to do.\n"), PROGRAM_NAME));
4843 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4844 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4845 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4846 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4847 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
4848 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
4849 dialog.set_default_response (RESPONSE_ACCEPT);
4850 dialog.set_position (WIN_POS_CENTER);
4855 switch (dialog.run ()) {
4856 case RESPONSE_ACCEPT:
4864 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
4866 HBox* hbox = new HBox();
4867 Image* image = new Image (Stock::DIALOG_WARNING, ICON_SIZE_DIALOG);
4868 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
4869 Label message (string_compose (_("\
4870 This session was created with a sample rate of %1 Hz, but\n\
4871 %2 is currently running at %3 Hz. If you load this session,\n\
4872 audio may be played at the wrong sample rate.\n"), desired, PROGRAM_NAME, actual));
4874 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4875 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4876 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4877 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4878 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
4879 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
4880 dialog.set_default_response (RESPONSE_ACCEPT);
4881 dialog.set_position (WIN_POS_CENTER);
4886 switch (dialog.run()) {
4887 case RESPONSE_ACCEPT:
4897 ARDOUR_UI::sr_mismatch_message (framecnt_t desired, framecnt_t actual)
4899 MessageDialog msg (string_compose (_("\
4900 This session was created with a sample rate of %1 Hz, but\n\
4901 %2 is currently running at %3 Hz.\n\
4902 Audio will be recorded and played at the wrong sample rate.\n\
4903 Re-Configure the Audio Engine in\n\
4904 Menu > Window > Audio/Midi Setup"),
4905 desired, PROGRAM_NAME, actual),
4907 Gtk::MESSAGE_WARNING);
4912 ARDOUR_UI::use_config ()
4914 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
4916 set_transport_controllable_state (*node);
4921 ARDOUR_UI::update_transport_clocks (framepos_t pos)
4923 if (UIConfiguration::instance().get_primary_clock_delta_edit_cursor()) {
4924 primary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
4926 primary_clock->set (pos);
4929 if (UIConfiguration::instance().get_secondary_clock_delta_edit_cursor()) {
4930 secondary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
4932 secondary_clock->set (pos);
4935 if (big_clock_window) {
4936 big_clock->set (pos);
4938 ARDOUR_UI::instance()->video_timeline->manual_seek_video_monitor(pos);
4942 ARDOUR_UI::step_edit_status_change (bool yn)
4944 // XXX should really store pre-step edit status of things
4945 // we make insensitive
4948 rec_button.set_active_state (Gtkmm2ext::ImplicitActive);
4949 rec_button.set_sensitive (false);
4951 rec_button.unset_active_state ();;
4952 rec_button.set_sensitive (true);
4957 ARDOUR_UI::record_state_changed ()
4959 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
4961 if (!_session || !big_clock_window) {
4962 /* why bother - the clock isn't visible */
4966 if (_session->record_status () == Session::Recording && _session->have_rec_enabled_track ()) {
4967 big_clock->set_active (true);
4969 big_clock->set_active (false);
4974 ARDOUR_UI::first_idle ()
4977 _session->allow_auto_play (true);
4981 editor->first_idle();
4984 Keyboard::set_can_save_keybindings (true);
4989 ARDOUR_UI::store_clock_modes ()
4991 XMLNode* node = new XMLNode(X_("ClockModes"));
4993 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
4994 XMLNode* child = new XMLNode (X_("Clock"));
4996 child->add_property (X_("name"), (*x)->name());
4997 child->add_property (X_("mode"), enum_2_string ((*x)->mode()));
4998 child->add_property (X_("on"), ((*x)->off() ? X_("no") : X_("yes")));
5000 node->add_child_nocopy (*child);
5003 _session->add_extra_xml (*node);
5004 _session->set_dirty ();
5007 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
5008 : Controllable (name), ui (u), type(tp)
5014 ARDOUR_UI::TransportControllable::set_value (double val, PBD::Controllable::GroupControlDisposition /*group_override*/)
5017 /* do nothing: these are radio-style actions */
5021 const char *action = 0;
5025 action = X_("Roll");
5028 action = X_("Stop");
5031 action = X_("GotoStart");
5034 action = X_("GotoEnd");
5037 action = X_("Loop");
5040 action = X_("PlaySelection");
5043 action = X_("Record");
5053 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
5061 ARDOUR_UI::TransportControllable::get_value (void) const
5088 ARDOUR_UI::setup_profile ()
5090 if (gdk_screen_width() < 1200 || getenv ("ARDOUR_NARROW_SCREEN")) {
5091 Profile->set_small_screen ();
5094 if (g_getenv ("TRX")) {
5095 Profile->set_trx ();
5098 if (g_getenv ("MIXBUS")) {
5099 Profile->set_mixbus ();
5104 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
5106 MissingFileDialog dialog (s, str, type);
5111 int result = dialog.run ();
5118 return 1; // quit entire session load
5121 result = dialog.get_action ();
5127 ARDOUR_UI::ambiguous_file (std::string file, std::vector<std::string> hits)
5129 AmbiguousFileDialog dialog (file, hits);
5136 return dialog.get_which ();
5139 /** Allocate our thread-local buffers */
5141 ARDOUR_UI::get_process_buffers ()
5143 _process_thread->get_buffers ();
5146 /** Drop our thread-local buffers */
5148 ARDOUR_UI::drop_process_buffers ()
5150 _process_thread->drop_buffers ();
5154 ARDOUR_UI::feedback_detected ()
5156 _feedback_exists = true;
5160 ARDOUR_UI::successful_graph_sort ()
5162 _feedback_exists = false;
5166 ARDOUR_UI::midi_panic ()
5169 _session->midi_panic();
5174 ARDOUR_UI::session_format_mismatch (std::string xml_path, std::string backup_path)
5176 const char* start_big = "<span size=\"x-large\" weight=\"bold\">";
5177 const char* end_big = "</span>";
5178 const char* start_mono = "<tt>";
5179 const char* end_mono = "</tt>";
5181 MessageDialog msg (string_compose (_("%4This is a session from an older version of %3%5\n\n"
5182 "%3 has copied the old session file\n\n%6%1%7\n\nto\n\n%6%2%7\n\n"
5183 "From now on, use the backup copy with older versions of %3"),
5184 xml_path, backup_path, PROGRAM_NAME,
5186 start_mono, end_mono), true);
5193 ARDOUR_UI::reset_peak_display ()
5195 if (!_session || !_session->master_out() || !editor_meter) return;
5196 editor_meter->clear_meters();
5197 editor_meter_max_peak = -INFINITY;
5198 editor_meter_peak_display.set_active_state ( Gtkmm2ext::Off );
5202 ARDOUR_UI::reset_group_peak_display (RouteGroup* group)
5204 if (!_session || !_session->master_out()) return;
5205 if (group == _session->master_out()->route_group()) {
5206 reset_peak_display ();
5211 ARDOUR_UI::reset_route_peak_display (Route* route)
5213 if (!_session || !_session->master_out()) return;
5214 if (_session->master_out().get() == route) {
5215 reset_peak_display ();
5220 ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate)
5222 audio_midi_setup->set_desired_sample_rate (desired_sample_rate);
5223 audio_midi_setup->set_position (WIN_POS_CENTER);
5225 if (Config->get_try_autostart_engine () || getenv ("TRY_AUTOSTART_ENGINE")) {
5226 audio_midi_setup->try_autostart ();
5227 if (ARDOUR::AudioEngine::instance()->running()) {
5233 int response = audio_midi_setup->run();
5235 case Gtk::RESPONSE_OK:
5236 if (!AudioEngine::instance()->running()) {
5250 ARDOUR_UI::transport_numpad_timeout ()
5252 _numpad_locate_happening = false;
5253 if (_numpad_timeout_connection.connected() )
5254 _numpad_timeout_connection.disconnect();
5259 ARDOUR_UI::transport_numpad_decimal ()
5261 _numpad_timeout_connection.disconnect();
5263 if (_numpad_locate_happening) {
5264 if (editor) editor->goto_nth_marker(_pending_locate_num - 1);
5265 _numpad_locate_happening = false;
5267 _pending_locate_num = 0;
5268 _numpad_locate_happening = true;
5269 _numpad_timeout_connection = Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::transport_numpad_timeout), 2*1000);
5274 ARDOUR_UI::transport_numpad_event (int num)
5276 if ( _numpad_locate_happening ) {
5277 _pending_locate_num = _pending_locate_num*10 + num;
5280 case 0: toggle_roll(false, false); break;
5281 case 1: transport_rewind(1); break;
5282 case 2: transport_forward(1); break;
5283 case 3: transport_record(true); break;
5284 case 4: toggle_session_auto_loop(); break;
5285 case 5: transport_record(false); toggle_session_auto_loop(); break;
5286 case 6: toggle_punch(); break;
5287 case 7: toggle_click(); break;
5288 case 8: toggle_auto_return(); break;
5289 case 9: toggle_follow_edits(); break;
5295 ARDOUR_UI::set_flat_buttons ()
5297 CairoWidget::set_flat_buttons( UIConfiguration::instance().get_flat_buttons() );
5301 ARDOUR_UI::audioengine_became_silent ()
5303 MessageDialog msg (string_compose (_("This is a free/demo copy of %1. It has just switched to silent mode."), PROGRAM_NAME),
5305 Gtk::MESSAGE_WARNING,
5309 msg.set_title (string_compose (_("%1 is now silent"), PROGRAM_NAME));
5311 Gtk::Label pay_label (string_compose (_("Please consider paying for a copy of %1 - you can pay whatever you want."), PROGRAM_NAME));
5312 Gtk::Label subscribe_label (_("Better yet become a subscriber - subscriptions start at US$1 per month."));
5313 Gtk::Button pay_button (_("Pay for a copy (via the web)"));
5314 Gtk::Button subscribe_button (_("Become a subscriber (via the web)"));
5315 Gtk::HBox pay_button_box;
5316 Gtk::HBox subscribe_button_box;
5318 pay_button_box.pack_start (pay_button, true, false);
5319 subscribe_button_box.pack_start (subscribe_button, true, false);
5321 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 */
5323 pay_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://ardour.org/download")));
5324 subscribe_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://community.ardour.org/s/subscribe")));
5326 msg.get_vbox()->pack_start (pay_label);
5327 msg.get_vbox()->pack_start (pay_button_box);
5328 msg.get_vbox()->pack_start (subscribe_label);
5329 msg.get_vbox()->pack_start (subscribe_button_box);
5331 msg.get_vbox()->show_all ();
5333 msg.add_button (_("Remain silent"), Gtk::RESPONSE_CANCEL);
5334 msg.add_button (_("Save and quit"), Gtk::RESPONSE_NO);
5335 msg.add_button (_("Give me more time"), Gtk::RESPONSE_YES);
5340 case Gtk::RESPONSE_YES:
5341 AudioEngine::instance()->reset_silence_countdown ();
5344 case Gtk::RESPONSE_NO:
5346 save_state_canfail ("");
5350 case Gtk::RESPONSE_CANCEL:
5352 /* don't reset, save session and exit */
5358 ARDOUR_UI::hide_application ()
5360 Application::instance ()-> hide ();
5364 ARDOUR_UI::setup_toplevel_window (Gtk::Window& window, const string& name, void* owner)
5366 /* icons, titles, WM stuff */
5368 static list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
5370 if (window_icons.empty()) {
5371 Glib::RefPtr<Gdk::Pixbuf> icon;
5372 if ((icon = ::get_icon (PROGRAM_NAME "-icon_16px")) != 0) {
5373 window_icons.push_back (icon);
5375 if ((icon = ::get_icon (PROGRAM_NAME "-icon_22px")) != 0) {
5376 window_icons.push_back (icon);
5378 if ((icon = ::get_icon (PROGRAM_NAME "-icon_32px")) != 0) {
5379 window_icons.push_back (icon);
5381 if ((icon = ::get_icon (PROGRAM_NAME "-icon_48px")) != 0) {
5382 window_icons.push_back (icon);
5386 if (!window_icons.empty()) {
5387 window.set_default_icon_list (window_icons);
5390 Gtkmm2ext::WindowTitle title (Glib::get_application_name());
5392 if (!name.empty()) {
5396 window.set_title (title.get_string());
5397 window.set_wmclass (string_compose (X_("%1_%1"), downcase (PROGRAM_NAME), downcase (name)), PROGRAM_NAME);
5399 window.set_flags (CAN_FOCUS);
5400 window.add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
5402 /* This is a hack to ensure that GTK-accelerators continue to
5403 * work. Once we switch over to entirely native bindings, this will be
5404 * unnecessary and should be removed
5406 window.add_accel_group (ActionManager::ui_manager->get_accel_group());
5408 window.signal_configure_event().connect (sigc::mem_fun (*this, &ARDOUR_UI::configure_handler));
5409 window.signal_window_state_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::tabbed_window_state_event_handler), owner));
5410 window.signal_key_press_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5411 window.signal_key_release_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5415 ARDOUR_UI::key_event_handler (GdkEventKey* ev, Gtk::Window* event_window)
5417 Gtkmm2ext::Bindings* bindings = 0;
5418 Gtk::Window* window = 0;
5420 /* until we get ardour bindings working, we are not handling key
5424 if (ev->type != GDK_KEY_PRESS) {
5428 if (event_window == &_main_window) {
5430 window = event_window;
5432 /* find current tab contents */
5434 Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page());
5436 /* see if it uses the ardour binding system */
5439 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(w->get_data ("ardour-bindings"));
5442 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("main window key event, bindings = %1, global = %2\n", bindings, &global_bindings));
5446 window = event_window;
5448 /* see if window uses ardour binding system */
5450 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(window->get_data ("ardour-bindings"));
5453 /* An empty binding set is treated as if it doesn't exist */
5455 if (bindings && bindings->empty()) {
5459 return key_press_focus_accelerator_handler (*window, ev, bindings);
5462 static Gtkmm2ext::Bindings*
5463 get_bindings_from_widget_heirarchy (GtkWidget* w)
5468 if ((p = g_object_get_data (G_OBJECT(w), "ardour-bindings")) != 0) {
5471 w = gtk_widget_get_parent (w);
5474 return reinterpret_cast<Gtkmm2ext::Bindings*> (p);
5478 ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev, Gtkmm2ext::Bindings* bindings)
5480 GtkWindow* win = window.gobj();
5481 GtkWidget* focus = gtk_window_get_focus (win);
5482 bool special_handling_of_unmodified_accelerators = false;
5483 const guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK));
5487 /* some widget has keyboard focus */
5489 if (GTK_IS_ENTRY(focus) || Keyboard::some_magic_widget_has_focus()) {
5491 /* A particular kind of focusable widget currently has keyboard
5492 * focus. All unmodified key events should go to that widget
5493 * first and not be used as an accelerator by default
5496 special_handling_of_unmodified_accelerators = true;
5500 Gtkmm2ext::Bindings* focus_bindings = get_bindings_from_widget_heirarchy (focus);
5501 if (focus_bindings) {
5502 bindings = focus_bindings;
5503 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Switch bindings based on focus widget, now using %1\n", bindings->name()));
5508 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",
5511 show_gdk_event_state (ev->state),
5512 special_handling_of_unmodified_accelerators,
5513 Keyboard::some_magic_widget_has_focus(),
5515 (focus ? gtk_widget_get_name (focus) : "no focus widget"),
5516 ((ev->state & mask) ? "yes" : "no"),
5517 window.get_title()));
5519 /* This exists to allow us to override the way GTK handles
5520 key events. The normal sequence is:
5522 a) event is delivered to a GtkWindow
5523 b) accelerators/mnemonics are activated
5524 c) if (b) didn't handle the event, propagate to
5525 the focus widget and/or focus chain
5527 The problem with this is that if the accelerators include
5528 keys without modifiers, such as the space bar or the
5529 letter "e", then pressing the key while typing into
5530 a text entry widget results in the accelerator being
5531 activated, instead of the desired letter appearing
5534 There is no good way of fixing this, but this
5535 represents a compromise. The idea is that
5536 key events involving modifiers (not Shift)
5537 get routed into the activation pathway first, then
5538 get propagated to the focus widget if necessary.
5540 If the key event doesn't involve modifiers,
5541 we deliver to the focus widget first, thus allowing
5542 it to get "normal text" without interference
5545 Of course, this can also be problematic: if there
5546 is a widget with focus, then it will swallow
5547 all "normal text" accelerators.
5551 if (!special_handling_of_unmodified_accelerators || (ev->state & mask)) {
5553 /* no special handling or there are modifiers in effect: accelerate first */
5555 DEBUG_TRACE (DEBUG::Accelerators, "\tactivate, then propagate\n");
5556 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tevent send-event:%1 time:%2 length:%3 name %7 string:%4 hardware_keycode:%5 group:%6\n",
5557 ev->send_event, ev->time, ev->length, ev->string, ev->hardware_keycode, ev->group, gdk_keyval_name (ev->keyval)));
5559 DEBUG_TRACE (DEBUG::Accelerators, "\tsending to window\n");
5560 KeyboardKey k (ev->state, ev->keyval);
5564 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tusing Ardour bindings %1 @ %2 for this event\n", bindings->name(), bindings));
5566 if (bindings->activate (k, Bindings::Press)) {
5567 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5572 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5574 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5575 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5579 DEBUG_TRACE (DEBUG::Accelerators, "\tnot accelerated, now propagate\n");
5581 if (gtk_window_propagate_key_event (win, ev)) {
5582 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate handled\n");
5588 /* no modifiers, propagate first */
5590 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate, then activate\n");
5592 if (gtk_window_propagate_key_event (win, ev)) {
5593 DEBUG_TRACE (DEBUG::Accelerators, "\thandled by propagate\n");
5597 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagation didn't handle, so activate\n");
5598 KeyboardKey k (ev->state, ev->keyval);
5602 DEBUG_TRACE (DEBUG::Accelerators, "\tusing Ardour bindings for this window\n");
5605 if (bindings->activate (k, Bindings::Press)) {
5606 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5612 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5614 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5615 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5620 DEBUG_TRACE (DEBUG::Accelerators, "\tnot handled\n");
5625 ARDOUR_UI::load_bindings ()
5627 if ((global_bindings = Bindings::get_bindings (X_("Global"), global_actions)) == 0) {
5628 error << _("Global keybindings are missing") << endmsg;
5633 ARDOUR_UI::cancel_solo ()
5637 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_control), 0.0, Controllable::NoGroup);
5639 _session->clear_all_solo_state (_session->get_routes()); // safeguard, ideally this won't do anything, check the log-window