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/file_archive.h"
60 #include "pbd/enumwriter.h"
61 #include "pbd/memento_command.h"
62 #include "pbd/openuri.h"
63 #include "pbd/stl_delete.h"
64 #include "pbd/file_utils.h"
65 #include "pbd/localtime_r.h"
66 #include "pbd/pthread_utils.h"
67 #include "pbd/replace_all.h"
68 #include "pbd/xml++.h"
70 #include "gtkmm2ext/application.h"
71 #include "gtkmm2ext/bindings.h"
72 #include "gtkmm2ext/gtk_ui.h"
73 #include "gtkmm2ext/utils.h"
74 #include "gtkmm2ext/click_box.h"
75 #include "gtkmm2ext/fastmeter.h"
76 #include "gtkmm2ext/popup.h"
77 #include "gtkmm2ext/window_title.h"
79 #include "ardour/ardour.h"
80 #include "ardour/audio_backend.h"
81 #include "ardour/audio_track.h"
82 #include "ardour/audioengine.h"
83 #include "ardour/audiofilesource.h"
84 #include "ardour/automation_watch.h"
85 #include "ardour/diskstream.h"
86 #include "ardour/filename_extensions.h"
87 #include "ardour/filesystem_paths.h"
88 #include "ardour/ltc_file_reader.h"
89 #include "ardour/midi_track.h"
90 #include "ardour/port.h"
91 #include "ardour/plugin_manager.h"
92 #include "ardour/process_thread.h"
93 #include "ardour/profile.h"
94 #include "ardour/recent_sessions.h"
95 #include "ardour/record_enable_control.h"
96 #include "ardour/session_directory.h"
97 #include "ardour/session_route.h"
98 #include "ardour/session_state_utils.h"
99 #include "ardour/session_utils.h"
100 #include "ardour/source_factory.h"
101 #include "ardour/slave.h"
102 #include "ardour/system_exec.h"
103 #include "ardour/track.h"
104 #include "ardour/vca_manager.h"
105 #include "ardour/utils.h"
107 #include "LuaBridge/LuaBridge.h"
109 #ifdef WINDOWS_VST_SUPPORT
112 #ifdef AUDIOUNIT_SUPPORT
113 #include "ardour/audio_unit.h"
116 // fix for OSX (nsm.h has a check function, AU/Apple defines check)
121 #include "timecode/time.h"
123 typedef uint64_t microseconds_t;
128 #include "add_route_dialog.h"
129 #include "ambiguous_file_dialog.h"
130 #include "ardour_ui.h"
131 #include "audio_clock.h"
132 #include "audio_region_view.h"
133 #include "big_clock_window.h"
134 #include "bundle_manager.h"
135 #include "duplicate_routes_dialog.h"
137 #include "engine_dialog.h"
138 #include "export_video_dialog.h"
139 #include "export_video_infobox.h"
140 #include "gain_meter.h"
141 #include "global_port_matrix.h"
142 #include "gui_object.h"
143 #include "gui_thread.h"
144 #include "keyboard.h"
145 #include "keyeditor.h"
146 #include "location_ui.h"
147 #include "lua_script_manager.h"
148 #include "luawindow.h"
149 #include "main_clock.h"
150 #include "missing_file_dialog.h"
151 #include "missing_plugin_dialog.h"
152 #include "mixer_ui.h"
153 #include "meterbridge.h"
154 #include "mouse_cursors.h"
157 #include "pingback.h"
158 #include "processor_box.h"
159 #include "prompter.h"
160 #include "public_editor.h"
161 #include "rc_option_editor.h"
162 #include "route_time_axis.h"
163 #include "route_params_ui.h"
164 #include "save_as_dialog.h"
165 #include "script_selector.h"
166 #include "session_dialog.h"
167 #include "session_metadata_dialog.h"
168 #include "session_option_editor.h"
169 #include "shuttle_control.h"
170 #include "speaker_dialog.h"
173 #include "theme_manager.h"
174 #include "time_axis_view_item.h"
177 #include "video_server_dialog.h"
178 #include "add_video_dialog.h"
179 #include "transcode_video_dialog.h"
181 #include "pbd/i18n.h"
183 using namespace ARDOUR;
184 using namespace ARDOUR_UI_UTILS;
186 using namespace Gtkmm2ext;
189 using namespace Editing;
191 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
193 sigc::signal<void, framepos_t, bool, framepos_t> ARDOUR_UI::Clock;
194 sigc::signal<void> ARDOUR_UI::CloseAllDialogs;
197 ask_about_configuration_copy (string const & old_dir, string const & new_dir, int version)
199 MessageDialog msg (string_compose (_("%1 %2.x has discovered configuration files from %1 %3.x.\n\n"
200 "Would you like these files to be copied and used for %1 %2.x?\n\n"
201 "(This will require you to restart %1.)"),
202 PROGRAM_NAME, PROGRAM_VERSION, version),
203 false, /* no markup */
206 true /* modal, though it hardly matters since it is the only window */
209 msg.set_default_response (Gtk::RESPONSE_YES);
212 return (msg.run() == Gtk::RESPONSE_YES);
216 libxml_generic_error_func (void* /* parsing_context*/,
224 vsnprintf (buf, sizeof (buf), msg, ap);
225 error << buf << endmsg;
230 libxml_structured_error_func (void* /* parsing_context*/,
238 replace_all (msg, "\n", "");
241 if (err->file && err->line) {
242 error << X_("XML error: ") << msg << " in " << err->file << " at line " << err->line;
245 error << ':' << err->int2;
250 error << X_("XML error: ") << msg << endmsg;
256 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
257 : Gtkmm2ext::UI (PROGRAM_NAME, X_("gui"), argcp, argvp)
258 , session_loaded (false)
259 , gui_object_state (new GUIObjectState)
260 , primary_clock (new MainClock (X_("primary"), X_("transport"), true ))
261 , secondary_clock (new MainClock (X_("secondary"), X_("secondary"), false))
262 , big_clock (new AudioClock (X_("bigclock"), false, "big", true, true, false, false))
264 , global_actions (X_("global"))
265 , ignore_dual_punch (false)
266 , main_window_visibility (0)
271 , _mixer_on_top (false)
272 , _initial_verbose_plugin_scan (false)
273 , first_time_engine_run (true)
274 , roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll))
275 , stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop))
276 , goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart))
277 , goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd))
278 , auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop))
279 , play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection))
280 , rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable))
281 , auto_return_button (ArdourButton::led_default_elements)
282 , follow_edits_button (ArdourButton::led_default_elements)
283 , auto_input_button (ArdourButton::led_default_elements)
284 , auditioning_alert_button (_("Audition"))
285 , solo_alert_button (_("Solo"))
286 , feedback_alert_button (_("Feedback"))
287 , error_alert_button ( ArdourButton::just_led_default_elements )
289 , editor_meter_peak_display()
290 , _numpad_locate_happening (false)
291 , _session_is_new (false)
292 , last_key_press_time (0)
296 , rc_option_editor (0)
297 , speaker_config_window (X_("speaker-config"), _("Speaker Configuration"))
298 , add_route_dialog (X_("add-routes"), _("Add Tracks/Busses"))
299 , about (X_("about"), _("About"))
300 , location_ui (X_("locations"), S_("Ranges|Locations"))
301 , route_params (X_("inspector"), _("Tracks and Busses"))
302 , audio_midi_setup (X_("audio-midi-setup"), _("Audio/MIDI Setup"))
303 , export_video_dialog (X_("video-export"), _("Video Export Dialog"))
304 , lua_script_window (X_("script-manager"), _("Script Manager"))
305 , session_option_editor (X_("session-options-editor"), _("Properties"), boost::bind (&ARDOUR_UI::create_session_option_editor, this))
306 , add_video_dialog (X_("add-video"), _("Add Video"), boost::bind (&ARDOUR_UI::create_add_video_dialog, this))
307 , bundle_manager (X_("bundle-manager"), _("Bundle Manager"), boost::bind (&ARDOUR_UI::create_bundle_manager, this))
308 , big_clock_window (X_("big-clock"), _("Big Clock"), boost::bind (&ARDOUR_UI::create_big_clock_window, this))
309 , audio_port_matrix (X_("audio-connection-manager"), _("Audio Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::AUDIO))
310 , midi_port_matrix (X_("midi-connection-manager"), _("MIDI Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::MIDI))
311 , key_editor (X_("key-editor"), _("Bindings Editor"), boost::bind (&ARDOUR_UI::create_key_editor, this))
312 , video_server_process (0)
314 , have_configure_timeout (false)
315 , last_configure_time (0)
317 , have_disk_speed_dialog_displayed (false)
318 , _status_bar_visibility (X_("status-bar"))
319 , _feedback_exists (false)
320 , _log_not_acknowledged (LogLevelNone)
321 , duplicate_routes_dialog (0)
322 , editor_visibility_button (S_("Window|Editor"))
323 , mixer_visibility_button (S_("Window|Mixer"))
324 , prefs_visibility_button (S_("Window|Preferences"))
326 Gtkmm2ext::init (localedir);
328 UIConfiguration::instance().post_gui_init ();
330 if (ARDOUR::handle_old_configuration_files (boost::bind (ask_about_configuration_copy, _1, _2, _3))) {
331 MessageDialog msg (string_compose (_("Your configuration files were copied. You can now restart %1."), PROGRAM_NAME), true);
333 /* configuration was modified, exit immediately */
338 if (string (VERSIONSTRING).find (".pre") != string::npos) {
339 /* check this is not being run from ./ardev etc. */
340 if (!running_from_source_tree ()) {
341 pre_release_dialog ();
345 if (theArdourUI == 0) {
349 /* track main window visibility */
351 main_window_visibility = new VisibilityTracker (_main_window);
353 /* stop libxml from spewing to stdout/stderr */
355 xmlSetGenericErrorFunc (this, libxml_generic_error_func);
356 xmlSetStructuredErrorFunc (this, libxml_structured_error_func);
358 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::parameter_changed));
359 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
360 UIConfiguration::instance().map_parameters (pc);
362 roll_button.set_controllable (roll_controllable);
363 stop_button.set_controllable (stop_controllable);
364 goto_start_button.set_controllable (goto_start_controllable);
365 goto_end_button.set_controllable (goto_end_controllable);
366 auto_loop_button.set_controllable (auto_loop_controllable);
367 play_selection_button.set_controllable (play_selection_controllable);
368 rec_button.set_controllable (rec_controllable);
370 roll_button.set_name ("transport button");
371 stop_button.set_name ("transport button");
372 goto_start_button.set_name ("transport button");
373 goto_end_button.set_name ("transport button");
374 auto_loop_button.set_name ("transport button");
375 play_selection_button.set_name ("transport button");
376 rec_button.set_name ("transport recenable button");
377 midi_panic_button.set_name ("transport button");
379 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
380 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
382 ARDOUR::Session::VersionMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_format_mismatch, this, _1, _2), gui_context());
384 /* handle dialog requests */
386 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
388 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
390 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
392 /* handle Audio/MIDI setup when session requires it */
394 ARDOUR::Session::AudioEngineSetupRequired.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::do_audio_midi_setup, this, _1));
396 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
398 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
400 /* handle sr mismatch with a dialog - cross-thread from engine */
401 ARDOUR::Session::NotifyAboutSampleRateMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::sr_mismatch_message, this, _1, _2), gui_context ());
403 /* handle requests to quit (coming from JACK session) */
405 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::finish, this), gui_context ());
407 /* tell the user about feedback */
409 ARDOUR::Session::FeedbackDetected.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::feedback_detected, this), gui_context ());
410 ARDOUR::Session::SuccessfulGraphSort.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::successful_graph_sort, this), gui_context ());
412 /* handle requests to deal with missing files */
414 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
416 /* and ambiguous files */
418 ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2));
420 /* also plugin scan messages */
421 ARDOUR::PluginScanMessage.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_dialog, this, _1, _2, _3), gui_context());
422 ARDOUR::PluginScanTimeout.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_timeout, this, _1), gui_context());
424 ARDOUR::GUIIdle.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::gui_idle_handler, this), gui_context());
426 Config->ParameterChanged.connect ( forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::set_flat_buttons, this), gui_context() );
429 /* lets get this party started */
431 setup_gtk_ardour_enums ();
434 SessionEvent::create_per_thread_pool ("GUI", 4096);
436 /* we like keyboards */
438 keyboard = new ArdourKeyboard(*this);
440 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
442 keyboard->set_state (*node, Stateful::loading_state_version);
445 UIConfiguration::instance().reset_dpi ();
447 TimeAxisViewItem::set_constant_heights ();
449 /* Set this up so that our window proxies can register actions */
451 ActionManager::init ();
453 /* The following must happen after ARDOUR::init() so that Config is set up */
455 const XMLNode* ui_xml = Config->extra_xml (X_("UI"));
458 key_editor.set_state (*ui_xml, 0);
459 session_option_editor.set_state (*ui_xml, 0);
460 speaker_config_window.set_state (*ui_xml, 0);
461 about.set_state (*ui_xml, 0);
462 add_route_dialog.set_state (*ui_xml, 0);
463 add_video_dialog.set_state (*ui_xml, 0);
464 route_params.set_state (*ui_xml, 0);
465 bundle_manager.set_state (*ui_xml, 0);
466 location_ui.set_state (*ui_xml, 0);
467 big_clock_window.set_state (*ui_xml, 0);
468 audio_port_matrix.set_state (*ui_xml, 0);
469 midi_port_matrix.set_state (*ui_xml, 0);
470 export_video_dialog.set_state (*ui_xml, 0);
471 lua_script_window.set_state (*ui_xml, 0);
474 /* Separate windows */
476 WM::Manager::instance().register_window (&key_editor);
477 WM::Manager::instance().register_window (&session_option_editor);
478 WM::Manager::instance().register_window (&speaker_config_window);
479 WM::Manager::instance().register_window (&about);
480 WM::Manager::instance().register_window (&add_route_dialog);
481 WM::Manager::instance().register_window (&add_video_dialog);
482 WM::Manager::instance().register_window (&route_params);
483 WM::Manager::instance().register_window (&audio_midi_setup);
484 WM::Manager::instance().register_window (&export_video_dialog);
485 WM::Manager::instance().register_window (&lua_script_window);
486 WM::Manager::instance().register_window (&bundle_manager);
487 WM::Manager::instance().register_window (&location_ui);
488 WM::Manager::instance().register_window (&big_clock_window);
489 WM::Manager::instance().register_window (&audio_port_matrix);
490 WM::Manager::instance().register_window (&midi_port_matrix);
492 /* do not retain position for add route dialog */
493 add_route_dialog.set_state_mask (WindowProxy::Size);
495 /* Trigger setting up the color scheme and loading the GTK RC file */
497 UIConfiguration::instance().load_rc_file (false);
499 _process_thread = new ProcessThread ();
500 _process_thread->init ();
502 UIConfiguration::instance().DPIReset.connect (sigc::mem_fun (*this, &ARDOUR_UI::resize_text_widgets));
508 ARDOUR_UI::pre_release_dialog ()
510 ArdourDialog d (_("Pre-Release Warning"), true, false);
511 d.add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
513 Label* label = manage (new Label);
514 label->set_markup (string_compose (_("<b>Welcome to this pre-release build of %1 %2</b>\n\n\
515 There are still several issues and bugs to be worked on,\n\
516 as well as general workflow improvements, before this can be considered\n\
517 release software. So, a few guidelines:\n\
519 1) Please do <b>NOT</b> use this software with the expectation that it is stable or reliable\n\
520 though it may be so, depending on your workflow.\n\
521 2) Please wait for a helpful writeup of new features.\n\
522 3) <b>Please do NOT use the forums at ardour.org to report issues</b>.\n\
523 4) Please <b>DO</b> use the bugtracker at http://tracker.ardour.org/ to report issues\n\
524 making sure to note the product version number as 5.0-pre.\n\
525 5) Please <b>DO</b> use the ardour-users mailing list to discuss ideas and pass on comments.\n\
526 6) Please <b>DO</b> join us on IRC for real time discussions about %1 %2. You\n\
527 can get there directly from within the program via the Help->Chat menu option.\n\
529 Full information on all the above can be found on the support page at\n\
531 http://ardour.org/support\n\
532 "), PROGRAM_NAME, VERSIONSTRING));
534 d.get_vbox()->set_border_width (12);
535 d.get_vbox()->pack_start (*label, false, false, 12);
536 d.get_vbox()->show_all ();
541 GlobalPortMatrixWindow*
542 ARDOUR_UI::create_global_port_matrix (ARDOUR::DataType type)
547 return new GlobalPortMatrixWindow (_session, type);
551 ARDOUR_UI::attach_to_engine ()
553 AudioEngine::instance()->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
554 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
558 ARDOUR_UI::engine_stopped ()
560 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
561 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
562 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
563 update_sample_rate (0);
568 ARDOUR_UI::engine_running ()
570 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
571 if (first_time_engine_run) {
573 first_time_engine_run = false;
577 _session->reset_xrun_count ();
579 update_disk_space ();
581 update_xrun_count ();
582 update_sample_rate (AudioEngine::instance()->sample_rate());
583 update_timecode_format ();
584 update_peak_thread_work ();
585 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, true);
586 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, false);
590 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
592 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
593 /* we can't rely on the original string continuing to exist when we are called
594 again in the GUI thread, so make a copy and note that we need to
597 char *copy = strdup (reason);
598 Gtkmm2ext::UI::instance()->call_slot (MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
602 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
603 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
605 update_sample_rate (0);
609 /* if the reason is a non-empty string, it means that the backend was shutdown
610 rather than just Ardour.
613 if (strlen (reason)) {
614 msgstr = string_compose (_("The audio backend was shutdown because:\n\n%1"), reason);
616 msgstr = string_compose (_("\
617 The audio backend has either been shutdown or it\n\
618 disconnected %1 because %1\n\
619 was not fast enough. Try to restart\n\
620 the audio backend and save the session."), PROGRAM_NAME);
623 MessageDialog msg (_main_window, msgstr);
624 pop_back_splash (msg);
628 free (const_cast<char*> (reason));
633 ARDOUR_UI::post_engine ()
635 /* Things to be done once (and once ONLY) after we have a backend running in the AudioEngine
637 #ifdef AUDIOUNIT_SUPPORT
639 if (AUPluginInfo::au_get_crashlog(au_msg)) {
640 popup_error(_("Audio Unit Plugin Scan Failed. Automatic AU scanning has been disabled. Please see the log window for further details."));
641 error << _("Audio Unit Plugin Scan Failed:") << endmsg;
642 info << au_msg << endmsg;
646 ARDOUR::init_post_engine ();
648 /* connect to important signals */
650 AudioEngine::instance()->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
651 AudioEngine::instance()->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
652 AudioEngine::instance()->BufferSizeChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
653 AudioEngine::instance()->Halted.connect_same_thread (halt_connection, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
654 AudioEngine::instance()->BecameSilent.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::audioengine_became_silent, this), gui_context());
656 if (setup_windows ()) {
657 throw failed_constructor ();
660 /* Do this after setup_windows (), as that's when the _status_bar_visibility is created */
661 XMLNode* n = Config->extra_xml (X_("UI"));
663 _status_bar_visibility.set_state (*n);
666 check_memory_locking();
668 /* this is the first point at which all the possible actions are
669 * available, because some of the available actions are dependent on
670 * aspects of the engine/backend.
673 if (ARDOUR_COMMAND_LINE::show_key_actions) {
676 vector<string> paths;
677 vector<string> labels;
678 vector<string> tooltips;
680 vector<Glib::RefPtr<Gtk::Action> > actions;
682 Gtkmm2ext::ActionMap::get_all_actions (paths, labels, tooltips, keys, actions);
684 vector<string>::iterator k;
685 vector<string>::iterator p;
687 for (p = paths.begin(), k = keys.begin(); p != paths.end(); ++k, ++p) {
692 cout << *p << " => " << *k << endl;
696 halt_connection.disconnect ();
697 AudioEngine::instance()->stop ();
701 /* this being a GUI and all, we want peakfiles */
703 AudioFileSource::set_build_peakfiles (true);
704 AudioFileSource::set_build_missing_peakfiles (true);
706 /* set default clock modes */
708 primary_clock->set_mode (AudioClock::Timecode);
709 secondary_clock->set_mode (AudioClock::BBT);
711 /* start the time-of-day-clock */
714 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
715 update_wall_clock ();
716 Glib::signal_timeout().connect_seconds (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 1);
721 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
722 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
723 Config->map_parameters (pc);
725 UIConfiguration::instance().map_parameters (pc);
729 ARDOUR_UI::~ARDOUR_UI ()
731 UIConfiguration::instance().save_state();
735 if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
736 // don't bother at 'real' exit. the OS cleans up for us.
737 delete big_clock; big_clock = 0;
738 delete primary_clock; primary_clock = 0;
739 delete secondary_clock; secondary_clock = 0;
740 delete _process_thread; _process_thread = 0;
741 delete meterbridge; meterbridge = 0;
742 delete luawindow; luawindow = 0;
743 delete editor; editor = 0;
744 delete mixer; mixer = 0;
746 delete gui_object_state; gui_object_state = 0;
747 delete main_window_visibility;
748 FastMeter::flush_pattern_cache ();
749 PixFader::flush_pattern_cache ();
753 /* Small trick to flush main-thread event pool.
754 * Other thread-pools are destroyed at pthread_exit(),
755 * but tmain thread termination is too late to trigger Pool::~Pool()
757 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.
758 delete ev->event_pool();
763 ARDOUR_UI::pop_back_splash (Gtk::Window& win)
765 if (Splash::instance()) {
766 Splash::instance()->pop_back_for (win);
771 ARDOUR_UI::configure_timeout ()
773 if (last_configure_time == 0) {
774 /* no configure events yet */
778 /* force a gap of 0.5 seconds since the last configure event
781 if (get_microseconds() - last_configure_time < 500000) {
784 have_configure_timeout = false;
785 save_ardour_state ();
791 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
793 if (have_configure_timeout) {
794 last_configure_time = get_microseconds();
796 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
797 have_configure_timeout = true;
804 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
806 XMLProperty const * prop;
808 if ((prop = node.property ("roll")) != 0) {
809 roll_controllable->set_id (prop->value());
811 if ((prop = node.property ("stop")) != 0) {
812 stop_controllable->set_id (prop->value());
814 if ((prop = node.property ("goto-start")) != 0) {
815 goto_start_controllable->set_id (prop->value());
817 if ((prop = node.property ("goto-end")) != 0) {
818 goto_end_controllable->set_id (prop->value());
820 if ((prop = node.property ("auto-loop")) != 0) {
821 auto_loop_controllable->set_id (prop->value());
823 if ((prop = node.property ("play-selection")) != 0) {
824 play_selection_controllable->set_id (prop->value());
826 if ((prop = node.property ("rec")) != 0) {
827 rec_controllable->set_id (prop->value());
829 if ((prop = node.property ("shuttle")) != 0) {
830 shuttle_box->controllable()->set_id (prop->value());
835 ARDOUR_UI::get_transport_controllable_state ()
837 XMLNode* node = new XMLNode(X_("TransportControllables"));
840 roll_controllable->id().print (buf, sizeof (buf));
841 node->add_property (X_("roll"), buf);
842 stop_controllable->id().print (buf, sizeof (buf));
843 node->add_property (X_("stop"), buf);
844 goto_start_controllable->id().print (buf, sizeof (buf));
845 node->add_property (X_("goto_start"), buf);
846 goto_end_controllable->id().print (buf, sizeof (buf));
847 node->add_property (X_("goto_end"), buf);
848 auto_loop_controllable->id().print (buf, sizeof (buf));
849 node->add_property (X_("auto_loop"), buf);
850 play_selection_controllable->id().print (buf, sizeof (buf));
851 node->add_property (X_("play_selection"), buf);
852 rec_controllable->id().print (buf, sizeof (buf));
853 node->add_property (X_("rec"), buf);
854 shuttle_box->controllable()->id().print (buf, sizeof (buf));
855 node->add_property (X_("shuttle"), buf);
861 ARDOUR_UI::save_session_at_its_request (std::string snapshot_name)
864 _session->save_state (snapshot_name);
869 ARDOUR_UI::autosave_session ()
871 if (g_main_depth() > 1) {
872 /* inside a recursive main loop,
873 give up because we may not be able to
879 if (!Config->get_periodic_safety_backups()) {
884 _session->maybe_write_autosave();
891 ARDOUR_UI::session_dirty_changed ()
898 ARDOUR_UI::update_autosave ()
900 if (_session && _session->dirty()) {
901 if (_autosave_connection.connected()) {
902 _autosave_connection.disconnect();
905 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
906 Config->get_periodic_safety_backup_interval() * 1000);
909 if (_autosave_connection.connected()) {
910 _autosave_connection.disconnect();
916 ARDOUR_UI::check_announcements ()
919 string _annc_filename;
922 _annc_filename = PROGRAM_NAME "_announcements_osx_";
923 #elif defined PLATFORM_WINDOWS
924 _annc_filename = PROGRAM_NAME "_announcements_windows_";
926 _annc_filename = PROGRAM_NAME "_announcements_linux_";
928 _annc_filename.append (VERSIONSTRING);
930 _announce_string = "";
932 std::string path = Glib::build_filename (user_config_directory(), _annc_filename);
933 FILE* fin = g_fopen (path.c_str(), "rb");
935 while (!feof (fin)) {
938 if ((len = fread (tmp, sizeof(char), 1024, fin)) == 0 || ferror (fin)) {
941 _announce_string.append (tmp, len);
946 pingback (VERSIONSTRING, path);
951 _hide_splash (gpointer arg)
953 ((ARDOUR_UI*)arg)->hide_splash();
958 ARDOUR_UI::starting ()
960 Application* app = Application::instance ();
962 bool brand_new_user = ArdourStartup::required ();
964 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
965 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::load_from_application_api));
967 if (ARDOUR_COMMAND_LINE::check_announcements) {
968 check_announcements ();
973 /* we need to create this early because it may need to set the
974 * audio backend end up.
978 audio_midi_setup.get (true);
980 std::cerr << "audio-midi engine setup failed."<< std::endl;
984 if ((nsm_url = g_getenv ("NSM_URL")) != 0) {
985 nsm = new NSM_Client;
986 if (!nsm->init (nsm_url)) {
987 /* the ardour executable may have different names:
989 * waf's obj.target for distro versions: eg ardour4, ardourvst4
990 * Ardour4, Mixbus3 for bundled versions + full path on OSX & windows
991 * argv[0] does not apply since we need the wrapper-script (not the binary itself)
993 * The wrapper startup script should set the environment variable 'ARDOUR_SELF'
995 const char *process_name = g_getenv ("ARDOUR_SELF");
996 nsm->announce (PROGRAM_NAME, ":dirty:", process_name ? process_name : "ardour4");
999 // wait for announce reply from nsm server
1000 for ( i = 0; i < 5000; ++i) {
1004 if (nsm->is_active()) {
1009 error << _("NSM server did not announce itself") << endmsg;
1012 // wait for open command from nsm server
1013 for ( i = 0; i < 5000; ++i) {
1015 Glib::usleep (1000);
1016 if (nsm->client_id ()) {
1022 error << _("NSM: no client ID provided") << endmsg;
1026 if (_session && nsm) {
1027 _session->set_nsm_state( nsm->is_active() );
1029 error << _("NSM: no session created") << endmsg;
1033 // nsm requires these actions disabled
1034 vector<string> action_names;
1035 action_names.push_back("SaveAs");
1036 action_names.push_back("Rename");
1037 action_names.push_back("New");
1038 action_names.push_back("Open");
1039 action_names.push_back("Recent");
1040 action_names.push_back("Close");
1042 for (vector<string>::const_iterator n = action_names.begin(); n != action_names.end(); ++n) {
1043 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), (*n).c_str());
1045 act->set_sensitive (false);
1052 error << _("NSM: initialization failed") << endmsg;
1058 if (brand_new_user) {
1059 _initial_verbose_plugin_scan = true;
1064 _initial_verbose_plugin_scan = false;
1065 switch (s.response ()) {
1066 case Gtk::RESPONSE_OK:
1073 // TODO: maybe IFF brand_new_user
1074 if (ARDOUR::Profile->get_mixbus () && Config->get_copy_demo_sessions ()) {
1075 std::string dspd (Config->get_default_session_parent_dir());
1076 Searchpath ds (ARDOUR::ardour_data_search_path());
1077 ds.add_subdirectory_to_paths ("sessions");
1078 vector<string> demos;
1079 find_files_matching_pattern (demos, ds, "*.tar.xz");
1081 ARDOUR::RecentSessions rs;
1082 ARDOUR::read_recent_sessions (rs);
1084 for (vector<string>::iterator i = demos.begin(); i != demos.end (); ++i) {
1085 /* "demo-session" must be inside "demo-session.tar.xz"
1088 std::string name = basename_nosuffix (basename_nosuffix (*i));
1089 std::string path = Glib::build_filename (dspd, name);
1090 /* skip if session-dir already exists */
1091 if (Glib::file_test(path.c_str(), Glib::FILE_TEST_IS_DIR)) {
1094 /* skip sessions that are already in 'recent'.
1095 * eg. a new user changed <session-default-dir> shorly after installation
1097 for (ARDOUR::RecentSessions::iterator r = rs.begin(); r != rs.end(); ++r) {
1098 if ((*r).first == name) {
1103 PBD::FileArchive ar (*i);
1104 if (0 == ar.inflate (dspd)) {
1105 store_recent_sessions (name, path);
1106 info << string_compose (_("Copied Demo Session %1."), name) << endmsg;
1112 #ifdef NO_PLUGIN_STATE
1114 ARDOUR::RecentSessions rs;
1115 ARDOUR::read_recent_sessions (rs);
1117 string path = Glib::build_filename (user_config_directory(), ".iknowaboutfreeversion");
1119 if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS) && !rs.empty()) {
1121 /* already used Ardour, have sessions ... warn about plugin state */
1123 ArdourDialog d (_("Free/Demo Version Warning"), true);
1125 Button b (string_compose (_("Subscribe and support development of %1"), PROGRAM_NAME));
1126 CheckButton c (_("Don't warn me about this again"));
1128 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"),
1129 string_compose (_("This is a free/demo version of %1"), PROGRAM_NAME),
1130 _("It will not restore OR save any plugin settings"),
1131 _("If you load an existing session with plugin settings\n"
1132 "they will not be used and will be lost."),
1133 _("To get full access to updates without this limitation\n"
1134 "consider becoming a subscriber for a low cost every month.")));
1135 l.set_justify (JUSTIFY_CENTER);
1137 b.signal_clicked().connect (mem_fun(*this, &ARDOUR_UI::launch_subscribe));
1139 d.get_vbox()->pack_start (l, true, true);
1140 d.get_vbox()->pack_start (b, false, false, 12);
1141 d.get_vbox()->pack_start (c, false, false, 12);
1143 d.add_button (_("Quit now"), RESPONSE_CANCEL);
1144 d.add_button (string_compose (_("Continue using %1"), PROGRAM_NAME), RESPONSE_OK);
1148 c.signal_toggled().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (toggle_file_existence), path)));
1150 if (d.run () != RESPONSE_OK) {
1156 /* go get a session */
1158 const bool new_session_required = (ARDOUR_COMMAND_LINE::new_session || brand_new_user);
1160 if (get_session_parameters (false, new_session_required, ARDOUR_COMMAND_LINE::load_template)) {
1161 std::cerr << "Cannot get session parameters."<< std::endl;
1168 WM::Manager::instance().show_visible ();
1170 /* We have to do this here since goto_editor_window() ends up calling show_all() on the
1171 * editor window, and we may want stuff to be hidden.
1173 _status_bar_visibility.update ();
1175 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
1177 if (splash && splash->is_visible()) {
1178 // in 1 second, hide the splash screen
1179 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
1182 /* all other dialogs are created conditionally */
1188 ARDOUR_UI::check_memory_locking ()
1190 #if defined(__APPLE__) || defined(PLATFORM_WINDOWS)
1191 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
1195 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
1197 if (AudioEngine::instance()->is_realtime() && memory_warning_node == 0) {
1199 struct rlimit limits;
1201 long pages, page_size;
1203 size_t pages_len=sizeof(pages);
1204 if ((page_size = getpagesize()) < 0 ||
1205 sysctlbyname("hw.availpages", &pages, &pages_len, NULL, 0))
1207 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0)
1212 ram = (int64_t) pages * (int64_t) page_size;
1215 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
1219 if (limits.rlim_cur != RLIM_INFINITY) {
1221 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
1225 _("WARNING: Your system has a limit for maximum amount of locked memory. "
1226 "This might cause %1 to run out of memory before your system "
1227 "runs out of memory. \n\n"
1228 "You can view the memory limit with 'ulimit -l', "
1229 "and it is normally controlled by %2"),
1232 X_("/etc/login.conf")
1234 X_(" /etc/security/limits.conf")
1238 msg.set_default_response (RESPONSE_OK);
1240 VBox* vbox = msg.get_vbox();
1242 CheckButton cb (_("Do not show this window again"));
1243 hbox.pack_start (cb, true, false);
1244 vbox->pack_start (hbox);
1249 pop_back_splash (msg);
1253 if (cb.get_active()) {
1254 XMLNode node (X_("no-memory-warning"));
1255 Config->add_instant_xml (node);
1260 #endif // !__APPLE__
1265 ARDOUR_UI::queue_finish ()
1267 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
1271 ARDOUR_UI::idle_finish ()
1274 return false; /* do not call again */
1281 ARDOUR_UI::instance()->video_timeline->sync_session_state();
1283 if (_session->dirty()) {
1284 vector<string> actions;
1285 actions.push_back (_("Don't quit"));
1286 actions.push_back (_("Just quit"));
1287 actions.push_back (_("Save and quit"));
1288 switch (ask_about_saving_session(actions)) {
1293 /* use the default name */
1294 if (save_state_canfail ("")) {
1295 /* failed - don't quit */
1296 MessageDialog msg (_main_window,
1297 string_compose (_("\
1298 %1 was unable to save your session.\n\n\
1299 If you still wish to quit, please use the\n\n\
1300 \"Just quit\" option."), PROGRAM_NAME));
1301 pop_back_splash(msg);
1311 second_connection.disconnect ();
1312 point_one_second_connection.disconnect ();
1313 point_zero_something_second_connection.disconnect();
1314 fps_connection.disconnect();
1317 delete ARDOUR_UI::instance()->video_timeline;
1318 ARDOUR_UI::instance()->video_timeline = NULL;
1319 stop_video_server();
1321 /* Save state before deleting the session, as that causes some
1322 windows to be destroyed before their visible state can be
1325 save_ardour_state ();
1327 key_editor->disconnect ();
1329 close_all_dialogs ();
1332 _session->set_clean ();
1333 _session->remove_pending_capture_state ();
1338 halt_connection.disconnect ();
1339 AudioEngine::instance()->stop ();
1340 #ifdef WINDOWS_VST_SUPPORT
1341 fst_stop_threading();
1347 ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
1349 ArdourDialog window (_("Unsaved Session"));
1350 Gtk::HBox dhbox; // the hbox for the image and text
1351 Gtk::Label prompt_label;
1352 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
1356 assert (actions.size() >= 3);
1358 window.add_button (actions[0], RESPONSE_REJECT);
1359 window.add_button (actions[1], RESPONSE_APPLY);
1360 window.add_button (actions[2], RESPONSE_ACCEPT);
1362 window.set_default_response (RESPONSE_ACCEPT);
1364 Gtk::Button noquit_button (msg);
1365 noquit_button.set_name ("EditorGTKButton");
1369 if (_session->snap_name() == _session->name()) {
1370 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?"),
1371 _session->snap_name());
1373 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?"),
1374 _session->snap_name());
1377 prompt_label.set_text (prompt);
1378 prompt_label.set_name (X_("PrompterLabel"));
1379 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
1381 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
1382 dhbox.set_homogeneous (false);
1383 dhbox.pack_start (*dimage, false, false, 5);
1384 dhbox.pack_start (prompt_label, true, false, 5);
1385 window.get_vbox()->pack_start (dhbox);
1387 window.set_name (_("Prompter"));
1388 window.set_modal (true);
1389 window.set_resizable (false);
1392 prompt_label.show();
1397 ResponseType r = (ResponseType) window.run();
1402 case RESPONSE_ACCEPT: // save and get out of here
1404 case RESPONSE_APPLY: // get out of here
1415 ARDOUR_UI::every_second ()
1418 update_xrun_count ();
1419 update_buffer_load ();
1420 update_disk_space ();
1421 update_timecode_format ();
1422 update_peak_thread_work ();
1424 if (nsm && nsm->is_active ()) {
1427 if (!_was_dirty && _session->dirty ()) {
1431 else if (_was_dirty && !_session->dirty ()){
1439 ARDOUR_UI::every_point_one_seconds ()
1441 // TODO get rid of this..
1442 // ShuttleControl is updated directly via TransportStateChange signal
1446 ARDOUR_UI::every_point_zero_something_seconds ()
1448 // august 2007: actual update frequency: 25Hz (40ms), not 100Hz
1450 if (editor_meter && UIConfiguration::instance().get_show_editor_meter()) {
1451 float mpeak = editor_meter->update_meters();
1452 if (mpeak > editor_meter_max_peak) {
1453 if (mpeak >= UIConfiguration::instance().get_meter_peak()) {
1454 editor_meter_peak_display.set_active_state ( Gtkmm2ext::ExplicitActive );
1461 ARDOUR_UI::set_fps_timeout_connection ()
1463 unsigned int interval = 40;
1464 if (!_session) return;
1465 if (_session->timecode_frames_per_second() != 0) {
1466 /* ideally we'll use a select() to sleep and not accumulate
1467 * idle time to provide a regular periodic signal.
1468 * See linux_vst_gui_support.cc 'elapsed_time_ms'.
1469 * However, that'll require a dedicated thread and cross-thread
1470 * signals to the GUI Thread..
1472 interval = floor(500. /* update twice per FPS, since Glib::signal_timeout is very irregular */
1473 * _session->frame_rate() / _session->nominal_frame_rate()
1474 / _session->timecode_frames_per_second()
1476 #ifdef PLATFORM_WINDOWS
1477 // the smallest windows scheduler time-slice is ~15ms.
1478 // periodic GUI timeouts shorter than that will cause
1479 // WaitForSingleObject to spinlock (100% of one CPU Core)
1480 // and gtk never enters idle mode.
1481 // also changing timeBeginPeriod(1) does not affect that in
1482 // any beneficial way, so we just limit the max rate for now.
1483 interval = std::max(30u, interval); // at most ~33Hz.
1485 interval = std::max(8u, interval); // at most 120Hz.
1488 fps_connection.disconnect();
1489 Timers::set_fps_interval (interval);
1493 ARDOUR_UI::update_sample_rate (framecnt_t)
1497 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
1499 if (!AudioEngine::instance()->connected()) {
1501 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1505 framecnt_t rate = AudioEngine::instance()->sample_rate();
1508 /* no sample rate available */
1509 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1512 if (fmod (rate, 1000.0) != 0.0) {
1513 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
1514 (float) rate / 1000.0f,
1515 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1517 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
1519 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1523 sample_rate_label.set_markup (buf);
1527 ARDOUR_UI::update_format ()
1530 format_label.set_text ("");
1535 s << _("File:") << X_(" <span foreground=\"green\">");
1537 switch (_session->config.get_native_file_header_format ()) {
1569 switch (_session->config.get_native_file_data_format ()) {
1583 format_label.set_markup (s.str ());
1587 ARDOUR_UI::update_xrun_count ()
1591 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1592 should also be changed.
1596 const unsigned int x = _session->get_xrun_count ();
1598 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">>10K</span>"), X_("red"));
1600 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">%u</span>"), x > 0 ? X_("red") : X_("green"), x);
1603 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">?</span>"), X_("yellow"));
1605 xrun_label.set_markup (buf);
1606 set_tip (xrun_label, _("Audio dropouts. Shift+click to reset"));
1610 ARDOUR_UI::update_cpu_load ()
1614 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1615 should also be changed.
1618 double const c = AudioEngine::instance()->get_dsp_load ();
1619 snprintf (buf, sizeof (buf), _("DSP: <span foreground=\"%s\">%5.1f%%</span>"), c >= 90 ? X_("red") : X_("green"), c);
1620 cpu_load_label.set_markup (buf);
1624 ARDOUR_UI::update_peak_thread_work ()
1627 const int c = SourceFactory::peak_work_queue_length ();
1629 snprintf (buf, sizeof (buf), _("PkBld: <span foreground=\"%s\">%d</span>"), c >= 2 ? X_("red") : X_("green"), c);
1630 peak_thread_work_label.set_markup (buf);
1632 peak_thread_work_label.set_markup (X_(""));
1637 ARDOUR_UI::update_buffer_load ()
1641 uint32_t const playback = _session ? _session->playback_load () : 100;
1642 uint32_t const capture = _session ? _session->capture_load () : 100;
1644 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1645 should also be changed.
1651 _("Buffers: <span foreground=\"green\">p:</span><span foreground=\"%s\">%" PRIu32 "%%</span> "
1652 "<span foreground=\"green\">c:</span><span foreground=\"%s\">%" PRIu32 "%%</span>"),
1653 playback <= 5 ? X_("red") : X_("green"),
1655 capture <= 5 ? X_("red") : X_("green"),
1659 buffer_load_label.set_markup (buf);
1661 buffer_load_label.set_text ("");
1666 ARDOUR_UI::count_recenabled_streams (Route& route)
1668 Track* track = dynamic_cast<Track*>(&route);
1669 if (track && track->rec_enable_control()->get_value()) {
1670 rec_enabled_streams += track->n_inputs().n_total();
1675 ARDOUR_UI::update_disk_space()
1677 if (_session == 0) {
1681 boost::optional<framecnt_t> opt_frames = _session->available_capture_duration();
1683 framecnt_t fr = _session->frame_rate();
1686 /* skip update - no SR available */
1691 /* Available space is unknown */
1692 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">Unknown</span>"));
1693 } else if (opt_frames.get_value_or (0) == max_framecnt) {
1694 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">24hrs+</span>"));
1696 rec_enabled_streams = 0;
1697 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams, false);
1699 framecnt_t frames = opt_frames.get_value_or (0);
1701 if (rec_enabled_streams) {
1702 frames /= rec_enabled_streams;
1709 hrs = frames / (fr * 3600);
1712 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">>24 hrs</span>"));
1714 frames -= hrs * fr * 3600;
1715 mins = frames / (fr * 60);
1716 frames -= mins * fr * 60;
1719 bool const low = (hrs == 0 && mins <= 30);
1723 _("Disk: <span foreground=\"%s\">%02dh:%02dm:%02ds</span>"),
1724 low ? X_("red") : X_("green"),
1730 disk_space_label.set_markup (buf);
1734 ARDOUR_UI::update_timecode_format ()
1740 TimecodeSlave* tcslave;
1741 SyncSource sync_src = Config->get_sync_source();
1743 if ((sync_src == LTC || sync_src == MTC) && (tcslave = dynamic_cast<TimecodeSlave*>(_session->slave())) != 0) {
1744 matching = (tcslave->apparent_timecode_format() == _session->config.get_timecode_format());
1749 snprintf (buf, sizeof (buf), S_("Timecode|TC: <span foreground=\"%s\">%s</span>"),
1750 matching ? X_("green") : X_("red"),
1751 Timecode::timecode_format_name (_session->config.get_timecode_format()).c_str());
1753 snprintf (buf, sizeof (buf), "TC: n/a");
1756 timecode_format_label.set_markup (buf);
1760 ARDOUR_UI::update_wall_clock ()
1764 static int last_min = -1;
1767 tm_now = localtime (&now);
1768 if (last_min != tm_now->tm_min) {
1770 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1771 wall_clock_label.set_text (buf);
1772 last_min = tm_now->tm_min;
1779 ARDOUR_UI::open_recent_session ()
1781 bool can_return = (_session != 0);
1783 SessionDialog recent_session_dialog;
1787 ResponseType r = (ResponseType) recent_session_dialog.run ();
1790 case RESPONSE_ACCEPT:
1794 recent_session_dialog.hide();
1801 recent_session_dialog.hide();
1805 std::string path = recent_session_dialog.session_folder();
1806 std::string state = recent_session_dialog.session_name (should_be_new);
1808 if (should_be_new == true) {
1812 _session_is_new = false;
1814 if (load_session (path, state) == 0) {
1820 if (splash && splash->is_visible()) {
1821 // in 1 second, hide the splash screen
1822 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
1827 ARDOUR_UI::check_audioengine (Gtk::Window& parent)
1829 if (!AudioEngine::instance()->connected()) {
1830 MessageDialog msg (parent, string_compose (
1831 _("%1 is not connected to any audio backend.\n"
1832 "You cannot open or close sessions in this condition"),
1834 pop_back_splash (msg);
1842 ARDOUR_UI::open_session ()
1844 if (!check_audioengine (_main_window)) {
1848 /* ardour sessions are folders */
1849 Gtk::FileChooserDialog open_session_selector(_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1850 open_session_selector.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1851 open_session_selector.add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1852 open_session_selector.set_default_response(Gtk::RESPONSE_ACCEPT);
1855 string session_parent_dir = Glib::path_get_dirname(_session->path());
1856 open_session_selector.set_current_folder(session_parent_dir);
1858 open_session_selector.set_current_folder(Config->get_default_session_parent_dir());
1861 Gtkmm2ext::add_volume_shortcuts (open_session_selector);
1863 /* add_shortcut_folder throws an exception if the folder being added already has a shortcut */
1864 string default_session_folder = Config->get_default_session_parent_dir();
1865 open_session_selector.add_shortcut_folder (default_session_folder);
1867 catch (Glib::Error & e) {
1868 std::cerr << "open_session_selector.add_shortcut_folder() threw Glib::Error " << e.what() << std::endl;
1871 FileFilter session_filter;
1872 session_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::statefile_suffix));
1873 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1874 open_session_selector.add_filter (session_filter);
1875 open_session_selector.set_filter (session_filter);
1877 int response = open_session_selector.run();
1878 open_session_selector.hide ();
1880 if (response == Gtk::RESPONSE_CANCEL) {
1884 string session_path = open_session_selector.get_filename();
1888 if (session_path.length() > 0) {
1889 if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1890 _session_is_new = isnew;
1891 load_session (path, name);
1897 ARDOUR_UI::session_add_vca (const string& name_template, uint32_t n)
1903 _session->vca_manager().create_vca (n, name_template);
1907 ARDOUR_UI::session_add_mixed_track (
1908 const ChanCount& input,
1909 const ChanCount& output,
1910 RouteGroup* route_group,
1912 const string& name_template,
1914 PluginInfoPtr instrument,
1915 Plugin::PresetRecord* pset,
1916 ARDOUR::PresentationInfo::order_t order)
1918 list<boost::shared_ptr<MidiTrack> > tracks;
1920 if (_session == 0) {
1921 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1926 tracks = _session->new_midi_track (input, output, instrument, pset, route_group, how_many, name_template, order, ARDOUR::Normal);
1928 if (tracks.size() != how_many) {
1929 error << string_compose(P_("could not create %1 new mixed track", "could not create %1 new mixed tracks", how_many), how_many) << endmsg;
1934 display_insufficient_ports_message ();
1939 for (list<boost::shared_ptr<MidiTrack> >::iterator i = tracks.begin(); i != tracks.end(); ++i) {
1940 (*i)->set_strict_io (true);
1946 ARDOUR_UI::session_add_midi_bus (
1947 RouteGroup* route_group,
1949 const string& name_template,
1951 PluginInfoPtr instrument,
1952 Plugin::PresetRecord* pset,
1953 ARDOUR::PresentationInfo::order_t order)
1957 if (_session == 0) {
1958 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1964 routes = _session->new_midi_route (route_group, how_many, name_template, instrument, pset, PresentationInfo::MidiBus, order);
1965 if (routes.size() != how_many) {
1966 error << string_compose(P_("could not create %1 new Midi Bus", "could not create %1 new Midi Busses", how_many), how_many) << endmsg;
1971 display_insufficient_ports_message ();
1976 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
1977 (*i)->set_strict_io (true);
1983 ARDOUR_UI::session_add_midi_route (
1985 RouteGroup* route_group,
1987 const string& name_template,
1989 PluginInfoPtr instrument,
1990 Plugin::PresetRecord* pset,
1991 ARDOUR::PresentationInfo::order_t order)
1993 ChanCount one_midi_channel;
1994 one_midi_channel.set (DataType::MIDI, 1);
1997 session_add_mixed_track (one_midi_channel, one_midi_channel, route_group, how_many, name_template, strict_io, instrument, pset, order);
1999 session_add_midi_bus (route_group, how_many, name_template, strict_io, instrument, pset, order);
2004 ARDOUR_UI::session_add_audio_route (
2006 int32_t input_channels,
2007 int32_t output_channels,
2008 ARDOUR::TrackMode mode,
2009 RouteGroup* route_group,
2011 string const & name_template,
2013 ARDOUR::PresentationInfo::order_t order)
2015 list<boost::shared_ptr<AudioTrack> > tracks;
2018 if (_session == 0) {
2019 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
2025 tracks = _session->new_audio_track (input_channels, output_channels, route_group, how_many, name_template, order, mode);
2027 if (tracks.size() != how_many) {
2028 error << string_compose (P_("could not create %1 new audio track", "could not create %1 new audio tracks", how_many), how_many)
2034 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template, PresentationInfo::AudioBus, order);
2036 if (routes.size() != how_many) {
2037 error << string_compose (P_("could not create %1 new audio bus", "could not create %1 new audio busses", how_many), how_many)
2044 display_insufficient_ports_message ();
2049 for (list<boost::shared_ptr<AudioTrack> >::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2050 (*i)->set_strict_io (true);
2052 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
2053 (*i)->set_strict_io (true);
2059 ARDOUR_UI::display_insufficient_ports_message ()
2061 MessageDialog msg (_main_window,
2062 string_compose (_("There are insufficient ports available\n\
2063 to create a new track or bus.\n\
2064 You should save %1, exit and\n\
2065 restart with more ports."), PROGRAM_NAME));
2066 pop_back_splash (msg);
2071 ARDOUR_UI::transport_goto_start ()
2074 _session->goto_start();
2076 /* force displayed area in editor to start no matter
2077 what "follow playhead" setting is.
2081 editor->center_screen (_session->current_start_frame ());
2087 ARDOUR_UI::transport_goto_zero ()
2090 _session->request_locate (0);
2092 /* force displayed area in editor to start no matter
2093 what "follow playhead" setting is.
2097 editor->reset_x_origin (0);
2103 ARDOUR_UI::transport_goto_wallclock ()
2105 if (_session && editor) {
2112 localtime_r (&now, &tmnow);
2114 framecnt_t frame_rate = _session->frame_rate();
2116 if (frame_rate == 0) {
2117 /* no frame rate available */
2121 frames = tmnow.tm_hour * (60 * 60 * frame_rate);
2122 frames += tmnow.tm_min * (60 * frame_rate);
2123 frames += tmnow.tm_sec * frame_rate;
2125 _session->request_locate (frames, _session->transport_rolling ());
2127 /* force displayed area in editor to start no matter
2128 what "follow playhead" setting is.
2132 editor->center_screen (frames);
2138 ARDOUR_UI::transport_goto_end ()
2141 framepos_t const frame = _session->current_end_frame();
2142 _session->request_locate (frame);
2144 /* force displayed area in editor to start no matter
2145 what "follow playhead" setting is.
2149 editor->center_screen (frame);
2155 ARDOUR_UI::transport_stop ()
2161 if (_session->is_auditioning()) {
2162 _session->cancel_audition ();
2166 _session->request_stop (false, true);
2169 /** Check if any tracks are record enabled. If none are, record enable all of them.
2170 * @return true if track record-enabled status was changed, false otherwise.
2173 ARDOUR_UI::trx_record_enable_all_tracks ()
2179 boost::shared_ptr<RouteList> rl = _session->get_tracks ();
2180 bool none_record_enabled = true;
2182 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
2183 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*r);
2186 if (t->rec_enable_control()->get_value()) {
2187 none_record_enabled = false;
2192 if (none_record_enabled) {
2193 _session->set_controls (route_list_to_control_list (rl, &Stripable::rec_enable_control), 1.0, Controllable::NoGroup);
2196 return none_record_enabled;
2200 ARDOUR_UI::transport_record (bool roll)
2203 switch (_session->record_status()) {
2204 case Session::Disabled:
2205 if (_session->ntracks() == 0) {
2206 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."));
2210 if (Profile->get_trx()) {
2211 roll = trx_record_enable_all_tracks ();
2213 _session->maybe_enable_record ();
2218 case Session::Recording:
2220 _session->request_stop();
2222 _session->disable_record (false, true);
2226 case Session::Enabled:
2227 _session->disable_record (false, true);
2233 ARDOUR_UI::transport_roll ()
2239 if (_session->is_auditioning()) {
2244 if (_session->config.get_external_sync()) {
2245 switch (Config->get_sync_source()) {
2249 /* transport controlled by the master */
2255 bool rolling = _session->transport_rolling();
2257 if (_session->get_play_loop()) {
2259 /* If loop playback is not a mode, then we should cancel
2260 it when this action is requested. If it is a mode
2261 we just leave it in place.
2264 if (!Config->get_loop_is_mode()) {
2265 /* XXX it is not possible to just leave seamless loop and keep
2266 playing at present (nov 4th 2009)
2268 if (!Config->get_seamless_loop()) {
2269 /* stop loop playback and stop rolling */
2270 _session->request_play_loop (false, true);
2271 } else if (rolling) {
2272 /* stop loop playback but keep rolling */
2273 _session->request_play_loop (false, false);
2277 } else if (_session->get_play_range () ) {
2278 /* stop playing a range if we currently are */
2279 _session->request_play_range (0, true);
2283 _session->request_transport_speed (1.0f);
2288 ARDOUR_UI::get_smart_mode() const
2290 return ( editor->get_smart_mode() );
2295 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
2301 if (_session->is_auditioning()) {
2302 _session->cancel_audition ();
2306 if (_session->config.get_external_sync()) {
2307 switch (Config->get_sync_source()) {
2311 /* transport controlled by the master */
2316 bool rolling = _session->transport_rolling();
2317 bool affect_transport = true;
2319 if (rolling && roll_out_of_bounded_mode) {
2320 /* drop out of loop/range playback but leave transport rolling */
2321 if (_session->get_play_loop()) {
2322 if (_session->actively_recording()) {
2324 /* just stop using the loop, then actually stop
2327 _session->request_play_loop (false, affect_transport);
2330 if (Config->get_seamless_loop()) {
2331 /* the disk buffers contain copies of the loop - we can't
2332 just keep playing, so stop the transport. the user
2333 can restart as they wish.
2335 affect_transport = true;
2337 /* disk buffers are normal, so we can keep playing */
2338 affect_transport = false;
2340 _session->request_play_loop (false, affect_transport);
2342 } else if (_session->get_play_range ()) {
2343 affect_transport = false;
2344 _session->request_play_range (0, true);
2348 if (affect_transport) {
2350 _session->request_stop (with_abort, true);
2352 } else if (!with_abort) { /* with_abort == true means the
2353 * command was intended to stop
2354 * transport, not start.
2357 /* the only external sync condition we can be in here
2358 * would be Engine (JACK) sync, in which case we still
2362 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
2363 _session->request_play_range (&editor->get_selection().time, true);
2364 _session->set_requested_return_frame( editor->get_selection().time.front().start ); //force an auto-return here
2366 _session->request_transport_speed (1.0f);
2372 ARDOUR_UI::toggle_session_auto_loop ()
2378 Location * looploc = _session->locations()->auto_loop_location();
2384 if (_session->get_play_loop()) {
2386 /* looping enabled, our job is to disable it */
2388 _session->request_play_loop (false);
2392 /* looping not enabled, our job is to enable it.
2394 loop-is-NOT-mode: this action always starts the transport rolling.
2395 loop-IS-mode: this action simply sets the loop play mechanism, but
2396 does not start transport.
2398 if (Config->get_loop_is_mode()) {
2399 _session->request_play_loop (true, false);
2401 _session->request_play_loop (true, true);
2405 //show the loop markers
2406 looploc->set_hidden (false, this);
2410 ARDOUR_UI::transport_play_selection ()
2416 editor->play_selection ();
2420 ARDOUR_UI::transport_play_preroll ()
2425 editor->play_with_preroll ();
2429 ARDOUR_UI::transport_rewind (int option)
2431 float current_transport_speed;
2434 current_transport_speed = _session->transport_speed();
2436 if (current_transport_speed >= 0.0f) {
2439 _session->request_transport_speed (-1.0f);
2442 _session->request_transport_speed (-4.0f);
2445 _session->request_transport_speed (-0.5f);
2450 _session->request_transport_speed (current_transport_speed * 1.5f);
2456 ARDOUR_UI::transport_forward (int option)
2462 float current_transport_speed = _session->transport_speed();
2464 if (current_transport_speed <= 0.0f) {
2467 _session->request_transport_speed (1.0f);
2470 _session->request_transport_speed (4.0f);
2473 _session->request_transport_speed (0.5f);
2478 _session->request_transport_speed (current_transport_speed * 1.5f);
2483 ARDOUR_UI::toggle_record_enable (uint16_t rid)
2489 boost::shared_ptr<Route> r;
2491 if ((r = _session->get_remote_nth_route (rid)) != 0) {
2493 boost::shared_ptr<Track> t;
2495 if ((t = boost::dynamic_pointer_cast<Track>(r)) != 0) {
2496 t->rec_enable_control()->set_value (!t->rec_enable_control()->get_value(), Controllable::UseGroup);
2502 ARDOUR_UI::map_transport_state ()
2505 auto_loop_button.unset_active_state ();
2506 play_selection_button.unset_active_state ();
2507 roll_button.unset_active_state ();
2508 stop_button.set_active_state (Gtkmm2ext::ExplicitActive);
2512 shuttle_box->map_transport_state ();
2514 float sp = _session->transport_speed();
2520 if (_session->get_play_range()) {
2522 play_selection_button.set_active_state (Gtkmm2ext::ExplicitActive);
2523 roll_button.unset_active_state ();
2524 auto_loop_button.unset_active_state ();
2526 } else if (_session->get_play_loop ()) {
2528 auto_loop_button.set_active (true);
2529 play_selection_button.set_active (false);
2530 if (Config->get_loop_is_mode()) {
2531 roll_button.set_active (true);
2533 roll_button.set_active (false);
2538 roll_button.set_active (true);
2539 play_selection_button.set_active (false);
2540 auto_loop_button.set_active (false);
2543 if (UIConfiguration::instance().get_follow_edits() && !_session->config.get_external_sync()) {
2544 /* light up both roll and play-selection if they are joined */
2545 roll_button.set_active (true);
2546 play_selection_button.set_active (true);
2549 stop_button.set_active (false);
2553 stop_button.set_active (true);
2554 roll_button.set_active (false);
2555 play_selection_button.set_active (false);
2556 if (Config->get_loop_is_mode ()) {
2557 auto_loop_button.set_active (_session->get_play_loop());
2559 auto_loop_button.set_active (false);
2561 update_disk_space ();
2566 ARDOUR_UI::blink_handler (bool blink_on)
2568 transport_rec_enable_blink (blink_on);
2569 solo_blink (blink_on);
2570 sync_blink (blink_on);
2571 audition_blink (blink_on);
2572 feedback_blink (blink_on);
2573 error_blink (blink_on);
2577 ARDOUR_UI::update_clocks ()
2579 if (!_session) return;
2581 if (editor && !editor->dragging_playhead()) {
2582 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD)); /* EMIT_SIGNAL */
2587 ARDOUR_UI::start_clocking ()
2589 if (UIConfiguration::instance().get_super_rapid_clock_update()) {
2590 clock_signal_connection = Timers::fps_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2592 clock_signal_connection = Timers::rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2597 ARDOUR_UI::stop_clocking ()
2599 clock_signal_connection.disconnect ();
2603 ARDOUR_UI::save_as_progress_update (float fraction, int64_t cnt, int64_t total, Gtk::Label* label, Gtk::ProgressBar* bar)
2607 snprintf (buf, sizeof (buf), _("Copied %" PRId64 " of %" PRId64), cnt, total);
2609 label->set_text (buf);
2610 bar->set_fraction (fraction);
2612 /* process events, redraws, etc. */
2614 while (gtk_events_pending()) {
2615 gtk_main_iteration ();
2618 return true; /* continue with save-as */
2622 ARDOUR_UI::save_session_as ()
2628 if (!save_as_dialog) {
2629 save_as_dialog = new SaveAsDialog;
2632 save_as_dialog->set_name (_session->name());
2634 int response = save_as_dialog->run ();
2636 save_as_dialog->hide ();
2639 case Gtk::RESPONSE_OK:
2648 sa.new_parent_folder = save_as_dialog->new_parent_folder ();
2649 sa.new_name = save_as_dialog->new_name ();
2650 sa.switch_to = save_as_dialog->switch_to();
2651 sa.copy_media = save_as_dialog->copy_media();
2652 sa.copy_external = save_as_dialog->copy_external();
2653 sa.include_media = save_as_dialog->include_media ();
2655 /* Only bother with a progress dialog if we're going to copy
2656 media into the save-as target. Without that choice, this
2657 will be very fast because we're only talking about a few kB's to
2658 perhaps a couple of MB's of data.
2661 ArdourDialog progress_dialog (_("Save As"), true);
2663 if (sa.include_media && sa.copy_media) {
2666 Gtk::ProgressBar progress_bar;
2668 progress_dialog.get_vbox()->pack_start (label);
2669 progress_dialog.get_vbox()->pack_start (progress_bar);
2671 progress_bar.show ();
2673 /* this signal will be emitted from within this, the calling thread,
2674 * after every file is copied. It provides information on percentage
2675 * complete (in terms of total data to copy), the number of files
2676 * copied so far, and the total number to copy.
2681 sa.Progress.connect_same_thread (c, boost::bind (&ARDOUR_UI::save_as_progress_update, this, _1, _2, _3, &label, &progress_bar));
2683 progress_dialog.show_all ();
2684 progress_dialog.present ();
2687 if (_session->save_as (sa)) {
2689 MessageDialog msg (string_compose (_("Save As failed: %1"), sa.failure_message));
2693 if (!sa.include_media) {
2694 unload_session (false);
2695 load_session (sa.final_session_folder_name, sa.new_name);
2700 ARDOUR_UI::quick_snapshot_session (bool switch_to_it)
2704 struct tm local_time;
2707 localtime_r (&n, &local_time);
2708 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2710 save_state (timebuf, switch_to_it);
2715 ARDOUR_UI::process_snapshot_session_prompter (ArdourPrompter& prompter, bool switch_to_it)
2719 prompter.get_result (snapname);
2721 bool do_save = (snapname.length() != 0);
2724 char illegal = Session::session_name_is_legal(snapname);
2726 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2727 "snapshot names may not contain a '%1' character"), illegal));
2733 vector<std::string> p;
2734 get_state_files_in_directory (_session->session_directory().root_path(), p);
2735 vector<string> n = get_file_names_no_extension (p);
2737 if (find (n.begin(), n.end(), snapname) != n.end()) {
2739 do_save = overwrite_file_dialog (prompter,
2740 _("Confirm Snapshot Overwrite"),
2741 _("A snapshot already exists with that name. Do you want to overwrite it?"));
2745 save_state (snapname, switch_to_it);
2755 /** Ask the user for the name of a new snapshot and then take it.
2759 ARDOUR_UI::snapshot_session (bool switch_to_it)
2761 ArdourPrompter prompter (true);
2763 prompter.set_name ("Prompter");
2764 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2766 prompter.set_title (_("Snapshot and switch"));
2767 prompter.set_prompt (_("New session name"));
2769 prompter.set_title (_("Take Snapshot"));
2770 prompter.set_prompt (_("Name of new snapshot"));
2774 prompter.set_initial_text (_session->snap_name());
2776 Glib::DateTime tm (g_date_time_new_now_local ());
2777 prompter.set_initial_text (tm.format ("%FT%H.%M.%S"));
2780 bool finished = false;
2782 switch (prompter.run()) {
2783 case RESPONSE_ACCEPT:
2785 finished = process_snapshot_session_prompter (prompter, switch_to_it);
2796 /** Ask the user for a new session name and then rename the session to it.
2800 ARDOUR_UI::rename_session ()
2806 ArdourPrompter prompter (true);
2809 prompter.set_name ("Prompter");
2810 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2811 prompter.set_title (_("Rename Session"));
2812 prompter.set_prompt (_("New session name"));
2815 switch (prompter.run()) {
2816 case RESPONSE_ACCEPT:
2818 prompter.get_result (name);
2820 bool do_rename = (name.length() != 0);
2823 char illegal = Session::session_name_is_legal (name);
2826 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2827 "session names may not contain a '%1' character"), illegal));
2832 switch (_session->rename (name)) {
2834 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
2835 msg.set_position (WIN_POS_MOUSE);
2843 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
2844 msg.set_position (WIN_POS_MOUSE);
2860 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2862 if (!_session || _session->deletion_in_progress()) {
2866 XMLNode* node = new XMLNode (X_("UI"));
2868 WM::Manager::instance().add_state (*node);
2870 node->add_child_nocopy (gui_object_state->get_state());
2872 _session->add_extra_xml (*node);
2874 if (export_video_dialog) {
2875 _session->add_extra_xml (export_video_dialog->get_state());
2878 save_state_canfail (name, switch_to_it);
2882 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2887 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2892 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2897 ARDOUR_UI::primary_clock_value_changed ()
2900 _session->request_locate (primary_clock->current_time ());
2905 ARDOUR_UI::big_clock_value_changed ()
2908 _session->request_locate (big_clock->current_time ());
2913 ARDOUR_UI::secondary_clock_value_changed ()
2916 _session->request_locate (secondary_clock->current_time ());
2921 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2923 if (_session == 0) {
2927 if (_session->step_editing()) {
2931 Session::RecordState const r = _session->record_status ();
2932 bool const h = _session->have_rec_enabled_track ();
2934 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2936 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2938 rec_button.set_active_state (Gtkmm2ext::Off);
2940 } else if (r == Session::Recording && h) {
2941 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2943 rec_button.unset_active_state ();
2948 ARDOUR_UI::process_save_template_prompter (ArdourPrompter& prompter)
2952 prompter.get_result (name);
2954 if (name.length()) {
2955 int failed = _session->save_template (name);
2957 if (failed == -2) { /* file already exists. */
2958 bool overwrite = overwrite_file_dialog (prompter,
2959 _("Confirm Template Overwrite"),
2960 _("A template already exists with that name. Do you want to overwrite it?"));
2963 _session->save_template (name, true);
2975 ARDOUR_UI::save_template ()
2977 ArdourPrompter prompter (true);
2979 if (!check_audioengine (_main_window)) {
2983 prompter.set_name (X_("Prompter"));
2984 prompter.set_title (_("Save Template"));
2985 prompter.set_prompt (_("Name for template:"));
2986 prompter.set_initial_text(_session->name() + _("-template"));
2987 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2989 bool finished = false;
2991 switch (prompter.run()) {
2992 case RESPONSE_ACCEPT:
2993 finished = process_save_template_prompter (prompter);
3004 ARDOUR_UI::edit_metadata ()
3006 SessionMetadataEditor dialog;
3007 dialog.set_session (_session);
3008 dialog.grab_focus ();
3013 ARDOUR_UI::import_metadata ()
3015 SessionMetadataImporter dialog;
3016 dialog.set_session (_session);
3021 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
3023 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
3025 MessageDialog msg (str,
3027 Gtk::MESSAGE_WARNING,
3028 Gtk::BUTTONS_YES_NO,
3032 msg.set_name (X_("OpenExistingDialog"));
3033 msg.set_title (_("Open Existing Session"));
3034 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
3035 msg.set_position (Gtk::WIN_POS_CENTER);
3036 pop_back_splash (msg);
3038 switch (msg.run()) {
3047 ARDOUR_UI::build_session_from_dialog (SessionDialog& sd, const std::string& session_path, const std::string& session_name)
3049 BusProfile bus_profile;
3053 bus_profile.master_out_channels = 2;
3054 bus_profile.input_ac = AutoConnectPhysical;
3055 bus_profile.output_ac = AutoConnectMaster;
3056 bus_profile.requested_physical_in = 0; // use all available
3057 bus_profile.requested_physical_out = 0; // use all available
3061 /* get settings from advanced section of NSD */
3063 if (sd.create_master_bus()) {
3064 bus_profile.master_out_channels = (uint32_t) sd.master_channel_count();
3066 bus_profile.master_out_channels = 0;
3069 if (sd.connect_inputs()) {
3070 bus_profile.input_ac = AutoConnectPhysical;
3072 bus_profile.input_ac = AutoConnectOption (0);
3075 bus_profile.output_ac = AutoConnectOption (0);
3077 if (sd.connect_outputs ()) {
3078 if (sd.connect_outs_to_master()) {
3079 bus_profile.output_ac = AutoConnectMaster;
3080 } else if (sd.connect_outs_to_physical()) {
3081 bus_profile.output_ac = AutoConnectPhysical;
3085 bus_profile.requested_physical_in = (uint32_t) sd.input_limit_count();
3086 bus_profile.requested_physical_out = (uint32_t) sd.output_limit_count();
3089 if (build_session (session_path, session_name, bus_profile)) {
3097 ARDOUR_UI::load_from_application_api (const std::string& path)
3099 ARDOUR_COMMAND_LINE::session_name = path;
3100 /* Cancel SessionDialog if it's visible to make OSX delegates work.
3102 * ARDOUR_UI::starting connects app->ShouldLoad signal and then shows a SessionDialog
3104 * - ShouldLoad does not arrive in time, ARDOUR_COMMAND_LINE::session_name is empty:
3105 * -> ARDOUR_UI::get_session_parameters starts a SessionDialog.
3106 * - ShouldLoad signal arrives, this function is called and sets ARDOUR_COMMAND_LINE::session_name
3107 * -> SessionDialog is not displayed
3110 if (_session_dialog) {
3111 std::string session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3112 std::string session_path = path;
3113 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_REGULAR)) {
3114 session_path = Glib::path_get_dirname (session_path);
3116 // signal the existing dialog in ARDOUR_UI::get_session_parameters()
3117 _session_dialog->set_provided_session (session_name, session_path);
3118 _session_dialog->response (RESPONSE_NONE);
3119 _session_dialog->hide();
3124 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
3125 /* /path/to/foo => /path/to/foo, foo */
3126 rv = load_session (path, basename_nosuffix (path));
3128 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
3129 rv =load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
3132 // if load_session fails -> pop up SessionDialog.
3134 ARDOUR_COMMAND_LINE::session_name = "";
3136 if (get_session_parameters (true, false)) {
3142 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
3144 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
3146 string session_name;
3147 string session_path;
3148 string template_name;
3150 bool likely_new = false;
3151 bool cancel_not_quit;
3153 /* deal with any existing DIRTY session now, rather than later. don't
3154 * treat a non-dirty session this way, so that it stays visible
3155 * as we bring up the new session dialog.
3158 if (_session && ARDOUR_UI::instance()->video_timeline) {
3159 ARDOUR_UI::instance()->video_timeline->sync_session_state();
3162 /* if there is already a session, relabel the button
3163 on the SessionDialog so that we don't Quit directly
3165 cancel_not_quit = (_session != 0);
3167 if (_session && _session->dirty()) {
3168 if (unload_session (false)) {
3169 /* unload cancelled by user */
3172 ARDOUR_COMMAND_LINE::session_name = "";
3175 if (!load_template.empty()) {
3176 should_be_new = true;
3177 template_name = load_template;
3180 session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3181 session_path = ARDOUR_COMMAND_LINE::session_name;
3183 if (!session_path.empty()) {
3184 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_EXISTS)) {
3185 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_IS_REGULAR)) {
3186 /* session/snapshot file, change path to be dir */
3187 session_path = Glib::path_get_dirname (session_path);
3192 SessionDialog session_dialog (should_be_new, session_name, session_path, load_template, cancel_not_quit);
3194 _session_dialog = &session_dialog;
3197 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
3199 /* if they named a specific statefile, use it, otherwise they are
3200 just giving a session folder, and we want to use it as is
3201 to find the session.
3204 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
3206 if (suffix != string::npos) {
3207 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
3208 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
3209 session_name = Glib::path_get_basename (session_name);
3211 session_path = ARDOUR_COMMAND_LINE::session_name;
3212 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
3217 session_dialog.clear_given ();
3220 if (should_be_new || session_name.empty()) {
3221 /* need the dialog to get info from user */
3223 cerr << "run dialog\n";
3225 switch (session_dialog.run()) {
3226 case RESPONSE_ACCEPT:
3229 /* this is used for async * app->ShouldLoad(). */
3230 continue; // while loop
3233 if (quit_on_cancel) {
3234 // JE - Currently (July 2014) this section can only get reached if the
3235 // user quits from the main 'Session Setup' dialog (i.e. reaching this
3236 // point does NOT indicate an abnormal termination). Therefore, let's
3237 // behave gracefully (i.e. let's do some cleanup) before we call exit()
3239 pthread_cancel_all ();
3247 session_dialog.hide ();
3250 /* if we run the startup dialog again, offer more than just "new session" */
3252 should_be_new = false;
3254 session_name = session_dialog.session_name (likely_new);
3255 session_path = session_dialog.session_folder ();
3261 string::size_type suffix = session_name.find (statefile_suffix);
3263 if (suffix != string::npos) {
3264 session_name = session_name.substr (0, suffix);
3267 /* this shouldn't happen, but we catch it just in case it does */
3269 if (session_name.empty()) {
3273 if (session_dialog.use_session_template()) {
3274 template_name = session_dialog.session_template_name();
3275 _session_is_new = true;
3278 if (session_name[0] == G_DIR_SEPARATOR ||
3279 #ifdef PLATFORM_WINDOWS
3280 (session_name.length() > 3 && session_name[1] == ':' && session_name[2] == G_DIR_SEPARATOR)
3282 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
3283 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)
3288 /* absolute path or cwd-relative path specified for session name: infer session folder
3289 from what was given.
3292 session_path = Glib::path_get_dirname (session_name);
3293 session_name = Glib::path_get_basename (session_name);
3297 session_path = session_dialog.session_folder();
3299 char illegal = Session::session_name_is_legal (session_name);
3302 MessageDialog msg (session_dialog,
3303 string_compose (_("To ensure compatibility with various systems\n"
3304 "session names may not contain a '%1' character"),
3307 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3312 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
3315 if (likely_new && !nsm) {
3317 std::string existing = Glib::build_filename (session_path, session_name);
3319 if (!ask_about_loading_existing_session (existing)) {
3320 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3325 _session_is_new = false;
3330 pop_back_splash (session_dialog);
3331 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
3333 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3337 char illegal = Session::session_name_is_legal(session_name);
3340 pop_back_splash (session_dialog);
3341 MessageDialog msg (session_dialog, string_compose(_("To ensure compatibility with various systems\n"
3342 "session names may not contain a '%1' character"), illegal));
3344 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3348 _session_is_new = true;
3351 if (likely_new && template_name.empty()) {
3353 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3357 ret = load_session (session_path, session_name, template_name);
3360 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
3364 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
3365 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
3369 /* clear this to avoid endless attempts to load the
3373 ARDOUR_COMMAND_LINE::session_name = "";
3377 _session_dialog = NULL;
3383 ARDOUR_UI::close_session()
3385 if (!check_audioengine (_main_window)) {
3389 if (unload_session (true)) {
3393 ARDOUR_COMMAND_LINE::session_name = "";
3395 if (get_session_parameters (true, false)) {
3398 if (splash && splash->is_visible()) {
3399 // in 1 second, hide the splash screen
3400 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
3404 /** @param snap_name Snapshot name (without .ardour suffix).
3405 * @return -2 if the load failed because we are not connected to the AudioEngine.
3408 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
3410 Session *new_session;
3415 unload_status = unload_session ();
3417 if (unload_status < 0) {
3419 } else if (unload_status > 0) {
3425 session_loaded = false;
3427 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
3430 new_session = new Session (*AudioEngine::instance(), path, snap_name, 0, mix_template);
3433 /* this one is special */
3435 catch (AudioEngine::PortRegistrationFailure& err) {
3437 MessageDialog msg (err.what(),
3440 Gtk::BUTTONS_CLOSE);
3442 msg.set_title (_("Port Registration Error"));
3443 msg.set_secondary_text (_("Click the Close button to try again."));
3444 msg.set_position (Gtk::WIN_POS_CENTER);
3445 pop_back_splash (msg);
3448 int response = msg.run ();
3453 case RESPONSE_CANCEL:
3460 catch (SessionException e) {
3461 MessageDialog msg (string_compose(
3462 _("Session \"%1 (snapshot %2)\" did not load successfully: %3"),
3463 path, snap_name, e.what()),
3468 msg.set_title (_("Loading Error"));
3469 msg.set_position (Gtk::WIN_POS_CENTER);
3470 pop_back_splash (msg);
3482 MessageDialog msg (string_compose(
3483 _("Session \"%1 (snapshot %2)\" did not load successfully"),
3489 msg.set_title (_("Loading Error"));
3490 msg.set_position (Gtk::WIN_POS_CENTER);
3491 pop_back_splash (msg);
3503 list<string> const u = new_session->unknown_processors ();
3505 MissingPluginDialog d (_session, u);
3510 if (!new_session->writable()) {
3511 MessageDialog msg (_("This session has been opened in read-only mode.\n\nYou will not be able to record or save."),
3516 msg.set_title (_("Read-only Session"));
3517 msg.set_position (Gtk::WIN_POS_CENTER);
3518 pop_back_splash (msg);
3525 /* Now the session been created, add the transport controls */
3526 new_session->add_controllable(roll_controllable);
3527 new_session->add_controllable(stop_controllable);
3528 new_session->add_controllable(goto_start_controllable);
3529 new_session->add_controllable(goto_end_controllable);
3530 new_session->add_controllable(auto_loop_controllable);
3531 new_session->add_controllable(play_selection_controllable);
3532 new_session->add_controllable(rec_controllable);
3534 set_session (new_session);
3536 session_loaded = true;
3539 _session->set_clean ();
3542 #ifdef WINDOWS_VST_SUPPORT
3543 fst_stop_threading();
3547 Timers::TimerSuspender t;
3551 #ifdef WINDOWS_VST_SUPPORT
3552 fst_start_threading();
3561 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
3563 Session *new_session;
3566 session_loaded = false;
3567 x = unload_session ();
3575 _session_is_new = true;
3578 new_session = new Session (*AudioEngine::instance(), path, snap_name, &bus_profile);
3581 catch (SessionException e) {
3583 MessageDialog msg (string_compose(_("Could not create session in \"%1\": %2"), path, e.what()));
3584 msg.set_title (_("Loading Error"));
3585 msg.set_position (Gtk::WIN_POS_CENTER);
3586 pop_back_splash (msg);
3592 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
3593 msg.set_title (_("Loading Error"));
3594 msg.set_position (Gtk::WIN_POS_CENTER);
3595 pop_back_splash (msg);
3600 /* Give the new session the default GUI state, if such things exist */
3603 n = Config->instant_xml (X_("Editor"));
3605 n->remove_nodes_and_delete ("Selection"); // no not apply selection to new sessions.
3606 new_session->add_instant_xml (*n, false);
3608 n = Config->instant_xml (X_("Mixer"));
3610 new_session->add_instant_xml (*n, false);
3613 n = Config->instant_xml (X_("Preferences"));
3615 new_session->add_instant_xml (*n, false);
3618 /* Put the playhead at 0 and scroll fully left */
3619 n = new_session->instant_xml (X_("Editor"));
3621 n->add_property (X_("playhead"), X_("0"));
3622 n->add_property (X_("left-frame"), X_("0"));
3625 set_session (new_session);
3627 session_loaded = true;
3629 new_session->save_state(new_session->name());
3635 ARDOUR_UI::launch_chat ()
3637 MessageDialog dialog(_("<b>Just ask and wait for an answer.\nIt may take from minutes to hours.</b>"), true);
3639 dialog.set_title (_("About the Chat"));
3640 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."));
3642 switch (dialog.run()) {
3645 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
3646 #elif defined PLATFORM_WINDOWS
3647 open_uri("http://webchat.freenode.net/?channels=ardour-windows");
3649 open_uri("http://webchat.freenode.net/?channels=ardour");
3658 ARDOUR_UI::launch_manual ()
3660 PBD::open_uri (Config->get_tutorial_manual_url());
3664 ARDOUR_UI::launch_reference ()
3666 PBD::open_uri (Config->get_reference_manual_url());
3670 ARDOUR_UI::launch_tracker ()
3672 PBD::open_uri ("http://tracker.ardour.org");
3676 ARDOUR_UI::launch_subscribe ()
3678 PBD::open_uri ("https://community.ardour.org/s/subscribe");
3682 ARDOUR_UI::launch_cheat_sheet ()
3685 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheat_sheet_osx.pdf");
3687 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheatsheet.pdf");
3692 ARDOUR_UI::launch_website ()
3694 PBD::open_uri ("http://ardour.org");
3698 ARDOUR_UI::launch_website_dev ()
3700 PBD::open_uri ("http://ardour.org/development.html");
3704 ARDOUR_UI::launch_forums ()
3706 PBD::open_uri ("https://community.ardour.org/forums");
3710 ARDOUR_UI::launch_howto_report ()
3712 PBD::open_uri ("http://ardour.org/reporting_bugs");
3716 ARDOUR_UI::loading_message (const std::string& msg)
3718 if (ARDOUR_COMMAND_LINE::no_splash) {
3726 splash->message (msg);
3730 ARDOUR_UI::show_splash ()
3734 splash = new Splash;
3744 ARDOUR_UI::hide_splash ()
3751 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title, const bool msg_delete)
3755 removed = rep.paths.size();
3758 MessageDialog msgd (_main_window,
3759 _("No files were ready for clean-up"),
3763 msgd.set_title (_("Clean-up"));
3764 msgd.set_secondary_text (_("If this seems suprising, \n\
3765 check for any existing snapshots.\n\
3766 These may still include regions that\n\
3767 require some unused files to continue to exist."));
3773 ArdourDialog results (_("Clean-up"), true, false);
3775 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
3776 CleanupResultsModelColumns() {
3780 Gtk::TreeModelColumn<std::string> visible_name;
3781 Gtk::TreeModelColumn<std::string> fullpath;
3785 CleanupResultsModelColumns results_columns;
3786 Glib::RefPtr<Gtk::ListStore> results_model;
3787 Gtk::TreeView results_display;
3789 results_model = ListStore::create (results_columns);
3790 results_display.set_model (results_model);
3791 results_display.append_column (list_title, results_columns.visible_name);
3793 results_display.set_name ("CleanupResultsList");
3794 results_display.set_headers_visible (true);
3795 results_display.set_headers_clickable (false);
3796 results_display.set_reorderable (false);
3798 Gtk::ScrolledWindow list_scroller;
3801 Gtk::HBox dhbox; // the hbox for the image and text
3802 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
3803 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
3805 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
3807 const string dead_directory = _session->session_directory().dead_path();
3810 %1 - number of files removed
3811 %2 - location of "dead"
3812 %3 - size of files affected
3813 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
3816 const char* bprefix;
3817 double space_adjusted = 0;
3819 if (rep.space < 1000) {
3821 space_adjusted = rep.space;
3822 } else if (rep.space < 1000000) {
3823 bprefix = _("kilo");
3824 space_adjusted = floorf((float)rep.space / 1000.0);
3825 } else if (rep.space < 1000000 * 1000) {
3826 bprefix = _("mega");
3827 space_adjusted = floorf((float)rep.space / (1000.0 * 1000.0));
3829 bprefix = _("giga");
3830 space_adjusted = floorf((float)rep.space / (1000.0 * 1000 * 1000.0));
3834 txt.set_markup (string_compose (P_("\
3835 The following file was deleted from %2,\n\
3836 releasing %3 %4bytes of disk space", "\
3837 The following %1 files were deleted from %2,\n\
3838 releasing %3 %4bytes of disk space", removed),
3839 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3841 txt.set_markup (string_compose (P_("\
3842 The following file was not in use and \n\
3843 has been moved to: %2\n\n\
3844 After a restart of %5\n\n\
3845 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3846 will release an additional %3 %4bytes of disk space.\n", "\
3847 The following %1 files were not in use and \n\
3848 have been moved to: %2\n\n\
3849 After a restart of %5\n\n\
3850 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3851 will release an additional %3 %4bytes of disk space.\n", removed),
3852 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3855 dhbox.pack_start (*dimage, true, false, 5);
3856 dhbox.pack_start (txt, true, false, 5);
3858 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
3859 TreeModel::Row row = *(results_model->append());
3860 row[results_columns.visible_name] = *i;
3861 row[results_columns.fullpath] = *i;
3864 list_scroller.add (results_display);
3865 list_scroller.set_size_request (-1, 150);
3866 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
3868 dvbox.pack_start (dhbox, true, false, 5);
3869 dvbox.pack_start (list_scroller, true, false, 5);
3870 ddhbox.pack_start (dvbox, true, false, 5);
3872 results.get_vbox()->pack_start (ddhbox, true, false, 5);
3873 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
3874 results.set_default_response (RESPONSE_CLOSE);
3875 results.set_position (Gtk::WIN_POS_MOUSE);
3877 results_display.show();
3878 list_scroller.show();
3885 //results.get_vbox()->show();
3886 results.set_resizable (false);
3893 ARDOUR_UI::cleanup ()
3895 if (_session == 0) {
3896 /* shouldn't happen: menu item is insensitive */
3901 MessageDialog checker (_("Are you sure you want to clean-up?"),
3903 Gtk::MESSAGE_QUESTION,
3906 checker.set_title (_("Clean-up"));
3908 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
3909 ALL undo/redo information will be lost if you clean-up.\n\
3910 Clean-up will move all unused files to a \"dead\" location."));
3912 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3913 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
3914 checker.set_default_response (RESPONSE_CANCEL);
3916 checker.set_name (_("CleanupDialog"));
3917 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3918 checker.set_position (Gtk::WIN_POS_MOUSE);
3920 switch (checker.run()) {
3921 case RESPONSE_ACCEPT:
3927 ARDOUR::CleanupReport rep;
3929 editor->prepare_for_cleanup ();
3931 /* do not allow flush until a session is reloaded */
3933 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3935 act->set_sensitive (false);
3938 if (_session->cleanup_sources (rep)) {
3939 editor->finish_cleanup ();
3943 editor->finish_cleanup ();
3946 display_cleanup_results (rep, _("Cleaned Files"), false);
3950 ARDOUR_UI::flush_trash ()
3952 if (_session == 0) {
3953 /* shouldn't happen: menu item is insensitive */
3957 ARDOUR::CleanupReport rep;
3959 if (_session->cleanup_trash_sources (rep)) {
3963 display_cleanup_results (rep, _("deleted file"), true);
3967 ARDOUR_UI::cleanup_peakfiles ()
3969 if (_session == 0) {
3970 /* shouldn't happen: menu item is insensitive */
3974 if (! _session->can_cleanup_peakfiles ()) {
3978 // get all region-views in this session
3980 TrackViewList empty;
3982 editor->get_regions_after(rs, (framepos_t) 0, empty);
3983 std::list<RegionView*> views = rs.by_layer();
3985 // remove displayed audio-region-views waveforms
3986 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
3987 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
3988 if (!arv) { continue ; }
3989 arv->delete_waves();
3992 // cleanup peak files:
3993 // - stop pending peakfile threads
3994 // - close peakfiles if any
3995 // - remove peak dir in session
3996 // - setup peakfiles (background thread)
3997 _session->cleanup_peakfiles ();
3999 // re-add waves to ARV
4000 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
4001 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
4002 if (!arv) { continue ; }
4003 arv->create_waves();
4007 PresentationInfo::order_t
4008 ARDOUR_UI::translate_order (RouteDialogs::InsertAt place)
4010 if (editor->get_selection().tracks.empty()) {
4011 return PresentationInfo::max_order;
4014 PresentationInfo::order_t order_hint = PresentationInfo::max_order;
4017 we want the new routes to have their order keys set starting from
4018 the highest order key in the selection + 1 (if available).
4021 if (place == RouteDialogs::AfterSelection) {
4022 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.back());
4024 order_hint = rtav->route()->presentation_info().order();
4027 } else if (place == RouteDialogs::BeforeSelection) {
4028 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.front());
4030 order_hint = rtav->route()->presentation_info().order();
4032 } else if (place == RouteDialogs::First) {
4035 /* leave order_hint at max_order */
4042 ARDOUR_UI::start_duplicate_routes ()
4044 if (!duplicate_routes_dialog) {
4045 duplicate_routes_dialog = new DuplicateRouteDialog;
4048 if (duplicate_routes_dialog->restart (_session)) {
4052 duplicate_routes_dialog->present ();
4056 ARDOUR_UI::add_route ()
4058 if (!add_route_dialog.get (false)) {
4059 add_route_dialog->signal_response().connect (sigc::mem_fun (*this, &ARDOUR_UI::add_route_dialog_finished));
4066 if (add_route_dialog->is_visible()) {
4067 /* we're already doing this */
4071 add_route_dialog->set_position (WIN_POS_MOUSE);
4072 add_route_dialog->present();
4076 ARDOUR_UI::add_route_dialog_finished (int r)
4080 add_route_dialog->hide();
4083 case RESPONSE_ACCEPT:
4090 if ((count = add_route_dialog->count()) <= 0) {
4094 PresentationInfo::order_t order = translate_order (add_route_dialog->insert_at());
4095 string template_path = add_route_dialog->track_template();
4096 DisplaySuspender ds;
4098 if (!template_path.empty()) {
4099 if (add_route_dialog->name_template_is_default()) {
4100 _session->new_route_from_template (count, order, template_path, string());
4102 _session->new_route_from_template (count, order, template_path, add_route_dialog->name_template());
4107 ChanCount input_chan= add_route_dialog->channels ();
4108 ChanCount output_chan;
4109 string name_template = add_route_dialog->name_template ();
4110 PluginInfoPtr instrument = add_route_dialog->requested_instrument ();
4111 RouteGroup* route_group = add_route_dialog->route_group ();
4112 AutoConnectOption oac = Config->get_output_auto_connect();
4113 bool strict_io = add_route_dialog->use_strict_io ();
4115 if (oac & AutoConnectMaster) {
4116 output_chan.set (DataType::AUDIO, (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan.n_audio()));
4117 output_chan.set (DataType::MIDI, 0);
4119 output_chan = input_chan;
4122 /* XXX do something with name template */
4124 switch (add_route_dialog->type_wanted()) {
4125 case AddRouteDialog::AudioTrack:
4126 session_add_audio_track (input_chan.n_audio(), output_chan.n_audio(), add_route_dialog->mode(), route_group, count, name_template, strict_io, order);
4128 case AddRouteDialog::MidiTrack:
4129 session_add_midi_track (route_group, count, name_template, strict_io, instrument, 0, order);
4131 case AddRouteDialog::MixedTrack:
4132 session_add_mixed_track (input_chan, output_chan, route_group, count, name_template, strict_io, instrument, 0, order);
4134 case AddRouteDialog::AudioBus:
4135 session_add_audio_bus (input_chan.n_audio(), output_chan.n_audio(), route_group, count, name_template, strict_io, order);
4137 case AddRouteDialog::MidiBus:
4138 session_add_midi_bus (route_group, count, name_template, strict_io, instrument, 0, order);
4140 case AddRouteDialog::VCAMaster:
4141 session_add_vca (name_template, count);
4147 ARDOUR_UI::add_lua_script ()
4153 LuaScriptInfoPtr spi;
4154 ScriptSelector ss ("Add Lua Session Script", LuaScriptInfo::Session);
4155 switch (ss.run ()) {
4156 case Gtk::RESPONSE_ACCEPT:
4164 std::string script = "";
4167 script = Glib::file_get_contents (spi->path);
4168 } catch (Glib::FileError e) {
4169 string msg = string_compose (_("Cannot read session script '%1': %2"), spi->path, e.what());
4170 MessageDialog am (msg);
4175 LuaScriptParamList lsp = LuaScriptParams::script_params (spi, "sess_params");
4176 std::vector<std::string> reg = _session->registered_lua_functions ();
4178 ScriptParameterDialog spd (_("Set Script Parameters"), spi, reg, lsp);
4179 switch (spd.run ()) {
4180 case Gtk::RESPONSE_ACCEPT:
4187 _session->register_lua_function (spd.name(), script, lsp);
4188 } catch (luabridge::LuaException const& e) {
4189 string msg = string_compose (_("Session script '%1' instantiation failed: %2"), spd.name(), e.what ());
4190 MessageDialog am (msg);
4192 } catch (SessionException e) {
4193 string msg = string_compose (_("Loading Session script '%1' failed: %2"), spd.name(), e.what ());
4194 MessageDialog am (msg);
4200 ARDOUR_UI::remove_lua_script ()
4205 if (_session->registered_lua_function_count () == 0) {
4206 string msg = _("There are no active Lua session scripts present in this session.");
4207 MessageDialog am (msg);
4212 std::vector<std::string> reg = _session->registered_lua_functions ();
4213 SessionScriptManager sm ("Remove Lua Session Script", reg);
4214 switch (sm.run ()) {
4215 case Gtk::RESPONSE_ACCEPT:
4221 _session->unregister_lua_function (sm.name());
4222 } catch (luabridge::LuaException const& e) {
4223 string msg = string_compose (_("Session script '%1' removal failed: %2"), sm.name(), e.what ());
4224 MessageDialog am (msg);
4230 ARDOUR_UI::stop_video_server (bool ask_confirm)
4232 if (!video_server_process && ask_confirm) {
4233 warning << string_compose (_("Video-Server was not launched by %1. The request to stop it is ignored."), PROGRAM_NAME) << endmsg;
4235 if (video_server_process) {
4237 ArdourDialog confirm (_("Stop Video-Server"), true);
4238 Label m (_("Do you really want to stop the Video Server?"));
4239 confirm.get_vbox()->pack_start (m, true, true);
4240 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
4241 confirm.add_button (_("Yes, Stop It"), Gtk::RESPONSE_ACCEPT);
4242 confirm.show_all ();
4243 if (confirm.run() == RESPONSE_CANCEL) {
4247 delete video_server_process;
4248 video_server_process =0;
4253 ARDOUR_UI::start_video_server_menu (Gtk::Window* float_window)
4255 ARDOUR_UI::start_video_server( float_window, true);
4259 ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg)
4265 if (ARDOUR_UI::instance()->video_timeline->check_server()) {
4266 if (video_server_process) {
4267 popup_error(_("The Video Server is already started."));
4269 popup_error(_("An external Video Server is configured and can be reached. Not starting a new instance."));
4275 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4277 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4279 VideoServerDialog *video_server_dialog = new VideoServerDialog (_session);
4281 video_server_dialog->set_transient_for (*float_window);
4284 if (!Config->get_show_video_server_dialog() && firsttime < 2) {
4285 video_server_dialog->hide();
4287 ResponseType r = (ResponseType) video_server_dialog->run ();
4288 video_server_dialog->hide();
4289 if (r != RESPONSE_ACCEPT) { return false; }
4290 if (video_server_dialog->show_again()) {
4291 Config->set_show_video_server_dialog(false);
4295 std::string icsd_exec = video_server_dialog->get_exec_path();
4296 std::string icsd_docroot = video_server_dialog->get_docroot();
4297 if (icsd_docroot.empty()) {
4298 #ifndef PLATFORM_WINDOWS
4299 icsd_docroot = X_("/");
4301 icsd_docroot = X_("C:\\");
4306 if (g_lstat (icsd_docroot.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode)) {
4307 warning << _("Specified docroot is not an existing directory.") << endmsg;
4310 #ifndef PLATFORM_WINDOWS
4311 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4312 || (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0 ) {
4313 warning << _("Given Video Server is not an executable file.") << endmsg;
4317 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4318 || (sb.st_mode & (S_IXUSR)) == 0 ) {
4319 warning << _("Given Video Server is not an executable file.") << endmsg;
4325 argp=(char**) calloc(9,sizeof(char*));
4326 argp[0] = strdup(icsd_exec.c_str());
4327 argp[1] = strdup("-P");
4328 argp[2] = (char*) calloc(16,sizeof(char)); snprintf(argp[2], 16, "%s", video_server_dialog->get_listenaddr().c_str());
4329 argp[3] = strdup("-p");
4330 argp[4] = (char*) calloc(6,sizeof(char)); snprintf(argp[4], 6, "%i", video_server_dialog->get_listenport());
4331 argp[5] = strdup("-C");
4332 argp[6] = (char*) calloc(6,sizeof(char)); snprintf(argp[6], 6, "%i", video_server_dialog->get_cachesize());
4333 argp[7] = strdup(icsd_docroot.c_str());
4335 stop_video_server();
4337 if (icsd_docroot == X_("/") || icsd_docroot == X_("C:\\")) {
4338 Config->set_video_advanced_setup(false);
4340 std::ostringstream osstream;
4341 osstream << "http://127.0.0.1:" << video_server_dialog->get_listenport() << "/";
4342 Config->set_video_server_url(osstream.str());
4343 Config->set_video_server_docroot(icsd_docroot);
4344 Config->set_video_advanced_setup(true);
4347 if (video_server_process) {
4348 delete video_server_process;
4351 video_server_process = new ARDOUR::SystemExec(icsd_exec, argp);
4352 if (video_server_process->start()) {
4353 warning << _("Cannot launch the video-server") << endmsg;
4356 int timeout = 120; // 6 sec
4357 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4358 Glib::usleep (50000);
4360 if (--timeout <= 0 || !video_server_process->is_running()) break;
4363 warning << _("Video-server was started but does not respond to requests...") << endmsg;
4365 if (!ARDOUR_UI::instance()->video_timeline->check_server_docroot()) {
4366 delete video_server_process;
4367 video_server_process = 0;
4375 ARDOUR_UI::add_video (Gtk::Window* float_window)
4381 if (!start_video_server(float_window, false)) {
4382 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4387 add_video_dialog->set_transient_for (*float_window);
4390 if (add_video_dialog->is_visible()) {
4391 /* we're already doing this */
4395 ResponseType r = (ResponseType) add_video_dialog->run ();
4396 add_video_dialog->hide();
4397 if (r != RESPONSE_ACCEPT) { return; }
4399 bool local_file, orig_local_file;
4400 std::string path = add_video_dialog->file_name(local_file);
4402 std::string orig_path = path;
4403 orig_local_file = local_file;
4405 bool auto_set_session_fps = add_video_dialog->auto_set_session_fps();
4407 if (local_file && !Glib::file_test(path, Glib::FILE_TEST_EXISTS)) {
4408 warning << string_compose(_("could not open %1"), path) << endmsg;
4411 if (!local_file && path.length() == 0) {
4412 warning << _("no video-file selected") << endmsg;
4416 std::string audio_from_video;
4417 bool detect_ltc = false;
4419 switch (add_video_dialog->import_option()) {
4420 case VTL_IMPORT_TRANSCODE:
4422 TranscodeVideoDialog *transcode_video_dialog;
4423 transcode_video_dialog = new TranscodeVideoDialog (_session, path);
4424 ResponseType r = (ResponseType) transcode_video_dialog->run ();
4425 transcode_video_dialog->hide();
4426 if (r != RESPONSE_ACCEPT) {
4427 delete transcode_video_dialog;
4431 audio_from_video = transcode_video_dialog->get_audiofile();
4433 if (!audio_from_video.empty() && transcode_video_dialog->detect_ltc()) {
4436 else if (!audio_from_video.empty()) {
4437 editor->embed_audio_from_video(
4439 video_timeline->get_offset(),
4440 (transcode_video_dialog->import_option() != VTL_IMPORT_NO_VIDEO)
4443 switch (transcode_video_dialog->import_option()) {
4444 case VTL_IMPORT_TRANSCODED:
4445 path = transcode_video_dialog->get_filename();
4448 case VTL_IMPORT_REFERENCE:
4451 delete transcode_video_dialog;
4454 delete transcode_video_dialog;
4458 case VTL_IMPORT_NONE:
4462 /* strip _session->session_directory().video_path() from video file if possible */
4463 if (local_file && !path.compare(0, _session->session_directory().video_path().size(), _session->session_directory().video_path())) {
4464 path=path.substr(_session->session_directory().video_path().size());
4465 if (path.at(0) == G_DIR_SEPARATOR) {
4466 path=path.substr(1);
4470 video_timeline->set_update_session_fps(auto_set_session_fps);
4472 if (video_timeline->video_file_info(path, local_file)) {
4473 XMLNode* node = new XMLNode(X_("Videotimeline"));
4474 node->add_property (X_("Filename"), path);
4475 node->add_property (X_("AutoFPS"), auto_set_session_fps?X_("1"):X_("0"));
4476 node->add_property (X_("LocalFile"), local_file?X_("1"):X_("0"));
4477 if (orig_local_file) {
4478 node->add_property (X_("OriginalVideoFile"), orig_path);
4480 node->remove_property (X_("OriginalVideoFile"));
4482 _session->add_extra_xml (*node);
4483 _session->set_dirty ();
4485 if (!audio_from_video.empty() && detect_ltc) {
4486 std::vector<LTCFileReader::LTCMap> ltc_seq;
4489 /* TODO ask user about TV standard (LTC alignment if any) */
4490 LTCFileReader ltcr (audio_from_video, video_timeline->get_video_file_fps());
4491 /* TODO ASK user which channel: 0 .. ltcr->channels() - 1 */
4493 ltc_seq = ltcr.read_ltc (/*channel*/ 0, /*max LTC frames to decode*/ 15);
4495 /* TODO seek near end of file, and read LTC until end.
4496 * if it fails to find any LTC frames, scan complete file
4498 * calculate drift of LTC compared to video-duration,
4499 * ask user for reference (timecode from start/mid/end)
4502 // LTCFileReader will have written error messages
4505 ::g_unlink(audio_from_video.c_str());
4507 if (ltc_seq.size() == 0) {
4508 PBD::error << _("No LTC detected, video will not be aligned.") << endmsg;
4510 /* the very first TC in the file is somteimes not aligned properly */
4511 int i = ltc_seq.size() -1;
4512 ARDOUR::frameoffset_t video_start_offset =
4513 _session->nominal_frame_rate() * (ltc_seq[i].timecode_sec - ltc_seq[i].framepos_sec);
4514 PBD::info << string_compose (_("Align video-start to %1 [samples]"), video_start_offset) << endmsg;
4515 video_timeline->set_offset(video_start_offset);
4519 _session->maybe_update_session_range(
4520 std::max(video_timeline->get_offset(), (ARDOUR::frameoffset_t) 0),
4521 std::max(video_timeline->get_offset() + video_timeline->get_duration(), (ARDOUR::frameoffset_t) 0));
4524 if (add_video_dialog->launch_xjadeo() && local_file) {
4525 editor->set_xjadeo_sensitive(true);
4526 editor->toggle_xjadeo_proc(1);
4528 editor->toggle_xjadeo_proc(0);
4530 editor->toggle_ruler_video(true);
4535 ARDOUR_UI::remove_video ()
4537 video_timeline->close_session();
4538 editor->toggle_ruler_video(false);
4541 video_timeline->set_offset_locked(false);
4542 video_timeline->set_offset(0);
4544 /* delete session state */
4545 XMLNode* node = new XMLNode(X_("Videotimeline"));
4546 _session->add_extra_xml(*node);
4547 node = new XMLNode(X_("Videomonitor"));
4548 _session->add_extra_xml(*node);
4549 node = new XMLNode(X_("Videoexport"));
4550 _session->add_extra_xml(*node);
4551 stop_video_server();
4555 ARDOUR_UI::flush_videotimeline_cache (bool localcacheonly)
4557 if (localcacheonly) {
4558 video_timeline->vmon_update();
4560 video_timeline->flush_cache();
4562 editor->queue_visual_videotimeline_update();
4566 ARDOUR_UI::export_video (bool range)
4568 if (ARDOUR::Config->get_show_video_export_info()) {
4569 ExportVideoInfobox infobox (_session);
4570 Gtk::ResponseType rv = (Gtk::ResponseType) infobox.run();
4571 if (infobox.show_again()) {
4572 ARDOUR::Config->set_show_video_export_info(false);
4575 case GTK_RESPONSE_YES:
4576 PBD::open_uri (ARDOUR::Config->get_reference_manual_url() + "/video-timeline/operations/#export");
4582 export_video_dialog->set_session (_session);
4583 export_video_dialog->apply_state(editor->get_selection().time, range);
4584 export_video_dialog->run ();
4585 export_video_dialog->hide ();
4589 ARDOUR_UI::preferences_settings () const
4594 node = _session->instant_xml(X_("Preferences"));
4596 node = Config->instant_xml(X_("Preferences"));
4600 node = new XMLNode (X_("Preferences"));
4607 ARDOUR_UI::mixer_settings () const
4612 node = _session->instant_xml(X_("Mixer"));
4614 node = Config->instant_xml(X_("Mixer"));
4618 node = new XMLNode (X_("Mixer"));
4625 ARDOUR_UI::main_window_settings () const
4630 node = _session->instant_xml(X_("Main"));
4632 node = Config->instant_xml(X_("Main"));
4636 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4637 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4642 node = new XMLNode (X_("Main"));
4649 ARDOUR_UI::editor_settings () const
4654 node = _session->instant_xml(X_("Editor"));
4656 node = Config->instant_xml(X_("Editor"));
4660 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4661 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4666 node = new XMLNode (X_("Editor"));
4673 ARDOUR_UI::keyboard_settings () const
4677 node = Config->extra_xml(X_("Keyboard"));
4680 node = new XMLNode (X_("Keyboard"));
4687 ARDOUR_UI::create_xrun_marker (framepos_t where)
4690 Location *location = new Location (*_session, where, where, _("xrun"), Location::IsMark);
4691 _session->locations()->add (location);
4696 ARDOUR_UI::halt_on_xrun_message ()
4698 cerr << "HALT on xrun\n";
4699 MessageDialog msg (_main_window, _("Recording was stopped because your system could not keep up."));
4704 ARDOUR_UI::xrun_handler (framepos_t where)
4710 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
4712 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
4713 create_xrun_marker(where);
4716 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
4717 halt_on_xrun_message ();
4722 ARDOUR_UI::disk_overrun_handler ()
4724 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
4726 if (!have_disk_speed_dialog_displayed) {
4727 have_disk_speed_dialog_displayed = true;
4728 MessageDialog* msg = new MessageDialog (_main_window, string_compose (_("\
4729 The disk system on your computer\n\
4730 was not able to keep up with %1.\n\
4732 Specifically, it failed to write data to disk\n\
4733 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
4734 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4740 /* TODO: this is getting elaborate enough to warrant being split into a dedicated class */
4741 static MessageDialog *scan_dlg = NULL;
4742 static ProgressBar *scan_pbar = NULL;
4743 static HBox *scan_tbox = NULL;
4744 static Gtk::Button *scan_timeout_button;
4747 ARDOUR_UI::cancel_plugin_scan ()
4749 PluginManager::instance().cancel_plugin_scan();
4753 ARDOUR_UI::cancel_plugin_timeout ()
4755 PluginManager::instance().cancel_plugin_timeout();
4756 scan_timeout_button->set_sensitive (false);
4760 ARDOUR_UI::plugin_scan_timeout (int timeout)
4762 if (!scan_dlg || !scan_dlg->is_mapped() || !scan_pbar) {
4766 scan_pbar->set_sensitive (false);
4767 scan_timeout_button->set_sensitive (true);
4768 scan_pbar->set_fraction ((float) timeout / (float) Config->get_vst_scan_timeout());
4771 scan_pbar->set_sensitive (false);
4772 scan_timeout_button->set_sensitive (false);
4778 ARDOUR_UI::plugin_scan_dialog (std::string type, std::string plugin, bool can_cancel)
4780 if (type == X_("closeme") && !(scan_dlg && scan_dlg->is_mapped())) {
4784 const bool cancelled = PluginManager::instance().cancelled();
4785 if (type != X_("closeme") && (!UIConfiguration::instance().get_show_plugin_scan_window()) && !_initial_verbose_plugin_scan) {
4786 if (cancelled && scan_dlg->is_mapped()) {
4791 if (cancelled || !can_cancel) {
4796 static Gtk::Button *cancel_button;
4798 scan_dlg = new MessageDialog("", false, MESSAGE_INFO, BUTTONS_NONE); // TODO manage
4799 VBox* vbox = scan_dlg->get_vbox();
4800 vbox->set_size_request(400,-1);
4801 scan_dlg->set_title (_("Scanning for plugins"));
4803 cancel_button = manage(new Gtk::Button(_("Cancel plugin scan")));
4804 cancel_button->set_name ("EditorGTKButton");
4805 cancel_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_scan) );
4806 cancel_button->show();
4808 scan_dlg->get_vbox()->pack_start ( *cancel_button, PACK_SHRINK);
4810 scan_tbox = manage( new HBox() );
4812 scan_timeout_button = manage(new Gtk::Button(_("Stop Timeout")));
4813 scan_timeout_button->set_name ("EditorGTKButton");
4814 scan_timeout_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_timeout) );
4815 scan_timeout_button->show();
4817 scan_pbar = manage(new ProgressBar());
4818 scan_pbar->set_orientation(Gtk::PROGRESS_RIGHT_TO_LEFT);
4819 scan_pbar->set_text(_("Scan Timeout"));
4822 scan_tbox->pack_start (*scan_pbar, PACK_EXPAND_WIDGET, 4);
4823 scan_tbox->pack_start (*scan_timeout_button, PACK_SHRINK, 4);
4825 scan_dlg->get_vbox()->pack_start (*scan_tbox, PACK_SHRINK, 4);
4828 assert(scan_dlg && scan_tbox && cancel_button);
4830 if (type == X_("closeme")) {
4834 scan_dlg->set_message(type + ": " + Glib::path_get_basename(plugin));
4837 if (!can_cancel || !cancelled) {
4838 scan_timeout_button->set_sensitive(false);
4840 cancel_button->set_sensitive(can_cancel && !cancelled);
4846 ARDOUR_UI::gui_idle_handler ()
4849 /* due to idle calls, gtk_events_pending() may always return true */
4850 while (gtk_events_pending() && --timeout) {
4851 gtk_main_iteration ();
4856 ARDOUR_UI::disk_underrun_handler ()
4858 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
4860 if (!have_disk_speed_dialog_displayed) {
4861 have_disk_speed_dialog_displayed = true;
4862 MessageDialog* msg = new MessageDialog (
4863 _main_window, string_compose (_("The disk system on your computer\n\
4864 was not able to keep up with %1.\n\
4866 Specifically, it failed to read data from disk\n\
4867 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
4868 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4874 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
4876 have_disk_speed_dialog_displayed = false;
4881 ARDOUR_UI::session_dialog (std::string msg)
4883 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
4887 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
4894 ARDOUR_UI::pending_state_dialog ()
4896 HBox* hbox = manage (new HBox());
4897 Image* image = manage (new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG));
4898 ArdourDialog dialog (_("Crash Recovery"), true);
4899 Label message (string_compose (_("\
4900 This session appears to have been in the\n\
4901 middle of recording when %1 or\n\
4902 the computer was shutdown.\n\
4904 %1 can recover any captured audio for\n\
4905 you, or it can ignore it. Please decide\n\
4906 what you would like to do.\n"), PROGRAM_NAME));
4907 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4908 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4909 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4910 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4911 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
4912 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
4913 dialog.set_default_response (RESPONSE_ACCEPT);
4914 dialog.set_position (WIN_POS_CENTER);
4919 switch (dialog.run ()) {
4920 case RESPONSE_ACCEPT:
4928 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
4930 HBox* hbox = new HBox();
4931 Image* image = new Image (Stock::DIALOG_WARNING, ICON_SIZE_DIALOG);
4932 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
4933 Label message (string_compose (_("\
4934 This session was created with a sample rate of %1 Hz, but\n\
4935 %2 is currently running at %3 Hz. If you load this session,\n\
4936 audio may be played at the wrong sample rate.\n"), desired, PROGRAM_NAME, actual));
4938 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4939 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4940 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4941 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4942 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
4943 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
4944 dialog.set_default_response (RESPONSE_ACCEPT);
4945 dialog.set_position (WIN_POS_CENTER);
4950 switch (dialog.run()) {
4951 case RESPONSE_ACCEPT:
4961 ARDOUR_UI::sr_mismatch_message (framecnt_t desired, framecnt_t actual)
4963 MessageDialog msg (string_compose (_("\
4964 This session was created with a sample rate of %1 Hz, but\n\
4965 %2 is currently running at %3 Hz.\n\
4966 Audio will be recorded and played at the wrong sample rate.\n\
4967 Re-Configure the Audio Engine in\n\
4968 Menu > Window > Audio/Midi Setup"),
4969 desired, PROGRAM_NAME, actual),
4971 Gtk::MESSAGE_WARNING);
4976 ARDOUR_UI::use_config ()
4978 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
4980 set_transport_controllable_state (*node);
4985 ARDOUR_UI::update_transport_clocks (framepos_t pos)
4987 if (UIConfiguration::instance().get_primary_clock_delta_edit_cursor()) {
4988 primary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
4990 primary_clock->set (pos);
4993 if (UIConfiguration::instance().get_secondary_clock_delta_edit_cursor()) {
4994 secondary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
4996 secondary_clock->set (pos);
4999 if (big_clock_window) {
5000 big_clock->set (pos);
5002 ARDOUR_UI::instance()->video_timeline->manual_seek_video_monitor(pos);
5006 ARDOUR_UI::step_edit_status_change (bool yn)
5008 // XXX should really store pre-step edit status of things
5009 // we make insensitive
5012 rec_button.set_active_state (Gtkmm2ext::ImplicitActive);
5013 rec_button.set_sensitive (false);
5015 rec_button.unset_active_state ();;
5016 rec_button.set_sensitive (true);
5021 ARDOUR_UI::record_state_changed ()
5023 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
5026 /* why bother - the clock isn't visible */
5030 ActionManager::set_sensitive (ActionManager::rec_sensitive_actions, !_session->actively_recording());
5032 if (big_clock_window) {
5033 if (_session->record_status () == Session::Recording && _session->have_rec_enabled_track ()) {
5034 big_clock->set_active (true);
5036 big_clock->set_active (false);
5043 ARDOUR_UI::first_idle ()
5046 _session->allow_auto_play (true);
5050 editor->first_idle();
5053 Keyboard::set_can_save_keybindings (true);
5058 ARDOUR_UI::store_clock_modes ()
5060 XMLNode* node = new XMLNode(X_("ClockModes"));
5062 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
5063 XMLNode* child = new XMLNode (X_("Clock"));
5065 child->add_property (X_("name"), (*x)->name());
5066 child->add_property (X_("mode"), enum_2_string ((*x)->mode()));
5067 child->add_property (X_("on"), ((*x)->off() ? X_("no") : X_("yes")));
5069 node->add_child_nocopy (*child);
5072 _session->add_extra_xml (*node);
5073 _session->set_dirty ();
5076 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
5077 : Controllable (name), ui (u), type(tp)
5083 ARDOUR_UI::TransportControllable::set_value (double val, PBD::Controllable::GroupControlDisposition /*group_override*/)
5086 /* do nothing: these are radio-style actions */
5090 const char *action = 0;
5094 action = X_("Roll");
5097 action = X_("Stop");
5100 action = X_("GotoStart");
5103 action = X_("GotoEnd");
5106 action = X_("Loop");
5109 action = X_("PlaySelection");
5112 action = X_("Record");
5122 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
5130 ARDOUR_UI::TransportControllable::get_value (void) const
5157 ARDOUR_UI::setup_profile ()
5159 if (gdk_screen_width() < 1200 || getenv ("ARDOUR_NARROW_SCREEN")) {
5160 Profile->set_small_screen ();
5163 if (g_getenv ("TRX")) {
5164 Profile->set_trx ();
5167 if (g_getenv ("MIXBUS")) {
5168 Profile->set_mixbus ();
5173 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
5175 MissingFileDialog dialog (s, str, type);
5180 int result = dialog.run ();
5187 return 1; // quit entire session load
5190 result = dialog.get_action ();
5196 ARDOUR_UI::ambiguous_file (std::string file, std::vector<std::string> hits)
5198 AmbiguousFileDialog dialog (file, hits);
5205 return dialog.get_which ();
5208 /** Allocate our thread-local buffers */
5210 ARDOUR_UI::get_process_buffers ()
5212 _process_thread->get_buffers ();
5215 /** Drop our thread-local buffers */
5217 ARDOUR_UI::drop_process_buffers ()
5219 _process_thread->drop_buffers ();
5223 ARDOUR_UI::feedback_detected ()
5225 _feedback_exists = true;
5229 ARDOUR_UI::successful_graph_sort ()
5231 _feedback_exists = false;
5235 ARDOUR_UI::midi_panic ()
5238 _session->midi_panic();
5243 ARDOUR_UI::session_format_mismatch (std::string xml_path, std::string backup_path)
5245 const char* start_big = "<span size=\"x-large\" weight=\"bold\">";
5246 const char* end_big = "</span>";
5247 const char* start_mono = "<tt>";
5248 const char* end_mono = "</tt>";
5250 MessageDialog msg (string_compose (_("%4This is a session from an older version of %3%5\n\n"
5251 "%3 has copied the old session file\n\n%6%1%7\n\nto\n\n%6%2%7\n\n"
5252 "From now on, use the backup copy with older versions of %3"),
5253 xml_path, backup_path, PROGRAM_NAME,
5255 start_mono, end_mono), true);
5262 ARDOUR_UI::reset_peak_display ()
5264 if (!_session || !_session->master_out() || !editor_meter) return;
5265 editor_meter->clear_meters();
5266 editor_meter_max_peak = -INFINITY;
5267 editor_meter_peak_display.set_active_state ( Gtkmm2ext::Off );
5271 ARDOUR_UI::reset_group_peak_display (RouteGroup* group)
5273 if (!_session || !_session->master_out()) return;
5274 if (group == _session->master_out()->route_group()) {
5275 reset_peak_display ();
5280 ARDOUR_UI::reset_route_peak_display (Route* route)
5282 if (!_session || !_session->master_out()) return;
5283 if (_session->master_out().get() == route) {
5284 reset_peak_display ();
5289 ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate)
5291 audio_midi_setup->set_desired_sample_rate (desired_sample_rate);
5292 audio_midi_setup->set_position (WIN_POS_CENTER);
5294 if (Config->get_try_autostart_engine () || getenv ("TRY_AUTOSTART_ENGINE")) {
5295 audio_midi_setup->try_autostart ();
5296 if (ARDOUR::AudioEngine::instance()->running()) {
5302 int response = audio_midi_setup->run();
5304 case Gtk::RESPONSE_OK:
5305 if (!AudioEngine::instance()->running()) {
5319 ARDOUR_UI::transport_numpad_timeout ()
5321 _numpad_locate_happening = false;
5322 if (_numpad_timeout_connection.connected() )
5323 _numpad_timeout_connection.disconnect();
5328 ARDOUR_UI::transport_numpad_decimal ()
5330 _numpad_timeout_connection.disconnect();
5332 if (_numpad_locate_happening) {
5333 if (editor) editor->goto_nth_marker(_pending_locate_num - 1);
5334 _numpad_locate_happening = false;
5336 _pending_locate_num = 0;
5337 _numpad_locate_happening = true;
5338 _numpad_timeout_connection = Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::transport_numpad_timeout), 2*1000);
5343 ARDOUR_UI::transport_numpad_event (int num)
5345 if ( _numpad_locate_happening ) {
5346 _pending_locate_num = _pending_locate_num*10 + num;
5349 case 0: toggle_roll(false, false); break;
5350 case 1: transport_rewind(1); break;
5351 case 2: transport_forward(1); break;
5352 case 3: transport_record(true); break;
5353 case 4: toggle_session_auto_loop(); break;
5354 case 5: transport_record(false); toggle_session_auto_loop(); break;
5355 case 6: toggle_punch(); break;
5356 case 7: toggle_click(); break;
5357 case 8: toggle_auto_return(); break;
5358 case 9: toggle_follow_edits(); break;
5364 ARDOUR_UI::set_flat_buttons ()
5366 CairoWidget::set_flat_buttons( UIConfiguration::instance().get_flat_buttons() );
5370 ARDOUR_UI::audioengine_became_silent ()
5372 MessageDialog msg (string_compose (_("This is a free/demo copy of %1. It has just switched to silent mode."), PROGRAM_NAME),
5374 Gtk::MESSAGE_WARNING,
5378 msg.set_title (string_compose (_("%1 is now silent"), PROGRAM_NAME));
5380 Gtk::Label pay_label (string_compose (_("Please consider paying for a copy of %1 - you can pay whatever you want."), PROGRAM_NAME));
5381 Gtk::Label subscribe_label (_("Better yet become a subscriber - subscriptions start at US$1 per month."));
5382 Gtk::Button pay_button (_("Pay for a copy (via the web)"));
5383 Gtk::Button subscribe_button (_("Become a subscriber (via the web)"));
5384 Gtk::HBox pay_button_box;
5385 Gtk::HBox subscribe_button_box;
5387 pay_button_box.pack_start (pay_button, true, false);
5388 subscribe_button_box.pack_start (subscribe_button, true, false);
5390 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 */
5392 pay_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://ardour.org/download")));
5393 subscribe_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://community.ardour.org/s/subscribe")));
5395 msg.get_vbox()->pack_start (pay_label);
5396 msg.get_vbox()->pack_start (pay_button_box);
5397 msg.get_vbox()->pack_start (subscribe_label);
5398 msg.get_vbox()->pack_start (subscribe_button_box);
5400 msg.get_vbox()->show_all ();
5402 msg.add_button (_("Remain silent"), Gtk::RESPONSE_CANCEL);
5403 msg.add_button (_("Save and quit"), Gtk::RESPONSE_NO);
5404 msg.add_button (_("Give me more time"), Gtk::RESPONSE_YES);
5409 case Gtk::RESPONSE_YES:
5410 AudioEngine::instance()->reset_silence_countdown ();
5413 case Gtk::RESPONSE_NO:
5415 save_state_canfail ("");
5419 case Gtk::RESPONSE_CANCEL:
5421 /* don't reset, save session and exit */
5427 ARDOUR_UI::hide_application ()
5429 Application::instance ()-> hide ();
5433 ARDOUR_UI::setup_toplevel_window (Gtk::Window& window, const string& name, void* owner)
5435 /* icons, titles, WM stuff */
5437 static list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
5439 if (window_icons.empty()) {
5440 Glib::RefPtr<Gdk::Pixbuf> icon;
5441 if ((icon = ::get_icon (PROGRAM_NAME "-icon_16px"))) {
5442 window_icons.push_back (icon);
5444 if ((icon = ::get_icon (PROGRAM_NAME "-icon_22px"))) {
5445 window_icons.push_back (icon);
5447 if ((icon = ::get_icon (PROGRAM_NAME "-icon_32px"))) {
5448 window_icons.push_back (icon);
5450 if ((icon = ::get_icon (PROGRAM_NAME "-icon_48px"))) {
5451 window_icons.push_back (icon);
5455 if (!window_icons.empty()) {
5456 window.set_default_icon_list (window_icons);
5459 Gtkmm2ext::WindowTitle title (Glib::get_application_name());
5461 if (!name.empty()) {
5465 window.set_title (title.get_string());
5466 window.set_wmclass (string_compose (X_("%1_%1"), downcase (PROGRAM_NAME), downcase (name)), PROGRAM_NAME);
5468 window.set_flags (CAN_FOCUS);
5469 window.add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
5471 /* This is a hack to ensure that GTK-accelerators continue to
5472 * work. Once we switch over to entirely native bindings, this will be
5473 * unnecessary and should be removed
5475 window.add_accel_group (ActionManager::ui_manager->get_accel_group());
5477 window.signal_configure_event().connect (sigc::mem_fun (*this, &ARDOUR_UI::configure_handler));
5478 window.signal_window_state_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::tabbed_window_state_event_handler), owner));
5479 window.signal_key_press_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5480 window.signal_key_release_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5484 ARDOUR_UI::key_event_handler (GdkEventKey* ev, Gtk::Window* event_window)
5486 Gtkmm2ext::Bindings* bindings = 0;
5487 Gtk::Window* window = 0;
5489 /* until we get ardour bindings working, we are not handling key
5493 if (ev->type != GDK_KEY_PRESS) {
5497 if (event_window == &_main_window) {
5499 window = event_window;
5501 /* find current tab contents */
5503 Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page());
5505 /* see if it uses the ardour binding system */
5508 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(w->get_data ("ardour-bindings"));
5511 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("main window key event, bindings = %1, global = %2\n", bindings, &global_bindings));
5515 window = event_window;
5517 /* see if window uses ardour binding system */
5519 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(window->get_data ("ardour-bindings"));
5522 /* An empty binding set is treated as if it doesn't exist */
5524 if (bindings && bindings->empty()) {
5528 return key_press_focus_accelerator_handler (*window, ev, bindings);
5531 static Gtkmm2ext::Bindings*
5532 get_bindings_from_widget_heirarchy (GtkWidget* w)
5537 if ((p = g_object_get_data (G_OBJECT(w), "ardour-bindings")) != 0) {
5540 w = gtk_widget_get_parent (w);
5543 return reinterpret_cast<Gtkmm2ext::Bindings*> (p);
5547 ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev, Gtkmm2ext::Bindings* bindings)
5549 GtkWindow* win = window.gobj();
5550 GtkWidget* focus = gtk_window_get_focus (win);
5551 bool special_handling_of_unmodified_accelerators = false;
5552 const guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK));
5556 /* some widget has keyboard focus */
5558 if (GTK_IS_ENTRY(focus) || Keyboard::some_magic_widget_has_focus()) {
5560 /* A particular kind of focusable widget currently has keyboard
5561 * focus. All unmodified key events should go to that widget
5562 * first and not be used as an accelerator by default
5565 special_handling_of_unmodified_accelerators = true;
5569 Gtkmm2ext::Bindings* focus_bindings = get_bindings_from_widget_heirarchy (focus);
5570 if (focus_bindings) {
5571 bindings = focus_bindings;
5572 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Switch bindings based on focus widget, now using %1\n", bindings->name()));
5577 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",
5580 Gtkmm2ext::show_gdk_event_state (ev->state),
5581 special_handling_of_unmodified_accelerators,
5582 Keyboard::some_magic_widget_has_focus(),
5584 (focus ? gtk_widget_get_name (focus) : "no focus widget"),
5585 ((ev->state & mask) ? "yes" : "no"),
5586 window.get_title()));
5588 /* This exists to allow us to override the way GTK handles
5589 key events. The normal sequence is:
5591 a) event is delivered to a GtkWindow
5592 b) accelerators/mnemonics are activated
5593 c) if (b) didn't handle the event, propagate to
5594 the focus widget and/or focus chain
5596 The problem with this is that if the accelerators include
5597 keys without modifiers, such as the space bar or the
5598 letter "e", then pressing the key while typing into
5599 a text entry widget results in the accelerator being
5600 activated, instead of the desired letter appearing
5603 There is no good way of fixing this, but this
5604 represents a compromise. The idea is that
5605 key events involving modifiers (not Shift)
5606 get routed into the activation pathway first, then
5607 get propagated to the focus widget if necessary.
5609 If the key event doesn't involve modifiers,
5610 we deliver to the focus widget first, thus allowing
5611 it to get "normal text" without interference
5614 Of course, this can also be problematic: if there
5615 is a widget with focus, then it will swallow
5616 all "normal text" accelerators.
5620 if (!special_handling_of_unmodified_accelerators || (ev->state & mask)) {
5622 /* no special handling or there are modifiers in effect: accelerate first */
5624 DEBUG_TRACE (DEBUG::Accelerators, "\tactivate, then propagate\n");
5625 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tevent send-event:%1 time:%2 length:%3 name %7 string:%4 hardware_keycode:%5 group:%6\n",
5626 ev->send_event, ev->time, ev->length, ev->string, ev->hardware_keycode, ev->group, gdk_keyval_name (ev->keyval)));
5628 DEBUG_TRACE (DEBUG::Accelerators, "\tsending to window\n");
5629 KeyboardKey k (ev->state, ev->keyval);
5633 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tusing Ardour bindings %1 @ %2 for this event\n", bindings->name(), bindings));
5635 if (bindings->activate (k, Bindings::Press)) {
5636 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5641 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5643 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5644 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5648 DEBUG_TRACE (DEBUG::Accelerators, "\tnot accelerated, now propagate\n");
5650 if (gtk_window_propagate_key_event (win, ev)) {
5651 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate handled\n");
5657 /* no modifiers, propagate first */
5659 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate, then activate\n");
5661 if (gtk_window_propagate_key_event (win, ev)) {
5662 DEBUG_TRACE (DEBUG::Accelerators, "\thandled by propagate\n");
5666 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagation didn't handle, so activate\n");
5667 KeyboardKey k (ev->state, ev->keyval);
5671 DEBUG_TRACE (DEBUG::Accelerators, "\tusing Ardour bindings for this window\n");
5674 if (bindings->activate (k, Bindings::Press)) {
5675 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5681 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5683 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5684 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5689 DEBUG_TRACE (DEBUG::Accelerators, "\tnot handled\n");
5694 ARDOUR_UI::load_bindings ()
5696 if ((global_bindings = Bindings::get_bindings (X_("Global"), global_actions)) == 0) {
5697 error << _("Global keybindings are missing") << endmsg;
5702 ARDOUR_UI::cancel_solo ()
5705 _session->cancel_all_solo ();
5710 ARDOUR_UI::reset_focus (Gtk::Widget* w)
5712 /* this resets focus to the first focusable parent of the given widget,
5713 * or, if there is no focusable parent, cancels focus in the toplevel
5714 * window that the given widget is packed into (if there is one).
5721 Gtk::Widget* top = w->get_toplevel();
5723 if (!top || !top->is_toplevel()) {
5727 w = w->get_parent ();
5731 if (w->is_toplevel()) {
5732 /* Setting the focus widget to a Gtk::Window causes all
5733 * subsequent calls to ::has_focus() on the nominal
5734 * focus widget in that window to return
5735 * false. Workaround: never set focus to the toplevel
5741 if (w->get_can_focus ()) {
5742 Gtk::Window* win = dynamic_cast<Gtk::Window*> (top);
5743 win->set_focus (*w);
5746 w = w->get_parent ();
5749 if (top == &_main_window) {
5753 /* no focusable parent found, cancel focus in top level window.
5754 C++ API cannot be used for this. Thanks, references.
5757 gtk_window_set_focus (GTK_WINDOW(top->gobj()), 0);