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"
180 #include "pbd/i18n.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 key_editor->disconnect ();
1289 close_all_dialogs ();
1292 _session->set_clean ();
1293 _session->remove_pending_capture_state ();
1298 halt_connection.disconnect ();
1299 AudioEngine::instance()->stop ();
1300 #ifdef WINDOWS_VST_SUPPORT
1301 fst_stop_threading();
1307 ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
1309 ArdourDialog window (_("Unsaved Session"));
1310 Gtk::HBox dhbox; // the hbox for the image and text
1311 Gtk::Label prompt_label;
1312 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
1316 assert (actions.size() >= 3);
1318 window.add_button (actions[0], RESPONSE_REJECT);
1319 window.add_button (actions[1], RESPONSE_APPLY);
1320 window.add_button (actions[2], RESPONSE_ACCEPT);
1322 window.set_default_response (RESPONSE_ACCEPT);
1324 Gtk::Button noquit_button (msg);
1325 noquit_button.set_name ("EditorGTKButton");
1329 if (_session->snap_name() == _session->name()) {
1330 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?"),
1331 _session->snap_name());
1333 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?"),
1334 _session->snap_name());
1337 prompt_label.set_text (prompt);
1338 prompt_label.set_name (X_("PrompterLabel"));
1339 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
1341 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
1342 dhbox.set_homogeneous (false);
1343 dhbox.pack_start (*dimage, false, false, 5);
1344 dhbox.pack_start (prompt_label, true, false, 5);
1345 window.get_vbox()->pack_start (dhbox);
1347 window.set_name (_("Prompter"));
1348 window.set_modal (true);
1349 window.set_resizable (false);
1352 prompt_label.show();
1357 ResponseType r = (ResponseType) window.run();
1362 case RESPONSE_ACCEPT: // save and get out of here
1364 case RESPONSE_APPLY: // get out of here
1375 ARDOUR_UI::every_second ()
1378 update_xrun_count ();
1379 update_buffer_load ();
1380 update_disk_space ();
1381 update_timecode_format ();
1382 update_peak_thread_work ();
1384 if (nsm && nsm->is_active ()) {
1387 if (!_was_dirty && _session->dirty ()) {
1391 else if (_was_dirty && !_session->dirty ()){
1399 ARDOUR_UI::every_point_one_seconds ()
1401 // TODO get rid of this..
1402 // ShuttleControl is updated directly via TransportStateChange signal
1406 ARDOUR_UI::every_point_zero_something_seconds ()
1408 // august 2007: actual update frequency: 25Hz (40ms), not 100Hz
1410 if (editor_meter && UIConfiguration::instance().get_show_editor_meter()) {
1411 float mpeak = editor_meter->update_meters();
1412 if (mpeak > editor_meter_max_peak) {
1413 if (mpeak >= UIConfiguration::instance().get_meter_peak()) {
1414 editor_meter_peak_display.set_active_state ( Gtkmm2ext::ExplicitActive );
1421 ARDOUR_UI::set_fps_timeout_connection ()
1423 unsigned int interval = 40;
1424 if (!_session) return;
1425 if (_session->timecode_frames_per_second() != 0) {
1426 /* ideally we'll use a select() to sleep and not accumulate
1427 * idle time to provide a regular periodic signal.
1428 * See linux_vst_gui_support.cc 'elapsed_time_ms'.
1429 * However, that'll require a dedicated thread and cross-thread
1430 * signals to the GUI Thread..
1432 interval = floor(500. /* update twice per FPS, since Glib::signal_timeout is very irregular */
1433 * _session->frame_rate() / _session->nominal_frame_rate()
1434 / _session->timecode_frames_per_second()
1436 #ifdef PLATFORM_WINDOWS
1437 // the smallest windows scheduler time-slice is ~15ms.
1438 // periodic GUI timeouts shorter than that will cause
1439 // WaitForSingleObject to spinlock (100% of one CPU Core)
1440 // and gtk never enters idle mode.
1441 // also changing timeBeginPeriod(1) does not affect that in
1442 // any beneficial way, so we just limit the max rate for now.
1443 interval = std::max(30u, interval); // at most ~33Hz.
1445 interval = std::max(8u, interval); // at most 120Hz.
1448 fps_connection.disconnect();
1449 Timers::set_fps_interval (interval);
1453 ARDOUR_UI::update_sample_rate (framecnt_t)
1457 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
1459 if (!AudioEngine::instance()->connected()) {
1461 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1465 framecnt_t rate = AudioEngine::instance()->sample_rate();
1468 /* no sample rate available */
1469 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1472 if (fmod (rate, 1000.0) != 0.0) {
1473 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
1474 (float) rate / 1000.0f,
1475 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1477 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
1479 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1483 sample_rate_label.set_markup (buf);
1487 ARDOUR_UI::update_format ()
1490 format_label.set_text ("");
1495 s << _("File:") << X_(" <span foreground=\"green\">");
1497 switch (_session->config.get_native_file_header_format ()) {
1529 switch (_session->config.get_native_file_data_format ()) {
1543 format_label.set_markup (s.str ());
1547 ARDOUR_UI::update_xrun_count ()
1551 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1552 should also be changed.
1556 const unsigned int x = _session->get_xrun_count ();
1558 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">>10K</span>"), X_("red"));
1560 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">%u</span>"), x > 0 ? X_("red") : X_("green"), x);
1563 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">?</span>"), X_("yellow"));
1565 xrun_label.set_markup (buf);
1566 set_tip (xrun_label, _("Audio dropouts. Shift+click to reset"));
1570 ARDOUR_UI::update_cpu_load ()
1574 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1575 should also be changed.
1578 double const c = AudioEngine::instance()->get_dsp_load ();
1579 snprintf (buf, sizeof (buf), _("DSP: <span foreground=\"%s\">%5.1f%%</span>"), c >= 90 ? X_("red") : X_("green"), c);
1580 cpu_load_label.set_markup (buf);
1584 ARDOUR_UI::update_peak_thread_work ()
1587 const int c = SourceFactory::peak_work_queue_length ();
1589 snprintf (buf, sizeof (buf), _("PkBld: <span foreground=\"%s\">%d</span>"), c >= 2 ? X_("red") : X_("green"), c);
1590 peak_thread_work_label.set_markup (buf);
1592 peak_thread_work_label.set_markup (X_(""));
1597 ARDOUR_UI::update_buffer_load ()
1601 uint32_t const playback = _session ? _session->playback_load () : 100;
1602 uint32_t const capture = _session ? _session->capture_load () : 100;
1604 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1605 should also be changed.
1611 _("Buffers: <span foreground=\"green\">p:</span><span foreground=\"%s\">%" PRIu32 "%%</span> "
1612 "<span foreground=\"green\">c:</span><span foreground=\"%s\">%" PRIu32 "%%</span>"),
1613 playback <= 5 ? X_("red") : X_("green"),
1615 capture <= 5 ? X_("red") : X_("green"),
1619 buffer_load_label.set_markup (buf);
1621 buffer_load_label.set_text ("");
1626 ARDOUR_UI::count_recenabled_streams (Route& route)
1628 Track* track = dynamic_cast<Track*>(&route);
1629 if (track && track->rec_enable_control()->get_value()) {
1630 rec_enabled_streams += track->n_inputs().n_total();
1635 ARDOUR_UI::update_disk_space()
1637 if (_session == 0) {
1641 boost::optional<framecnt_t> opt_frames = _session->available_capture_duration();
1643 framecnt_t fr = _session->frame_rate();
1646 /* skip update - no SR available */
1651 /* Available space is unknown */
1652 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">Unknown</span>"));
1653 } else if (opt_frames.get_value_or (0) == max_framecnt) {
1654 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">24hrs+</span>"));
1656 rec_enabled_streams = 0;
1657 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams, false);
1659 framecnt_t frames = opt_frames.get_value_or (0);
1661 if (rec_enabled_streams) {
1662 frames /= rec_enabled_streams;
1669 hrs = frames / (fr * 3600);
1672 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">>24 hrs</span>"));
1674 frames -= hrs * fr * 3600;
1675 mins = frames / (fr * 60);
1676 frames -= mins * fr * 60;
1679 bool const low = (hrs == 0 && mins <= 30);
1683 _("Disk: <span foreground=\"%s\">%02dh:%02dm:%02ds</span>"),
1684 low ? X_("red") : X_("green"),
1690 disk_space_label.set_markup (buf);
1694 ARDOUR_UI::update_timecode_format ()
1700 TimecodeSlave* tcslave;
1701 SyncSource sync_src = Config->get_sync_source();
1703 if ((sync_src == LTC || sync_src == MTC) && (tcslave = dynamic_cast<TimecodeSlave*>(_session->slave())) != 0) {
1704 matching = (tcslave->apparent_timecode_format() == _session->config.get_timecode_format());
1709 snprintf (buf, sizeof (buf), S_("Timecode|TC: <span foreground=\"%s\">%s</span>"),
1710 matching ? X_("green") : X_("red"),
1711 Timecode::timecode_format_name (_session->config.get_timecode_format()).c_str());
1713 snprintf (buf, sizeof (buf), "TC: n/a");
1716 timecode_format_label.set_markup (buf);
1720 ARDOUR_UI::update_wall_clock ()
1724 static int last_min = -1;
1727 tm_now = localtime (&now);
1728 if (last_min != tm_now->tm_min) {
1730 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1731 wall_clock_label.set_text (buf);
1732 last_min = tm_now->tm_min;
1739 ARDOUR_UI::open_recent_session ()
1741 bool can_return = (_session != 0);
1743 SessionDialog recent_session_dialog;
1747 ResponseType r = (ResponseType) recent_session_dialog.run ();
1750 case RESPONSE_ACCEPT:
1754 recent_session_dialog.hide();
1761 recent_session_dialog.hide();
1765 std::string path = recent_session_dialog.session_folder();
1766 std::string state = recent_session_dialog.session_name (should_be_new);
1768 if (should_be_new == true) {
1772 _session_is_new = false;
1774 if (load_session (path, state) == 0) {
1780 if (splash && splash->is_visible()) {
1781 // in 1 second, hide the splash screen
1782 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
1787 ARDOUR_UI::check_audioengine (Gtk::Window& parent)
1789 if (!AudioEngine::instance()->connected()) {
1790 MessageDialog msg (parent, string_compose (
1791 _("%1 is not connected to any audio backend.\n"
1792 "You cannot open or close sessions in this condition"),
1794 pop_back_splash (msg);
1802 ARDOUR_UI::open_session ()
1804 if (!check_audioengine (_main_window)) {
1808 /* ardour sessions are folders */
1809 Gtk::FileChooserDialog open_session_selector(_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1810 open_session_selector.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1811 open_session_selector.add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1812 open_session_selector.set_default_response(Gtk::RESPONSE_ACCEPT);
1815 string session_parent_dir = Glib::path_get_dirname(_session->path());
1816 open_session_selector.set_current_folder(session_parent_dir);
1818 open_session_selector.set_current_folder(Config->get_default_session_parent_dir());
1821 Gtkmm2ext::add_volume_shortcuts (open_session_selector);
1823 /* add_shortcut_folder throws an exception if the folder being added already has a shortcut */
1824 string default_session_folder = Config->get_default_session_parent_dir();
1825 open_session_selector.add_shortcut_folder (default_session_folder);
1827 catch (Glib::Error & e) {
1828 std::cerr << "open_session_selector.add_shortcut_folder() threw Glib::Error " << e.what() << std::endl;
1831 FileFilter session_filter;
1832 session_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::statefile_suffix));
1833 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1834 open_session_selector.add_filter (session_filter);
1835 open_session_selector.set_filter (session_filter);
1837 int response = open_session_selector.run();
1838 open_session_selector.hide ();
1840 if (response == Gtk::RESPONSE_CANCEL) {
1844 string session_path = open_session_selector.get_filename();
1848 if (session_path.length() > 0) {
1849 if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1850 _session_is_new = isnew;
1851 load_session (path, name);
1857 ARDOUR_UI::session_add_vca (const string& name_template, uint32_t n)
1863 _session->vca_manager().create_vca (n, name_template);
1867 ARDOUR_UI::session_add_mixed_track (
1868 const ChanCount& input,
1869 const ChanCount& output,
1870 RouteGroup* route_group,
1872 const string& name_template,
1874 PluginInfoPtr instrument,
1875 Plugin::PresetRecord* pset,
1876 ARDOUR::PresentationInfo::order_t order)
1878 list<boost::shared_ptr<MidiTrack> > tracks;
1880 if (_session == 0) {
1881 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1886 tracks = _session->new_midi_track (input, output, instrument, pset, route_group, how_many, name_template, order, ARDOUR::Normal);
1888 if (tracks.size() != how_many) {
1889 error << string_compose(P_("could not create %1 new mixed track", "could not create %1 new mixed tracks", how_many), how_many) << endmsg;
1894 display_insufficient_ports_message ();
1899 for (list<boost::shared_ptr<MidiTrack> >::iterator i = tracks.begin(); i != tracks.end(); ++i) {
1900 (*i)->set_strict_io (true);
1906 ARDOUR_UI::session_add_midi_bus (
1907 RouteGroup* route_group,
1909 const string& name_template,
1911 PluginInfoPtr instrument,
1912 Plugin::PresetRecord* pset,
1913 ARDOUR::PresentationInfo::order_t order)
1917 if (_session == 0) {
1918 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1924 routes = _session->new_midi_route (route_group, how_many, name_template, instrument, pset, PresentationInfo::MidiBus, order);
1925 if (routes.size() != how_many) {
1926 error << string_compose(P_("could not create %1 new Midi Bus", "could not create %1 new Midi Busses", how_many), how_many) << endmsg;
1931 display_insufficient_ports_message ();
1936 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
1937 (*i)->set_strict_io (true);
1943 ARDOUR_UI::session_add_midi_route (
1945 RouteGroup* route_group,
1947 const string& name_template,
1949 PluginInfoPtr instrument,
1950 Plugin::PresetRecord* pset,
1951 ARDOUR::PresentationInfo::order_t order)
1953 ChanCount one_midi_channel;
1954 one_midi_channel.set (DataType::MIDI, 1);
1957 session_add_mixed_track (one_midi_channel, one_midi_channel, route_group, how_many, name_template, strict_io, instrument, pset, order);
1959 session_add_midi_bus (route_group, how_many, name_template, strict_io, instrument, pset, order);
1964 ARDOUR_UI::session_add_audio_route (
1966 int32_t input_channels,
1967 int32_t output_channels,
1968 ARDOUR::TrackMode mode,
1969 RouteGroup* route_group,
1971 string const & name_template,
1973 ARDOUR::PresentationInfo::order_t order)
1975 list<boost::shared_ptr<AudioTrack> > tracks;
1978 if (_session == 0) {
1979 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1985 tracks = _session->new_audio_track (input_channels, output_channels, route_group, how_many, name_template, order, mode);
1987 if (tracks.size() != how_many) {
1988 error << string_compose (P_("could not create %1 new audio track", "could not create %1 new audio tracks", how_many), how_many)
1994 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template, PresentationInfo::AudioBus, order);
1996 if (routes.size() != how_many) {
1997 error << string_compose (P_("could not create %1 new audio bus", "could not create %1 new audio busses", how_many), how_many)
2004 display_insufficient_ports_message ();
2009 for (list<boost::shared_ptr<AudioTrack> >::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2010 (*i)->set_strict_io (true);
2012 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
2013 (*i)->set_strict_io (true);
2019 ARDOUR_UI::display_insufficient_ports_message ()
2021 MessageDialog msg (_main_window,
2022 string_compose (_("There are insufficient ports available\n\
2023 to create a new track or bus.\n\
2024 You should save %1, exit and\n\
2025 restart with more ports."), PROGRAM_NAME));
2026 pop_back_splash (msg);
2031 ARDOUR_UI::transport_goto_start ()
2034 _session->goto_start();
2036 /* force displayed area in editor to start no matter
2037 what "follow playhead" setting is.
2041 editor->center_screen (_session->current_start_frame ());
2047 ARDOUR_UI::transport_goto_zero ()
2050 _session->request_locate (0);
2052 /* force displayed area in editor to start no matter
2053 what "follow playhead" setting is.
2057 editor->reset_x_origin (0);
2063 ARDOUR_UI::transport_goto_wallclock ()
2065 if (_session && editor) {
2072 localtime_r (&now, &tmnow);
2074 framecnt_t frame_rate = _session->frame_rate();
2076 if (frame_rate == 0) {
2077 /* no frame rate available */
2081 frames = tmnow.tm_hour * (60 * 60 * frame_rate);
2082 frames += tmnow.tm_min * (60 * frame_rate);
2083 frames += tmnow.tm_sec * frame_rate;
2085 _session->request_locate (frames, _session->transport_rolling ());
2087 /* force displayed area in editor to start no matter
2088 what "follow playhead" setting is.
2092 editor->center_screen (frames);
2098 ARDOUR_UI::transport_goto_end ()
2101 framepos_t const frame = _session->current_end_frame();
2102 _session->request_locate (frame);
2104 /* force displayed area in editor to start no matter
2105 what "follow playhead" setting is.
2109 editor->center_screen (frame);
2115 ARDOUR_UI::transport_stop ()
2121 if (_session->is_auditioning()) {
2122 _session->cancel_audition ();
2126 _session->request_stop (false, true);
2129 /** Check if any tracks are record enabled. If none are, record enable all of them.
2130 * @return true if track record-enabled status was changed, false otherwise.
2133 ARDOUR_UI::trx_record_enable_all_tracks ()
2139 boost::shared_ptr<RouteList> rl = _session->get_tracks ();
2140 bool none_record_enabled = true;
2142 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
2143 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*r);
2146 if (t->rec_enable_control()->get_value()) {
2147 none_record_enabled = false;
2152 if (none_record_enabled) {
2153 _session->set_controls (route_list_to_control_list (rl, &Stripable::rec_enable_control), 1.0, Controllable::NoGroup);
2156 return none_record_enabled;
2160 ARDOUR_UI::transport_record (bool roll)
2163 switch (_session->record_status()) {
2164 case Session::Disabled:
2165 if (_session->ntracks() == 0) {
2166 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."));
2170 if (Profile->get_trx()) {
2171 roll = trx_record_enable_all_tracks ();
2173 _session->maybe_enable_record ();
2178 case Session::Recording:
2180 _session->request_stop();
2182 _session->disable_record (false, true);
2186 case Session::Enabled:
2187 _session->disable_record (false, true);
2193 ARDOUR_UI::transport_roll ()
2199 if (_session->is_auditioning()) {
2204 if (_session->config.get_external_sync()) {
2205 switch (Config->get_sync_source()) {
2209 /* transport controlled by the master */
2215 bool rolling = _session->transport_rolling();
2217 if (_session->get_play_loop()) {
2219 /* If loop playback is not a mode, then we should cancel
2220 it when this action is requested. If it is a mode
2221 we just leave it in place.
2224 if (!Config->get_loop_is_mode()) {
2225 /* XXX it is not possible to just leave seamless loop and keep
2226 playing at present (nov 4th 2009)
2228 if (!Config->get_seamless_loop()) {
2229 /* stop loop playback and stop rolling */
2230 _session->request_play_loop (false, true);
2231 } else if (rolling) {
2232 /* stop loop playback but keep rolling */
2233 _session->request_play_loop (false, false);
2237 } else if (_session->get_play_range () ) {
2238 /* stop playing a range if we currently are */
2239 _session->request_play_range (0, true);
2243 _session->request_transport_speed (1.0f);
2248 ARDOUR_UI::get_smart_mode() const
2250 return ( editor->get_smart_mode() );
2255 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
2261 if (_session->is_auditioning()) {
2262 _session->cancel_audition ();
2266 if (_session->config.get_external_sync()) {
2267 switch (Config->get_sync_source()) {
2271 /* transport controlled by the master */
2276 bool rolling = _session->transport_rolling();
2277 bool affect_transport = true;
2279 if (rolling && roll_out_of_bounded_mode) {
2280 /* drop out of loop/range playback but leave transport rolling */
2281 if (_session->get_play_loop()) {
2282 if (_session->actively_recording()) {
2284 /* just stop using the loop, then actually stop
2287 _session->request_play_loop (false, affect_transport);
2290 if (Config->get_seamless_loop()) {
2291 /* the disk buffers contain copies of the loop - we can't
2292 just keep playing, so stop the transport. the user
2293 can restart as they wish.
2295 affect_transport = true;
2297 /* disk buffers are normal, so we can keep playing */
2298 affect_transport = false;
2300 _session->request_play_loop (false, affect_transport);
2302 } else if (_session->get_play_range ()) {
2303 affect_transport = false;
2304 _session->request_play_range (0, true);
2308 if (affect_transport) {
2310 _session->request_stop (with_abort, true);
2312 } else if (!with_abort) { /* with_abort == true means the
2313 * command was intended to stop
2314 * transport, not start.
2317 /* the only external sync condition we can be in here
2318 * would be Engine (JACK) sync, in which case we still
2322 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
2323 _session->request_play_range (&editor->get_selection().time, true);
2324 _session->set_requested_return_frame( editor->get_selection().time.front().start ); //force an auto-return here
2326 _session->request_transport_speed (1.0f);
2332 ARDOUR_UI::toggle_session_auto_loop ()
2338 Location * looploc = _session->locations()->auto_loop_location();
2344 if (_session->get_play_loop()) {
2346 /* looping enabled, our job is to disable it */
2348 _session->request_play_loop (false);
2352 /* looping not enabled, our job is to enable it.
2354 loop-is-NOT-mode: this action always starts the transport rolling.
2355 loop-IS-mode: this action simply sets the loop play mechanism, but
2356 does not start transport.
2358 if (Config->get_loop_is_mode()) {
2359 _session->request_play_loop (true, false);
2361 _session->request_play_loop (true, true);
2365 //show the loop markers
2366 looploc->set_hidden (false, this);
2370 ARDOUR_UI::transport_play_selection ()
2376 editor->play_selection ();
2380 ARDOUR_UI::transport_play_preroll ()
2385 editor->play_with_preroll ();
2389 ARDOUR_UI::transport_rewind (int option)
2391 float current_transport_speed;
2394 current_transport_speed = _session->transport_speed();
2396 if (current_transport_speed >= 0.0f) {
2399 _session->request_transport_speed (-1.0f);
2402 _session->request_transport_speed (-4.0f);
2405 _session->request_transport_speed (-0.5f);
2410 _session->request_transport_speed (current_transport_speed * 1.5f);
2416 ARDOUR_UI::transport_forward (int option)
2422 float current_transport_speed = _session->transport_speed();
2424 if (current_transport_speed <= 0.0f) {
2427 _session->request_transport_speed (1.0f);
2430 _session->request_transport_speed (4.0f);
2433 _session->request_transport_speed (0.5f);
2438 _session->request_transport_speed (current_transport_speed * 1.5f);
2443 ARDOUR_UI::toggle_record_enable (uint16_t rid)
2449 boost::shared_ptr<Route> r;
2451 if ((r = _session->get_remote_nth_route (rid)) != 0) {
2453 boost::shared_ptr<Track> t;
2455 if ((t = boost::dynamic_pointer_cast<Track>(r)) != 0) {
2456 t->rec_enable_control()->set_value (!t->rec_enable_control()->get_value(), Controllable::UseGroup);
2462 ARDOUR_UI::map_transport_state ()
2465 auto_loop_button.unset_active_state ();
2466 play_selection_button.unset_active_state ();
2467 roll_button.unset_active_state ();
2468 stop_button.set_active_state (Gtkmm2ext::ExplicitActive);
2472 shuttle_box->map_transport_state ();
2474 float sp = _session->transport_speed();
2480 if (_session->get_play_range()) {
2482 play_selection_button.set_active_state (Gtkmm2ext::ExplicitActive);
2483 roll_button.unset_active_state ();
2484 auto_loop_button.unset_active_state ();
2486 } else if (_session->get_play_loop ()) {
2488 auto_loop_button.set_active (true);
2489 play_selection_button.set_active (false);
2490 if (Config->get_loop_is_mode()) {
2491 roll_button.set_active (true);
2493 roll_button.set_active (false);
2498 roll_button.set_active (true);
2499 play_selection_button.set_active (false);
2500 auto_loop_button.set_active (false);
2503 if (UIConfiguration::instance().get_follow_edits() && !_session->config.get_external_sync()) {
2504 /* light up both roll and play-selection if they are joined */
2505 roll_button.set_active (true);
2506 play_selection_button.set_active (true);
2509 stop_button.set_active (false);
2513 stop_button.set_active (true);
2514 roll_button.set_active (false);
2515 play_selection_button.set_active (false);
2516 if (Config->get_loop_is_mode ()) {
2517 auto_loop_button.set_active (_session->get_play_loop());
2519 auto_loop_button.set_active (false);
2521 update_disk_space ();
2526 ARDOUR_UI::blink_handler (bool blink_on)
2528 transport_rec_enable_blink (blink_on);
2529 solo_blink (blink_on);
2530 sync_blink (blink_on);
2531 audition_blink (blink_on);
2532 feedback_blink (blink_on);
2533 error_blink (blink_on);
2537 ARDOUR_UI::update_clocks ()
2539 if (!_session) return;
2541 if (editor && !editor->dragging_playhead()) {
2542 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD)); /* EMIT_SIGNAL */
2547 ARDOUR_UI::start_clocking ()
2549 if (UIConfiguration::instance().get_super_rapid_clock_update()) {
2550 clock_signal_connection = Timers::fps_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2552 clock_signal_connection = Timers::rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2557 ARDOUR_UI::stop_clocking ()
2559 clock_signal_connection.disconnect ();
2563 ARDOUR_UI::save_as_progress_update (float fraction, int64_t cnt, int64_t total, Gtk::Label* label, Gtk::ProgressBar* bar)
2567 snprintf (buf, sizeof (buf), _("Copied %" PRId64 " of %" PRId64), cnt, total);
2569 label->set_text (buf);
2570 bar->set_fraction (fraction);
2572 /* process events, redraws, etc. */
2574 while (gtk_events_pending()) {
2575 gtk_main_iteration ();
2578 return true; /* continue with save-as */
2582 ARDOUR_UI::save_session_as ()
2588 if (!save_as_dialog) {
2589 save_as_dialog = new SaveAsDialog;
2592 save_as_dialog->set_name (_session->name());
2594 int response = save_as_dialog->run ();
2596 save_as_dialog->hide ();
2599 case Gtk::RESPONSE_OK:
2608 sa.new_parent_folder = save_as_dialog->new_parent_folder ();
2609 sa.new_name = save_as_dialog->new_name ();
2610 sa.switch_to = save_as_dialog->switch_to();
2611 sa.copy_media = save_as_dialog->copy_media();
2612 sa.copy_external = save_as_dialog->copy_external();
2613 sa.include_media = save_as_dialog->include_media ();
2615 /* Only bother with a progress dialog if we're going to copy
2616 media into the save-as target. Without that choice, this
2617 will be very fast because we're only talking about a few kB's to
2618 perhaps a couple of MB's of data.
2621 ArdourDialog progress_dialog (_("Save As"), true);
2623 if (sa.include_media && sa.copy_media) {
2626 Gtk::ProgressBar progress_bar;
2628 progress_dialog.get_vbox()->pack_start (label);
2629 progress_dialog.get_vbox()->pack_start (progress_bar);
2631 progress_bar.show ();
2633 /* this signal will be emitted from within this, the calling thread,
2634 * after every file is copied. It provides information on percentage
2635 * complete (in terms of total data to copy), the number of files
2636 * copied so far, and the total number to copy.
2641 sa.Progress.connect_same_thread (c, boost::bind (&ARDOUR_UI::save_as_progress_update, this, _1, _2, _3, &label, &progress_bar));
2643 progress_dialog.show_all ();
2644 progress_dialog.present ();
2647 if (_session->save_as (sa)) {
2649 MessageDialog msg (string_compose (_("Save As failed: %1"), sa.failure_message));
2653 if (!sa.include_media) {
2654 unload_session (false);
2655 load_session (sa.final_session_folder_name, sa.new_name);
2660 ARDOUR_UI::quick_snapshot_session (bool switch_to_it)
2664 struct tm local_time;
2667 localtime_r (&n, &local_time);
2668 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2670 save_state (timebuf, switch_to_it);
2675 ARDOUR_UI::process_snapshot_session_prompter (ArdourPrompter& prompter, bool switch_to_it)
2679 prompter.get_result (snapname);
2681 bool do_save = (snapname.length() != 0);
2684 char illegal = Session::session_name_is_legal(snapname);
2686 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2687 "snapshot names may not contain a '%1' character"), illegal));
2693 vector<std::string> p;
2694 get_state_files_in_directory (_session->session_directory().root_path(), p);
2695 vector<string> n = get_file_names_no_extension (p);
2697 if (find (n.begin(), n.end(), snapname) != n.end()) {
2699 do_save = overwrite_file_dialog (prompter,
2700 _("Confirm Snapshot Overwrite"),
2701 _("A snapshot already exists with that name. Do you want to overwrite it?"));
2705 save_state (snapname, switch_to_it);
2715 /** Ask the user for the name of a new snapshot and then take it.
2719 ARDOUR_UI::snapshot_session (bool switch_to_it)
2721 ArdourPrompter prompter (true);
2723 prompter.set_name ("Prompter");
2724 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2726 prompter.set_title (_("Snapshot and switch"));
2727 prompter.set_prompt (_("New session name"));
2729 prompter.set_title (_("Take Snapshot"));
2730 prompter.set_prompt (_("Name of new snapshot"));
2734 prompter.set_initial_text (_session->snap_name());
2738 struct tm local_time;
2741 localtime_r (&n, &local_time);
2742 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2743 prompter.set_initial_text (timebuf);
2746 bool finished = false;
2748 switch (prompter.run()) {
2749 case RESPONSE_ACCEPT:
2751 finished = process_snapshot_session_prompter (prompter, switch_to_it);
2762 /** Ask the user for a new session name and then rename the session to it.
2766 ARDOUR_UI::rename_session ()
2772 ArdourPrompter prompter (true);
2775 prompter.set_name ("Prompter");
2776 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2777 prompter.set_title (_("Rename Session"));
2778 prompter.set_prompt (_("New session name"));
2781 switch (prompter.run()) {
2782 case RESPONSE_ACCEPT:
2784 prompter.get_result (name);
2786 bool do_rename = (name.length() != 0);
2789 char illegal = Session::session_name_is_legal (name);
2792 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2793 "session names may not contain a '%1' character"), illegal));
2798 switch (_session->rename (name)) {
2800 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
2801 msg.set_position (WIN_POS_MOUSE);
2809 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
2810 msg.set_position (WIN_POS_MOUSE);
2826 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2828 if (!_session || _session->deletion_in_progress()) {
2832 XMLNode* node = new XMLNode (X_("UI"));
2834 WM::Manager::instance().add_state (*node);
2836 node->add_child_nocopy (gui_object_state->get_state());
2838 _session->add_extra_xml (*node);
2840 if (export_video_dialog) {
2841 _session->add_extra_xml (export_video_dialog->get_state());
2844 save_state_canfail (name, switch_to_it);
2848 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2853 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2858 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2863 ARDOUR_UI::primary_clock_value_changed ()
2866 _session->request_locate (primary_clock->current_time ());
2871 ARDOUR_UI::big_clock_value_changed ()
2874 _session->request_locate (big_clock->current_time ());
2879 ARDOUR_UI::secondary_clock_value_changed ()
2882 _session->request_locate (secondary_clock->current_time ());
2887 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2889 if (_session == 0) {
2893 if (_session->step_editing()) {
2897 Session::RecordState const r = _session->record_status ();
2898 bool const h = _session->have_rec_enabled_track ();
2900 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2902 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2904 rec_button.set_active_state (Gtkmm2ext::Off);
2906 } else if (r == Session::Recording && h) {
2907 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2909 rec_button.unset_active_state ();
2914 ARDOUR_UI::process_save_template_prompter (ArdourPrompter& prompter)
2918 prompter.get_result (name);
2920 if (name.length()) {
2921 int failed = _session->save_template (name);
2923 if (failed == -2) { /* file already exists. */
2924 bool overwrite = overwrite_file_dialog (prompter,
2925 _("Confirm Template Overwrite"),
2926 _("A template already exists with that name. Do you want to overwrite it?"));
2929 _session->save_template (name, true);
2941 ARDOUR_UI::save_template ()
2943 ArdourPrompter prompter (true);
2945 if (!check_audioengine (_main_window)) {
2949 prompter.set_name (X_("Prompter"));
2950 prompter.set_title (_("Save Template"));
2951 prompter.set_prompt (_("Name for template:"));
2952 prompter.set_initial_text(_session->name() + _("-template"));
2953 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2955 bool finished = false;
2957 switch (prompter.run()) {
2958 case RESPONSE_ACCEPT:
2959 finished = process_save_template_prompter (prompter);
2970 ARDOUR_UI::edit_metadata ()
2972 SessionMetadataEditor dialog;
2973 dialog.set_session (_session);
2974 dialog.grab_focus ();
2979 ARDOUR_UI::import_metadata ()
2981 SessionMetadataImporter dialog;
2982 dialog.set_session (_session);
2987 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
2989 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2991 MessageDialog msg (str,
2993 Gtk::MESSAGE_WARNING,
2994 Gtk::BUTTONS_YES_NO,
2998 msg.set_name (X_("OpenExistingDialog"));
2999 msg.set_title (_("Open Existing Session"));
3000 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
3001 msg.set_position (Gtk::WIN_POS_CENTER);
3002 pop_back_splash (msg);
3004 switch (msg.run()) {
3013 ARDOUR_UI::build_session_from_dialog (SessionDialog& sd, const std::string& session_path, const std::string& session_name)
3015 BusProfile bus_profile;
3019 bus_profile.master_out_channels = 2;
3020 bus_profile.input_ac = AutoConnectPhysical;
3021 bus_profile.output_ac = AutoConnectMaster;
3022 bus_profile.requested_physical_in = 0; // use all available
3023 bus_profile.requested_physical_out = 0; // use all available
3027 /* get settings from advanced section of NSD */
3029 if (sd.create_master_bus()) {
3030 bus_profile.master_out_channels = (uint32_t) sd.master_channel_count();
3032 bus_profile.master_out_channels = 0;
3035 if (sd.connect_inputs()) {
3036 bus_profile.input_ac = AutoConnectPhysical;
3038 bus_profile.input_ac = AutoConnectOption (0);
3041 bus_profile.output_ac = AutoConnectOption (0);
3043 if (sd.connect_outputs ()) {
3044 if (sd.connect_outs_to_master()) {
3045 bus_profile.output_ac = AutoConnectMaster;
3046 } else if (sd.connect_outs_to_physical()) {
3047 bus_profile.output_ac = AutoConnectPhysical;
3051 bus_profile.requested_physical_in = (uint32_t) sd.input_limit_count();
3052 bus_profile.requested_physical_out = (uint32_t) sd.output_limit_count();
3055 if (build_session (session_path, session_name, bus_profile)) {
3063 ARDOUR_UI::load_from_application_api (const std::string& path)
3065 ARDOUR_COMMAND_LINE::session_name = path;
3066 /* Cancel SessionDialog if it's visible to make OSX delegates work.
3068 * ARDOUR_UI::starting connects app->ShouldLoad signal and then shows a SessionDialog
3070 * - ShouldLoad does not arrive in time, ARDOUR_COMMAND_LINE::session_name is empty:
3071 * -> ARDOUR_UI::get_session_parameters starts a SessionDialog.
3072 * - ShouldLoad signal arrives, this function is called and sets ARDOUR_COMMAND_LINE::session_name
3073 * -> SessionDialog is not displayed
3076 if (_session_dialog) {
3077 std::string session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3078 std::string session_path = path;
3079 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_REGULAR)) {
3080 session_path = Glib::path_get_dirname (session_path);
3082 // signal the existing dialog in ARDOUR_UI::get_session_parameters()
3083 _session_dialog->set_provided_session (session_name, session_path);
3084 _session_dialog->response (RESPONSE_NONE);
3085 _session_dialog->hide();
3090 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
3091 /* /path/to/foo => /path/to/foo, foo */
3092 rv = load_session (path, basename_nosuffix (path));
3094 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
3095 rv =load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
3098 // if load_session fails -> pop up SessionDialog.
3100 ARDOUR_COMMAND_LINE::session_name = "";
3102 if (get_session_parameters (true, false)) {
3108 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
3110 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
3112 string session_name;
3113 string session_path;
3114 string template_name;
3116 bool likely_new = false;
3117 bool cancel_not_quit;
3119 /* deal with any existing DIRTY session now, rather than later. don't
3120 * treat a non-dirty session this way, so that it stays visible
3121 * as we bring up the new session dialog.
3124 if (_session && ARDOUR_UI::instance()->video_timeline) {
3125 ARDOUR_UI::instance()->video_timeline->sync_session_state();
3128 /* if there is already a session, relabel the button
3129 on the SessionDialog so that we don't Quit directly
3131 cancel_not_quit = (_session != 0);
3133 if (_session && _session->dirty()) {
3134 if (unload_session (false)) {
3135 /* unload cancelled by user */
3138 ARDOUR_COMMAND_LINE::session_name = "";
3141 if (!load_template.empty()) {
3142 should_be_new = true;
3143 template_name = load_template;
3146 session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3147 session_path = ARDOUR_COMMAND_LINE::session_name;
3149 if (!session_path.empty()) {
3150 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_EXISTS)) {
3151 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_IS_REGULAR)) {
3152 /* session/snapshot file, change path to be dir */
3153 session_path = Glib::path_get_dirname (session_path);
3158 SessionDialog session_dialog (should_be_new, session_name, session_path, load_template, cancel_not_quit);
3160 _session_dialog = &session_dialog;
3163 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
3165 /* if they named a specific statefile, use it, otherwise they are
3166 just giving a session folder, and we want to use it as is
3167 to find the session.
3170 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
3172 if (suffix != string::npos) {
3173 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
3174 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
3175 session_name = Glib::path_get_basename (session_name);
3177 session_path = ARDOUR_COMMAND_LINE::session_name;
3178 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
3183 session_dialog.clear_given ();
3186 if (should_be_new || session_name.empty()) {
3187 /* need the dialog to get info from user */
3189 cerr << "run dialog\n";
3191 switch (session_dialog.run()) {
3192 case RESPONSE_ACCEPT:
3195 /* this is used for async * app->ShouldLoad(). */
3196 continue; // while loop
3199 if (quit_on_cancel) {
3200 // JE - Currently (July 2014) this section can only get reached if the
3201 // user quits from the main 'Session Setup' dialog (i.e. reaching this
3202 // point does NOT indicate an abnormal termination). Therefore, let's
3203 // behave gracefully (i.e. let's do some cleanup) before we call exit()
3205 pthread_cancel_all ();
3213 session_dialog.hide ();
3216 /* if we run the startup dialog again, offer more than just "new session" */
3218 should_be_new = false;
3220 session_name = session_dialog.session_name (likely_new);
3221 session_path = session_dialog.session_folder ();
3227 string::size_type suffix = session_name.find (statefile_suffix);
3229 if (suffix != string::npos) {
3230 session_name = session_name.substr (0, suffix);
3233 /* this shouldn't happen, but we catch it just in case it does */
3235 if (session_name.empty()) {
3239 if (session_dialog.use_session_template()) {
3240 template_name = session_dialog.session_template_name();
3241 _session_is_new = true;
3244 if (session_name[0] == G_DIR_SEPARATOR ||
3245 #ifdef PLATFORM_WINDOWS
3246 (session_name.length() > 3 && session_name[1] == ':' && session_name[2] == G_DIR_SEPARATOR)
3248 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
3249 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)
3254 /* absolute path or cwd-relative path specified for session name: infer session folder
3255 from what was given.
3258 session_path = Glib::path_get_dirname (session_name);
3259 session_name = Glib::path_get_basename (session_name);
3263 session_path = session_dialog.session_folder();
3265 char illegal = Session::session_name_is_legal (session_name);
3268 MessageDialog msg (session_dialog,
3269 string_compose (_("To ensure compatibility with various systems\n"
3270 "session names may not contain a '%1' character"),
3273 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3278 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
3281 if (likely_new && !nsm) {
3283 std::string existing = Glib::build_filename (session_path, session_name);
3285 if (!ask_about_loading_existing_session (existing)) {
3286 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3291 _session_is_new = false;
3296 pop_back_splash (session_dialog);
3297 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
3299 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3303 char illegal = Session::session_name_is_legal(session_name);
3306 pop_back_splash (session_dialog);
3307 MessageDialog msg (session_dialog, string_compose(_("To ensure compatibility with various systems\n"
3308 "session names may not contain a '%1' character"), illegal));
3310 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3314 _session_is_new = true;
3317 if (likely_new && template_name.empty()) {
3319 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3323 ret = load_session (session_path, session_name, template_name);
3326 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
3330 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
3331 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
3335 /* clear this to avoid endless attempts to load the
3339 ARDOUR_COMMAND_LINE::session_name = "";
3343 _session_dialog = NULL;
3349 ARDOUR_UI::close_session()
3351 if (!check_audioengine (_main_window)) {
3355 if (unload_session (true)) {
3359 ARDOUR_COMMAND_LINE::session_name = "";
3361 if (get_session_parameters (true, false)) {
3364 if (splash && splash->is_visible()) {
3365 // in 1 second, hide the splash screen
3366 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
3370 /** @param snap_name Snapshot name (without .ardour suffix).
3371 * @return -2 if the load failed because we are not connected to the AudioEngine.
3374 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
3376 Session *new_session;
3381 unload_status = unload_session ();
3383 if (unload_status < 0) {
3385 } else if (unload_status > 0) {
3391 session_loaded = false;
3393 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
3396 new_session = new Session (*AudioEngine::instance(), path, snap_name, 0, mix_template);
3399 /* this one is special */
3401 catch (AudioEngine::PortRegistrationFailure& err) {
3403 MessageDialog msg (err.what(),
3406 Gtk::BUTTONS_CLOSE);
3408 msg.set_title (_("Port Registration Error"));
3409 msg.set_secondary_text (_("Click the Close button to try again."));
3410 msg.set_position (Gtk::WIN_POS_CENTER);
3411 pop_back_splash (msg);
3414 int response = msg.run ();
3419 case RESPONSE_CANCEL:
3426 catch (SessionException e) {
3427 MessageDialog msg (string_compose(
3428 _("Session \"%1 (snapshot %2)\" did not load successfully: %3"),
3429 path, snap_name, e.what()),
3434 msg.set_title (_("Loading Error"));
3435 msg.set_position (Gtk::WIN_POS_CENTER);
3436 pop_back_splash (msg);
3448 MessageDialog msg (string_compose(
3449 _("Session \"%1 (snapshot %2)\" did not load successfully"),
3455 msg.set_title (_("Loading Error"));
3456 msg.set_position (Gtk::WIN_POS_CENTER);
3457 pop_back_splash (msg);
3469 list<string> const u = new_session->unknown_processors ();
3471 MissingPluginDialog d (_session, u);
3476 if (!new_session->writable()) {
3477 MessageDialog msg (_("This session has been opened in read-only mode.\n\nYou will not be able to record or save."),
3482 msg.set_title (_("Read-only Session"));
3483 msg.set_position (Gtk::WIN_POS_CENTER);
3484 pop_back_splash (msg);
3491 /* Now the session been created, add the transport controls */
3492 new_session->add_controllable(roll_controllable);
3493 new_session->add_controllable(stop_controllable);
3494 new_session->add_controllable(goto_start_controllable);
3495 new_session->add_controllable(goto_end_controllable);
3496 new_session->add_controllable(auto_loop_controllable);
3497 new_session->add_controllable(play_selection_controllable);
3498 new_session->add_controllable(rec_controllable);
3500 set_session (new_session);
3502 session_loaded = true;
3505 _session->set_clean ();
3508 #ifdef WINDOWS_VST_SUPPORT
3509 fst_stop_threading();
3513 Timers::TimerSuspender t;
3517 #ifdef WINDOWS_VST_SUPPORT
3518 fst_start_threading();
3527 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
3529 Session *new_session;
3532 session_loaded = false;
3533 x = unload_session ();
3541 _session_is_new = true;
3544 new_session = new Session (*AudioEngine::instance(), path, snap_name, &bus_profile);
3547 catch (SessionException e) {
3549 MessageDialog msg (string_compose(_("Could not create session in \"%1\": %2"), path, e.what()));
3550 msg.set_title (_("Loading Error"));
3551 msg.set_position (Gtk::WIN_POS_CENTER);
3552 pop_back_splash (msg);
3558 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
3559 msg.set_title (_("Loading Error"));
3560 msg.set_position (Gtk::WIN_POS_CENTER);
3561 pop_back_splash (msg);
3566 /* Give the new session the default GUI state, if such things exist */
3569 n = Config->instant_xml (X_("Editor"));
3571 n->remove_nodes_and_delete ("Selection"); // no not apply selection to new sessions.
3572 new_session->add_instant_xml (*n, false);
3574 n = Config->instant_xml (X_("Mixer"));
3576 new_session->add_instant_xml (*n, false);
3579 n = Config->instant_xml (X_("Preferences"));
3581 new_session->add_instant_xml (*n, false);
3584 /* Put the playhead at 0 and scroll fully left */
3585 n = new_session->instant_xml (X_("Editor"));
3587 n->add_property (X_("playhead"), X_("0"));
3588 n->add_property (X_("left-frame"), X_("0"));
3591 set_session (new_session);
3593 session_loaded = true;
3595 new_session->save_state(new_session->name());
3601 ARDOUR_UI::launch_chat ()
3603 MessageDialog dialog(_("<b>Just ask and wait for an answer.\nIt may take from minutes to hours.</b>"), true);
3605 dialog.set_title (_("About the Chat"));
3606 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."));
3608 switch (dialog.run()) {
3611 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
3612 #elif defined PLATFORM_WINDOWS
3613 open_uri("http://webchat.freenode.net/?channels=ardour-windows");
3615 open_uri("http://webchat.freenode.net/?channels=ardour");
3624 ARDOUR_UI::launch_manual ()
3626 PBD::open_uri (Config->get_tutorial_manual_url());
3630 ARDOUR_UI::launch_reference ()
3632 PBD::open_uri (Config->get_reference_manual_url());
3636 ARDOUR_UI::launch_tracker ()
3638 PBD::open_uri ("http://tracker.ardour.org");
3642 ARDOUR_UI::launch_subscribe ()
3644 PBD::open_uri ("https://community.ardour.org/s/subscribe");
3648 ARDOUR_UI::launch_cheat_sheet ()
3651 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheat_sheet_osx.pdf");
3653 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheatsheet.pdf");
3658 ARDOUR_UI::launch_website ()
3660 PBD::open_uri ("http://ardour.org");
3664 ARDOUR_UI::launch_website_dev ()
3666 PBD::open_uri ("http://ardour.org/development.html");
3670 ARDOUR_UI::launch_forums ()
3672 PBD::open_uri ("https://community.ardour.org/forums");
3676 ARDOUR_UI::launch_howto_report ()
3678 PBD::open_uri ("http://ardour.org/reporting_bugs");
3682 ARDOUR_UI::loading_message (const std::string& msg)
3684 if (ARDOUR_COMMAND_LINE::no_splash) {
3692 splash->message (msg);
3696 ARDOUR_UI::show_splash ()
3700 splash = new Splash;
3710 ARDOUR_UI::hide_splash ()
3717 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title, const bool msg_delete)
3721 removed = rep.paths.size();
3724 MessageDialog msgd (_main_window,
3725 _("No files were ready for clean-up"),
3729 msgd.set_title (_("Clean-up"));
3730 msgd.set_secondary_text (_("If this seems suprising, \n\
3731 check for any existing snapshots.\n\
3732 These may still include regions that\n\
3733 require some unused files to continue to exist."));
3739 ArdourDialog results (_("Clean-up"), true, false);
3741 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
3742 CleanupResultsModelColumns() {
3746 Gtk::TreeModelColumn<std::string> visible_name;
3747 Gtk::TreeModelColumn<std::string> fullpath;
3751 CleanupResultsModelColumns results_columns;
3752 Glib::RefPtr<Gtk::ListStore> results_model;
3753 Gtk::TreeView results_display;
3755 results_model = ListStore::create (results_columns);
3756 results_display.set_model (results_model);
3757 results_display.append_column (list_title, results_columns.visible_name);
3759 results_display.set_name ("CleanupResultsList");
3760 results_display.set_headers_visible (true);
3761 results_display.set_headers_clickable (false);
3762 results_display.set_reorderable (false);
3764 Gtk::ScrolledWindow list_scroller;
3767 Gtk::HBox dhbox; // the hbox for the image and text
3768 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
3769 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
3771 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
3773 const string dead_directory = _session->session_directory().dead_path();
3776 %1 - number of files removed
3777 %2 - location of "dead"
3778 %3 - size of files affected
3779 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
3782 const char* bprefix;
3783 double space_adjusted = 0;
3785 if (rep.space < 1000) {
3787 space_adjusted = rep.space;
3788 } else if (rep.space < 1000000) {
3789 bprefix = _("kilo");
3790 space_adjusted = floorf((float)rep.space / 1000.0);
3791 } else if (rep.space < 1000000 * 1000) {
3792 bprefix = _("mega");
3793 space_adjusted = floorf((float)rep.space / (1000.0 * 1000.0));
3795 bprefix = _("giga");
3796 space_adjusted = floorf((float)rep.space / (1000.0 * 1000 * 1000.0));
3800 txt.set_markup (string_compose (P_("\
3801 The following file was deleted from %2,\n\
3802 releasing %3 %4bytes of disk space", "\
3803 The following %1 files were deleted from %2,\n\
3804 releasing %3 %4bytes of disk space", removed),
3805 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3807 txt.set_markup (string_compose (P_("\
3808 The following file was not in use and \n\
3809 has been moved to: %2\n\n\
3810 After a restart of %5\n\n\
3811 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3812 will release an additional %3 %4bytes of disk space.\n", "\
3813 The following %1 files were not in use and \n\
3814 have been moved to: %2\n\n\
3815 After a restart of %5\n\n\
3816 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3817 will release an additional %3 %4bytes of disk space.\n", removed),
3818 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3821 dhbox.pack_start (*dimage, true, false, 5);
3822 dhbox.pack_start (txt, true, false, 5);
3824 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
3825 TreeModel::Row row = *(results_model->append());
3826 row[results_columns.visible_name] = *i;
3827 row[results_columns.fullpath] = *i;
3830 list_scroller.add (results_display);
3831 list_scroller.set_size_request (-1, 150);
3832 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
3834 dvbox.pack_start (dhbox, true, false, 5);
3835 dvbox.pack_start (list_scroller, true, false, 5);
3836 ddhbox.pack_start (dvbox, true, false, 5);
3838 results.get_vbox()->pack_start (ddhbox, true, false, 5);
3839 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
3840 results.set_default_response (RESPONSE_CLOSE);
3841 results.set_position (Gtk::WIN_POS_MOUSE);
3843 results_display.show();
3844 list_scroller.show();
3851 //results.get_vbox()->show();
3852 results.set_resizable (false);
3859 ARDOUR_UI::cleanup ()
3861 if (_session == 0) {
3862 /* shouldn't happen: menu item is insensitive */
3867 MessageDialog checker (_("Are you sure you want to clean-up?"),
3869 Gtk::MESSAGE_QUESTION,
3872 checker.set_title (_("Clean-up"));
3874 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
3875 ALL undo/redo information will be lost if you clean-up.\n\
3876 Clean-up will move all unused files to a \"dead\" location."));
3878 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3879 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
3880 checker.set_default_response (RESPONSE_CANCEL);
3882 checker.set_name (_("CleanupDialog"));
3883 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3884 checker.set_position (Gtk::WIN_POS_MOUSE);
3886 switch (checker.run()) {
3887 case RESPONSE_ACCEPT:
3893 ARDOUR::CleanupReport rep;
3895 editor->prepare_for_cleanup ();
3897 /* do not allow flush until a session is reloaded */
3899 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3901 act->set_sensitive (false);
3904 if (_session->cleanup_sources (rep)) {
3905 editor->finish_cleanup ();
3909 editor->finish_cleanup ();
3912 display_cleanup_results (rep, _("Cleaned Files"), false);
3916 ARDOUR_UI::flush_trash ()
3918 if (_session == 0) {
3919 /* shouldn't happen: menu item is insensitive */
3923 ARDOUR::CleanupReport rep;
3925 if (_session->cleanup_trash_sources (rep)) {
3929 display_cleanup_results (rep, _("deleted file"), true);
3933 ARDOUR_UI::cleanup_peakfiles ()
3935 if (_session == 0) {
3936 /* shouldn't happen: menu item is insensitive */
3940 if (! _session->can_cleanup_peakfiles ()) {
3944 // get all region-views in this session
3946 TrackViewList empty;
3948 editor->get_regions_after(rs, (framepos_t) 0, empty);
3949 std::list<RegionView*> views = rs.by_layer();
3951 // remove displayed audio-region-views waveforms
3952 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
3953 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
3954 if (!arv) { continue ; }
3955 arv->delete_waves();
3958 // cleanup peak files:
3959 // - stop pending peakfile threads
3960 // - close peakfiles if any
3961 // - remove peak dir in session
3962 // - setup peakfiles (background thread)
3963 _session->cleanup_peakfiles ();
3965 // re-add waves to ARV
3966 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
3967 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
3968 if (!arv) { continue ; }
3969 arv->create_waves();
3973 PresentationInfo::order_t
3974 ARDOUR_UI::translate_order (RouteDialogs::InsertAt place)
3976 if (editor->get_selection().tracks.empty()) {
3977 return PresentationInfo::max_order;
3980 PresentationInfo::order_t order_hint = PresentationInfo::max_order;
3983 we want the new routes to have their order keys set starting from
3984 the highest order key in the selection + 1 (if available).
3987 if (place == RouteDialogs::AfterSelection) {
3988 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.back());
3990 order_hint = rtav->route()->presentation_info().order();
3993 } else if (place == RouteDialogs::BeforeSelection) {
3994 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.front());
3996 order_hint = rtav->route()->presentation_info().order();
3998 } else if (place == RouteDialogs::First) {
4001 /* leave order_hint at max_order */
4008 ARDOUR_UI::start_duplicate_routes ()
4010 if (!duplicate_routes_dialog) {
4011 duplicate_routes_dialog = new DuplicateRouteDialog;
4014 if (duplicate_routes_dialog->restart (_session)) {
4018 duplicate_routes_dialog->present ();
4022 ARDOUR_UI::add_route ()
4024 if (!add_route_dialog.get (false)) {
4025 add_route_dialog->signal_response().connect (sigc::mem_fun (*this, &ARDOUR_UI::add_route_dialog_finished));
4032 if (add_route_dialog->is_visible()) {
4033 /* we're already doing this */
4037 add_route_dialog->set_position (WIN_POS_MOUSE);
4038 add_route_dialog->present();
4042 ARDOUR_UI::add_route_dialog_finished (int r)
4046 add_route_dialog->hide();
4049 case RESPONSE_ACCEPT:
4056 if ((count = add_route_dialog->count()) <= 0) {
4060 PresentationInfo::order_t order = translate_order (add_route_dialog->insert_at());
4061 string template_path = add_route_dialog->track_template();
4062 DisplaySuspender ds;
4064 if (!template_path.empty()) {
4065 if (add_route_dialog->name_template_is_default()) {
4066 _session->new_route_from_template (count, template_path, string());
4068 _session->new_route_from_template (count, template_path, add_route_dialog->name_template());
4073 ChanCount input_chan= add_route_dialog->channels ();
4074 ChanCount output_chan;
4075 string name_template = add_route_dialog->name_template ();
4076 PluginInfoPtr instrument = add_route_dialog->requested_instrument ();
4077 RouteGroup* route_group = add_route_dialog->route_group ();
4078 AutoConnectOption oac = Config->get_output_auto_connect();
4079 bool strict_io = add_route_dialog->use_strict_io ();
4081 if (oac & AutoConnectMaster) {
4082 output_chan.set (DataType::AUDIO, (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan.n_audio()));
4083 output_chan.set (DataType::MIDI, 0);
4085 output_chan = input_chan;
4088 /* XXX do something with name template */
4090 switch (add_route_dialog->type_wanted()) {
4091 case AddRouteDialog::AudioTrack:
4092 session_add_audio_track (input_chan.n_audio(), output_chan.n_audio(), add_route_dialog->mode(), route_group, count, name_template, strict_io, order);
4094 case AddRouteDialog::MidiTrack:
4095 session_add_midi_track (route_group, count, name_template, strict_io, instrument, 0, order);
4097 case AddRouteDialog::MixedTrack:
4098 session_add_mixed_track (input_chan, output_chan, route_group, count, name_template, strict_io, instrument, 0, order);
4100 case AddRouteDialog::AudioBus:
4101 session_add_audio_bus (input_chan.n_audio(), output_chan.n_audio(), route_group, count, name_template, strict_io, order);
4103 case AddRouteDialog::MidiBus:
4104 session_add_midi_bus (route_group, count, name_template, strict_io, instrument, 0, order);
4106 case AddRouteDialog::VCAMaster:
4107 session_add_vca (name_template, count);
4113 ARDOUR_UI::add_lua_script ()
4119 LuaScriptInfoPtr spi;
4120 ScriptSelector ss ("Add Lua Session Script", LuaScriptInfo::Session);
4121 switch (ss.run ()) {
4122 case Gtk::RESPONSE_ACCEPT:
4130 std::string script = "";
4133 script = Glib::file_get_contents (spi->path);
4134 } catch (Glib::FileError e) {
4135 string msg = string_compose (_("Cannot read session script '%1': %2"), spi->path, e.what());
4136 MessageDialog am (msg);
4141 LuaScriptParamList lsp = LuaScriptParams::script_params (spi, "sess_params");
4142 std::vector<std::string> reg = _session->registered_lua_functions ();
4144 ScriptParameterDialog spd (_("Set Script Parameters"), spi, reg, lsp);
4145 switch (spd.run ()) {
4146 case Gtk::RESPONSE_ACCEPT:
4153 _session->register_lua_function (spd.name(), script, lsp);
4154 } catch (luabridge::LuaException const& e) {
4155 string msg = string_compose (_("Session script '%1' instantiation failed: %2"), spd.name(), e.what ());
4156 MessageDialog am (msg);
4158 } catch (SessionException e) {
4159 string msg = string_compose (_("Loading Session script '%1' failed: %2"), spd.name(), e.what ());
4160 MessageDialog am (msg);
4166 ARDOUR_UI::remove_lua_script ()
4171 if (_session->registered_lua_function_count () == 0) {
4172 string msg = _("There are no active Lua session scripts present in this session.");
4173 MessageDialog am (msg);
4178 std::vector<std::string> reg = _session->registered_lua_functions ();
4179 SessionScriptManager sm ("Remove Lua Session Script", reg);
4180 switch (sm.run ()) {
4181 case Gtk::RESPONSE_ACCEPT:
4187 _session->unregister_lua_function (sm.name());
4188 } catch (luabridge::LuaException const& e) {
4189 string msg = string_compose (_("Session script '%1' removal failed: %2"), sm.name(), e.what ());
4190 MessageDialog am (msg);
4196 ARDOUR_UI::stop_video_server (bool ask_confirm)
4198 if (!video_server_process && ask_confirm) {
4199 warning << string_compose (_("Video-Server was not launched by %1. The request to stop it is ignored."), PROGRAM_NAME) << endmsg;
4201 if (video_server_process) {
4203 ArdourDialog confirm (_("Stop Video-Server"), true);
4204 Label m (_("Do you really want to stop the Video Server?"));
4205 confirm.get_vbox()->pack_start (m, true, true);
4206 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
4207 confirm.add_button (_("Yes, Stop It"), Gtk::RESPONSE_ACCEPT);
4208 confirm.show_all ();
4209 if (confirm.run() == RESPONSE_CANCEL) {
4213 delete video_server_process;
4214 video_server_process =0;
4219 ARDOUR_UI::start_video_server_menu (Gtk::Window* float_window)
4221 ARDOUR_UI::start_video_server( float_window, true);
4225 ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg)
4231 if (ARDOUR_UI::instance()->video_timeline->check_server()) {
4232 if (video_server_process) {
4233 popup_error(_("The Video Server is already started."));
4235 popup_error(_("An external Video Server is configured and can be reached. Not starting a new instance."));
4241 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4243 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4245 VideoServerDialog *video_server_dialog = new VideoServerDialog (_session);
4247 video_server_dialog->set_transient_for (*float_window);
4250 if (!Config->get_show_video_server_dialog() && firsttime < 2) {
4251 video_server_dialog->hide();
4253 ResponseType r = (ResponseType) video_server_dialog->run ();
4254 video_server_dialog->hide();
4255 if (r != RESPONSE_ACCEPT) { return false; }
4256 if (video_server_dialog->show_again()) {
4257 Config->set_show_video_server_dialog(false);
4261 std::string icsd_exec = video_server_dialog->get_exec_path();
4262 std::string icsd_docroot = video_server_dialog->get_docroot();
4263 if (icsd_docroot.empty()) {
4264 #ifndef PLATFORM_WINDOWS
4265 icsd_docroot = X_("/");
4267 icsd_docroot = X_("C:\\");
4272 if (g_lstat (icsd_docroot.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode)) {
4273 warning << _("Specified docroot is not an existing directory.") << endmsg;
4276 #ifndef PLATFORM_WINDOWS
4277 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4278 || (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0 ) {
4279 warning << _("Given Video Server is not an executable file.") << endmsg;
4283 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4284 || (sb.st_mode & (S_IXUSR)) == 0 ) {
4285 warning << _("Given Video Server is not an executable file.") << endmsg;
4291 argp=(char**) calloc(9,sizeof(char*));
4292 argp[0] = strdup(icsd_exec.c_str());
4293 argp[1] = strdup("-P");
4294 argp[2] = (char*) calloc(16,sizeof(char)); snprintf(argp[2], 16, "%s", video_server_dialog->get_listenaddr().c_str());
4295 argp[3] = strdup("-p");
4296 argp[4] = (char*) calloc(6,sizeof(char)); snprintf(argp[4], 6, "%i", video_server_dialog->get_listenport());
4297 argp[5] = strdup("-C");
4298 argp[6] = (char*) calloc(6,sizeof(char)); snprintf(argp[6], 6, "%i", video_server_dialog->get_cachesize());
4299 argp[7] = strdup(icsd_docroot.c_str());
4301 stop_video_server();
4303 if (icsd_docroot == X_("/") || icsd_docroot == X_("C:\\")) {
4304 Config->set_video_advanced_setup(false);
4306 std::ostringstream osstream;
4307 osstream << "http://127.0.0.1:" << video_server_dialog->get_listenport() << "/";
4308 Config->set_video_server_url(osstream.str());
4309 Config->set_video_server_docroot(icsd_docroot);
4310 Config->set_video_advanced_setup(true);
4313 if (video_server_process) {
4314 delete video_server_process;
4317 video_server_process = new ARDOUR::SystemExec(icsd_exec, argp);
4318 if (video_server_process->start()) {
4319 warning << _("Cannot launch the video-server") << endmsg;
4322 int timeout = 120; // 6 sec
4323 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4324 Glib::usleep (50000);
4326 if (--timeout <= 0 || !video_server_process->is_running()) break;
4329 warning << _("Video-server was started but does not respond to requests...") << endmsg;
4331 if (!ARDOUR_UI::instance()->video_timeline->check_server_docroot()) {
4332 delete video_server_process;
4333 video_server_process = 0;
4341 ARDOUR_UI::add_video (Gtk::Window* float_window)
4347 if (!start_video_server(float_window, false)) {
4348 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4353 add_video_dialog->set_transient_for (*float_window);
4356 if (add_video_dialog->is_visible()) {
4357 /* we're already doing this */
4361 ResponseType r = (ResponseType) add_video_dialog->run ();
4362 add_video_dialog->hide();
4363 if (r != RESPONSE_ACCEPT) { return; }
4365 bool local_file, orig_local_file;
4366 std::string path = add_video_dialog->file_name(local_file);
4368 std::string orig_path = path;
4369 orig_local_file = local_file;
4371 bool auto_set_session_fps = add_video_dialog->auto_set_session_fps();
4373 if (local_file && !Glib::file_test(path, Glib::FILE_TEST_EXISTS)) {
4374 warning << string_compose(_("could not open %1"), path) << endmsg;
4377 if (!local_file && path.length() == 0) {
4378 warning << _("no video-file selected") << endmsg;
4382 std::string audio_from_video;
4383 bool detect_ltc = false;
4385 switch (add_video_dialog->import_option()) {
4386 case VTL_IMPORT_TRANSCODE:
4388 TranscodeVideoDialog *transcode_video_dialog;
4389 transcode_video_dialog = new TranscodeVideoDialog (_session, path);
4390 ResponseType r = (ResponseType) transcode_video_dialog->run ();
4391 transcode_video_dialog->hide();
4392 if (r != RESPONSE_ACCEPT) {
4393 delete transcode_video_dialog;
4397 audio_from_video = transcode_video_dialog->get_audiofile();
4399 if (!audio_from_video.empty() && transcode_video_dialog->detect_ltc()) {
4402 else if (!audio_from_video.empty()) {
4403 editor->embed_audio_from_video(
4405 video_timeline->get_offset(),
4406 (transcode_video_dialog->import_option() != VTL_IMPORT_NO_VIDEO)
4409 switch (transcode_video_dialog->import_option()) {
4410 case VTL_IMPORT_TRANSCODED:
4411 path = transcode_video_dialog->get_filename();
4414 case VTL_IMPORT_REFERENCE:
4417 delete transcode_video_dialog;
4420 delete transcode_video_dialog;
4424 case VTL_IMPORT_NONE:
4428 /* strip _session->session_directory().video_path() from video file if possible */
4429 if (local_file && !path.compare(0, _session->session_directory().video_path().size(), _session->session_directory().video_path())) {
4430 path=path.substr(_session->session_directory().video_path().size());
4431 if (path.at(0) == G_DIR_SEPARATOR) {
4432 path=path.substr(1);
4436 video_timeline->set_update_session_fps(auto_set_session_fps);
4438 if (video_timeline->video_file_info(path, local_file)) {
4439 XMLNode* node = new XMLNode(X_("Videotimeline"));
4440 node->add_property (X_("Filename"), path);
4441 node->add_property (X_("AutoFPS"), auto_set_session_fps?X_("1"):X_("0"));
4442 node->add_property (X_("LocalFile"), local_file?X_("1"):X_("0"));
4443 if (orig_local_file) {
4444 node->add_property (X_("OriginalVideoFile"), orig_path);
4446 node->remove_property (X_("OriginalVideoFile"));
4448 _session->add_extra_xml (*node);
4449 _session->set_dirty ();
4451 if (!audio_from_video.empty() && detect_ltc) {
4452 std::vector<LTCFileReader::LTCMap> ltc_seq;
4455 /* TODO ask user about TV standard (LTC alignment if any) */
4456 LTCFileReader ltcr (audio_from_video, video_timeline->get_video_file_fps());
4457 /* TODO ASK user which channel: 0 .. ltcr->channels() - 1 */
4459 ltc_seq = ltcr.read_ltc (/*channel*/ 0, /*max LTC frames to decode*/ 15);
4461 /* TODO seek near end of file, and read LTC until end.
4462 * if it fails to find any LTC frames, scan complete file
4464 * calculate drift of LTC compared to video-duration,
4465 * ask user for reference (timecode from start/mid/end)
4468 // LTCFileReader will have written error messages
4471 ::g_unlink(audio_from_video.c_str());
4473 if (ltc_seq.size() == 0) {
4474 PBD::error << _("No LTC detected, video will not be aligned.") << endmsg;
4476 /* the very first TC in the file is somteimes not aligned properly */
4477 int i = ltc_seq.size() -1;
4478 ARDOUR::frameoffset_t video_start_offset =
4479 _session->nominal_frame_rate() * (ltc_seq[i].timecode_sec - ltc_seq[i].framepos_sec);
4480 PBD::info << string_compose (_("Align video-start to %1 [samples]"), video_start_offset) << endmsg;
4481 video_timeline->set_offset(video_start_offset);
4485 _session->maybe_update_session_range(
4486 std::max(video_timeline->get_offset(), (ARDOUR::frameoffset_t) 0),
4487 std::max(video_timeline->get_offset() + video_timeline->get_duration(), (ARDOUR::frameoffset_t) 0));
4490 if (add_video_dialog->launch_xjadeo() && local_file) {
4491 editor->set_xjadeo_sensitive(true);
4492 editor->toggle_xjadeo_proc(1);
4494 editor->toggle_xjadeo_proc(0);
4496 editor->toggle_ruler_video(true);
4501 ARDOUR_UI::remove_video ()
4503 video_timeline->close_session();
4504 editor->toggle_ruler_video(false);
4507 video_timeline->set_offset_locked(false);
4508 video_timeline->set_offset(0);
4510 /* delete session state */
4511 XMLNode* node = new XMLNode(X_("Videotimeline"));
4512 _session->add_extra_xml(*node);
4513 node = new XMLNode(X_("Videomonitor"));
4514 _session->add_extra_xml(*node);
4515 node = new XMLNode(X_("Videoexport"));
4516 _session->add_extra_xml(*node);
4517 stop_video_server();
4521 ARDOUR_UI::flush_videotimeline_cache (bool localcacheonly)
4523 if (localcacheonly) {
4524 video_timeline->vmon_update();
4526 video_timeline->flush_cache();
4528 editor->queue_visual_videotimeline_update();
4532 ARDOUR_UI::export_video (bool range)
4534 if (ARDOUR::Config->get_show_video_export_info()) {
4535 ExportVideoInfobox infobox (_session);
4536 Gtk::ResponseType rv = (Gtk::ResponseType) infobox.run();
4537 if (infobox.show_again()) {
4538 ARDOUR::Config->set_show_video_export_info(false);
4541 case GTK_RESPONSE_YES:
4542 PBD::open_uri (ARDOUR::Config->get_reference_manual_url() + "/video-timeline/operations/#export");
4548 export_video_dialog->set_session (_session);
4549 export_video_dialog->apply_state(editor->get_selection().time, range);
4550 export_video_dialog->run ();
4551 export_video_dialog->hide ();
4555 ARDOUR_UI::preferences_settings () const
4560 node = _session->instant_xml(X_("Preferences"));
4562 node = Config->instant_xml(X_("Preferences"));
4566 node = new XMLNode (X_("Preferences"));
4573 ARDOUR_UI::mixer_settings () const
4578 node = _session->instant_xml(X_("Mixer"));
4580 node = Config->instant_xml(X_("Mixer"));
4584 node = new XMLNode (X_("Mixer"));
4591 ARDOUR_UI::main_window_settings () const
4596 node = _session->instant_xml(X_("Main"));
4598 node = Config->instant_xml(X_("Main"));
4602 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4603 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4608 node = new XMLNode (X_("Main"));
4615 ARDOUR_UI::editor_settings () const
4620 node = _session->instant_xml(X_("Editor"));
4622 node = Config->instant_xml(X_("Editor"));
4626 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4627 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4632 node = new XMLNode (X_("Editor"));
4639 ARDOUR_UI::keyboard_settings () const
4643 node = Config->extra_xml(X_("Keyboard"));
4646 node = new XMLNode (X_("Keyboard"));
4653 ARDOUR_UI::create_xrun_marker (framepos_t where)
4656 Location *location = new Location (*_session, where, where, _("xrun"), Location::IsMark);
4657 _session->locations()->add (location);
4662 ARDOUR_UI::halt_on_xrun_message ()
4664 cerr << "HALT on xrun\n";
4665 MessageDialog msg (_main_window, _("Recording was stopped because your system could not keep up."));
4670 ARDOUR_UI::xrun_handler (framepos_t where)
4676 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
4678 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
4679 create_xrun_marker(where);
4682 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
4683 halt_on_xrun_message ();
4688 ARDOUR_UI::disk_overrun_handler ()
4690 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
4692 if (!have_disk_speed_dialog_displayed) {
4693 have_disk_speed_dialog_displayed = true;
4694 MessageDialog* msg = new MessageDialog (_main_window, string_compose (_("\
4695 The disk system on your computer\n\
4696 was not able to keep up with %1.\n\
4698 Specifically, it failed to write data to disk\n\
4699 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
4700 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4706 /* TODO: this is getting elaborate enough to warrant being split into a dedicated class */
4707 static MessageDialog *scan_dlg = NULL;
4708 static ProgressBar *scan_pbar = NULL;
4709 static HBox *scan_tbox = NULL;
4710 static Gtk::Button *scan_timeout_button;
4713 ARDOUR_UI::cancel_plugin_scan ()
4715 PluginManager::instance().cancel_plugin_scan();
4719 ARDOUR_UI::cancel_plugin_timeout ()
4721 PluginManager::instance().cancel_plugin_timeout();
4722 scan_timeout_button->set_sensitive (false);
4726 ARDOUR_UI::plugin_scan_timeout (int timeout)
4728 if (!scan_dlg || !scan_dlg->is_mapped() || !scan_pbar) {
4732 scan_pbar->set_sensitive (false);
4733 scan_timeout_button->set_sensitive (true);
4734 scan_pbar->set_fraction ((float) timeout / (float) Config->get_vst_scan_timeout());
4737 scan_pbar->set_sensitive (false);
4738 scan_timeout_button->set_sensitive (false);
4744 ARDOUR_UI::plugin_scan_dialog (std::string type, std::string plugin, bool can_cancel)
4746 if (type == X_("closeme") && !(scan_dlg && scan_dlg->is_mapped())) {
4750 const bool cancelled = PluginManager::instance().cancelled();
4751 if (type != X_("closeme") && (!UIConfiguration::instance().get_show_plugin_scan_window()) && !_initial_verbose_plugin_scan) {
4752 if (cancelled && scan_dlg->is_mapped()) {
4757 if (cancelled || !can_cancel) {
4762 static Gtk::Button *cancel_button;
4764 scan_dlg = new MessageDialog("", false, MESSAGE_INFO, BUTTONS_NONE); // TODO manage
4765 VBox* vbox = scan_dlg->get_vbox();
4766 vbox->set_size_request(400,-1);
4767 scan_dlg->set_title (_("Scanning for plugins"));
4769 cancel_button = manage(new Gtk::Button(_("Cancel plugin scan")));
4770 cancel_button->set_name ("EditorGTKButton");
4771 cancel_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_scan) );
4772 cancel_button->show();
4774 scan_dlg->get_vbox()->pack_start ( *cancel_button, PACK_SHRINK);
4776 scan_tbox = manage( new HBox() );
4778 scan_timeout_button = manage(new Gtk::Button(_("Stop Timeout")));
4779 scan_timeout_button->set_name ("EditorGTKButton");
4780 scan_timeout_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_timeout) );
4781 scan_timeout_button->show();
4783 scan_pbar = manage(new ProgressBar());
4784 scan_pbar->set_orientation(Gtk::PROGRESS_RIGHT_TO_LEFT);
4785 scan_pbar->set_text(_("Scan Timeout"));
4788 scan_tbox->pack_start (*scan_pbar, PACK_EXPAND_WIDGET, 4);
4789 scan_tbox->pack_start (*scan_timeout_button, PACK_SHRINK, 4);
4791 scan_dlg->get_vbox()->pack_start (*scan_tbox, PACK_SHRINK, 4);
4794 assert(scan_dlg && scan_tbox && cancel_button);
4796 if (type == X_("closeme")) {
4800 scan_dlg->set_message(type + ": " + Glib::path_get_basename(plugin));
4803 if (!can_cancel || !cancelled) {
4804 scan_timeout_button->set_sensitive(false);
4806 cancel_button->set_sensitive(can_cancel && !cancelled);
4812 ARDOUR_UI::gui_idle_handler ()
4815 /* due to idle calls, gtk_events_pending() may always return true */
4816 while (gtk_events_pending() && --timeout) {
4817 gtk_main_iteration ();
4822 ARDOUR_UI::disk_underrun_handler ()
4824 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
4826 if (!have_disk_speed_dialog_displayed) {
4827 have_disk_speed_dialog_displayed = true;
4828 MessageDialog* msg = new MessageDialog (
4829 _main_window, string_compose (_("The disk system on your computer\n\
4830 was not able to keep up with %1.\n\
4832 Specifically, it failed to read data from disk\n\
4833 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
4834 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4840 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
4842 have_disk_speed_dialog_displayed = false;
4847 ARDOUR_UI::session_dialog (std::string msg)
4849 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
4853 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
4860 ARDOUR_UI::pending_state_dialog ()
4862 HBox* hbox = manage (new HBox());
4863 Image* image = manage (new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG));
4864 ArdourDialog dialog (_("Crash Recovery"), true);
4865 Label message (string_compose (_("\
4866 This session appears to have been in the\n\
4867 middle of recording when %1 or\n\
4868 the computer was shutdown.\n\
4870 %1 can recover any captured audio for\n\
4871 you, or it can ignore it. Please decide\n\
4872 what you would like to do.\n"), PROGRAM_NAME));
4873 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4874 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4875 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4876 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4877 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
4878 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
4879 dialog.set_default_response (RESPONSE_ACCEPT);
4880 dialog.set_position (WIN_POS_CENTER);
4885 switch (dialog.run ()) {
4886 case RESPONSE_ACCEPT:
4894 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
4896 HBox* hbox = new HBox();
4897 Image* image = new Image (Stock::DIALOG_WARNING, ICON_SIZE_DIALOG);
4898 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
4899 Label message (string_compose (_("\
4900 This session was created with a sample rate of %1 Hz, but\n\
4901 %2 is currently running at %3 Hz. If you load this session,\n\
4902 audio may be played at the wrong sample rate.\n"), desired, PROGRAM_NAME, actual));
4904 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4905 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4906 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4907 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4908 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
4909 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
4910 dialog.set_default_response (RESPONSE_ACCEPT);
4911 dialog.set_position (WIN_POS_CENTER);
4916 switch (dialog.run()) {
4917 case RESPONSE_ACCEPT:
4927 ARDOUR_UI::sr_mismatch_message (framecnt_t desired, framecnt_t actual)
4929 MessageDialog msg (string_compose (_("\
4930 This session was created with a sample rate of %1 Hz, but\n\
4931 %2 is currently running at %3 Hz.\n\
4932 Audio will be recorded and played at the wrong sample rate.\n\
4933 Re-Configure the Audio Engine in\n\
4934 Menu > Window > Audio/Midi Setup"),
4935 desired, PROGRAM_NAME, actual),
4937 Gtk::MESSAGE_WARNING);
4942 ARDOUR_UI::use_config ()
4944 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
4946 set_transport_controllable_state (*node);
4951 ARDOUR_UI::update_transport_clocks (framepos_t pos)
4953 if (UIConfiguration::instance().get_primary_clock_delta_edit_cursor()) {
4954 primary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
4956 primary_clock->set (pos);
4959 if (UIConfiguration::instance().get_secondary_clock_delta_edit_cursor()) {
4960 secondary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
4962 secondary_clock->set (pos);
4965 if (big_clock_window) {
4966 big_clock->set (pos);
4968 ARDOUR_UI::instance()->video_timeline->manual_seek_video_monitor(pos);
4972 ARDOUR_UI::step_edit_status_change (bool yn)
4974 // XXX should really store pre-step edit status of things
4975 // we make insensitive
4978 rec_button.set_active_state (Gtkmm2ext::ImplicitActive);
4979 rec_button.set_sensitive (false);
4981 rec_button.unset_active_state ();;
4982 rec_button.set_sensitive (true);
4987 ARDOUR_UI::record_state_changed ()
4989 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
4991 if (!_session || !big_clock_window) {
4992 /* why bother - the clock isn't visible */
4996 if (_session->record_status () == Session::Recording && _session->have_rec_enabled_track ()) {
4997 big_clock->set_active (true);
4999 big_clock->set_active (false);
5004 ARDOUR_UI::first_idle ()
5007 _session->allow_auto_play (true);
5011 editor->first_idle();
5014 Keyboard::set_can_save_keybindings (true);
5019 ARDOUR_UI::store_clock_modes ()
5021 XMLNode* node = new XMLNode(X_("ClockModes"));
5023 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
5024 XMLNode* child = new XMLNode (X_("Clock"));
5026 child->add_property (X_("name"), (*x)->name());
5027 child->add_property (X_("mode"), enum_2_string ((*x)->mode()));
5028 child->add_property (X_("on"), ((*x)->off() ? X_("no") : X_("yes")));
5030 node->add_child_nocopy (*child);
5033 _session->add_extra_xml (*node);
5034 _session->set_dirty ();
5037 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
5038 : Controllable (name), ui (u), type(tp)
5044 ARDOUR_UI::TransportControllable::set_value (double val, PBD::Controllable::GroupControlDisposition /*group_override*/)
5047 /* do nothing: these are radio-style actions */
5051 const char *action = 0;
5055 action = X_("Roll");
5058 action = X_("Stop");
5061 action = X_("GotoStart");
5064 action = X_("GotoEnd");
5067 action = X_("Loop");
5070 action = X_("PlaySelection");
5073 action = X_("Record");
5083 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
5091 ARDOUR_UI::TransportControllable::get_value (void) const
5118 ARDOUR_UI::setup_profile ()
5120 if (gdk_screen_width() < 1200 || getenv ("ARDOUR_NARROW_SCREEN")) {
5121 Profile->set_small_screen ();
5124 if (g_getenv ("TRX")) {
5125 Profile->set_trx ();
5128 if (g_getenv ("MIXBUS")) {
5129 Profile->set_mixbus ();
5134 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
5136 MissingFileDialog dialog (s, str, type);
5141 int result = dialog.run ();
5148 return 1; // quit entire session load
5151 result = dialog.get_action ();
5157 ARDOUR_UI::ambiguous_file (std::string file, std::vector<std::string> hits)
5159 AmbiguousFileDialog dialog (file, hits);
5166 return dialog.get_which ();
5169 /** Allocate our thread-local buffers */
5171 ARDOUR_UI::get_process_buffers ()
5173 _process_thread->get_buffers ();
5176 /** Drop our thread-local buffers */
5178 ARDOUR_UI::drop_process_buffers ()
5180 _process_thread->drop_buffers ();
5184 ARDOUR_UI::feedback_detected ()
5186 _feedback_exists = true;
5190 ARDOUR_UI::successful_graph_sort ()
5192 _feedback_exists = false;
5196 ARDOUR_UI::midi_panic ()
5199 _session->midi_panic();
5204 ARDOUR_UI::session_format_mismatch (std::string xml_path, std::string backup_path)
5206 const char* start_big = "<span size=\"x-large\" weight=\"bold\">";
5207 const char* end_big = "</span>";
5208 const char* start_mono = "<tt>";
5209 const char* end_mono = "</tt>";
5211 MessageDialog msg (string_compose (_("%4This is a session from an older version of %3%5\n\n"
5212 "%3 has copied the old session file\n\n%6%1%7\n\nto\n\n%6%2%7\n\n"
5213 "From now on, use the backup copy with older versions of %3"),
5214 xml_path, backup_path, PROGRAM_NAME,
5216 start_mono, end_mono), true);
5223 ARDOUR_UI::reset_peak_display ()
5225 if (!_session || !_session->master_out() || !editor_meter) return;
5226 editor_meter->clear_meters();
5227 editor_meter_max_peak = -INFINITY;
5228 editor_meter_peak_display.set_active_state ( Gtkmm2ext::Off );
5232 ARDOUR_UI::reset_group_peak_display (RouteGroup* group)
5234 if (!_session || !_session->master_out()) return;
5235 if (group == _session->master_out()->route_group()) {
5236 reset_peak_display ();
5241 ARDOUR_UI::reset_route_peak_display (Route* route)
5243 if (!_session || !_session->master_out()) return;
5244 if (_session->master_out().get() == route) {
5245 reset_peak_display ();
5250 ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate)
5252 audio_midi_setup->set_desired_sample_rate (desired_sample_rate);
5253 audio_midi_setup->set_position (WIN_POS_CENTER);
5255 if (Config->get_try_autostart_engine () || getenv ("TRY_AUTOSTART_ENGINE")) {
5256 audio_midi_setup->try_autostart ();
5257 if (ARDOUR::AudioEngine::instance()->running()) {
5263 int response = audio_midi_setup->run();
5265 case Gtk::RESPONSE_OK:
5266 if (!AudioEngine::instance()->running()) {
5280 ARDOUR_UI::transport_numpad_timeout ()
5282 _numpad_locate_happening = false;
5283 if (_numpad_timeout_connection.connected() )
5284 _numpad_timeout_connection.disconnect();
5289 ARDOUR_UI::transport_numpad_decimal ()
5291 _numpad_timeout_connection.disconnect();
5293 if (_numpad_locate_happening) {
5294 if (editor) editor->goto_nth_marker(_pending_locate_num - 1);
5295 _numpad_locate_happening = false;
5297 _pending_locate_num = 0;
5298 _numpad_locate_happening = true;
5299 _numpad_timeout_connection = Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::transport_numpad_timeout), 2*1000);
5304 ARDOUR_UI::transport_numpad_event (int num)
5306 if ( _numpad_locate_happening ) {
5307 _pending_locate_num = _pending_locate_num*10 + num;
5310 case 0: toggle_roll(false, false); break;
5311 case 1: transport_rewind(1); break;
5312 case 2: transport_forward(1); break;
5313 case 3: transport_record(true); break;
5314 case 4: toggle_session_auto_loop(); break;
5315 case 5: transport_record(false); toggle_session_auto_loop(); break;
5316 case 6: toggle_punch(); break;
5317 case 7: toggle_click(); break;
5318 case 8: toggle_auto_return(); break;
5319 case 9: toggle_follow_edits(); break;
5325 ARDOUR_UI::set_flat_buttons ()
5327 CairoWidget::set_flat_buttons( UIConfiguration::instance().get_flat_buttons() );
5331 ARDOUR_UI::audioengine_became_silent ()
5333 MessageDialog msg (string_compose (_("This is a free/demo copy of %1. It has just switched to silent mode."), PROGRAM_NAME),
5335 Gtk::MESSAGE_WARNING,
5339 msg.set_title (string_compose (_("%1 is now silent"), PROGRAM_NAME));
5341 Gtk::Label pay_label (string_compose (_("Please consider paying for a copy of %1 - you can pay whatever you want."), PROGRAM_NAME));
5342 Gtk::Label subscribe_label (_("Better yet become a subscriber - subscriptions start at US$1 per month."));
5343 Gtk::Button pay_button (_("Pay for a copy (via the web)"));
5344 Gtk::Button subscribe_button (_("Become a subscriber (via the web)"));
5345 Gtk::HBox pay_button_box;
5346 Gtk::HBox subscribe_button_box;
5348 pay_button_box.pack_start (pay_button, true, false);
5349 subscribe_button_box.pack_start (subscribe_button, true, false);
5351 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 */
5353 pay_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://ardour.org/download")));
5354 subscribe_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://community.ardour.org/s/subscribe")));
5356 msg.get_vbox()->pack_start (pay_label);
5357 msg.get_vbox()->pack_start (pay_button_box);
5358 msg.get_vbox()->pack_start (subscribe_label);
5359 msg.get_vbox()->pack_start (subscribe_button_box);
5361 msg.get_vbox()->show_all ();
5363 msg.add_button (_("Remain silent"), Gtk::RESPONSE_CANCEL);
5364 msg.add_button (_("Save and quit"), Gtk::RESPONSE_NO);
5365 msg.add_button (_("Give me more time"), Gtk::RESPONSE_YES);
5370 case Gtk::RESPONSE_YES:
5371 AudioEngine::instance()->reset_silence_countdown ();
5374 case Gtk::RESPONSE_NO:
5376 save_state_canfail ("");
5380 case Gtk::RESPONSE_CANCEL:
5382 /* don't reset, save session and exit */
5388 ARDOUR_UI::hide_application ()
5390 Application::instance ()-> hide ();
5394 ARDOUR_UI::setup_toplevel_window (Gtk::Window& window, const string& name, void* owner)
5396 /* icons, titles, WM stuff */
5398 static list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
5400 if (window_icons.empty()) {
5401 Glib::RefPtr<Gdk::Pixbuf> icon;
5402 if ((icon = ::get_icon (PROGRAM_NAME "-icon_16px"))) {
5403 window_icons.push_back (icon);
5405 if ((icon = ::get_icon (PROGRAM_NAME "-icon_22px"))) {
5406 window_icons.push_back (icon);
5408 if ((icon = ::get_icon (PROGRAM_NAME "-icon_32px"))) {
5409 window_icons.push_back (icon);
5411 if ((icon = ::get_icon (PROGRAM_NAME "-icon_48px"))) {
5412 window_icons.push_back (icon);
5416 if (!window_icons.empty()) {
5417 window.set_default_icon_list (window_icons);
5420 Gtkmm2ext::WindowTitle title (Glib::get_application_name());
5422 if (!name.empty()) {
5426 window.set_title (title.get_string());
5427 window.set_wmclass (string_compose (X_("%1_%1"), downcase (PROGRAM_NAME), downcase (name)), PROGRAM_NAME);
5429 window.set_flags (CAN_FOCUS);
5430 window.add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
5432 /* This is a hack to ensure that GTK-accelerators continue to
5433 * work. Once we switch over to entirely native bindings, this will be
5434 * unnecessary and should be removed
5436 window.add_accel_group (ActionManager::ui_manager->get_accel_group());
5438 window.signal_configure_event().connect (sigc::mem_fun (*this, &ARDOUR_UI::configure_handler));
5439 window.signal_window_state_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::tabbed_window_state_event_handler), owner));
5440 window.signal_key_press_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5441 window.signal_key_release_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5445 ARDOUR_UI::key_event_handler (GdkEventKey* ev, Gtk::Window* event_window)
5447 Gtkmm2ext::Bindings* bindings = 0;
5448 Gtk::Window* window = 0;
5450 /* until we get ardour bindings working, we are not handling key
5454 if (ev->type != GDK_KEY_PRESS) {
5458 if (event_window == &_main_window) {
5460 window = event_window;
5462 /* find current tab contents */
5464 Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page());
5466 /* see if it uses the ardour binding system */
5469 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(w->get_data ("ardour-bindings"));
5472 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("main window key event, bindings = %1, global = %2\n", bindings, &global_bindings));
5476 window = event_window;
5478 /* see if window uses ardour binding system */
5480 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(window->get_data ("ardour-bindings"));
5483 /* An empty binding set is treated as if it doesn't exist */
5485 if (bindings && bindings->empty()) {
5489 return key_press_focus_accelerator_handler (*window, ev, bindings);
5492 static Gtkmm2ext::Bindings*
5493 get_bindings_from_widget_heirarchy (GtkWidget* w)
5498 if ((p = g_object_get_data (G_OBJECT(w), "ardour-bindings")) != 0) {
5501 w = gtk_widget_get_parent (w);
5504 return reinterpret_cast<Gtkmm2ext::Bindings*> (p);
5508 ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev, Gtkmm2ext::Bindings* bindings)
5510 GtkWindow* win = window.gobj();
5511 GtkWidget* focus = gtk_window_get_focus (win);
5512 bool special_handling_of_unmodified_accelerators = false;
5513 const guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK));
5517 /* some widget has keyboard focus */
5519 if (GTK_IS_ENTRY(focus) || Keyboard::some_magic_widget_has_focus()) {
5521 /* A particular kind of focusable widget currently has keyboard
5522 * focus. All unmodified key events should go to that widget
5523 * first and not be used as an accelerator by default
5526 special_handling_of_unmodified_accelerators = true;
5530 Gtkmm2ext::Bindings* focus_bindings = get_bindings_from_widget_heirarchy (focus);
5531 if (focus_bindings) {
5532 bindings = focus_bindings;
5533 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Switch bindings based on focus widget, now using %1\n", bindings->name()));
5538 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",
5541 Gtkmm2ext::show_gdk_event_state (ev->state),
5542 special_handling_of_unmodified_accelerators,
5543 Keyboard::some_magic_widget_has_focus(),
5545 (focus ? gtk_widget_get_name (focus) : "no focus widget"),
5546 ((ev->state & mask) ? "yes" : "no"),
5547 window.get_title()));
5549 /* This exists to allow us to override the way GTK handles
5550 key events. The normal sequence is:
5552 a) event is delivered to a GtkWindow
5553 b) accelerators/mnemonics are activated
5554 c) if (b) didn't handle the event, propagate to
5555 the focus widget and/or focus chain
5557 The problem with this is that if the accelerators include
5558 keys without modifiers, such as the space bar or the
5559 letter "e", then pressing the key while typing into
5560 a text entry widget results in the accelerator being
5561 activated, instead of the desired letter appearing
5564 There is no good way of fixing this, but this
5565 represents a compromise. The idea is that
5566 key events involving modifiers (not Shift)
5567 get routed into the activation pathway first, then
5568 get propagated to the focus widget if necessary.
5570 If the key event doesn't involve modifiers,
5571 we deliver to the focus widget first, thus allowing
5572 it to get "normal text" without interference
5575 Of course, this can also be problematic: if there
5576 is a widget with focus, then it will swallow
5577 all "normal text" accelerators.
5581 if (!special_handling_of_unmodified_accelerators || (ev->state & mask)) {
5583 /* no special handling or there are modifiers in effect: accelerate first */
5585 DEBUG_TRACE (DEBUG::Accelerators, "\tactivate, then propagate\n");
5586 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tevent send-event:%1 time:%2 length:%3 name %7 string:%4 hardware_keycode:%5 group:%6\n",
5587 ev->send_event, ev->time, ev->length, ev->string, ev->hardware_keycode, ev->group, gdk_keyval_name (ev->keyval)));
5589 DEBUG_TRACE (DEBUG::Accelerators, "\tsending to window\n");
5590 KeyboardKey k (ev->state, ev->keyval);
5594 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tusing Ardour bindings %1 @ %2 for this event\n", bindings->name(), bindings));
5596 if (bindings->activate (k, Bindings::Press)) {
5597 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5602 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5604 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5605 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5609 DEBUG_TRACE (DEBUG::Accelerators, "\tnot accelerated, now propagate\n");
5611 if (gtk_window_propagate_key_event (win, ev)) {
5612 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate handled\n");
5618 /* no modifiers, propagate first */
5620 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate, then activate\n");
5622 if (gtk_window_propagate_key_event (win, ev)) {
5623 DEBUG_TRACE (DEBUG::Accelerators, "\thandled by propagate\n");
5627 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagation didn't handle, so activate\n");
5628 KeyboardKey k (ev->state, ev->keyval);
5632 DEBUG_TRACE (DEBUG::Accelerators, "\tusing Ardour bindings for this window\n");
5635 if (bindings->activate (k, Bindings::Press)) {
5636 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5642 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5644 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5645 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5650 DEBUG_TRACE (DEBUG::Accelerators, "\tnot handled\n");
5655 ARDOUR_UI::load_bindings ()
5657 if ((global_bindings = Bindings::get_bindings (X_("Global"), global_actions)) == 0) {
5658 error << _("Global keybindings are missing") << endmsg;
5663 ARDOUR_UI::cancel_solo ()
5666 _session->cancel_all_solo ();