2 Copyright (C) 1999-2013 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include "gtk2ardour-config.h"
22 #include "gtk2ardour-version.h"
32 #ifndef PLATFORM_WINDOWS
33 #include <sys/resource.h>
37 #include <sys/types.h>
38 #include <sys/sysctl.h>
48 #include "pbd/gstdio_compat.h"
50 #include <gtkmm/messagedialog.h>
51 #include <gtkmm/accelmap.h>
52 #include <gtkmm/stock.h>
54 #include "pbd/error.h"
55 #include "pbd/basename.h"
56 #include "pbd/compose.h"
57 #include "pbd/convert.h"
58 #include "pbd/failed_constructor.h"
59 #include "pbd/enumwriter.h"
60 #include "pbd/memento_command.h"
61 #include "pbd/openuri.h"
62 #include "pbd/stl_delete.h"
63 #include "pbd/file_utils.h"
64 #include "pbd/localtime_r.h"
65 #include "pbd/pthread_utils.h"
66 #include "pbd/replace_all.h"
67 #include "pbd/xml++.h"
69 #include "gtkmm2ext/application.h"
70 #include "gtkmm2ext/bindings.h"
71 #include "gtkmm2ext/gtk_ui.h"
72 #include "gtkmm2ext/utils.h"
73 #include "gtkmm2ext/click_box.h"
74 #include "gtkmm2ext/fastmeter.h"
75 #include "gtkmm2ext/popup.h"
76 #include "gtkmm2ext/window_title.h"
78 #include "ardour/ardour.h"
79 #include "ardour/audio_backend.h"
80 #include "ardour/audio_track.h"
81 #include "ardour/audioengine.h"
82 #include "ardour/audiofilesource.h"
83 #include "ardour/automation_watch.h"
84 #include "ardour/diskstream.h"
85 #include "ardour/filename_extensions.h"
86 #include "ardour/filesystem_paths.h"
87 #include "ardour/ltc_file_reader.h"
88 #include "ardour/midi_track.h"
89 #include "ardour/port.h"
90 #include "ardour/plugin_manager.h"
91 #include "ardour/process_thread.h"
92 #include "ardour/profile.h"
93 #include "ardour/recent_sessions.h"
94 #include "ardour/record_enable_control.h"
95 #include "ardour/session_directory.h"
96 #include "ardour/session_route.h"
97 #include "ardour/session_state_utils.h"
98 #include "ardour/session_utils.h"
99 #include "ardour/source_factory.h"
100 #include "ardour/slave.h"
101 #include "ardour/system_exec.h"
102 #include "ardour/track.h"
103 #include "ardour/vca_manager.h"
104 #include "ardour/utils.h"
106 #include "LuaBridge/LuaBridge.h"
108 #ifdef WINDOWS_VST_SUPPORT
111 #ifdef AUDIOUNIT_SUPPORT
112 #include "ardour/audio_unit.h"
115 // fix for OSX (nsm.h has a check function, AU/Apple defines check)
120 #include "timecode/time.h"
122 typedef uint64_t microseconds_t;
127 #include "add_route_dialog.h"
128 #include "ambiguous_file_dialog.h"
129 #include "ardour_ui.h"
130 #include "audio_clock.h"
131 #include "audio_region_view.h"
132 #include "big_clock_window.h"
133 #include "bundle_manager.h"
134 #include "duplicate_routes_dialog.h"
136 #include "engine_dialog.h"
137 #include "export_video_dialog.h"
138 #include "export_video_infobox.h"
139 #include "gain_meter.h"
140 #include "global_port_matrix.h"
141 #include "gui_object.h"
142 #include "gui_thread.h"
143 #include "keyboard.h"
144 #include "keyeditor.h"
145 #include "location_ui.h"
146 #include "lua_script_manager.h"
147 #include "luawindow.h"
148 #include "main_clock.h"
149 #include "missing_file_dialog.h"
150 #include "missing_plugin_dialog.h"
151 #include "mixer_ui.h"
152 #include "meterbridge.h"
153 #include "mouse_cursors.h"
156 #include "pingback.h"
157 #include "processor_box.h"
158 #include "prompter.h"
159 #include "public_editor.h"
160 #include "rc_option_editor.h"
161 #include "route_time_axis.h"
162 #include "route_params_ui.h"
163 #include "save_as_dialog.h"
164 #include "script_selector.h"
165 #include "session_dialog.h"
166 #include "session_metadata_dialog.h"
167 #include "session_option_editor.h"
168 #include "shuttle_control.h"
169 #include "speaker_dialog.h"
172 #include "theme_manager.h"
173 #include "time_axis_view_item.h"
176 #include "video_server_dialog.h"
177 #include "add_video_dialog.h"
178 #include "transcode_video_dialog.h"
182 using namespace ARDOUR;
183 using namespace ARDOUR_UI_UTILS;
185 using namespace Gtkmm2ext;
188 using namespace Editing;
190 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
192 sigc::signal<void, framepos_t, bool, framepos_t> ARDOUR_UI::Clock;
193 sigc::signal<void> ARDOUR_UI::CloseAllDialogs;
196 ask_about_configuration_copy (string const & old_dir, string const & new_dir, int version)
198 MessageDialog msg (string_compose (_("%1 %2.x has discovered configuration files from %1 %3.x.\n\n"
199 "Would you like these files to be copied and used for %1 %2.x?\n\n"
200 "(This will require you to restart %1.)"),
201 PROGRAM_NAME, PROGRAM_VERSION, version),
202 false, /* no markup */
205 true /* modal, though it hardly matters since it is the only window */
208 msg.set_default_response (Gtk::RESPONSE_YES);
211 return (msg.run() == Gtk::RESPONSE_YES);
215 libxml_generic_error_func (void* /* parsing_context*/,
223 vsnprintf (buf, sizeof (buf), msg, ap);
224 error << buf << endmsg;
229 libxml_structured_error_func (void* /* parsing_context*/,
237 replace_all (msg, "\n", "");
240 if (err->file && err->line) {
241 error << X_("XML error: ") << msg << " in " << err->file << " at line " << err->line;
244 error << ':' << err->int2;
249 error << X_("XML error: ") << msg << endmsg;
255 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
256 : Gtkmm2ext::UI (PROGRAM_NAME, X_("gui"), argcp, argvp)
257 , session_loaded (false)
258 , gui_object_state (new GUIObjectState)
259 , primary_clock (new MainClock (X_("primary"), X_("transport"), true ))
260 , secondary_clock (new MainClock (X_("secondary"), X_("secondary"), false))
261 , big_clock (new AudioClock (X_("bigclock"), false, "big", true, true, false, false))
263 , global_actions (X_("global"))
264 , ignore_dual_punch (false)
265 , main_window_visibility (0)
270 , _mixer_on_top (false)
271 , _initial_verbose_plugin_scan (false)
272 , first_time_engine_run (true)
273 , roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll))
274 , stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop))
275 , goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart))
276 , goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd))
277 , auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop))
278 , play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection))
279 , rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable))
280 , auto_return_button (ArdourButton::led_default_elements)
281 , follow_edits_button (ArdourButton::led_default_elements)
282 , auto_input_button (ArdourButton::led_default_elements)
283 , auditioning_alert_button (_("Audition"))
284 , solo_alert_button (_("Solo"))
285 , feedback_alert_button (_("Feedback"))
286 , error_alert_button ( ArdourButton::just_led_default_elements )
288 , editor_meter_peak_display()
289 , _numpad_locate_happening (false)
290 , _session_is_new (false)
291 , last_key_press_time (0)
295 , rc_option_editor (0)
296 , speaker_config_window (X_("speaker-config"), _("Speaker Configuration"))
297 , add_route_dialog (X_("add-routes"), _("Add Tracks/Busses"))
298 , about (X_("about"), _("About"))
299 , location_ui (X_("locations"), S_("Ranges|Locations"))
300 , route_params (X_("inspector"), _("Tracks and Busses"))
301 , audio_midi_setup (X_("audio-midi-setup"), _("Audio/MIDI Setup"))
302 , export_video_dialog (X_("video-export"), _("Video Export Dialog"))
303 , lua_script_window (X_("script-manager"), _("Script Manager"))
304 , session_option_editor (X_("session-options-editor"), _("Properties"), boost::bind (&ARDOUR_UI::create_session_option_editor, this))
305 , add_video_dialog (X_("add-video"), _("Add Video"), boost::bind (&ARDOUR_UI::create_add_video_dialog, this))
306 , bundle_manager (X_("bundle-manager"), _("Bundle Manager"), boost::bind (&ARDOUR_UI::create_bundle_manager, this))
307 , big_clock_window (X_("big-clock"), _("Big Clock"), boost::bind (&ARDOUR_UI::create_big_clock_window, this))
308 , audio_port_matrix (X_("audio-connection-manager"), _("Audio Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::AUDIO))
309 , midi_port_matrix (X_("midi-connection-manager"), _("MIDI Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::MIDI))
310 , key_editor (X_("key-editor"), _("Bindings Editor"), boost::bind (&ARDOUR_UI::create_key_editor, this))
311 , video_server_process (0)
313 , have_configure_timeout (false)
314 , last_configure_time (0)
316 , have_disk_speed_dialog_displayed (false)
317 , _status_bar_visibility (X_("status-bar"))
318 , _feedback_exists (false)
319 , _log_not_acknowledged (LogLevelNone)
320 , duplicate_routes_dialog (0)
321 , editor_visibility_button (S_("Window|Editor"))
322 , mixer_visibility_button (S_("Window|Mixer"))
323 , prefs_visibility_button (S_("Window|Preferences"))
325 Gtkmm2ext::init (localedir);
327 UIConfiguration::instance().post_gui_init ();
329 if (ARDOUR::handle_old_configuration_files (boost::bind (ask_about_configuration_copy, _1, _2, _3))) {
330 MessageDialog msg (string_compose (_("Your configuration files were copied. You can now restart %1."), PROGRAM_NAME), true);
332 /* configuration was modified, exit immediately */
337 if (string (VERSIONSTRING).find (".pre") != string::npos) {
338 /* check this is not being run from ./ardev etc. */
339 if (!running_from_source_tree ()) {
340 pre_release_dialog ();
344 if (theArdourUI == 0) {
348 /* track main window visibility */
350 main_window_visibility = new VisibilityTracker (_main_window);
352 /* stop libxml from spewing to stdout/stderr */
354 xmlSetGenericErrorFunc (this, libxml_generic_error_func);
355 xmlSetStructuredErrorFunc (this, libxml_structured_error_func);
357 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::parameter_changed));
358 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
359 UIConfiguration::instance().map_parameters (pc);
361 roll_button.set_controllable (roll_controllable);
362 stop_button.set_controllable (stop_controllable);
363 goto_start_button.set_controllable (goto_start_controllable);
364 goto_end_button.set_controllable (goto_end_controllable);
365 auto_loop_button.set_controllable (auto_loop_controllable);
366 play_selection_button.set_controllable (play_selection_controllable);
367 rec_button.set_controllable (rec_controllable);
369 roll_button.set_name ("transport button");
370 stop_button.set_name ("transport button");
371 goto_start_button.set_name ("transport button");
372 goto_end_button.set_name ("transport button");
373 auto_loop_button.set_name ("transport button");
374 play_selection_button.set_name ("transport button");
375 rec_button.set_name ("transport recenable button");
376 midi_panic_button.set_name ("transport button");
378 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
379 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
381 ARDOUR::Session::VersionMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_format_mismatch, this, _1, _2), gui_context());
383 /* handle dialog requests */
385 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
387 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
389 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
391 /* handle Audio/MIDI setup when session requires it */
393 ARDOUR::Session::AudioEngineSetupRequired.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::do_audio_midi_setup, this, _1));
395 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
397 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
399 /* handle sr mismatch with a dialog - cross-thread from engine */
400 ARDOUR::Session::NotifyAboutSampleRateMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::sr_mismatch_message, this, _1, _2), gui_context ());
402 /* handle requests to quit (coming from JACK session) */
404 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::finish, this), gui_context ());
406 /* tell the user about feedback */
408 ARDOUR::Session::FeedbackDetected.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::feedback_detected, this), gui_context ());
409 ARDOUR::Session::SuccessfulGraphSort.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::successful_graph_sort, this), gui_context ());
411 /* handle requests to deal with missing files */
413 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
415 /* and ambiguous files */
417 ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2));
419 /* also plugin scan messages */
420 ARDOUR::PluginScanMessage.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_dialog, this, _1, _2, _3), gui_context());
421 ARDOUR::PluginScanTimeout.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_timeout, this, _1), gui_context());
423 ARDOUR::GUIIdle.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::gui_idle_handler, this), gui_context());
425 Config->ParameterChanged.connect ( forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::set_flat_buttons, this), gui_context() );
428 /* lets get this party started */
430 setup_gtk_ardour_enums ();
433 SessionEvent::create_per_thread_pool ("GUI", 4096);
435 /* we like keyboards */
437 keyboard = new ArdourKeyboard(*this);
439 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
441 keyboard->set_state (*node, Stateful::loading_state_version);
444 UIConfiguration::instance().reset_dpi ();
446 TimeAxisViewItem::set_constant_heights ();
448 /* Set this up so that our window proxies can register actions */
450 ActionManager::init ();
452 /* The following must happen after ARDOUR::init() so that Config is set up */
454 const XMLNode* ui_xml = Config->extra_xml (X_("UI"));
457 key_editor.set_state (*ui_xml, 0);
458 session_option_editor.set_state (*ui_xml, 0);
459 speaker_config_window.set_state (*ui_xml, 0);
460 about.set_state (*ui_xml, 0);
461 add_route_dialog.set_state (*ui_xml, 0);
462 add_video_dialog.set_state (*ui_xml, 0);
463 route_params.set_state (*ui_xml, 0);
464 bundle_manager.set_state (*ui_xml, 0);
465 location_ui.set_state (*ui_xml, 0);
466 big_clock_window.set_state (*ui_xml, 0);
467 audio_port_matrix.set_state (*ui_xml, 0);
468 midi_port_matrix.set_state (*ui_xml, 0);
469 export_video_dialog.set_state (*ui_xml, 0);
470 lua_script_window.set_state (*ui_xml, 0);
473 /* Separate windows */
475 WM::Manager::instance().register_window (&key_editor);
476 WM::Manager::instance().register_window (&session_option_editor);
477 WM::Manager::instance().register_window (&speaker_config_window);
478 WM::Manager::instance().register_window (&about);
479 WM::Manager::instance().register_window (&add_route_dialog);
480 WM::Manager::instance().register_window (&add_video_dialog);
481 WM::Manager::instance().register_window (&route_params);
482 WM::Manager::instance().register_window (&audio_midi_setup);
483 WM::Manager::instance().register_window (&export_video_dialog);
484 WM::Manager::instance().register_window (&lua_script_window);
485 WM::Manager::instance().register_window (&bundle_manager);
486 WM::Manager::instance().register_window (&location_ui);
487 WM::Manager::instance().register_window (&big_clock_window);
488 WM::Manager::instance().register_window (&audio_port_matrix);
489 WM::Manager::instance().register_window (&midi_port_matrix);
491 /* do not retain position for add route dialog */
492 add_route_dialog.set_state_mask (WindowProxy::Size);
494 /* Trigger setting up the color scheme and loading the GTK RC file */
496 UIConfiguration::instance().load_rc_file (false);
498 _process_thread = new ProcessThread ();
499 _process_thread->init ();
501 UIConfiguration::instance().DPIReset.connect (sigc::mem_fun (*this, &ARDOUR_UI::resize_text_widgets));
507 ARDOUR_UI::pre_release_dialog ()
509 ArdourDialog d (_("Pre-Release Warning"), true, false);
510 d.add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
512 Label* label = manage (new Label);
513 label->set_markup (string_compose (_("<b>Welcome to this pre-release build of %1 %2</b>\n\n\
514 There are still several issues and bugs to be worked on,\n\
515 as well as general workflow improvements, before this can be considered\n\
516 release software. So, a few guidelines:\n\
518 1) Please do <b>NOT</b> use this software with the expectation that it is stable or reliable\n\
519 though it may be so, depending on your workflow.\n\
520 2) Please wait for a helpful writeup of new features.\n\
521 3) <b>Please do NOT use the forums at ardour.org to report issues</b>.\n\
522 4) Please <b>DO</b> use the bugtracker at http://tracker.ardour.org/ to report issues\n\
523 making sure to note the product version number as 5.0-pre.\n\
524 5) Please <b>DO</b> use the ardour-users mailing list to discuss ideas and pass on comments.\n\
525 6) Please <b>DO</b> join us on IRC for real time discussions about %1 %2. You\n\
526 can get there directly from within the program via the Help->Chat menu option.\n\
528 Full information on all the above can be found on the support page at\n\
530 http://ardour.org/support\n\
531 "), PROGRAM_NAME, VERSIONSTRING));
533 d.get_vbox()->set_border_width (12);
534 d.get_vbox()->pack_start (*label, false, false, 12);
535 d.get_vbox()->show_all ();
540 GlobalPortMatrixWindow*
541 ARDOUR_UI::create_global_port_matrix (ARDOUR::DataType type)
546 return new GlobalPortMatrixWindow (_session, type);
550 ARDOUR_UI::attach_to_engine ()
552 AudioEngine::instance()->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
553 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
557 ARDOUR_UI::engine_stopped ()
559 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
560 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
561 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
562 update_sample_rate (0);
567 ARDOUR_UI::engine_running ()
569 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
570 if (first_time_engine_run) {
572 first_time_engine_run = false;
576 _session->reset_xrun_count ();
578 update_disk_space ();
580 update_xrun_count ();
581 update_sample_rate (AudioEngine::instance()->sample_rate());
582 update_timecode_format ();
583 update_peak_thread_work ();
584 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, true);
585 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, false);
589 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
591 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
592 /* we can't rely on the original string continuing to exist when we are called
593 again in the GUI thread, so make a copy and note that we need to
596 char *copy = strdup (reason);
597 Gtkmm2ext::UI::instance()->call_slot (MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
601 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
602 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
604 update_sample_rate (0);
608 /* if the reason is a non-empty string, it means that the backend was shutdown
609 rather than just Ardour.
612 if (strlen (reason)) {
613 msgstr = string_compose (_("The audio backend was shutdown because:\n\n%1"), reason);
615 msgstr = string_compose (_("\
616 The audio backend has either been shutdown or it\n\
617 disconnected %1 because %1\n\
618 was not fast enough. Try to restart\n\
619 the audio backend and save the session."), PROGRAM_NAME);
622 MessageDialog msg (_main_window, msgstr);
623 pop_back_splash (msg);
627 free (const_cast<char*> (reason));
632 ARDOUR_UI::post_engine ()
634 /* Things to be done once (and once ONLY) after we have a backend running in the AudioEngine
636 #ifdef AUDIOUNIT_SUPPORT
638 if (AUPluginInfo::au_get_crashlog(au_msg)) {
639 popup_error(_("Audio Unit Plugin Scan Failed. Automatic AU scanning has been disabled. Please see the log window for further details."));
640 error << _("Audio Unit Plugin Scan Failed:") << endmsg;
641 info << au_msg << endmsg;
645 ARDOUR::init_post_engine ();
647 /* connect to important signals */
649 AudioEngine::instance()->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
650 AudioEngine::instance()->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
651 AudioEngine::instance()->BufferSizeChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
652 AudioEngine::instance()->Halted.connect_same_thread (halt_connection, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
653 AudioEngine::instance()->BecameSilent.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::audioengine_became_silent, this), gui_context());
655 if (setup_windows ()) {
656 throw failed_constructor ();
659 /* Do this after setup_windows (), as that's when the _status_bar_visibility is created */
660 XMLNode* n = Config->extra_xml (X_("UI"));
662 _status_bar_visibility.set_state (*n);
665 check_memory_locking();
667 /* this is the first point at which all the possible actions are
668 * available, because some of the available actions are dependent on
669 * aspects of the engine/backend.
672 if (ARDOUR_COMMAND_LINE::show_key_actions) {
675 vector<string> paths;
676 vector<string> labels;
677 vector<string> tooltips;
679 vector<Glib::RefPtr<Gtk::Action> > actions;
681 Gtkmm2ext::ActionMap::get_all_actions (paths, labels, tooltips, keys, actions);
683 vector<string>::iterator k;
684 vector<string>::iterator p;
686 for (p = paths.begin(), k = keys.begin(); p != paths.end(); ++k, ++p) {
691 cout << *p << " => " << *k << endl;
695 halt_connection.disconnect ();
696 AudioEngine::instance()->stop ();
700 /* this being a GUI and all, we want peakfiles */
702 AudioFileSource::set_build_peakfiles (true);
703 AudioFileSource::set_build_missing_peakfiles (true);
705 /* set default clock modes */
707 primary_clock->set_mode (AudioClock::Timecode);
708 secondary_clock->set_mode (AudioClock::BBT);
710 /* start the time-of-day-clock */
713 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
714 update_wall_clock ();
715 Glib::signal_timeout().connect_seconds (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 1);
720 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
721 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
722 Config->map_parameters (pc);
724 UIConfiguration::instance().map_parameters (pc);
728 ARDOUR_UI::~ARDOUR_UI ()
730 UIConfiguration::instance().save_state();
734 if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
735 // don't bother at 'real' exit. the OS cleans up for us.
736 delete big_clock; big_clock = 0;
737 delete primary_clock; primary_clock = 0;
738 delete secondary_clock; secondary_clock = 0;
739 delete _process_thread; _process_thread = 0;
740 delete meterbridge; meterbridge = 0;
741 delete luawindow; luawindow = 0;
742 delete editor; editor = 0;
743 delete mixer; mixer = 0;
745 delete gui_object_state; gui_object_state = 0;
746 delete main_window_visibility;
747 FastMeter::flush_pattern_cache ();
748 PixFader::flush_pattern_cache ();
752 /* Small trick to flush main-thread event pool.
753 * Other thread-pools are destroyed at pthread_exit(),
754 * but tmain thread termination is too late to trigger Pool::~Pool()
756 SessionEvent* ev = new SessionEvent (SessionEvent::SetTransportSpeed, SessionEvent::Clear, SessionEvent::Immediate, 0, 0); // get the pool reference, values don't matter since the event is never queued.
757 delete ev->event_pool();
762 ARDOUR_UI::pop_back_splash (Gtk::Window& win)
764 if (Splash::instance()) {
765 Splash::instance()->pop_back_for (win);
770 ARDOUR_UI::configure_timeout ()
772 if (last_configure_time == 0) {
773 /* no configure events yet */
777 /* force a gap of 0.5 seconds since the last configure event
780 if (get_microseconds() - last_configure_time < 500000) {
783 have_configure_timeout = false;
784 save_ardour_state ();
790 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
792 if (have_configure_timeout) {
793 last_configure_time = get_microseconds();
795 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
796 have_configure_timeout = true;
803 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
805 XMLProperty const * prop;
807 if ((prop = node.property ("roll")) != 0) {
808 roll_controllable->set_id (prop->value());
810 if ((prop = node.property ("stop")) != 0) {
811 stop_controllable->set_id (prop->value());
813 if ((prop = node.property ("goto-start")) != 0) {
814 goto_start_controllable->set_id (prop->value());
816 if ((prop = node.property ("goto-end")) != 0) {
817 goto_end_controllable->set_id (prop->value());
819 if ((prop = node.property ("auto-loop")) != 0) {
820 auto_loop_controllable->set_id (prop->value());
822 if ((prop = node.property ("play-selection")) != 0) {
823 play_selection_controllable->set_id (prop->value());
825 if ((prop = node.property ("rec")) != 0) {
826 rec_controllable->set_id (prop->value());
828 if ((prop = node.property ("shuttle")) != 0) {
829 shuttle_box->controllable()->set_id (prop->value());
834 ARDOUR_UI::get_transport_controllable_state ()
836 XMLNode* node = new XMLNode(X_("TransportControllables"));
839 roll_controllable->id().print (buf, sizeof (buf));
840 node->add_property (X_("roll"), buf);
841 stop_controllable->id().print (buf, sizeof (buf));
842 node->add_property (X_("stop"), buf);
843 goto_start_controllable->id().print (buf, sizeof (buf));
844 node->add_property (X_("goto_start"), buf);
845 goto_end_controllable->id().print (buf, sizeof (buf));
846 node->add_property (X_("goto_end"), buf);
847 auto_loop_controllable->id().print (buf, sizeof (buf));
848 node->add_property (X_("auto_loop"), buf);
849 play_selection_controllable->id().print (buf, sizeof (buf));
850 node->add_property (X_("play_selection"), buf);
851 rec_controllable->id().print (buf, sizeof (buf));
852 node->add_property (X_("rec"), buf);
853 shuttle_box->controllable()->id().print (buf, sizeof (buf));
854 node->add_property (X_("shuttle"), buf);
860 ARDOUR_UI::save_session_at_its_request (std::string snapshot_name)
863 _session->save_state (snapshot_name);
868 ARDOUR_UI::autosave_session ()
870 if (g_main_depth() > 1) {
871 /* inside a recursive main loop,
872 give up because we may not be able to
878 if (!Config->get_periodic_safety_backups()) {
883 _session->maybe_write_autosave();
890 ARDOUR_UI::session_dirty_changed ()
897 ARDOUR_UI::update_autosave ()
899 if (_session && _session->dirty()) {
900 if (_autosave_connection.connected()) {
901 _autosave_connection.disconnect();
904 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
905 Config->get_periodic_safety_backup_interval() * 1000);
908 if (_autosave_connection.connected()) {
909 _autosave_connection.disconnect();
915 ARDOUR_UI::check_announcements ()
918 string _annc_filename;
921 _annc_filename = PROGRAM_NAME "_announcements_osx_";
922 #elif defined PLATFORM_WINDOWS
923 _annc_filename = PROGRAM_NAME "_announcements_windows_";
925 _annc_filename = PROGRAM_NAME "_announcements_linux_";
927 _annc_filename.append (VERSIONSTRING);
929 _announce_string = "";
931 std::string path = Glib::build_filename (user_config_directory(), _annc_filename);
932 FILE* fin = g_fopen (path.c_str(), "rb");
934 while (!feof (fin)) {
937 if ((len = fread (tmp, sizeof(char), 1024, fin)) == 0 || ferror (fin)) {
940 _announce_string.append (tmp, len);
945 pingback (VERSIONSTRING, path);
950 _hide_splash (gpointer arg)
952 ((ARDOUR_UI*)arg)->hide_splash();
957 ARDOUR_UI::starting ()
959 Application* app = Application::instance ();
961 bool brand_new_user = ArdourStartup::required ();
963 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
964 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::load_from_application_api));
966 if (ARDOUR_COMMAND_LINE::check_announcements) {
967 check_announcements ();
972 /* we need to create this early because it may need to set the
973 * audio backend end up.
977 audio_midi_setup.get (true);
979 std::cerr << "audio-midi engine setup failed."<< std::endl;
983 if ((nsm_url = g_getenv ("NSM_URL")) != 0) {
984 nsm = new NSM_Client;
985 if (!nsm->init (nsm_url)) {
986 /* the ardour executable may have different names:
988 * waf's obj.target for distro versions: eg ardour4, ardourvst4
989 * Ardour4, Mixbus3 for bundled versions + full path on OSX & windows
990 * argv[0] does not apply since we need the wrapper-script (not the binary itself)
992 * The wrapper startup script should set the environment variable 'ARDOUR_SELF'
994 const char *process_name = g_getenv ("ARDOUR_SELF");
995 nsm->announce (PROGRAM_NAME, ":dirty:", process_name ? process_name : "ardour4");
998 // wait for announce reply from nsm server
999 for ( i = 0; i < 5000; ++i) {
1003 if (nsm->is_active()) {
1008 error << _("NSM server did not announce itself") << endmsg;
1011 // wait for open command from nsm server
1012 for ( i = 0; i < 5000; ++i) {
1014 Glib::usleep (1000);
1015 if (nsm->client_id ()) {
1021 error << _("NSM: no client ID provided") << endmsg;
1025 if (_session && nsm) {
1026 _session->set_nsm_state( nsm->is_active() );
1028 error << _("NSM: no session created") << endmsg;
1032 // nsm requires these actions disabled
1033 vector<string> action_names;
1034 action_names.push_back("SaveAs");
1035 action_names.push_back("Rename");
1036 action_names.push_back("New");
1037 action_names.push_back("Open");
1038 action_names.push_back("Recent");
1039 action_names.push_back("Close");
1041 for (vector<string>::const_iterator n = action_names.begin(); n != action_names.end(); ++n) {
1042 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), (*n).c_str());
1044 act->set_sensitive (false);
1051 error << _("NSM: initialization failed") << endmsg;
1057 if (brand_new_user) {
1058 _initial_verbose_plugin_scan = true;
1063 _initial_verbose_plugin_scan = false;
1064 switch (s.response ()) {
1065 case Gtk::RESPONSE_OK:
1072 #ifdef NO_PLUGIN_STATE
1074 ARDOUR::RecentSessions rs;
1075 ARDOUR::read_recent_sessions (rs);
1077 string path = Glib::build_filename (user_config_directory(), ".iknowaboutfreeversion");
1079 if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS) && !rs.empty()) {
1081 /* already used Ardour, have sessions ... warn about plugin state */
1083 ArdourDialog d (_("Free/Demo Version Warning"), true);
1085 Button b (string_compose (_("Subscribe and support development of %1"), PROGRAM_NAME));
1086 CheckButton c (_("Don't warn me about this again"));
1088 l.set_markup (string_compose (_("<span weight=\"bold\" size=\"large\">%1</span>\n\n<b>%2</b>\n\n<i>%3</i>\n\n%4"),
1089 string_compose (_("This is a free/demo version of %1"), PROGRAM_NAME),
1090 _("It will not restore OR save any plugin settings"),
1091 _("If you load an existing session with plugin settings\n"
1092 "they will not be used and will be lost."),
1093 _("To get full access to updates without this limitation\n"
1094 "consider becoming a subscriber for a low cost every month.")));
1095 l.set_justify (JUSTIFY_CENTER);
1097 b.signal_clicked().connect (mem_fun(*this, &ARDOUR_UI::launch_subscribe));
1099 d.get_vbox()->pack_start (l, true, true);
1100 d.get_vbox()->pack_start (b, false, false, 12);
1101 d.get_vbox()->pack_start (c, false, false, 12);
1103 d.add_button (_("Quit now"), RESPONSE_CANCEL);
1104 d.add_button (string_compose (_("Continue using %1"), PROGRAM_NAME), RESPONSE_OK);
1108 c.signal_toggled().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (toggle_file_existence), path)));
1110 if (d.run () != RESPONSE_OK) {
1116 /* go get a session */
1118 const bool new_session_required = (ARDOUR_COMMAND_LINE::new_session || brand_new_user);
1120 if (get_session_parameters (false, new_session_required, ARDOUR_COMMAND_LINE::load_template)) {
1121 std::cerr << "Cannot get session parameters."<< std::endl;
1128 WM::Manager::instance().show_visible ();
1130 /* We have to do this here since goto_editor_window() ends up calling show_all() on the
1131 * editor window, and we may want stuff to be hidden.
1133 _status_bar_visibility.update ();
1135 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
1137 if (splash && splash->is_visible()) {
1138 // in 1 second, hide the splash screen
1139 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
1142 /* all other dialogs are created conditionally */
1148 ARDOUR_UI::check_memory_locking ()
1150 #if defined(__APPLE__) || defined(PLATFORM_WINDOWS)
1151 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
1155 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
1157 if (AudioEngine::instance()->is_realtime() && memory_warning_node == 0) {
1159 struct rlimit limits;
1161 long pages, page_size;
1163 size_t pages_len=sizeof(pages);
1164 if ((page_size = getpagesize()) < 0 ||
1165 sysctlbyname("hw.availpages", &pages, &pages_len, NULL, 0))
1167 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0)
1172 ram = (int64_t) pages * (int64_t) page_size;
1175 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
1179 if (limits.rlim_cur != RLIM_INFINITY) {
1181 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
1185 _("WARNING: Your system has a limit for maximum amount of locked memory. "
1186 "This might cause %1 to run out of memory before your system "
1187 "runs out of memory. \n\n"
1188 "You can view the memory limit with 'ulimit -l', "
1189 "and it is normally controlled by %2"),
1192 X_("/etc/login.conf")
1194 X_(" /etc/security/limits.conf")
1198 msg.set_default_response (RESPONSE_OK);
1200 VBox* vbox = msg.get_vbox();
1202 CheckButton cb (_("Do not show this window again"));
1203 hbox.pack_start (cb, true, false);
1204 vbox->pack_start (hbox);
1209 pop_back_splash (msg);
1213 if (cb.get_active()) {
1214 XMLNode node (X_("no-memory-warning"));
1215 Config->add_instant_xml (node);
1220 #endif // !__APPLE__
1225 ARDOUR_UI::queue_finish ()
1227 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
1231 ARDOUR_UI::idle_finish ()
1234 return false; /* do not call again */
1241 ARDOUR_UI::instance()->video_timeline->sync_session_state();
1243 if (_session->dirty()) {
1244 vector<string> actions;
1245 actions.push_back (_("Don't quit"));
1246 actions.push_back (_("Just quit"));
1247 actions.push_back (_("Save and quit"));
1248 switch (ask_about_saving_session(actions)) {
1253 /* use the default name */
1254 if (save_state_canfail ("")) {
1255 /* failed - don't quit */
1256 MessageDialog msg (_main_window,
1257 string_compose (_("\
1258 %1 was unable to save your session.\n\n\
1259 If you still wish to quit, please use the\n\n\
1260 \"Just quit\" option."), PROGRAM_NAME));
1261 pop_back_splash(msg);
1271 second_connection.disconnect ();
1272 point_one_second_connection.disconnect ();
1273 point_zero_something_second_connection.disconnect();
1274 fps_connection.disconnect();
1277 delete ARDOUR_UI::instance()->video_timeline;
1278 ARDOUR_UI::instance()->video_timeline = NULL;
1279 stop_video_server();
1281 /* Save state before deleting the session, as that causes some
1282 windows to be destroyed before their visible state can be
1285 save_ardour_state ();
1287 close_all_dialogs ();
1290 _session->set_clean ();
1291 _session->remove_pending_capture_state ();
1296 halt_connection.disconnect ();
1297 AudioEngine::instance()->stop ();
1298 #ifdef WINDOWS_VST_SUPPORT
1299 fst_stop_threading();
1305 ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
1307 ArdourDialog window (_("Unsaved Session"));
1308 Gtk::HBox dhbox; // the hbox for the image and text
1309 Gtk::Label prompt_label;
1310 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
1314 assert (actions.size() >= 3);
1316 window.add_button (actions[0], RESPONSE_REJECT);
1317 window.add_button (actions[1], RESPONSE_APPLY);
1318 window.add_button (actions[2], RESPONSE_ACCEPT);
1320 window.set_default_response (RESPONSE_ACCEPT);
1322 Gtk::Button noquit_button (msg);
1323 noquit_button.set_name ("EditorGTKButton");
1327 if (_session->snap_name() == _session->name()) {
1328 prompt = string_compose(_("The session \"%1\"\nhas not been saved.\n\nAny changes made this time\nwill be lost unless you save it.\n\nWhat do you want to do?"),
1329 _session->snap_name());
1331 prompt = string_compose(_("The snapshot \"%1\"\nhas not been saved.\n\nAny changes made this time\nwill be lost unless you save it.\n\nWhat do you want to do?"),
1332 _session->snap_name());
1335 prompt_label.set_text (prompt);
1336 prompt_label.set_name (X_("PrompterLabel"));
1337 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
1339 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
1340 dhbox.set_homogeneous (false);
1341 dhbox.pack_start (*dimage, false, false, 5);
1342 dhbox.pack_start (prompt_label, true, false, 5);
1343 window.get_vbox()->pack_start (dhbox);
1345 window.set_name (_("Prompter"));
1346 window.set_modal (true);
1347 window.set_resizable (false);
1350 prompt_label.show();
1355 ResponseType r = (ResponseType) window.run();
1360 case RESPONSE_ACCEPT: // save and get out of here
1362 case RESPONSE_APPLY: // get out of here
1373 ARDOUR_UI::every_second ()
1376 update_xrun_count ();
1377 update_buffer_load ();
1378 update_disk_space ();
1379 update_timecode_format ();
1380 update_peak_thread_work ();
1382 if (nsm && nsm->is_active ()) {
1385 if (!_was_dirty && _session->dirty ()) {
1389 else if (_was_dirty && !_session->dirty ()){
1397 ARDOUR_UI::every_point_one_seconds ()
1399 // TODO get rid of this..
1400 // ShuttleControl is updated directly via TransportStateChange signal
1404 ARDOUR_UI::every_point_zero_something_seconds ()
1406 // august 2007: actual update frequency: 25Hz (40ms), not 100Hz
1408 if (editor_meter && UIConfiguration::instance().get_show_editor_meter()) {
1409 float mpeak = editor_meter->update_meters();
1410 if (mpeak > editor_meter_max_peak) {
1411 if (mpeak >= UIConfiguration::instance().get_meter_peak()) {
1412 editor_meter_peak_display.set_active_state ( Gtkmm2ext::ExplicitActive );
1419 ARDOUR_UI::set_fps_timeout_connection ()
1421 unsigned int interval = 40;
1422 if (!_session) return;
1423 if (_session->timecode_frames_per_second() != 0) {
1424 /* ideally we'll use a select() to sleep and not accumulate
1425 * idle time to provide a regular periodic signal.
1426 * See linux_vst_gui_support.cc 'elapsed_time_ms'.
1427 * However, that'll require a dedicated thread and cross-thread
1428 * signals to the GUI Thread..
1430 interval = floor(500. /* update twice per FPS, since Glib::signal_timeout is very irregular */
1431 * _session->frame_rate() / _session->nominal_frame_rate()
1432 / _session->timecode_frames_per_second()
1434 #ifdef PLATFORM_WINDOWS
1435 // the smallest windows scheduler time-slice is ~15ms.
1436 // periodic GUI timeouts shorter than that will cause
1437 // WaitForSingleObject to spinlock (100% of one CPU Core)
1438 // and gtk never enters idle mode.
1439 // also changing timeBeginPeriod(1) does not affect that in
1440 // any beneficial way, so we just limit the max rate for now.
1441 interval = std::max(30u, interval); // at most ~33Hz.
1443 interval = std::max(8u, interval); // at most 120Hz.
1446 fps_connection.disconnect();
1447 Timers::set_fps_interval (interval);
1451 ARDOUR_UI::update_sample_rate (framecnt_t)
1455 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
1457 if (!AudioEngine::instance()->connected()) {
1459 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1463 framecnt_t rate = AudioEngine::instance()->sample_rate();
1466 /* no sample rate available */
1467 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1470 if (fmod (rate, 1000.0) != 0.0) {
1471 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
1472 (float) rate / 1000.0f,
1473 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1475 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
1477 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1481 sample_rate_label.set_markup (buf);
1485 ARDOUR_UI::update_format ()
1488 format_label.set_text ("");
1493 s << _("File:") << X_(" <span foreground=\"green\">");
1495 switch (_session->config.get_native_file_header_format ()) {
1527 switch (_session->config.get_native_file_data_format ()) {
1541 format_label.set_markup (s.str ());
1545 ARDOUR_UI::update_xrun_count ()
1549 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1550 should also be changed.
1554 const unsigned int x = _session->get_xrun_count ();
1556 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">>10K</span>"), X_("red"));
1558 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">%u</span>"), x > 0 ? X_("red") : X_("green"), x);
1561 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">?</span>"), X_("yellow"));
1563 xrun_label.set_markup (buf);
1564 set_tip (xrun_label, _("Audio dropouts. Shift+click to reset"));
1568 ARDOUR_UI::update_cpu_load ()
1572 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1573 should also be changed.
1576 double const c = AudioEngine::instance()->get_dsp_load ();
1577 snprintf (buf, sizeof (buf), _("DSP: <span foreground=\"%s\">%5.1f%%</span>"), c >= 90 ? X_("red") : X_("green"), c);
1578 cpu_load_label.set_markup (buf);
1582 ARDOUR_UI::update_peak_thread_work ()
1585 const int c = SourceFactory::peak_work_queue_length ();
1587 snprintf (buf, sizeof (buf), _("PkBld: <span foreground=\"%s\">%d</span>"), c >= 2 ? X_("red") : X_("green"), c);
1588 peak_thread_work_label.set_markup (buf);
1590 peak_thread_work_label.set_markup (X_(""));
1595 ARDOUR_UI::update_buffer_load ()
1599 uint32_t const playback = _session ? _session->playback_load () : 100;
1600 uint32_t const capture = _session ? _session->capture_load () : 100;
1602 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1603 should also be changed.
1609 _("Buffers: <span foreground=\"green\">p:</span><span foreground=\"%s\">%" PRIu32 "%%</span> "
1610 "<span foreground=\"green\">c:</span><span foreground=\"%s\">%" PRIu32 "%%</span>"),
1611 playback <= 5 ? X_("red") : X_("green"),
1613 capture <= 5 ? X_("red") : X_("green"),
1617 buffer_load_label.set_markup (buf);
1619 buffer_load_label.set_text ("");
1624 ARDOUR_UI::count_recenabled_streams (Route& route)
1626 Track* track = dynamic_cast<Track*>(&route);
1627 if (track && track->rec_enable_control()->get_value()) {
1628 rec_enabled_streams += track->n_inputs().n_total();
1633 ARDOUR_UI::update_disk_space()
1635 if (_session == 0) {
1639 boost::optional<framecnt_t> opt_frames = _session->available_capture_duration();
1641 framecnt_t fr = _session->frame_rate();
1644 /* skip update - no SR available */
1649 /* Available space is unknown */
1650 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">Unknown</span>"));
1651 } else if (opt_frames.get_value_or (0) == max_framecnt) {
1652 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">24hrs+</span>"));
1654 rec_enabled_streams = 0;
1655 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams, false);
1657 framecnt_t frames = opt_frames.get_value_or (0);
1659 if (rec_enabled_streams) {
1660 frames /= rec_enabled_streams;
1667 hrs = frames / (fr * 3600);
1670 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">>24 hrs</span>"));
1672 frames -= hrs * fr * 3600;
1673 mins = frames / (fr * 60);
1674 frames -= mins * fr * 60;
1677 bool const low = (hrs == 0 && mins <= 30);
1681 _("Disk: <span foreground=\"%s\">%02dh:%02dm:%02ds</span>"),
1682 low ? X_("red") : X_("green"),
1688 disk_space_label.set_markup (buf);
1692 ARDOUR_UI::update_timecode_format ()
1698 TimecodeSlave* tcslave;
1699 SyncSource sync_src = Config->get_sync_source();
1701 if ((sync_src == LTC || sync_src == MTC) && (tcslave = dynamic_cast<TimecodeSlave*>(_session->slave())) != 0) {
1702 matching = (tcslave->apparent_timecode_format() == _session->config.get_timecode_format());
1707 snprintf (buf, sizeof (buf), S_("Timecode|TC: <span foreground=\"%s\">%s</span>"),
1708 matching ? X_("green") : X_("red"),
1709 Timecode::timecode_format_name (_session->config.get_timecode_format()).c_str());
1711 snprintf (buf, sizeof (buf), "TC: n/a");
1714 timecode_format_label.set_markup (buf);
1718 ARDOUR_UI::update_wall_clock ()
1722 static int last_min = -1;
1725 tm_now = localtime (&now);
1726 if (last_min != tm_now->tm_min) {
1728 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1729 wall_clock_label.set_text (buf);
1730 last_min = tm_now->tm_min;
1737 ARDOUR_UI::open_recent_session ()
1739 bool can_return = (_session != 0);
1741 SessionDialog recent_session_dialog;
1745 ResponseType r = (ResponseType) recent_session_dialog.run ();
1748 case RESPONSE_ACCEPT:
1752 recent_session_dialog.hide();
1759 recent_session_dialog.hide();
1763 std::string path = recent_session_dialog.session_folder();
1764 std::string state = recent_session_dialog.session_name (should_be_new);
1766 if (should_be_new == true) {
1770 _session_is_new = false;
1772 if (load_session (path, state) == 0) {
1778 if (splash && splash->is_visible()) {
1779 // in 1 second, hide the splash screen
1780 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
1785 ARDOUR_UI::check_audioengine (Gtk::Window& parent)
1787 if (!AudioEngine::instance()->connected()) {
1788 MessageDialog msg (parent, string_compose (
1789 _("%1 is not connected to any audio backend.\n"
1790 "You cannot open or close sessions in this condition"),
1792 pop_back_splash (msg);
1800 ARDOUR_UI::open_session ()
1802 if (!check_audioengine (_main_window)) {
1806 /* ardour sessions are folders */
1807 Gtk::FileChooserDialog open_session_selector(_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1808 open_session_selector.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1809 open_session_selector.add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1810 open_session_selector.set_default_response(Gtk::RESPONSE_ACCEPT);
1813 string session_parent_dir = Glib::path_get_dirname(_session->path());
1814 open_session_selector.set_current_folder(session_parent_dir);
1816 open_session_selector.set_current_folder(Config->get_default_session_parent_dir());
1819 Gtkmm2ext::add_volume_shortcuts (open_session_selector);
1821 /* add_shortcut_folder throws an exception if the folder being added already has a shortcut */
1822 string default_session_folder = Config->get_default_session_parent_dir();
1823 open_session_selector.add_shortcut_folder (default_session_folder);
1825 catch (Glib::Error & e) {
1826 std::cerr << "open_session_selector.add_shortcut_folder() threw Glib::Error " << e.what() << std::endl;
1829 FileFilter session_filter;
1830 session_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::statefile_suffix));
1831 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1832 open_session_selector.add_filter (session_filter);
1833 open_session_selector.set_filter (session_filter);
1835 int response = open_session_selector.run();
1836 open_session_selector.hide ();
1838 if (response == Gtk::RESPONSE_CANCEL) {
1842 string session_path = open_session_selector.get_filename();
1846 if (session_path.length() > 0) {
1847 if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1848 _session_is_new = isnew;
1849 load_session (path, name);
1855 ARDOUR_UI::session_add_vca (const string& name_template, uint32_t n)
1861 _session->vca_manager().create_vca (n, name_template);
1865 ARDOUR_UI::session_add_mixed_track (
1866 const ChanCount& input,
1867 const ChanCount& output,
1868 RouteGroup* route_group,
1870 const string& name_template,
1872 PluginInfoPtr instrument,
1873 Plugin::PresetRecord* pset,
1874 ARDOUR::PresentationInfo::order_t order)
1876 list<boost::shared_ptr<MidiTrack> > tracks;
1878 if (_session == 0) {
1879 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1884 tracks = _session->new_midi_track (input, output, instrument, pset, route_group, how_many, name_template, order, ARDOUR::Normal);
1886 if (tracks.size() != how_many) {
1887 error << string_compose(P_("could not create %1 new mixed track", "could not create %1 new mixed tracks", how_many), how_many) << endmsg;
1892 display_insufficient_ports_message ();
1897 for (list<boost::shared_ptr<MidiTrack> >::iterator i = tracks.begin(); i != tracks.end(); ++i) {
1898 (*i)->set_strict_io (true);
1904 ARDOUR_UI::session_add_midi_bus (
1905 RouteGroup* route_group,
1907 const string& name_template,
1909 PluginInfoPtr instrument,
1910 Plugin::PresetRecord* pset,
1911 ARDOUR::PresentationInfo::order_t order)
1915 if (_session == 0) {
1916 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1922 routes = _session->new_midi_route (route_group, how_many, name_template, instrument, pset, PresentationInfo::MidiBus, order);
1923 if (routes.size() != how_many) {
1924 error << string_compose(P_("could not create %1 new Midi Bus", "could not create %1 new Midi Busses", how_many), how_many) << endmsg;
1929 display_insufficient_ports_message ();
1934 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
1935 (*i)->set_strict_io (true);
1941 ARDOUR_UI::session_add_midi_route (
1943 RouteGroup* route_group,
1945 const string& name_template,
1947 PluginInfoPtr instrument,
1948 Plugin::PresetRecord* pset,
1949 ARDOUR::PresentationInfo::order_t order)
1951 ChanCount one_midi_channel;
1952 one_midi_channel.set (DataType::MIDI, 1);
1955 session_add_mixed_track (one_midi_channel, one_midi_channel, route_group, how_many, name_template, strict_io, instrument, pset, order);
1957 session_add_midi_bus (route_group, how_many, name_template, strict_io, instrument, pset, order);
1962 ARDOUR_UI::session_add_audio_route (
1964 int32_t input_channels,
1965 int32_t output_channels,
1966 ARDOUR::TrackMode mode,
1967 RouteGroup* route_group,
1969 string const & name_template,
1971 ARDOUR::PresentationInfo::order_t order)
1973 list<boost::shared_ptr<AudioTrack> > tracks;
1976 if (_session == 0) {
1977 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1983 tracks = _session->new_audio_track (input_channels, output_channels, route_group, how_many, name_template, order, mode);
1985 if (tracks.size() != how_many) {
1986 error << string_compose (P_("could not create %1 new audio track", "could not create %1 new audio tracks", how_many), how_many)
1992 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template, PresentationInfo::AudioBus, order);
1994 if (routes.size() != how_many) {
1995 error << string_compose (P_("could not create %1 new audio bus", "could not create %1 new audio busses", how_many), how_many)
2002 display_insufficient_ports_message ();
2007 for (list<boost::shared_ptr<AudioTrack> >::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2008 (*i)->set_strict_io (true);
2010 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
2011 (*i)->set_strict_io (true);
2017 ARDOUR_UI::display_insufficient_ports_message ()
2019 MessageDialog msg (_main_window,
2020 string_compose (_("There are insufficient ports available\n\
2021 to create a new track or bus.\n\
2022 You should save %1, exit and\n\
2023 restart with more ports."), PROGRAM_NAME));
2024 pop_back_splash (msg);
2029 ARDOUR_UI::transport_goto_start ()
2032 _session->goto_start();
2034 /* force displayed area in editor to start no matter
2035 what "follow playhead" setting is.
2039 editor->center_screen (_session->current_start_frame ());
2045 ARDOUR_UI::transport_goto_zero ()
2048 _session->request_locate (0);
2050 /* force displayed area in editor to start no matter
2051 what "follow playhead" setting is.
2055 editor->reset_x_origin (0);
2061 ARDOUR_UI::transport_goto_wallclock ()
2063 if (_session && editor) {
2070 localtime_r (&now, &tmnow);
2072 framecnt_t frame_rate = _session->frame_rate();
2074 if (frame_rate == 0) {
2075 /* no frame rate available */
2079 frames = tmnow.tm_hour * (60 * 60 * frame_rate);
2080 frames += tmnow.tm_min * (60 * frame_rate);
2081 frames += tmnow.tm_sec * frame_rate;
2083 _session->request_locate (frames, _session->transport_rolling ());
2085 /* force displayed area in editor to start no matter
2086 what "follow playhead" setting is.
2090 editor->center_screen (frames);
2096 ARDOUR_UI::transport_goto_end ()
2099 framepos_t const frame = _session->current_end_frame();
2100 _session->request_locate (frame);
2102 /* force displayed area in editor to start no matter
2103 what "follow playhead" setting is.
2107 editor->center_screen (frame);
2113 ARDOUR_UI::transport_stop ()
2119 if (_session->is_auditioning()) {
2120 _session->cancel_audition ();
2124 _session->request_stop (false, true);
2127 /** Check if any tracks are record enabled. If none are, record enable all of them.
2128 * @return true if track record-enabled status was changed, false otherwise.
2131 ARDOUR_UI::trx_record_enable_all_tracks ()
2137 boost::shared_ptr<RouteList> rl = _session->get_tracks ();
2138 bool none_record_enabled = true;
2140 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
2141 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*r);
2144 if (t->rec_enable_control()->get_value()) {
2145 none_record_enabled = false;
2150 if (none_record_enabled) {
2151 _session->set_controls (route_list_to_control_list (rl, &Stripable::rec_enable_control), 1.0, Controllable::NoGroup);
2154 return none_record_enabled;
2158 ARDOUR_UI::transport_record (bool roll)
2161 switch (_session->record_status()) {
2162 case Session::Disabled:
2163 if (_session->ntracks() == 0) {
2164 MessageDialog msg (_main_window, _("Please create one or more tracks before trying to record.\nYou can do this with the \"Add Track or Bus\" option in the Session menu."));
2168 if (Profile->get_trx()) {
2169 roll = trx_record_enable_all_tracks ();
2171 _session->maybe_enable_record ();
2176 case Session::Recording:
2178 _session->request_stop();
2180 _session->disable_record (false, true);
2184 case Session::Enabled:
2185 _session->disable_record (false, true);
2191 ARDOUR_UI::transport_roll ()
2197 if (_session->is_auditioning()) {
2202 if (_session->config.get_external_sync()) {
2203 switch (Config->get_sync_source()) {
2207 /* transport controlled by the master */
2213 bool rolling = _session->transport_rolling();
2215 if (_session->get_play_loop()) {
2217 /* If loop playback is not a mode, then we should cancel
2218 it when this action is requested. If it is a mode
2219 we just leave it in place.
2222 if (!Config->get_loop_is_mode()) {
2223 /* XXX it is not possible to just leave seamless loop and keep
2224 playing at present (nov 4th 2009)
2226 if (!Config->get_seamless_loop()) {
2227 /* stop loop playback and stop rolling */
2228 _session->request_play_loop (false, true);
2229 } else if (rolling) {
2230 /* stop loop playback but keep rolling */
2231 _session->request_play_loop (false, false);
2235 } else if (_session->get_play_range () ) {
2236 /* stop playing a range if we currently are */
2237 _session->request_play_range (0, true);
2241 _session->request_transport_speed (1.0f);
2246 ARDOUR_UI::get_smart_mode() const
2248 return ( editor->get_smart_mode() );
2253 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
2259 if (_session->is_auditioning()) {
2260 _session->cancel_audition ();
2264 if (_session->config.get_external_sync()) {
2265 switch (Config->get_sync_source()) {
2269 /* transport controlled by the master */
2274 bool rolling = _session->transport_rolling();
2275 bool affect_transport = true;
2277 if (rolling && roll_out_of_bounded_mode) {
2278 /* drop out of loop/range playback but leave transport rolling */
2279 if (_session->get_play_loop()) {
2280 if (_session->actively_recording()) {
2282 /* just stop using the loop, then actually stop
2285 _session->request_play_loop (false, affect_transport);
2288 if (Config->get_seamless_loop()) {
2289 /* the disk buffers contain copies of the loop - we can't
2290 just keep playing, so stop the transport. the user
2291 can restart as they wish.
2293 affect_transport = true;
2295 /* disk buffers are normal, so we can keep playing */
2296 affect_transport = false;
2298 _session->request_play_loop (false, affect_transport);
2300 } else if (_session->get_play_range ()) {
2301 affect_transport = false;
2302 _session->request_play_range (0, true);
2306 if (affect_transport) {
2308 _session->request_stop (with_abort, true);
2310 } else if (!with_abort) { /* with_abort == true means the
2311 * command was intended to stop
2312 * transport, not start.
2315 /* the only external sync condition we can be in here
2316 * would be Engine (JACK) sync, in which case we still
2320 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
2321 _session->request_play_range (&editor->get_selection().time, true);
2322 _session->set_requested_return_frame( editor->get_selection().time.front().start ); //force an auto-return here
2324 _session->request_transport_speed (1.0f);
2330 ARDOUR_UI::toggle_session_auto_loop ()
2336 Location * looploc = _session->locations()->auto_loop_location();
2342 if (_session->get_play_loop()) {
2344 /* looping enabled, our job is to disable it */
2346 _session->request_play_loop (false);
2350 /* looping not enabled, our job is to enable it.
2352 loop-is-NOT-mode: this action always starts the transport rolling.
2353 loop-IS-mode: this action simply sets the loop play mechanism, but
2354 does not start transport.
2356 if (Config->get_loop_is_mode()) {
2357 _session->request_play_loop (true, false);
2359 _session->request_play_loop (true, true);
2363 //show the loop markers
2364 looploc->set_hidden (false, this);
2368 ARDOUR_UI::transport_play_selection ()
2374 editor->play_selection ();
2378 ARDOUR_UI::transport_play_preroll ()
2383 editor->play_with_preroll ();
2387 ARDOUR_UI::transport_rewind (int option)
2389 float current_transport_speed;
2392 current_transport_speed = _session->transport_speed();
2394 if (current_transport_speed >= 0.0f) {
2397 _session->request_transport_speed (-1.0f);
2400 _session->request_transport_speed (-4.0f);
2403 _session->request_transport_speed (-0.5f);
2408 _session->request_transport_speed (current_transport_speed * 1.5f);
2414 ARDOUR_UI::transport_forward (int option)
2420 float current_transport_speed = _session->transport_speed();
2422 if (current_transport_speed <= 0.0f) {
2425 _session->request_transport_speed (1.0f);
2428 _session->request_transport_speed (4.0f);
2431 _session->request_transport_speed (0.5f);
2436 _session->request_transport_speed (current_transport_speed * 1.5f);
2441 ARDOUR_UI::toggle_record_enable (uint16_t rid)
2447 boost::shared_ptr<Route> r;
2449 if ((r = _session->get_remote_nth_route (rid)) != 0) {
2451 boost::shared_ptr<Track> t;
2453 if ((t = boost::dynamic_pointer_cast<Track>(r)) != 0) {
2454 t->rec_enable_control()->set_value (!t->rec_enable_control()->get_value(), Controllable::UseGroup);
2460 ARDOUR_UI::map_transport_state ()
2463 auto_loop_button.unset_active_state ();
2464 play_selection_button.unset_active_state ();
2465 roll_button.unset_active_state ();
2466 stop_button.set_active_state (Gtkmm2ext::ExplicitActive);
2470 shuttle_box->map_transport_state ();
2472 float sp = _session->transport_speed();
2478 if (_session->get_play_range()) {
2480 play_selection_button.set_active_state (Gtkmm2ext::ExplicitActive);
2481 roll_button.unset_active_state ();
2482 auto_loop_button.unset_active_state ();
2484 } else if (_session->get_play_loop ()) {
2486 auto_loop_button.set_active (true);
2487 play_selection_button.set_active (false);
2488 if (Config->get_loop_is_mode()) {
2489 roll_button.set_active (true);
2491 roll_button.set_active (false);
2496 roll_button.set_active (true);
2497 play_selection_button.set_active (false);
2498 auto_loop_button.set_active (false);
2501 if (UIConfiguration::instance().get_follow_edits() && !_session->config.get_external_sync()) {
2502 /* light up both roll and play-selection if they are joined */
2503 roll_button.set_active (true);
2504 play_selection_button.set_active (true);
2507 stop_button.set_active (false);
2511 stop_button.set_active (true);
2512 roll_button.set_active (false);
2513 play_selection_button.set_active (false);
2514 if (Config->get_loop_is_mode ()) {
2515 auto_loop_button.set_active (_session->get_play_loop());
2517 auto_loop_button.set_active (false);
2519 update_disk_space ();
2524 ARDOUR_UI::blink_handler (bool blink_on)
2526 transport_rec_enable_blink (blink_on);
2527 solo_blink (blink_on);
2528 sync_blink (blink_on);
2529 audition_blink (blink_on);
2530 feedback_blink (blink_on);
2531 error_blink (blink_on);
2535 ARDOUR_UI::update_clocks ()
2537 if (!_session) return;
2539 if (editor && !editor->dragging_playhead()) {
2540 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD)); /* EMIT_SIGNAL */
2545 ARDOUR_UI::start_clocking ()
2547 if (UIConfiguration::instance().get_super_rapid_clock_update()) {
2548 clock_signal_connection = Timers::fps_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2550 clock_signal_connection = Timers::rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2555 ARDOUR_UI::stop_clocking ()
2557 clock_signal_connection.disconnect ();
2561 ARDOUR_UI::save_as_progress_update (float fraction, int64_t cnt, int64_t total, Gtk::Label* label, Gtk::ProgressBar* bar)
2565 snprintf (buf, sizeof (buf), _("Copied %" PRId64 " of %" PRId64), cnt, total);
2567 label->set_text (buf);
2568 bar->set_fraction (fraction);
2570 /* process events, redraws, etc. */
2572 while (gtk_events_pending()) {
2573 gtk_main_iteration ();
2576 return true; /* continue with save-as */
2580 ARDOUR_UI::save_session_as ()
2586 if (!save_as_dialog) {
2587 save_as_dialog = new SaveAsDialog;
2590 save_as_dialog->set_name (_session->name());
2592 int response = save_as_dialog->run ();
2594 save_as_dialog->hide ();
2597 case Gtk::RESPONSE_OK:
2606 sa.new_parent_folder = save_as_dialog->new_parent_folder ();
2607 sa.new_name = save_as_dialog->new_name ();
2608 sa.switch_to = save_as_dialog->switch_to();
2609 sa.copy_media = save_as_dialog->copy_media();
2610 sa.copy_external = save_as_dialog->copy_external();
2611 sa.include_media = save_as_dialog->include_media ();
2613 /* Only bother with a progress dialog if we're going to copy
2614 media into the save-as target. Without that choice, this
2615 will be very fast because we're only talking about a few kB's to
2616 perhaps a couple of MB's of data.
2619 ArdourDialog progress_dialog (_("Save As"), true);
2621 if (sa.include_media && sa.copy_media) {
2624 Gtk::ProgressBar progress_bar;
2626 progress_dialog.get_vbox()->pack_start (label);
2627 progress_dialog.get_vbox()->pack_start (progress_bar);
2629 progress_bar.show ();
2631 /* this signal will be emitted from within this, the calling thread,
2632 * after every file is copied. It provides information on percentage
2633 * complete (in terms of total data to copy), the number of files
2634 * copied so far, and the total number to copy.
2639 sa.Progress.connect_same_thread (c, boost::bind (&ARDOUR_UI::save_as_progress_update, this, _1, _2, _3, &label, &progress_bar));
2641 progress_dialog.show_all ();
2642 progress_dialog.present ();
2645 if (_session->save_as (sa)) {
2647 MessageDialog msg (string_compose (_("Save As failed: %1"), sa.failure_message));
2651 if (!sa.include_media) {
2652 unload_session (false);
2653 load_session (sa.final_session_folder_name, sa.new_name);
2658 ARDOUR_UI::quick_snapshot_session (bool switch_to_it)
2662 struct tm local_time;
2665 localtime_r (&n, &local_time);
2666 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2668 save_state (timebuf, switch_to_it);
2673 ARDOUR_UI::process_snapshot_session_prompter (ArdourPrompter& prompter, bool switch_to_it)
2677 prompter.get_result (snapname);
2679 bool do_save = (snapname.length() != 0);
2682 char illegal = Session::session_name_is_legal(snapname);
2684 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2685 "snapshot names may not contain a '%1' character"), illegal));
2691 vector<std::string> p;
2692 get_state_files_in_directory (_session->session_directory().root_path(), p);
2693 vector<string> n = get_file_names_no_extension (p);
2695 if (find (n.begin(), n.end(), snapname) != n.end()) {
2697 do_save = overwrite_file_dialog (prompter,
2698 _("Confirm Snapshot Overwrite"),
2699 _("A snapshot already exists with that name. Do you want to overwrite it?"));
2703 save_state (snapname, switch_to_it);
2713 /** Ask the user for the name of a new snapshot and then take it.
2717 ARDOUR_UI::snapshot_session (bool switch_to_it)
2719 ArdourPrompter prompter (true);
2721 prompter.set_name ("Prompter");
2722 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2724 prompter.set_title (_("Snapshot and switch"));
2725 prompter.set_prompt (_("New session name"));
2727 prompter.set_title (_("Take Snapshot"));
2728 prompter.set_prompt (_("Name of new snapshot"));
2732 prompter.set_initial_text (_session->snap_name());
2736 struct tm local_time;
2739 localtime_r (&n, &local_time);
2740 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2741 prompter.set_initial_text (timebuf);
2744 bool finished = false;
2746 switch (prompter.run()) {
2747 case RESPONSE_ACCEPT:
2749 finished = process_snapshot_session_prompter (prompter, switch_to_it);
2760 /** Ask the user for a new session name and then rename the session to it.
2764 ARDOUR_UI::rename_session ()
2770 ArdourPrompter prompter (true);
2773 prompter.set_name ("Prompter");
2774 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2775 prompter.set_title (_("Rename Session"));
2776 prompter.set_prompt (_("New session name"));
2779 switch (prompter.run()) {
2780 case RESPONSE_ACCEPT:
2782 prompter.get_result (name);
2784 bool do_rename = (name.length() != 0);
2787 char illegal = Session::session_name_is_legal (name);
2790 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2791 "session names may not contain a '%1' character"), illegal));
2796 switch (_session->rename (name)) {
2798 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
2799 msg.set_position (WIN_POS_MOUSE);
2807 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
2808 msg.set_position (WIN_POS_MOUSE);
2824 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2826 if (!_session || _session->deletion_in_progress()) {
2830 XMLNode* node = new XMLNode (X_("UI"));
2832 WM::Manager::instance().add_state (*node);
2834 node->add_child_nocopy (gui_object_state->get_state());
2836 _session->add_extra_xml (*node);
2838 if (export_video_dialog) {
2839 _session->add_extra_xml (export_video_dialog->get_state());
2842 save_state_canfail (name, switch_to_it);
2846 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2851 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2856 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2861 ARDOUR_UI::primary_clock_value_changed ()
2864 _session->request_locate (primary_clock->current_time ());
2869 ARDOUR_UI::big_clock_value_changed ()
2872 _session->request_locate (big_clock->current_time ());
2877 ARDOUR_UI::secondary_clock_value_changed ()
2880 _session->request_locate (secondary_clock->current_time ());
2885 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2887 if (_session == 0) {
2891 if (_session->step_editing()) {
2895 Session::RecordState const r = _session->record_status ();
2896 bool const h = _session->have_rec_enabled_track ();
2898 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2900 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2902 rec_button.set_active_state (Gtkmm2ext::Off);
2904 } else if (r == Session::Recording && h) {
2905 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2907 rec_button.unset_active_state ();
2912 ARDOUR_UI::process_save_template_prompter (ArdourPrompter& prompter)
2916 prompter.get_result (name);
2918 if (name.length()) {
2919 int failed = _session->save_template (name);
2921 if (failed == -2) { /* file already exists. */
2922 bool overwrite = overwrite_file_dialog (prompter,
2923 _("Confirm Template Overwrite"),
2924 _("A template already exists with that name. Do you want to overwrite it?"));
2927 _session->save_template (name, true);
2939 ARDOUR_UI::save_template ()
2941 ArdourPrompter prompter (true);
2943 if (!check_audioengine (_main_window)) {
2947 prompter.set_name (X_("Prompter"));
2948 prompter.set_title (_("Save Template"));
2949 prompter.set_prompt (_("Name for template:"));
2950 prompter.set_initial_text(_session->name() + _("-template"));
2951 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2953 bool finished = false;
2955 switch (prompter.run()) {
2956 case RESPONSE_ACCEPT:
2957 finished = process_save_template_prompter (prompter);
2968 ARDOUR_UI::edit_metadata ()
2970 SessionMetadataEditor dialog;
2971 dialog.set_session (_session);
2972 dialog.grab_focus ();
2977 ARDOUR_UI::import_metadata ()
2979 SessionMetadataImporter dialog;
2980 dialog.set_session (_session);
2985 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
2987 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2989 MessageDialog msg (str,
2991 Gtk::MESSAGE_WARNING,
2992 Gtk::BUTTONS_YES_NO,
2996 msg.set_name (X_("OpenExistingDialog"));
2997 msg.set_title (_("Open Existing Session"));
2998 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
2999 msg.set_position (Gtk::WIN_POS_CENTER);
3000 pop_back_splash (msg);
3002 switch (msg.run()) {
3011 ARDOUR_UI::build_session_from_dialog (SessionDialog& sd, const std::string& session_path, const std::string& session_name)
3013 BusProfile bus_profile;
3017 bus_profile.master_out_channels = 2;
3018 bus_profile.input_ac = AutoConnectPhysical;
3019 bus_profile.output_ac = AutoConnectMaster;
3020 bus_profile.requested_physical_in = 0; // use all available
3021 bus_profile.requested_physical_out = 0; // use all available
3025 /* get settings from advanced section of NSD */
3027 if (sd.create_master_bus()) {
3028 bus_profile.master_out_channels = (uint32_t) sd.master_channel_count();
3030 bus_profile.master_out_channels = 0;
3033 if (sd.connect_inputs()) {
3034 bus_profile.input_ac = AutoConnectPhysical;
3036 bus_profile.input_ac = AutoConnectOption (0);
3039 bus_profile.output_ac = AutoConnectOption (0);
3041 if (sd.connect_outputs ()) {
3042 if (sd.connect_outs_to_master()) {
3043 bus_profile.output_ac = AutoConnectMaster;
3044 } else if (sd.connect_outs_to_physical()) {
3045 bus_profile.output_ac = AutoConnectPhysical;
3049 bus_profile.requested_physical_in = (uint32_t) sd.input_limit_count();
3050 bus_profile.requested_physical_out = (uint32_t) sd.output_limit_count();
3053 if (build_session (session_path, session_name, bus_profile)) {
3061 ARDOUR_UI::load_from_application_api (const std::string& path)
3063 ARDOUR_COMMAND_LINE::session_name = path;
3064 /* Cancel SessionDialog if it's visible to make OSX delegates work.
3066 * ARDOUR_UI::starting connects app->ShouldLoad signal and then shows a SessionDialog
3068 * - ShouldLoad does not arrive in time, ARDOUR_COMMAND_LINE::session_name is empty:
3069 * -> ARDOUR_UI::get_session_parameters starts a SessionDialog.
3070 * - ShouldLoad signal arrives, this function is called and sets ARDOUR_COMMAND_LINE::session_name
3071 * -> SessionDialog is not displayed
3074 if (_session_dialog) {
3075 std::string session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3076 std::string session_path = path;
3077 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_REGULAR)) {
3078 session_path = Glib::path_get_dirname (session_path);
3080 // signal the existing dialog in ARDOUR_UI::get_session_parameters()
3081 _session_dialog->set_provided_session (session_name, session_path);
3082 _session_dialog->response (RESPONSE_NONE);
3083 _session_dialog->hide();
3088 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
3089 /* /path/to/foo => /path/to/foo, foo */
3090 rv = load_session (path, basename_nosuffix (path));
3092 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
3093 rv =load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
3096 // if load_session fails -> pop up SessionDialog.
3098 ARDOUR_COMMAND_LINE::session_name = "";
3100 if (get_session_parameters (true, false)) {
3106 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
3108 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
3110 string session_name;
3111 string session_path;
3112 string template_name;
3114 bool likely_new = false;
3115 bool cancel_not_quit;
3117 /* deal with any existing DIRTY session now, rather than later. don't
3118 * treat a non-dirty session this way, so that it stays visible
3119 * as we bring up the new session dialog.
3122 if (_session && ARDOUR_UI::instance()->video_timeline) {
3123 ARDOUR_UI::instance()->video_timeline->sync_session_state();
3126 /* if there is already a session, relabel the button
3127 on the SessionDialog so that we don't Quit directly
3129 cancel_not_quit = (_session != 0);
3131 if (_session && _session->dirty()) {
3132 if (unload_session (false)) {
3133 /* unload cancelled by user */
3136 ARDOUR_COMMAND_LINE::session_name = "";
3139 if (!load_template.empty()) {
3140 should_be_new = true;
3141 template_name = load_template;
3144 session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3145 session_path = ARDOUR_COMMAND_LINE::session_name;
3147 if (!session_path.empty()) {
3148 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_EXISTS)) {
3149 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_IS_REGULAR)) {
3150 /* session/snapshot file, change path to be dir */
3151 session_path = Glib::path_get_dirname (session_path);
3156 SessionDialog session_dialog (should_be_new, session_name, session_path, load_template, cancel_not_quit);
3158 _session_dialog = &session_dialog;
3161 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
3163 /* if they named a specific statefile, use it, otherwise they are
3164 just giving a session folder, and we want to use it as is
3165 to find the session.
3168 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
3170 if (suffix != string::npos) {
3171 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
3172 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
3173 session_name = Glib::path_get_basename (session_name);
3175 session_path = ARDOUR_COMMAND_LINE::session_name;
3176 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
3181 session_dialog.clear_given ();
3184 if (should_be_new || session_name.empty()) {
3185 /* need the dialog to get info from user */
3187 cerr << "run dialog\n";
3189 switch (session_dialog.run()) {
3190 case RESPONSE_ACCEPT:
3193 /* this is used for async * app->ShouldLoad(). */
3194 continue; // while loop
3197 if (quit_on_cancel) {
3198 // JE - Currently (July 2014) this section can only get reached if the
3199 // user quits from the main 'Session Setup' dialog (i.e. reaching this
3200 // point does NOT indicate an abnormal termination). Therefore, let's
3201 // behave gracefully (i.e. let's do some cleanup) before we call exit()
3203 pthread_cancel_all ();
3211 session_dialog.hide ();
3214 /* if we run the startup dialog again, offer more than just "new session" */
3216 should_be_new = false;
3218 session_name = session_dialog.session_name (likely_new);
3219 session_path = session_dialog.session_folder ();
3225 string::size_type suffix = session_name.find (statefile_suffix);
3227 if (suffix != string::npos) {
3228 session_name = session_name.substr (0, suffix);
3231 /* this shouldn't happen, but we catch it just in case it does */
3233 if (session_name.empty()) {
3237 if (session_dialog.use_session_template()) {
3238 template_name = session_dialog.session_template_name();
3239 _session_is_new = true;
3242 if (session_name[0] == G_DIR_SEPARATOR ||
3243 #ifdef PLATFORM_WINDOWS
3244 (session_name.length() > 3 && session_name[1] == ':' && session_name[2] == G_DIR_SEPARATOR)
3246 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
3247 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)
3252 /* absolute path or cwd-relative path specified for session name: infer session folder
3253 from what was given.
3256 session_path = Glib::path_get_dirname (session_name);
3257 session_name = Glib::path_get_basename (session_name);
3261 session_path = session_dialog.session_folder();
3263 char illegal = Session::session_name_is_legal (session_name);
3266 MessageDialog msg (session_dialog,
3267 string_compose (_("To ensure compatibility with various systems\n"
3268 "session names may not contain a '%1' character"),
3271 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3276 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
3279 if (likely_new && !nsm) {
3281 std::string existing = Glib::build_filename (session_path, session_name);
3283 if (!ask_about_loading_existing_session (existing)) {
3284 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3289 _session_is_new = false;
3294 pop_back_splash (session_dialog);
3295 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
3297 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3301 char illegal = Session::session_name_is_legal(session_name);
3304 pop_back_splash (session_dialog);
3305 MessageDialog msg (session_dialog, string_compose(_("To ensure compatibility with various systems\n"
3306 "session names may not contain a '%1' character"), illegal));
3308 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3312 _session_is_new = true;
3315 if (likely_new && template_name.empty()) {
3317 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3321 ret = load_session (session_path, session_name, template_name);
3324 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
3328 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
3329 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
3333 /* clear this to avoid endless attempts to load the
3337 ARDOUR_COMMAND_LINE::session_name = "";
3341 _session_dialog = NULL;
3347 ARDOUR_UI::close_session()
3349 if (!check_audioengine (_main_window)) {
3353 if (unload_session (true)) {
3357 ARDOUR_COMMAND_LINE::session_name = "";
3359 if (get_session_parameters (true, false)) {
3362 if (splash && splash->is_visible()) {
3363 // in 1 second, hide the splash screen
3364 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
3368 /** @param snap_name Snapshot name (without .ardour suffix).
3369 * @return -2 if the load failed because we are not connected to the AudioEngine.
3372 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
3374 Session *new_session;
3379 unload_status = unload_session ();
3381 if (unload_status < 0) {
3383 } else if (unload_status > 0) {
3389 session_loaded = false;
3391 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
3394 new_session = new Session (*AudioEngine::instance(), path, snap_name, 0, mix_template);
3397 /* this one is special */
3399 catch (AudioEngine::PortRegistrationFailure& err) {
3401 MessageDialog msg (err.what(),
3404 Gtk::BUTTONS_CLOSE);
3406 msg.set_title (_("Port Registration Error"));
3407 msg.set_secondary_text (_("Click the Close button to try again."));
3408 msg.set_position (Gtk::WIN_POS_CENTER);
3409 pop_back_splash (msg);
3412 int response = msg.run ();
3417 case RESPONSE_CANCEL:
3424 catch (SessionException e) {
3425 MessageDialog msg (string_compose(
3426 _("Session \"%1 (snapshot %2)\" did not load successfully: %3"),
3427 path, snap_name, e.what()),
3432 msg.set_title (_("Loading Error"));
3433 msg.set_position (Gtk::WIN_POS_CENTER);
3434 pop_back_splash (msg);
3446 MessageDialog msg (string_compose(
3447 _("Session \"%1 (snapshot %2)\" did not load successfully"),
3453 msg.set_title (_("Loading Error"));
3454 msg.set_position (Gtk::WIN_POS_CENTER);
3455 pop_back_splash (msg);
3467 list<string> const u = new_session->unknown_processors ();
3469 MissingPluginDialog d (_session, u);
3474 if (!new_session->writable()) {
3475 MessageDialog msg (_("This session has been opened in read-only mode.\n\nYou will not be able to record or save."),
3480 msg.set_title (_("Read-only Session"));
3481 msg.set_position (Gtk::WIN_POS_CENTER);
3482 pop_back_splash (msg);
3489 /* Now the session been created, add the transport controls */
3490 new_session->add_controllable(roll_controllable);
3491 new_session->add_controllable(stop_controllable);
3492 new_session->add_controllable(goto_start_controllable);
3493 new_session->add_controllable(goto_end_controllable);
3494 new_session->add_controllable(auto_loop_controllable);
3495 new_session->add_controllable(play_selection_controllable);
3496 new_session->add_controllable(rec_controllable);
3498 set_session (new_session);
3500 session_loaded = true;
3503 _session->set_clean ();
3506 #ifdef WINDOWS_VST_SUPPORT
3507 fst_stop_threading();
3511 Timers::TimerSuspender t;
3515 #ifdef WINDOWS_VST_SUPPORT
3516 fst_start_threading();
3525 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
3527 Session *new_session;
3530 session_loaded = false;
3531 x = unload_session ();
3539 _session_is_new = true;
3542 new_session = new Session (*AudioEngine::instance(), path, snap_name, &bus_profile);
3545 catch (SessionException e) {
3547 MessageDialog msg (string_compose(_("Could not create session in \"%1\": %2"), path, e.what()));
3548 msg.set_title (_("Loading Error"));
3549 msg.set_position (Gtk::WIN_POS_CENTER);
3550 pop_back_splash (msg);
3556 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
3557 msg.set_title (_("Loading Error"));
3558 msg.set_position (Gtk::WIN_POS_CENTER);
3559 pop_back_splash (msg);
3564 /* Give the new session the default GUI state, if such things exist */
3567 n = Config->instant_xml (X_("Editor"));
3569 n->remove_nodes_and_delete ("Selection"); // no not apply selection to new sessions.
3570 new_session->add_instant_xml (*n, false);
3572 n = Config->instant_xml (X_("Mixer"));
3574 new_session->add_instant_xml (*n, false);
3577 n = Config->instant_xml (X_("Preferences"));
3579 new_session->add_instant_xml (*n, false);
3582 /* Put the playhead at 0 and scroll fully left */
3583 n = new_session->instant_xml (X_("Editor"));
3585 n->add_property (X_("playhead"), X_("0"));
3586 n->add_property (X_("left-frame"), X_("0"));
3589 set_session (new_session);
3591 session_loaded = true;
3593 new_session->save_state(new_session->name());
3599 ARDOUR_UI::launch_chat ()
3601 MessageDialog dialog(_("<b>Just ask and wait for an answer.\nIt may take from minutes to hours.</b>"), true);
3603 dialog.set_title (_("About the Chat"));
3604 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."));
3606 switch (dialog.run()) {
3609 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
3610 #elif defined PLATFORM_WINDOWS
3611 open_uri("http://webchat.freenode.net/?channels=ardour-windows");
3613 open_uri("http://webchat.freenode.net/?channels=ardour");
3622 ARDOUR_UI::launch_manual ()
3624 PBD::open_uri (Config->get_tutorial_manual_url());
3628 ARDOUR_UI::launch_reference ()
3630 PBD::open_uri (Config->get_reference_manual_url());
3634 ARDOUR_UI::launch_tracker ()
3636 PBD::open_uri ("http://tracker.ardour.org");
3640 ARDOUR_UI::launch_subscribe ()
3642 PBD::open_uri ("https://community.ardour.org/s/subscribe");
3646 ARDOUR_UI::launch_cheat_sheet ()
3649 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheat_sheet_osx.pdf");
3651 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheatsheet.pdf");
3656 ARDOUR_UI::launch_website ()
3658 PBD::open_uri ("http://ardour.org");
3662 ARDOUR_UI::launch_website_dev ()
3664 PBD::open_uri ("http://ardour.org/development.html");
3668 ARDOUR_UI::launch_forums ()
3670 PBD::open_uri ("https://community.ardour.org/forums");
3674 ARDOUR_UI::launch_howto_report ()
3676 PBD::open_uri ("http://ardour.org/reporting_bugs");
3680 ARDOUR_UI::loading_message (const std::string& msg)
3682 if (ARDOUR_COMMAND_LINE::no_splash) {
3690 splash->message (msg);
3694 ARDOUR_UI::show_splash ()
3698 splash = new Splash;
3708 ARDOUR_UI::hide_splash ()
3715 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title, const bool msg_delete)
3719 removed = rep.paths.size();
3722 MessageDialog msgd (_main_window,
3723 _("No files were ready for clean-up"),
3727 msgd.set_title (_("Clean-up"));
3728 msgd.set_secondary_text (_("If this seems suprising, \n\
3729 check for any existing snapshots.\n\
3730 These may still include regions that\n\
3731 require some unused files to continue to exist."));
3737 ArdourDialog results (_("Clean-up"), true, false);
3739 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
3740 CleanupResultsModelColumns() {
3744 Gtk::TreeModelColumn<std::string> visible_name;
3745 Gtk::TreeModelColumn<std::string> fullpath;
3749 CleanupResultsModelColumns results_columns;
3750 Glib::RefPtr<Gtk::ListStore> results_model;
3751 Gtk::TreeView results_display;
3753 results_model = ListStore::create (results_columns);
3754 results_display.set_model (results_model);
3755 results_display.append_column (list_title, results_columns.visible_name);
3757 results_display.set_name ("CleanupResultsList");
3758 results_display.set_headers_visible (true);
3759 results_display.set_headers_clickable (false);
3760 results_display.set_reorderable (false);
3762 Gtk::ScrolledWindow list_scroller;
3765 Gtk::HBox dhbox; // the hbox for the image and text
3766 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
3767 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
3769 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
3771 const string dead_directory = _session->session_directory().dead_path();
3774 %1 - number of files removed
3775 %2 - location of "dead"
3776 %3 - size of files affected
3777 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
3780 const char* bprefix;
3781 double space_adjusted = 0;
3783 if (rep.space < 1000) {
3785 space_adjusted = rep.space;
3786 } else if (rep.space < 1000000) {
3787 bprefix = _("kilo");
3788 space_adjusted = floorf((float)rep.space / 1000.0);
3789 } else if (rep.space < 1000000 * 1000) {
3790 bprefix = _("mega");
3791 space_adjusted = floorf((float)rep.space / (1000.0 * 1000.0));
3793 bprefix = _("giga");
3794 space_adjusted = floorf((float)rep.space / (1000.0 * 1000 * 1000.0));
3798 txt.set_markup (string_compose (P_("\
3799 The following file was deleted from %2,\n\
3800 releasing %3 %4bytes of disk space", "\
3801 The following %1 files were deleted from %2,\n\
3802 releasing %3 %4bytes of disk space", removed),
3803 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3805 txt.set_markup (string_compose (P_("\
3806 The following file was not in use and \n\
3807 has been moved to: %2\n\n\
3808 After a restart of %5\n\n\
3809 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3810 will release an additional %3 %4bytes of disk space.\n", "\
3811 The following %1 files were not in use and \n\
3812 have been moved to: %2\n\n\
3813 After a restart of %5\n\n\
3814 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3815 will release an additional %3 %4bytes of disk space.\n", removed),
3816 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3819 dhbox.pack_start (*dimage, true, false, 5);
3820 dhbox.pack_start (txt, true, false, 5);
3822 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
3823 TreeModel::Row row = *(results_model->append());
3824 row[results_columns.visible_name] = *i;
3825 row[results_columns.fullpath] = *i;
3828 list_scroller.add (results_display);
3829 list_scroller.set_size_request (-1, 150);
3830 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
3832 dvbox.pack_start (dhbox, true, false, 5);
3833 dvbox.pack_start (list_scroller, true, false, 5);
3834 ddhbox.pack_start (dvbox, true, false, 5);
3836 results.get_vbox()->pack_start (ddhbox, true, false, 5);
3837 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
3838 results.set_default_response (RESPONSE_CLOSE);
3839 results.set_position (Gtk::WIN_POS_MOUSE);
3841 results_display.show();
3842 list_scroller.show();
3849 //results.get_vbox()->show();
3850 results.set_resizable (false);
3857 ARDOUR_UI::cleanup ()
3859 if (_session == 0) {
3860 /* shouldn't happen: menu item is insensitive */
3865 MessageDialog checker (_("Are you sure you want to clean-up?"),
3867 Gtk::MESSAGE_QUESTION,
3870 checker.set_title (_("Clean-up"));
3872 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
3873 ALL undo/redo information will be lost if you clean-up.\n\
3874 Clean-up will move all unused files to a \"dead\" location."));
3876 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3877 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
3878 checker.set_default_response (RESPONSE_CANCEL);
3880 checker.set_name (_("CleanupDialog"));
3881 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3882 checker.set_position (Gtk::WIN_POS_MOUSE);
3884 switch (checker.run()) {
3885 case RESPONSE_ACCEPT:
3891 ARDOUR::CleanupReport rep;
3893 editor->prepare_for_cleanup ();
3895 /* do not allow flush until a session is reloaded */
3897 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3899 act->set_sensitive (false);
3902 if (_session->cleanup_sources (rep)) {
3903 editor->finish_cleanup ();
3907 editor->finish_cleanup ();
3910 display_cleanup_results (rep, _("Cleaned Files"), false);
3914 ARDOUR_UI::flush_trash ()
3916 if (_session == 0) {
3917 /* shouldn't happen: menu item is insensitive */
3921 ARDOUR::CleanupReport rep;
3923 if (_session->cleanup_trash_sources (rep)) {
3927 display_cleanup_results (rep, _("deleted file"), true);
3931 ARDOUR_UI::cleanup_peakfiles ()
3933 if (_session == 0) {
3934 /* shouldn't happen: menu item is insensitive */
3938 if (! _session->can_cleanup_peakfiles ()) {
3942 // get all region-views in this session
3944 TrackViewList empty;
3946 editor->get_regions_after(rs, (framepos_t) 0, empty);
3947 std::list<RegionView*> views = rs.by_layer();
3949 // remove displayed audio-region-views waveforms
3950 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
3951 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
3952 if (!arv) { continue ; }
3953 arv->delete_waves();
3956 // cleanup peak files:
3957 // - stop pending peakfile threads
3958 // - close peakfiles if any
3959 // - remove peak dir in session
3960 // - setup peakfiles (background thread)
3961 _session->cleanup_peakfiles ();
3963 // re-add waves to ARV
3964 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
3965 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
3966 if (!arv) { continue ; }
3967 arv->create_waves();
3971 PresentationInfo::order_t
3972 ARDOUR_UI::translate_order (AddRouteDialog::InsertAt place)
3974 if (editor->get_selection().tracks.empty()) {
3975 return PresentationInfo::max_order;
3978 PresentationInfo::order_t order_hint = PresentationInfo::max_order;
3981 we want the new routes to have their order keys set starting from
3982 the highest order key in the selection + 1 (if available).
3985 if (place == AddRouteDialog::AfterSelection) {
3986 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.back());
3988 order_hint = rtav->route()->presentation_info().order();
3991 } else if (place == AddRouteDialog::BeforeSelection) {
3992 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.front());
3994 order_hint = rtav->route()->presentation_info().order();
3996 } else if (place == AddRouteDialog::First) {
3999 /* leave order_hint at max_order */
4006 ARDOUR_UI::start_duplicate_routes ()
4008 if (!duplicate_routes_dialog) {
4009 duplicate_routes_dialog = new DuplicateRouteDialog;
4012 if (duplicate_routes_dialog->restart (_session)) {
4016 duplicate_routes_dialog->present ();
4020 ARDOUR_UI::add_route ()
4022 if (!add_route_dialog.get (false)) {
4023 add_route_dialog->signal_response().connect (sigc::mem_fun (*this, &ARDOUR_UI::add_route_dialog_finished));
4030 if (add_route_dialog->is_visible()) {
4031 /* we're already doing this */
4035 add_route_dialog->set_position (WIN_POS_MOUSE);
4036 add_route_dialog->present();
4040 ARDOUR_UI::add_route_dialog_finished (int r)
4044 add_route_dialog->hide();
4047 case RESPONSE_ACCEPT:
4054 if ((count = add_route_dialog->count()) <= 0) {
4058 PresentationInfo::order_t order = translate_order (add_route_dialog->insert_at());
4059 string template_path = add_route_dialog->track_template();
4060 DisplaySuspender ds;
4062 if (!template_path.empty()) {
4063 if (add_route_dialog->name_template_is_default()) {
4064 _session->new_route_from_template (count, template_path, string());
4066 _session->new_route_from_template (count, template_path, add_route_dialog->name_template());
4071 ChanCount input_chan= add_route_dialog->channels ();
4072 ChanCount output_chan;
4073 string name_template = add_route_dialog->name_template ();
4074 PluginInfoPtr instrument = add_route_dialog->requested_instrument ();
4075 RouteGroup* route_group = add_route_dialog->route_group ();
4076 AutoConnectOption oac = Config->get_output_auto_connect();
4077 bool strict_io = add_route_dialog->use_strict_io ();
4079 if (oac & AutoConnectMaster) {
4080 output_chan.set (DataType::AUDIO, (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan.n_audio()));
4081 output_chan.set (DataType::MIDI, 0);
4083 output_chan = input_chan;
4086 /* XXX do something with name template */
4088 switch (add_route_dialog->type_wanted()) {
4089 case AddRouteDialog::AudioTrack:
4090 session_add_audio_track (input_chan.n_audio(), output_chan.n_audio(), add_route_dialog->mode(), route_group, count, name_template, strict_io, order);
4092 case AddRouteDialog::MidiTrack:
4093 session_add_midi_track (route_group, count, name_template, strict_io, instrument, 0, order);
4095 case AddRouteDialog::MixedTrack:
4096 session_add_mixed_track (input_chan, output_chan, route_group, count, name_template, strict_io, instrument, 0, order);
4098 case AddRouteDialog::AudioBus:
4099 session_add_audio_bus (input_chan.n_audio(), output_chan.n_audio(), route_group, count, name_template, strict_io, order);
4101 case AddRouteDialog::MidiBus:
4102 session_add_midi_bus (route_group, count, name_template, strict_io, instrument, 0, order);
4104 case AddRouteDialog::VCAMaster:
4105 session_add_vca (name_template, count);
4111 ARDOUR_UI::add_lua_script ()
4117 LuaScriptInfoPtr spi;
4118 ScriptSelector ss ("Add Lua Session Script", LuaScriptInfo::Session);
4119 switch (ss.run ()) {
4120 case Gtk::RESPONSE_ACCEPT:
4128 std::string script = "";
4131 script = Glib::file_get_contents (spi->path);
4132 } catch (Glib::FileError e) {
4133 string msg = string_compose (_("Cannot read session script '%1': %2"), spi->path, e.what());
4134 MessageDialog am (msg);
4139 LuaScriptParamList lsp = LuaScriptParams::script_params (spi, "sess_params");
4140 std::vector<std::string> reg = _session->registered_lua_functions ();
4142 ScriptParameterDialog spd (_("Set Script Parameters"), spi, reg, lsp);
4143 switch (spd.run ()) {
4144 case Gtk::RESPONSE_ACCEPT:
4151 _session->register_lua_function (spd.name(), script, lsp);
4152 } catch (luabridge::LuaException const& e) {
4153 string msg = string_compose (_("Session script '%1' instantiation failed: %2"), spd.name(), e.what ());
4154 MessageDialog am (msg);
4156 } catch (SessionException e) {
4157 string msg = string_compose (_("Loading Session script '%1' failed: %2"), spd.name(), e.what ());
4158 MessageDialog am (msg);
4164 ARDOUR_UI::remove_lua_script ()
4169 if (_session->registered_lua_function_count () == 0) {
4170 string msg = _("There are no active Lua session scripts present in this session.");
4171 MessageDialog am (msg);
4176 std::vector<std::string> reg = _session->registered_lua_functions ();
4177 SessionScriptManager sm ("Remove Lua Session Script", reg);
4178 switch (sm.run ()) {
4179 case Gtk::RESPONSE_ACCEPT:
4185 _session->unregister_lua_function (sm.name());
4186 } catch (luabridge::LuaException const& e) {
4187 string msg = string_compose (_("Session script '%1' removal failed: %2"), sm.name(), e.what ());
4188 MessageDialog am (msg);
4194 ARDOUR_UI::stop_video_server (bool ask_confirm)
4196 if (!video_server_process && ask_confirm) {
4197 warning << string_compose (_("Video-Server was not launched by %1. The request to stop it is ignored."), PROGRAM_NAME) << endmsg;
4199 if (video_server_process) {
4201 ArdourDialog confirm (_("Stop Video-Server"), true);
4202 Label m (_("Do you really want to stop the Video Server?"));
4203 confirm.get_vbox()->pack_start (m, true, true);
4204 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
4205 confirm.add_button (_("Yes, Stop It"), Gtk::RESPONSE_ACCEPT);
4206 confirm.show_all ();
4207 if (confirm.run() == RESPONSE_CANCEL) {
4211 delete video_server_process;
4212 video_server_process =0;
4217 ARDOUR_UI::start_video_server_menu (Gtk::Window* float_window)
4219 ARDOUR_UI::start_video_server( float_window, true);
4223 ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg)
4229 if (ARDOUR_UI::instance()->video_timeline->check_server()) {
4230 if (video_server_process) {
4231 popup_error(_("The Video Server is already started."));
4233 popup_error(_("An external Video Server is configured and can be reached. Not starting a new instance."));
4239 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4241 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4243 VideoServerDialog *video_server_dialog = new VideoServerDialog (_session);
4245 video_server_dialog->set_transient_for (*float_window);
4248 if (!Config->get_show_video_server_dialog() && firsttime < 2) {
4249 video_server_dialog->hide();
4251 ResponseType r = (ResponseType) video_server_dialog->run ();
4252 video_server_dialog->hide();
4253 if (r != RESPONSE_ACCEPT) { return false; }
4254 if (video_server_dialog->show_again()) {
4255 Config->set_show_video_server_dialog(false);
4259 std::string icsd_exec = video_server_dialog->get_exec_path();
4260 std::string icsd_docroot = video_server_dialog->get_docroot();
4261 if (icsd_docroot.empty()) {
4262 #ifndef PLATFORM_WINDOWS
4263 icsd_docroot = X_("/");
4265 icsd_docroot = X_("C:\\");
4270 if (g_lstat (icsd_docroot.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode)) {
4271 warning << _("Specified docroot is not an existing directory.") << endmsg;
4274 #ifndef PLATFORM_WINDOWS
4275 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4276 || (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0 ) {
4277 warning << _("Given Video Server is not an executable file.") << endmsg;
4281 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4282 || (sb.st_mode & (S_IXUSR)) == 0 ) {
4283 warning << _("Given Video Server is not an executable file.") << endmsg;
4289 argp=(char**) calloc(9,sizeof(char*));
4290 argp[0] = strdup(icsd_exec.c_str());
4291 argp[1] = strdup("-P");
4292 argp[2] = (char*) calloc(16,sizeof(char)); snprintf(argp[2], 16, "%s", video_server_dialog->get_listenaddr().c_str());
4293 argp[3] = strdup("-p");
4294 argp[4] = (char*) calloc(6,sizeof(char)); snprintf(argp[4], 6, "%i", video_server_dialog->get_listenport());
4295 argp[5] = strdup("-C");
4296 argp[6] = (char*) calloc(6,sizeof(char)); snprintf(argp[6], 6, "%i", video_server_dialog->get_cachesize());
4297 argp[7] = strdup(icsd_docroot.c_str());
4299 stop_video_server();
4301 if (icsd_docroot == X_("/") || icsd_docroot == X_("C:\\")) {
4302 Config->set_video_advanced_setup(false);
4304 std::ostringstream osstream;
4305 osstream << "http://127.0.0.1:" << video_server_dialog->get_listenport() << "/";
4306 Config->set_video_server_url(osstream.str());
4307 Config->set_video_server_docroot(icsd_docroot);
4308 Config->set_video_advanced_setup(true);
4311 if (video_server_process) {
4312 delete video_server_process;
4315 video_server_process = new ARDOUR::SystemExec(icsd_exec, argp);
4316 if (video_server_process->start()) {
4317 warning << _("Cannot launch the video-server") << endmsg;
4320 int timeout = 120; // 6 sec
4321 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4322 Glib::usleep (50000);
4324 if (--timeout <= 0 || !video_server_process->is_running()) break;
4327 warning << _("Video-server was started but does not respond to requests...") << endmsg;
4329 if (!ARDOUR_UI::instance()->video_timeline->check_server_docroot()) {
4330 delete video_server_process;
4331 video_server_process = 0;
4339 ARDOUR_UI::add_video (Gtk::Window* float_window)
4345 if (!start_video_server(float_window, false)) {
4346 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4351 add_video_dialog->set_transient_for (*float_window);
4354 if (add_video_dialog->is_visible()) {
4355 /* we're already doing this */
4359 ResponseType r = (ResponseType) add_video_dialog->run ();
4360 add_video_dialog->hide();
4361 if (r != RESPONSE_ACCEPT) { return; }
4363 bool local_file, orig_local_file;
4364 std::string path = add_video_dialog->file_name(local_file);
4366 std::string orig_path = path;
4367 orig_local_file = local_file;
4369 bool auto_set_session_fps = add_video_dialog->auto_set_session_fps();
4371 if (local_file && !Glib::file_test(path, Glib::FILE_TEST_EXISTS)) {
4372 warning << string_compose(_("could not open %1"), path) << endmsg;
4375 if (!local_file && path.length() == 0) {
4376 warning << _("no video-file selected") << endmsg;
4380 std::string audio_from_video;
4381 bool detect_ltc = false;
4383 switch (add_video_dialog->import_option()) {
4384 case VTL_IMPORT_TRANSCODE:
4386 TranscodeVideoDialog *transcode_video_dialog;
4387 transcode_video_dialog = new TranscodeVideoDialog (_session, path);
4388 ResponseType r = (ResponseType) transcode_video_dialog->run ();
4389 transcode_video_dialog->hide();
4390 if (r != RESPONSE_ACCEPT) {
4391 delete transcode_video_dialog;
4395 audio_from_video = transcode_video_dialog->get_audiofile();
4397 if (!audio_from_video.empty() && transcode_video_dialog->detect_ltc()) {
4400 else if (!audio_from_video.empty()) {
4401 editor->embed_audio_from_video(
4403 video_timeline->get_offset(),
4404 (transcode_video_dialog->import_option() != VTL_IMPORT_NO_VIDEO)
4407 switch (transcode_video_dialog->import_option()) {
4408 case VTL_IMPORT_TRANSCODED:
4409 path = transcode_video_dialog->get_filename();
4412 case VTL_IMPORT_REFERENCE:
4415 delete transcode_video_dialog;
4418 delete transcode_video_dialog;
4422 case VTL_IMPORT_NONE:
4426 /* strip _session->session_directory().video_path() from video file if possible */
4427 if (local_file && !path.compare(0, _session->session_directory().video_path().size(), _session->session_directory().video_path())) {
4428 path=path.substr(_session->session_directory().video_path().size());
4429 if (path.at(0) == G_DIR_SEPARATOR) {
4430 path=path.substr(1);
4434 video_timeline->set_update_session_fps(auto_set_session_fps);
4436 if (video_timeline->video_file_info(path, local_file)) {
4437 XMLNode* node = new XMLNode(X_("Videotimeline"));
4438 node->add_property (X_("Filename"), path);
4439 node->add_property (X_("AutoFPS"), auto_set_session_fps?X_("1"):X_("0"));
4440 node->add_property (X_("LocalFile"), local_file?X_("1"):X_("0"));
4441 if (orig_local_file) {
4442 node->add_property (X_("OriginalVideoFile"), orig_path);
4444 node->remove_property (X_("OriginalVideoFile"));
4446 _session->add_extra_xml (*node);
4447 _session->set_dirty ();
4449 if (!audio_from_video.empty() && detect_ltc) {
4450 std::vector<LTCFileReader::LTCMap> ltc_seq;
4453 /* TODO ask user about TV standard (LTC alignment if any) */
4454 LTCFileReader ltcr (audio_from_video, video_timeline->get_video_file_fps());
4455 /* TODO ASK user which channel: 0 .. ltcr->channels() - 1 */
4457 ltc_seq = ltcr.read_ltc (/*channel*/ 0, /*max LTC frames to decode*/ 15);
4459 /* TODO seek near end of file, and read LTC until end.
4460 * if it fails to find any LTC frames, scan complete file
4462 * calculate drift of LTC compared to video-duration,
4463 * ask user for reference (timecode from start/mid/end)
4466 // LTCFileReader will have written error messages
4469 ::g_unlink(audio_from_video.c_str());
4471 if (ltc_seq.size() == 0) {
4472 PBD::error << _("No LTC detected, video will not be aligned.") << endmsg;
4474 /* the very first TC in the file is somteimes not aligned properly */
4475 int i = ltc_seq.size() -1;
4476 ARDOUR::frameoffset_t video_start_offset =
4477 _session->nominal_frame_rate() * (ltc_seq[i].timecode_sec - ltc_seq[i].framepos_sec);
4478 PBD::info << string_compose (_("Align video-start to %1 [samples]"), video_start_offset) << endmsg;
4479 video_timeline->set_offset(video_start_offset);
4483 _session->maybe_update_session_range(
4484 std::max(video_timeline->get_offset(), (ARDOUR::frameoffset_t) 0),
4485 std::max(video_timeline->get_offset() + video_timeline->get_duration(), (ARDOUR::frameoffset_t) 0));
4488 if (add_video_dialog->launch_xjadeo() && local_file) {
4489 editor->set_xjadeo_sensitive(true);
4490 editor->toggle_xjadeo_proc(1);
4492 editor->toggle_xjadeo_proc(0);
4494 editor->toggle_ruler_video(true);
4499 ARDOUR_UI::remove_video ()
4501 video_timeline->close_session();
4502 editor->toggle_ruler_video(false);
4505 video_timeline->set_offset_locked(false);
4506 video_timeline->set_offset(0);
4508 /* delete session state */
4509 XMLNode* node = new XMLNode(X_("Videotimeline"));
4510 _session->add_extra_xml(*node);
4511 node = new XMLNode(X_("Videomonitor"));
4512 _session->add_extra_xml(*node);
4513 node = new XMLNode(X_("Videoexport"));
4514 _session->add_extra_xml(*node);
4515 stop_video_server();
4519 ARDOUR_UI::flush_videotimeline_cache (bool localcacheonly)
4521 if (localcacheonly) {
4522 video_timeline->vmon_update();
4524 video_timeline->flush_cache();
4526 editor->queue_visual_videotimeline_update();
4530 ARDOUR_UI::export_video (bool range)
4532 if (ARDOUR::Config->get_show_video_export_info()) {
4533 ExportVideoInfobox infobox (_session);
4534 Gtk::ResponseType rv = (Gtk::ResponseType) infobox.run();
4535 if (infobox.show_again()) {
4536 ARDOUR::Config->set_show_video_export_info(false);
4539 case GTK_RESPONSE_YES:
4540 PBD::open_uri (ARDOUR::Config->get_reference_manual_url() + "/video-timeline/operations/#export");
4546 export_video_dialog->set_session (_session);
4547 export_video_dialog->apply_state(editor->get_selection().time, range);
4548 export_video_dialog->run ();
4549 export_video_dialog->hide ();
4553 ARDOUR_UI::preferences_settings () const
4558 node = _session->instant_xml(X_("Preferences"));
4560 node = Config->instant_xml(X_("Preferences"));
4564 node = new XMLNode (X_("Preferences"));
4571 ARDOUR_UI::mixer_settings () const
4576 node = _session->instant_xml(X_("Mixer"));
4578 node = Config->instant_xml(X_("Mixer"));
4582 node = new XMLNode (X_("Mixer"));
4589 ARDOUR_UI::main_window_settings () const
4594 node = _session->instant_xml(X_("Main"));
4596 node = Config->instant_xml(X_("Main"));
4600 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4601 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4606 node = new XMLNode (X_("Main"));
4613 ARDOUR_UI::editor_settings () const
4618 node = _session->instant_xml(X_("Editor"));
4620 node = Config->instant_xml(X_("Editor"));
4624 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4625 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4630 node = new XMLNode (X_("Editor"));
4637 ARDOUR_UI::keyboard_settings () const
4641 node = Config->extra_xml(X_("Keyboard"));
4644 node = new XMLNode (X_("Keyboard"));
4651 ARDOUR_UI::create_xrun_marker (framepos_t where)
4654 Location *location = new Location (*_session, where, where, _("xrun"), Location::IsMark);
4655 _session->locations()->add (location);
4660 ARDOUR_UI::halt_on_xrun_message ()
4662 cerr << "HALT on xrun\n";
4663 MessageDialog msg (_main_window, _("Recording was stopped because your system could not keep up."));
4668 ARDOUR_UI::xrun_handler (framepos_t where)
4674 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
4676 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
4677 create_xrun_marker(where);
4680 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
4681 halt_on_xrun_message ();
4686 ARDOUR_UI::disk_overrun_handler ()
4688 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
4690 if (!have_disk_speed_dialog_displayed) {
4691 have_disk_speed_dialog_displayed = true;
4692 MessageDialog* msg = new MessageDialog (_main_window, string_compose (_("\
4693 The disk system on your computer\n\
4694 was not able to keep up with %1.\n\
4696 Specifically, it failed to write data to disk\n\
4697 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
4698 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4704 /* TODO: this is getting elaborate enough to warrant being split into a dedicated class */
4705 static MessageDialog *scan_dlg = NULL;
4706 static ProgressBar *scan_pbar = NULL;
4707 static HBox *scan_tbox = NULL;
4708 static Gtk::Button *scan_timeout_button;
4711 ARDOUR_UI::cancel_plugin_scan ()
4713 PluginManager::instance().cancel_plugin_scan();
4717 ARDOUR_UI::cancel_plugin_timeout ()
4719 PluginManager::instance().cancel_plugin_timeout();
4720 scan_timeout_button->set_sensitive (false);
4724 ARDOUR_UI::plugin_scan_timeout (int timeout)
4726 if (!scan_dlg || !scan_dlg->is_mapped() || !scan_pbar) {
4730 scan_pbar->set_sensitive (false);
4731 scan_timeout_button->set_sensitive (true);
4732 scan_pbar->set_fraction ((float) timeout / (float) Config->get_vst_scan_timeout());
4735 scan_pbar->set_sensitive (false);
4736 scan_timeout_button->set_sensitive (false);
4742 ARDOUR_UI::plugin_scan_dialog (std::string type, std::string plugin, bool can_cancel)
4744 if (type == X_("closeme") && !(scan_dlg && scan_dlg->is_mapped())) {
4748 const bool cancelled = PluginManager::instance().cancelled();
4749 if (type != X_("closeme") && (!UIConfiguration::instance().get_show_plugin_scan_window()) && !_initial_verbose_plugin_scan) {
4750 if (cancelled && scan_dlg->is_mapped()) {
4755 if (cancelled || !can_cancel) {
4760 static Gtk::Button *cancel_button;
4762 scan_dlg = new MessageDialog("", false, MESSAGE_INFO, BUTTONS_NONE); // TODO manage
4763 VBox* vbox = scan_dlg->get_vbox();
4764 vbox->set_size_request(400,-1);
4765 scan_dlg->set_title (_("Scanning for plugins"));
4767 cancel_button = manage(new Gtk::Button(_("Cancel plugin scan")));
4768 cancel_button->set_name ("EditorGTKButton");
4769 cancel_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_scan) );
4770 cancel_button->show();
4772 scan_dlg->get_vbox()->pack_start ( *cancel_button, PACK_SHRINK);
4774 scan_tbox = manage( new HBox() );
4776 scan_timeout_button = manage(new Gtk::Button(_("Stop Timeout")));
4777 scan_timeout_button->set_name ("EditorGTKButton");
4778 scan_timeout_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_timeout) );
4779 scan_timeout_button->show();
4781 scan_pbar = manage(new ProgressBar());
4782 scan_pbar->set_orientation(Gtk::PROGRESS_RIGHT_TO_LEFT);
4783 scan_pbar->set_text(_("Scan Timeout"));
4786 scan_tbox->pack_start (*scan_pbar, PACK_EXPAND_WIDGET, 4);
4787 scan_tbox->pack_start (*scan_timeout_button, PACK_SHRINK, 4);
4789 scan_dlg->get_vbox()->pack_start (*scan_tbox, PACK_SHRINK, 4);
4792 assert(scan_dlg && scan_tbox && cancel_button);
4794 if (type == X_("closeme")) {
4798 scan_dlg->set_message(type + ": " + Glib::path_get_basename(plugin));
4801 if (!can_cancel || !cancelled) {
4802 scan_timeout_button->set_sensitive(false);
4804 cancel_button->set_sensitive(can_cancel && !cancelled);
4810 ARDOUR_UI::gui_idle_handler ()
4813 /* due to idle calls, gtk_events_pending() may always return true */
4814 while (gtk_events_pending() && --timeout) {
4815 gtk_main_iteration ();
4820 ARDOUR_UI::disk_underrun_handler ()
4822 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
4824 if (!have_disk_speed_dialog_displayed) {
4825 have_disk_speed_dialog_displayed = true;
4826 MessageDialog* msg = new MessageDialog (
4827 _main_window, string_compose (_("The disk system on your computer\n\
4828 was not able to keep up with %1.\n\
4830 Specifically, it failed to read data from disk\n\
4831 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
4832 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4838 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
4840 have_disk_speed_dialog_displayed = false;
4845 ARDOUR_UI::session_dialog (std::string msg)
4847 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
4851 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
4858 ARDOUR_UI::pending_state_dialog ()
4860 HBox* hbox = manage (new HBox());
4861 Image* image = manage (new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG));
4862 ArdourDialog dialog (_("Crash Recovery"), true);
4863 Label message (string_compose (_("\
4864 This session appears to have been in the\n\
4865 middle of recording when %1 or\n\
4866 the computer was shutdown.\n\
4868 %1 can recover any captured audio for\n\
4869 you, or it can ignore it. Please decide\n\
4870 what you would like to do.\n"), PROGRAM_NAME));
4871 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4872 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4873 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4874 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4875 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
4876 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
4877 dialog.set_default_response (RESPONSE_ACCEPT);
4878 dialog.set_position (WIN_POS_CENTER);
4883 switch (dialog.run ()) {
4884 case RESPONSE_ACCEPT:
4892 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
4894 HBox* hbox = new HBox();
4895 Image* image = new Image (Stock::DIALOG_WARNING, ICON_SIZE_DIALOG);
4896 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
4897 Label message (string_compose (_("\
4898 This session was created with a sample rate of %1 Hz, but\n\
4899 %2 is currently running at %3 Hz. If you load this session,\n\
4900 audio may be played at the wrong sample rate.\n"), desired, PROGRAM_NAME, actual));
4902 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4903 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4904 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4905 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4906 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
4907 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
4908 dialog.set_default_response (RESPONSE_ACCEPT);
4909 dialog.set_position (WIN_POS_CENTER);
4914 switch (dialog.run()) {
4915 case RESPONSE_ACCEPT:
4925 ARDOUR_UI::sr_mismatch_message (framecnt_t desired, framecnt_t actual)
4927 MessageDialog msg (string_compose (_("\
4928 This session was created with a sample rate of %1 Hz, but\n\
4929 %2 is currently running at %3 Hz.\n\
4930 Audio will be recorded and played at the wrong sample rate.\n\
4931 Re-Configure the Audio Engine in\n\
4932 Menu > Window > Audio/Midi Setup"),
4933 desired, PROGRAM_NAME, actual),
4935 Gtk::MESSAGE_WARNING);
4940 ARDOUR_UI::use_config ()
4942 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
4944 set_transport_controllable_state (*node);
4949 ARDOUR_UI::update_transport_clocks (framepos_t pos)
4951 if (UIConfiguration::instance().get_primary_clock_delta_edit_cursor()) {
4952 primary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
4954 primary_clock->set (pos);
4957 if (UIConfiguration::instance().get_secondary_clock_delta_edit_cursor()) {
4958 secondary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
4960 secondary_clock->set (pos);
4963 if (big_clock_window) {
4964 big_clock->set (pos);
4966 ARDOUR_UI::instance()->video_timeline->manual_seek_video_monitor(pos);
4970 ARDOUR_UI::step_edit_status_change (bool yn)
4972 // XXX should really store pre-step edit status of things
4973 // we make insensitive
4976 rec_button.set_active_state (Gtkmm2ext::ImplicitActive);
4977 rec_button.set_sensitive (false);
4979 rec_button.unset_active_state ();;
4980 rec_button.set_sensitive (true);
4985 ARDOUR_UI::record_state_changed ()
4987 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
4989 if (!_session || !big_clock_window) {
4990 /* why bother - the clock isn't visible */
4994 if (_session->record_status () == Session::Recording && _session->have_rec_enabled_track ()) {
4995 big_clock->set_active (true);
4997 big_clock->set_active (false);
5002 ARDOUR_UI::first_idle ()
5005 _session->allow_auto_play (true);
5009 editor->first_idle();
5012 Keyboard::set_can_save_keybindings (true);
5017 ARDOUR_UI::store_clock_modes ()
5019 XMLNode* node = new XMLNode(X_("ClockModes"));
5021 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
5022 XMLNode* child = new XMLNode (X_("Clock"));
5024 child->add_property (X_("name"), (*x)->name());
5025 child->add_property (X_("mode"), enum_2_string ((*x)->mode()));
5026 child->add_property (X_("on"), ((*x)->off() ? X_("no") : X_("yes")));
5028 node->add_child_nocopy (*child);
5031 _session->add_extra_xml (*node);
5032 _session->set_dirty ();
5035 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
5036 : Controllable (name), ui (u), type(tp)
5042 ARDOUR_UI::TransportControllable::set_value (double val, PBD::Controllable::GroupControlDisposition /*group_override*/)
5045 /* do nothing: these are radio-style actions */
5049 const char *action = 0;
5053 action = X_("Roll");
5056 action = X_("Stop");
5059 action = X_("GotoStart");
5062 action = X_("GotoEnd");
5065 action = X_("Loop");
5068 action = X_("PlaySelection");
5071 action = X_("Record");
5081 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
5089 ARDOUR_UI::TransportControllable::get_value (void) const
5116 ARDOUR_UI::setup_profile ()
5118 if (gdk_screen_width() < 1200 || getenv ("ARDOUR_NARROW_SCREEN")) {
5119 Profile->set_small_screen ();
5122 if (g_getenv ("TRX")) {
5123 Profile->set_trx ();
5126 if (g_getenv ("MIXBUS")) {
5127 Profile->set_mixbus ();
5132 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
5134 MissingFileDialog dialog (s, str, type);
5139 int result = dialog.run ();
5146 return 1; // quit entire session load
5149 result = dialog.get_action ();
5155 ARDOUR_UI::ambiguous_file (std::string file, std::vector<std::string> hits)
5157 AmbiguousFileDialog dialog (file, hits);
5164 return dialog.get_which ();
5167 /** Allocate our thread-local buffers */
5169 ARDOUR_UI::get_process_buffers ()
5171 _process_thread->get_buffers ();
5174 /** Drop our thread-local buffers */
5176 ARDOUR_UI::drop_process_buffers ()
5178 _process_thread->drop_buffers ();
5182 ARDOUR_UI::feedback_detected ()
5184 _feedback_exists = true;
5188 ARDOUR_UI::successful_graph_sort ()
5190 _feedback_exists = false;
5194 ARDOUR_UI::midi_panic ()
5197 _session->midi_panic();
5202 ARDOUR_UI::session_format_mismatch (std::string xml_path, std::string backup_path)
5204 const char* start_big = "<span size=\"x-large\" weight=\"bold\">";
5205 const char* end_big = "</span>";
5206 const char* start_mono = "<tt>";
5207 const char* end_mono = "</tt>";
5209 MessageDialog msg (string_compose (_("%4This is a session from an older version of %3%5\n\n"
5210 "%3 has copied the old session file\n\n%6%1%7\n\nto\n\n%6%2%7\n\n"
5211 "From now on, use the backup copy with older versions of %3"),
5212 xml_path, backup_path, PROGRAM_NAME,
5214 start_mono, end_mono), true);
5221 ARDOUR_UI::reset_peak_display ()
5223 if (!_session || !_session->master_out() || !editor_meter) return;
5224 editor_meter->clear_meters();
5225 editor_meter_max_peak = -INFINITY;
5226 editor_meter_peak_display.set_active_state ( Gtkmm2ext::Off );
5230 ARDOUR_UI::reset_group_peak_display (RouteGroup* group)
5232 if (!_session || !_session->master_out()) return;
5233 if (group == _session->master_out()->route_group()) {
5234 reset_peak_display ();
5239 ARDOUR_UI::reset_route_peak_display (Route* route)
5241 if (!_session || !_session->master_out()) return;
5242 if (_session->master_out().get() == route) {
5243 reset_peak_display ();
5248 ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate)
5250 audio_midi_setup->set_desired_sample_rate (desired_sample_rate);
5251 audio_midi_setup->set_position (WIN_POS_CENTER);
5253 if (Config->get_try_autostart_engine () || getenv ("TRY_AUTOSTART_ENGINE")) {
5254 audio_midi_setup->try_autostart ();
5255 if (ARDOUR::AudioEngine::instance()->running()) {
5261 int response = audio_midi_setup->run();
5263 case Gtk::RESPONSE_OK:
5264 if (!AudioEngine::instance()->running()) {
5278 ARDOUR_UI::transport_numpad_timeout ()
5280 _numpad_locate_happening = false;
5281 if (_numpad_timeout_connection.connected() )
5282 _numpad_timeout_connection.disconnect();
5287 ARDOUR_UI::transport_numpad_decimal ()
5289 _numpad_timeout_connection.disconnect();
5291 if (_numpad_locate_happening) {
5292 if (editor) editor->goto_nth_marker(_pending_locate_num - 1);
5293 _numpad_locate_happening = false;
5295 _pending_locate_num = 0;
5296 _numpad_locate_happening = true;
5297 _numpad_timeout_connection = Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::transport_numpad_timeout), 2*1000);
5302 ARDOUR_UI::transport_numpad_event (int num)
5304 if ( _numpad_locate_happening ) {
5305 _pending_locate_num = _pending_locate_num*10 + num;
5308 case 0: toggle_roll(false, false); break;
5309 case 1: transport_rewind(1); break;
5310 case 2: transport_forward(1); break;
5311 case 3: transport_record(true); break;
5312 case 4: toggle_session_auto_loop(); break;
5313 case 5: transport_record(false); toggle_session_auto_loop(); break;
5314 case 6: toggle_punch(); break;
5315 case 7: toggle_click(); break;
5316 case 8: toggle_auto_return(); break;
5317 case 9: toggle_follow_edits(); break;
5323 ARDOUR_UI::set_flat_buttons ()
5325 CairoWidget::set_flat_buttons( UIConfiguration::instance().get_flat_buttons() );
5329 ARDOUR_UI::audioengine_became_silent ()
5331 MessageDialog msg (string_compose (_("This is a free/demo copy of %1. It has just switched to silent mode."), PROGRAM_NAME),
5333 Gtk::MESSAGE_WARNING,
5337 msg.set_title (string_compose (_("%1 is now silent"), PROGRAM_NAME));
5339 Gtk::Label pay_label (string_compose (_("Please consider paying for a copy of %1 - you can pay whatever you want."), PROGRAM_NAME));
5340 Gtk::Label subscribe_label (_("Better yet become a subscriber - subscriptions start at US$1 per month."));
5341 Gtk::Button pay_button (_("Pay for a copy (via the web)"));
5342 Gtk::Button subscribe_button (_("Become a subscriber (via the web)"));
5343 Gtk::HBox pay_button_box;
5344 Gtk::HBox subscribe_button_box;
5346 pay_button_box.pack_start (pay_button, true, false);
5347 subscribe_button_box.pack_start (subscribe_button, true, false);
5349 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 */
5351 pay_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://ardour.org/download")));
5352 subscribe_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://community.ardour.org/s/subscribe")));
5354 msg.get_vbox()->pack_start (pay_label);
5355 msg.get_vbox()->pack_start (pay_button_box);
5356 msg.get_vbox()->pack_start (subscribe_label);
5357 msg.get_vbox()->pack_start (subscribe_button_box);
5359 msg.get_vbox()->show_all ();
5361 msg.add_button (_("Remain silent"), Gtk::RESPONSE_CANCEL);
5362 msg.add_button (_("Save and quit"), Gtk::RESPONSE_NO);
5363 msg.add_button (_("Give me more time"), Gtk::RESPONSE_YES);
5368 case Gtk::RESPONSE_YES:
5369 AudioEngine::instance()->reset_silence_countdown ();
5372 case Gtk::RESPONSE_NO:
5374 save_state_canfail ("");
5378 case Gtk::RESPONSE_CANCEL:
5380 /* don't reset, save session and exit */
5386 ARDOUR_UI::hide_application ()
5388 Application::instance ()-> hide ();
5392 ARDOUR_UI::setup_toplevel_window (Gtk::Window& window, const string& name, void* owner)
5394 /* icons, titles, WM stuff */
5396 static list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
5398 if (window_icons.empty()) {
5399 Glib::RefPtr<Gdk::Pixbuf> icon;
5400 if ((icon = ::get_icon (PROGRAM_NAME "-icon_16px")) != 0) {
5401 window_icons.push_back (icon);
5403 if ((icon = ::get_icon (PROGRAM_NAME "-icon_22px")) != 0) {
5404 window_icons.push_back (icon);
5406 if ((icon = ::get_icon (PROGRAM_NAME "-icon_32px")) != 0) {
5407 window_icons.push_back (icon);
5409 if ((icon = ::get_icon (PROGRAM_NAME "-icon_48px")) != 0) {
5410 window_icons.push_back (icon);
5414 if (!window_icons.empty()) {
5415 window.set_default_icon_list (window_icons);
5418 Gtkmm2ext::WindowTitle title (Glib::get_application_name());
5420 if (!name.empty()) {
5424 window.set_title (title.get_string());
5425 window.set_wmclass (string_compose (X_("%1_%1"), downcase (PROGRAM_NAME), downcase (name)), PROGRAM_NAME);
5427 window.set_flags (CAN_FOCUS);
5428 window.add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
5430 /* This is a hack to ensure that GTK-accelerators continue to
5431 * work. Once we switch over to entirely native bindings, this will be
5432 * unnecessary and should be removed
5434 window.add_accel_group (ActionManager::ui_manager->get_accel_group());
5436 window.signal_configure_event().connect (sigc::mem_fun (*this, &ARDOUR_UI::configure_handler));
5437 window.signal_window_state_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::tabbed_window_state_event_handler), owner));
5438 window.signal_key_press_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5439 window.signal_key_release_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5443 ARDOUR_UI::key_event_handler (GdkEventKey* ev, Gtk::Window* event_window)
5445 Gtkmm2ext::Bindings* bindings = 0;
5446 Gtk::Window* window = 0;
5448 /* until we get ardour bindings working, we are not handling key
5452 if (ev->type != GDK_KEY_PRESS) {
5456 if (event_window == &_main_window) {
5458 window = event_window;
5460 /* find current tab contents */
5462 Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page());
5464 /* see if it uses the ardour binding system */
5467 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(w->get_data ("ardour-bindings"));
5470 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("main window key event, bindings = %1, global = %2\n", bindings, &global_bindings));
5474 window = event_window;
5476 /* see if window uses ardour binding system */
5478 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(window->get_data ("ardour-bindings"));
5481 /* An empty binding set is treated as if it doesn't exist */
5483 if (bindings && bindings->empty()) {
5487 return key_press_focus_accelerator_handler (*window, ev, bindings);
5490 static Gtkmm2ext::Bindings*
5491 get_bindings_from_widget_heirarchy (GtkWidget* w)
5496 if ((p = g_object_get_data (G_OBJECT(w), "ardour-bindings")) != 0) {
5499 w = gtk_widget_get_parent (w);
5502 return reinterpret_cast<Gtkmm2ext::Bindings*> (p);
5506 ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev, Gtkmm2ext::Bindings* bindings)
5508 GtkWindow* win = window.gobj();
5509 GtkWidget* focus = gtk_window_get_focus (win);
5510 bool special_handling_of_unmodified_accelerators = false;
5511 const guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK));
5515 /* some widget has keyboard focus */
5517 if (GTK_IS_ENTRY(focus) || Keyboard::some_magic_widget_has_focus()) {
5519 /* A particular kind of focusable widget currently has keyboard
5520 * focus. All unmodified key events should go to that widget
5521 * first and not be used as an accelerator by default
5524 special_handling_of_unmodified_accelerators = true;
5528 Gtkmm2ext::Bindings* focus_bindings = get_bindings_from_widget_heirarchy (focus);
5529 if (focus_bindings) {
5530 bindings = focus_bindings;
5531 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Switch bindings based on focus widget, now using %1\n", bindings->name()));
5536 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",
5539 show_gdk_event_state (ev->state),
5540 special_handling_of_unmodified_accelerators,
5541 Keyboard::some_magic_widget_has_focus(),
5543 (focus ? gtk_widget_get_name (focus) : "no focus widget"),
5544 ((ev->state & mask) ? "yes" : "no"),
5545 window.get_title()));
5547 /* This exists to allow us to override the way GTK handles
5548 key events. The normal sequence is:
5550 a) event is delivered to a GtkWindow
5551 b) accelerators/mnemonics are activated
5552 c) if (b) didn't handle the event, propagate to
5553 the focus widget and/or focus chain
5555 The problem with this is that if the accelerators include
5556 keys without modifiers, such as the space bar or the
5557 letter "e", then pressing the key while typing into
5558 a text entry widget results in the accelerator being
5559 activated, instead of the desired letter appearing
5562 There is no good way of fixing this, but this
5563 represents a compromise. The idea is that
5564 key events involving modifiers (not Shift)
5565 get routed into the activation pathway first, then
5566 get propagated to the focus widget if necessary.
5568 If the key event doesn't involve modifiers,
5569 we deliver to the focus widget first, thus allowing
5570 it to get "normal text" without interference
5573 Of course, this can also be problematic: if there
5574 is a widget with focus, then it will swallow
5575 all "normal text" accelerators.
5579 if (!special_handling_of_unmodified_accelerators || (ev->state & mask)) {
5581 /* no special handling or there are modifiers in effect: accelerate first */
5583 DEBUG_TRACE (DEBUG::Accelerators, "\tactivate, then propagate\n");
5584 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tevent send-event:%1 time:%2 length:%3 name %7 string:%4 hardware_keycode:%5 group:%6\n",
5585 ev->send_event, ev->time, ev->length, ev->string, ev->hardware_keycode, ev->group, gdk_keyval_name (ev->keyval)));
5587 DEBUG_TRACE (DEBUG::Accelerators, "\tsending to window\n");
5588 KeyboardKey k (ev->state, ev->keyval);
5592 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tusing Ardour bindings %1 @ %2 for this event\n", bindings->name(), bindings));
5594 if (bindings->activate (k, Bindings::Press)) {
5595 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5600 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5602 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5603 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5607 DEBUG_TRACE (DEBUG::Accelerators, "\tnot accelerated, now propagate\n");
5609 if (gtk_window_propagate_key_event (win, ev)) {
5610 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate handled\n");
5616 /* no modifiers, propagate first */
5618 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate, then activate\n");
5620 if (gtk_window_propagate_key_event (win, ev)) {
5621 DEBUG_TRACE (DEBUG::Accelerators, "\thandled by propagate\n");
5625 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagation didn't handle, so activate\n");
5626 KeyboardKey k (ev->state, ev->keyval);
5630 DEBUG_TRACE (DEBUG::Accelerators, "\tusing Ardour bindings for this window\n");
5633 if (bindings->activate (k, Bindings::Press)) {
5634 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5640 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5642 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5643 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5648 DEBUG_TRACE (DEBUG::Accelerators, "\tnot handled\n");
5653 ARDOUR_UI::load_bindings ()
5655 if ((global_bindings = Bindings::get_bindings (X_("Global"), global_actions)) == 0) {
5656 error << _("Global keybindings are missing") << endmsg;
5661 ARDOUR_UI::cancel_solo ()
5664 _session->cancel_all_solo ();