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/scoped_file_descriptor.h"
69 #include "pbd/xml++.h"
71 #include "gtkmm2ext/application.h"
72 #include "gtkmm2ext/bindings.h"
73 #include "gtkmm2ext/gtk_ui.h"
74 #include "gtkmm2ext/utils.h"
75 #include "gtkmm2ext/click_box.h"
76 #include "gtkmm2ext/fastmeter.h"
77 #include "gtkmm2ext/popup.h"
78 #include "gtkmm2ext/window_title.h"
80 #include "ardour/ardour.h"
81 #include "ardour/audio_backend.h"
82 #include "ardour/audio_track.h"
83 #include "ardour/audioengine.h"
84 #include "ardour/audiofilesource.h"
85 #include "ardour/automation_watch.h"
86 #include "ardour/diskstream.h"
87 #include "ardour/filename_extensions.h"
88 #include "ardour/filesystem_paths.h"
89 #include "ardour/ltc_file_reader.h"
90 #include "ardour/midi_track.h"
91 #include "ardour/port.h"
92 #include "ardour/plugin_manager.h"
93 #include "ardour/process_thread.h"
94 #include "ardour/profile.h"
95 #include "ardour/recent_sessions.h"
96 #include "ardour/record_enable_control.h"
97 #include "ardour/session_directory.h"
98 #include "ardour/session_route.h"
99 #include "ardour/session_state_utils.h"
100 #include "ardour/session_utils.h"
101 #include "ardour/source_factory.h"
102 #include "ardour/slave.h"
103 #include "ardour/system_exec.h"
104 #include "ardour/track.h"
105 #include "ardour/vca_manager.h"
106 #include "ardour/utils.h"
108 #include "LuaBridge/LuaBridge.h"
110 #ifdef WINDOWS_VST_SUPPORT
113 #ifdef AUDIOUNIT_SUPPORT
114 #include "ardour/audio_unit.h"
117 // fix for OSX (nsm.h has a check function, AU/Apple defines check)
122 #include "timecode/time.h"
124 typedef uint64_t microseconds_t;
129 #include "add_route_dialog.h"
130 #include "ambiguous_file_dialog.h"
131 #include "ardour_ui.h"
132 #include "audio_clock.h"
133 #include "audio_region_view.h"
134 #include "big_clock_window.h"
135 #include "bundle_manager.h"
136 #include "duplicate_routes_dialog.h"
138 #include "engine_dialog.h"
139 #include "export_video_dialog.h"
140 #include "export_video_infobox.h"
141 #include "gain_meter.h"
142 #include "global_port_matrix.h"
143 #include "gui_object.h"
144 #include "gui_thread.h"
145 #include "keyboard.h"
146 #include "keyeditor.h"
147 #include "location_ui.h"
148 #include "lua_script_manager.h"
149 #include "luawindow.h"
150 #include "main_clock.h"
151 #include "missing_file_dialog.h"
152 #include "missing_plugin_dialog.h"
153 #include "mixer_ui.h"
154 #include "meterbridge.h"
155 #include "mouse_cursors.h"
158 #include "pingback.h"
159 #include "processor_box.h"
160 #include "prompter.h"
161 #include "public_editor.h"
162 #include "rc_option_editor.h"
163 #include "route_time_axis.h"
164 #include "route_params_ui.h"
165 #include "save_as_dialog.h"
166 #include "script_selector.h"
167 #include "session_archive_dialog.h"
168 #include "session_dialog.h"
169 #include "session_metadata_dialog.h"
170 #include "session_option_editor.h"
171 #include "speaker_dialog.h"
174 #include "time_axis_view_item.h"
175 #include "time_info_box.h"
178 #include "utils_videotl.h"
179 #include "video_server_dialog.h"
180 #include "add_video_dialog.h"
181 #include "transcode_video_dialog.h"
183 #include "pbd/i18n.h"
185 using namespace ARDOUR;
186 using namespace ARDOUR_UI_UTILS;
188 using namespace Gtkmm2ext;
191 using namespace Editing;
193 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
195 sigc::signal<void, framepos_t, bool, framepos_t> ARDOUR_UI::Clock;
196 sigc::signal<void> ARDOUR_UI::CloseAllDialogs;
199 ask_about_configuration_copy (string const & old_dir, string const & new_dir, int version)
201 MessageDialog msg (string_compose (_("%1 %2.x has discovered configuration files from %1 %3.x.\n\n"
202 "Would you like these files to be copied and used for %1 %2.x?\n\n"
203 "(This will require you to restart %1.)"),
204 PROGRAM_NAME, PROGRAM_VERSION, version),
205 false, /* no markup */
208 true /* modal, though it hardly matters since it is the only window */
211 msg.set_default_response (Gtk::RESPONSE_YES);
214 return (msg.run() == Gtk::RESPONSE_YES);
218 libxml_generic_error_func (void* /* parsing_context*/,
226 vsnprintf (buf, sizeof (buf), msg, ap);
227 error << buf << endmsg;
232 libxml_structured_error_func (void* /* parsing_context*/,
240 replace_all (msg, "\n", "");
243 if (err->file && err->line) {
244 error << X_("XML error: ") << msg << " in " << err->file << " at line " << err->line;
247 error << ':' << err->int2;
252 error << X_("XML error: ") << msg << endmsg;
258 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
259 : Gtkmm2ext::UI (PROGRAM_NAME, X_("gui"), argcp, argvp)
260 , session_loaded (false)
261 , gui_object_state (new GUIObjectState)
262 , primary_clock (new MainClock (X_("primary"), X_("transport"), true ))
263 , secondary_clock (new MainClock (X_("secondary"), X_("secondary"), false))
264 , big_clock (new AudioClock (X_("bigclock"), false, "big", true, true, false, false))
266 , global_actions (X_("global"))
267 , ignore_dual_punch (false)
268 , main_window_visibility (0)
273 , _mixer_on_top (false)
274 , _initial_verbose_plugin_scan (false)
275 , first_time_engine_run (true)
276 , secondary_clock_spacer (0)
277 , auto_input_button (ArdourButton::led_default_elements)
279 , auto_return_button (ArdourButton::led_default_elements)
280 , follow_edits_button (ArdourButton::led_default_elements)
281 , auditioning_alert_button (_("Audition"))
282 , solo_alert_button (_("Solo"))
283 , feedback_alert_button (_("Feedback"))
284 , error_alert_button ( ArdourButton::just_led_default_elements )
286 , editor_meter_peak_display()
287 , _numpad_locate_happening (false)
288 , _session_is_new (false)
289 , last_key_press_time (0)
293 , rc_option_editor (0)
294 , speaker_config_window (X_("speaker-config"), _("Speaker Configuration"))
295 , add_route_dialog (X_("add-routes"), _("Add Tracks/Busses"))
296 , about (X_("about"), _("About"))
297 , location_ui (X_("locations"), S_("Ranges|Locations"))
298 , route_params (X_("inspector"), _("Tracks and Busses"))
299 , audio_midi_setup (X_("audio-midi-setup"), _("Audio/MIDI Setup"))
300 , export_video_dialog (X_("video-export"), _("Video Export Dialog"))
301 , lua_script_window (X_("script-manager"), _("Script Manager"))
302 , session_option_editor (X_("session-options-editor"), _("Properties"), boost::bind (&ARDOUR_UI::create_session_option_editor, this))
303 , add_video_dialog (X_("add-video"), _("Add Video"), boost::bind (&ARDOUR_UI::create_add_video_dialog, this))
304 , bundle_manager (X_("bundle-manager"), _("Bundle Manager"), boost::bind (&ARDOUR_UI::create_bundle_manager, this))
305 , big_clock_window (X_("big-clock"), _("Big Clock"), boost::bind (&ARDOUR_UI::create_big_clock_window, this))
306 , audio_port_matrix (X_("audio-connection-manager"), _("Audio Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::AUDIO))
307 , midi_port_matrix (X_("midi-connection-manager"), _("MIDI Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::MIDI))
308 , key_editor (X_("key-editor"), _("Keyboard Shortcuts"), boost::bind (&ARDOUR_UI::create_key_editor, this))
309 , video_server_process (0)
311 , have_configure_timeout (false)
312 , last_configure_time (0)
314 , have_disk_speed_dialog_displayed (false)
315 , _status_bar_visibility (X_("status-bar"))
316 , _feedback_exists (false)
317 , _log_not_acknowledged (LogLevelNone)
318 , duplicate_routes_dialog (0)
319 , editor_visibility_button (S_("Window|Editor"))
320 , mixer_visibility_button (S_("Window|Mixer"))
321 , prefs_visibility_button (S_("Window|Preferences"))
323 Gtkmm2ext::init (localedir);
325 UIConfiguration::instance().post_gui_init ();
327 if (ARDOUR::handle_old_configuration_files (boost::bind (ask_about_configuration_copy, _1, _2, _3))) {
329 /* "touch" the been-here-before path now that config has been migrated */
330 PBD::ScopedFileDescriptor fout (g_open (been_here_before_path ().c_str(), O_CREAT|O_TRUNC|O_RDWR, 0666));
332 MessageDialog msg (string_compose (_("Your configuration files were copied. You can now restart %1."), PROGRAM_NAME), true);
334 /* configuration was modified, exit immediately */
339 if (string (VERSIONSTRING).find (".pre") != string::npos) {
340 /* check this is not being run from ./ardev etc. */
341 if (!running_from_source_tree ()) {
342 pre_release_dialog ();
346 if (theArdourUI == 0) {
350 /* track main window visibility */
352 main_window_visibility = new VisibilityTracker (_main_window);
354 /* stop libxml from spewing to stdout/stderr */
356 xmlSetGenericErrorFunc (this, libxml_generic_error_func);
357 xmlSetStructuredErrorFunc (this, libxml_structured_error_func);
359 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::parameter_changed));
360 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
361 UIConfiguration::instance().map_parameters (pc);
363 Glib::RefPtr<Gtk::Action> act;
365 act = ActionManager::get_action ("Transport/Roll");
366 roll_button.set_related_action (act);
367 act = ActionManager::get_action ("Transport/Stop");
368 stop_button.set_related_action (act);
369 act = ActionManager::get_action ("Transport/GotoStart");
370 goto_start_button.set_related_action (act);
371 act = ActionManager::get_action ("Transport/GotoEnd");
372 goto_end_button.set_related_action (act);
373 act = ActionManager::get_action ("Transport/Loop");
374 auto_loop_button.set_related_action (act);
375 act = ActionManager::get_action ("Transport/PlaySelection");
376 play_selection_button.set_related_action (act);
377 act = ActionManager::get_action ("Transport/Record");
378 rec_button.set_related_action (act);
380 roll_button.set_name ("transport button");
381 stop_button.set_name ("transport button");
382 goto_start_button.set_name ("transport button");
383 goto_end_button.set_name ("transport button");
384 auto_loop_button.set_name ("transport button");
385 play_selection_button.set_name ("transport button");
386 rec_button.set_name ("transport recenable button");
387 midi_panic_button.set_name ("transport button");
389 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
390 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
392 ARDOUR::Session::VersionMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_format_mismatch, this, _1, _2), gui_context());
394 /* handle dialog requests */
396 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
398 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
400 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
402 /* handle Audio/MIDI setup when session requires it */
404 ARDOUR::Session::AudioEngineSetupRequired.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::do_audio_midi_setup, this, _1));
406 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
408 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
410 /* handle sr mismatch with a dialog - cross-thread from engine */
411 ARDOUR::Session::NotifyAboutSampleRateMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::sr_mismatch_message, this, _1, _2), gui_context ());
413 /* handle requests to quit (coming from JACK session) */
415 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::finish, this), gui_context ());
417 /* tell the user about feedback */
419 ARDOUR::Session::FeedbackDetected.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::feedback_detected, this), gui_context ());
420 ARDOUR::Session::SuccessfulGraphSort.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::successful_graph_sort, this), gui_context ());
422 /* handle requests to deal with missing files */
424 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
426 /* and ambiguous files */
428 ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2));
430 /* also plugin scan messages */
431 ARDOUR::PluginScanMessage.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_dialog, this, _1, _2, _3), gui_context());
432 ARDOUR::PluginScanTimeout.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_timeout, this, _1), gui_context());
434 ARDOUR::GUIIdle.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::gui_idle_handler, this), gui_context());
436 Config->ParameterChanged.connect ( forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::set_flat_buttons, this), gui_context() );
439 /* lets get this party started */
441 setup_gtk_ardour_enums ();
444 SessionEvent::create_per_thread_pool ("GUI", 4096);
446 /* we like keyboards */
448 keyboard = new ArdourKeyboard(*this);
450 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
452 keyboard->set_state (*node, Stateful::loading_state_version);
455 UIConfiguration::instance().reset_dpi ();
457 TimeAxisViewItem::set_constant_heights ();
459 /* Set this up so that our window proxies can register actions */
461 ActionManager::init ();
463 /* The following must happen after ARDOUR::init() so that Config is set up */
465 const XMLNode* ui_xml = Config->extra_xml (X_("UI"));
468 key_editor.set_state (*ui_xml, 0);
469 session_option_editor.set_state (*ui_xml, 0);
470 speaker_config_window.set_state (*ui_xml, 0);
471 about.set_state (*ui_xml, 0);
472 add_route_dialog.set_state (*ui_xml, 0);
473 add_video_dialog.set_state (*ui_xml, 0);
474 route_params.set_state (*ui_xml, 0);
475 bundle_manager.set_state (*ui_xml, 0);
476 location_ui.set_state (*ui_xml, 0);
477 big_clock_window.set_state (*ui_xml, 0);
478 audio_port_matrix.set_state (*ui_xml, 0);
479 midi_port_matrix.set_state (*ui_xml, 0);
480 export_video_dialog.set_state (*ui_xml, 0);
481 lua_script_window.set_state (*ui_xml, 0);
484 /* Separate windows */
486 WM::Manager::instance().register_window (&key_editor);
487 WM::Manager::instance().register_window (&session_option_editor);
488 WM::Manager::instance().register_window (&speaker_config_window);
489 WM::Manager::instance().register_window (&about);
490 WM::Manager::instance().register_window (&add_route_dialog);
491 WM::Manager::instance().register_window (&add_video_dialog);
492 WM::Manager::instance().register_window (&route_params);
493 WM::Manager::instance().register_window (&audio_midi_setup);
494 WM::Manager::instance().register_window (&export_video_dialog);
495 WM::Manager::instance().register_window (&lua_script_window);
496 WM::Manager::instance().register_window (&bundle_manager);
497 WM::Manager::instance().register_window (&location_ui);
498 WM::Manager::instance().register_window (&big_clock_window);
499 WM::Manager::instance().register_window (&audio_port_matrix);
500 WM::Manager::instance().register_window (&midi_port_matrix);
502 /* do not retain position for add route dialog */
503 add_route_dialog.set_state_mask (WindowProxy::Size);
505 /* Trigger setting up the color scheme and loading the GTK RC file */
507 UIConfiguration::instance().load_rc_file (false);
509 _process_thread = new ProcessThread ();
510 _process_thread->init ();
512 UIConfiguration::instance().DPIReset.connect (sigc::mem_fun (*this, &ARDOUR_UI::resize_text_widgets));
518 ARDOUR_UI::pre_release_dialog ()
520 ArdourDialog d (_("Pre-Release Warning"), true, false);
521 d.add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
523 Label* label = manage (new Label);
524 label->set_markup (string_compose (_("<b>Welcome to this pre-release build of %1 %2</b>\n\n\
525 There are still several issues and bugs to be worked on,\n\
526 as well as general workflow improvements, before this can be considered\n\
527 release software. So, a few guidelines:\n\
529 1) Please do <b>NOT</b> use this software with the expectation that it is stable or reliable\n\
530 though it may be so, depending on your workflow.\n\
531 2) Please wait for a helpful writeup of new features.\n\
532 3) <b>Please do NOT use the forums at ardour.org to report issues</b>.\n\
533 4) Please <b>DO</b> use the bugtracker at http://tracker.ardour.org/ to report issues\n\
534 making sure to note the product version number as 5.0-pre.\n\
535 5) Please <b>DO</b> use the ardour-users mailing list to discuss ideas and pass on comments.\n\
536 6) Please <b>DO</b> join us on IRC for real time discussions about %1 %2. You\n\
537 can get there directly from within the program via the Help->Chat menu option.\n\
539 Full information on all the above can be found on the support page at\n\
541 http://ardour.org/support\n\
542 "), PROGRAM_NAME, VERSIONSTRING));
544 d.get_vbox()->set_border_width (12);
545 d.get_vbox()->pack_start (*label, false, false, 12);
546 d.get_vbox()->show_all ();
551 GlobalPortMatrixWindow*
552 ARDOUR_UI::create_global_port_matrix (ARDOUR::DataType type)
557 return new GlobalPortMatrixWindow (_session, type);
561 ARDOUR_UI::attach_to_engine ()
563 AudioEngine::instance()->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
564 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
568 ARDOUR_UI::engine_stopped ()
570 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
571 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
572 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
573 update_sample_rate (0);
578 ARDOUR_UI::engine_running ()
580 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
581 if (first_time_engine_run) {
583 first_time_engine_run = false;
587 _session->reset_xrun_count ();
589 update_disk_space ();
591 update_xrun_count ();
592 update_sample_rate (AudioEngine::instance()->sample_rate());
593 update_timecode_format ();
594 update_peak_thread_work ();
595 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, true);
596 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, false);
600 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
602 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
603 /* we can't rely on the original string continuing to exist when we are called
604 again in the GUI thread, so make a copy and note that we need to
607 char *copy = strdup (reason);
608 Gtkmm2ext::UI::instance()->call_slot (MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
612 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
613 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
615 update_sample_rate (0);
619 /* if the reason is a non-empty string, it means that the backend was shutdown
620 rather than just Ardour.
623 if (strlen (reason)) {
624 msgstr = string_compose (_("The audio backend was shutdown because:\n\n%1"), reason);
626 msgstr = string_compose (_("\
627 The audio backend has either been shutdown or it\n\
628 disconnected %1 because %1\n\
629 was not fast enough. Try to restart\n\
630 the audio backend and save the session."), PROGRAM_NAME);
633 MessageDialog msg (_main_window, msgstr);
634 pop_back_splash (msg);
638 free (const_cast<char*> (reason));
643 ARDOUR_UI::post_engine ()
645 /* Things to be done once (and once ONLY) after we have a backend running in the AudioEngine
647 #ifdef AUDIOUNIT_SUPPORT
649 if (AUPluginInfo::au_get_crashlog(au_msg)) {
650 popup_error(_("Audio Unit Plugin Scan Failed. Automatic AU scanning has been disabled. Please see the log window for further details."));
651 error << _("Audio Unit Plugin Scan Failed:") << endmsg;
652 info << au_msg << endmsg;
656 ARDOUR::init_post_engine ();
658 /* connect to important signals */
660 AudioEngine::instance()->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
661 AudioEngine::instance()->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
662 AudioEngine::instance()->BufferSizeChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
663 AudioEngine::instance()->Halted.connect_same_thread (halt_connection, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
664 AudioEngine::instance()->BecameSilent.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::audioengine_became_silent, this), gui_context());
666 if (setup_windows ()) {
667 throw failed_constructor ();
670 /* Do this after setup_windows (), as that's when the _status_bar_visibility is created */
671 XMLNode* n = Config->extra_xml (X_("UI"));
673 _status_bar_visibility.set_state (*n);
676 check_memory_locking();
678 /* this is the first point at which all the possible actions are
679 * available, because some of the available actions are dependent on
680 * aspects of the engine/backend.
683 if (ARDOUR_COMMAND_LINE::show_key_actions) {
686 vector<string> paths;
687 vector<string> labels;
688 vector<string> tooltips;
690 vector<Glib::RefPtr<Gtk::Action> > actions;
692 Gtkmm2ext::ActionMap::get_all_actions (paths, labels, tooltips, keys, actions);
694 vector<string>::iterator k;
695 vector<string>::iterator p;
697 for (p = paths.begin(), k = keys.begin(); p != paths.end(); ++k, ++p) {
702 cout << *p << " => " << *k << endl;
706 halt_connection.disconnect ();
707 AudioEngine::instance()->stop ();
711 /* this being a GUI and all, we want peakfiles */
713 AudioFileSource::set_build_peakfiles (true);
714 AudioFileSource::set_build_missing_peakfiles (true);
716 /* set default clock modes */
718 primary_clock->set_mode (AudioClock::Timecode);
719 secondary_clock->set_mode (AudioClock::BBT);
721 /* start the time-of-day-clock */
724 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
725 update_wall_clock ();
726 Glib::signal_timeout().connect_seconds (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 1);
731 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
732 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
733 Config->map_parameters (pc);
735 UIConfiguration::instance().map_parameters (pc);
739 ARDOUR_UI::~ARDOUR_UI ()
741 UIConfiguration::instance().save_state();
745 if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
746 // don't bother at 'real' exit. the OS cleans up for us.
747 delete big_clock; big_clock = 0;
748 delete primary_clock; primary_clock = 0;
749 delete secondary_clock; secondary_clock = 0;
750 delete _process_thread; _process_thread = 0;
751 delete time_info_box; time_info_box = 0;
752 delete meterbridge; meterbridge = 0;
753 delete luawindow; luawindow = 0;
754 delete editor; editor = 0;
755 delete mixer; mixer = 0;
756 delete rc_option_editor; rc_option_editor = 0; // failed to wrap object warning
758 delete gui_object_state; gui_object_state = 0;
759 delete main_window_visibility;
760 FastMeter::flush_pattern_cache ();
761 PixFader::flush_pattern_cache ();
765 /* Small trick to flush main-thread event pool.
766 * Other thread-pools are destroyed at pthread_exit(),
767 * but tmain thread termination is too late to trigger Pool::~Pool()
769 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.
770 delete ev->event_pool();
775 ARDOUR_UI::pop_back_splash (Gtk::Window& win)
777 if (Splash::instance()) {
778 Splash::instance()->pop_back_for (win);
783 ARDOUR_UI::configure_timeout ()
785 if (last_configure_time == 0) {
786 /* no configure events yet */
790 /* force a gap of 0.5 seconds since the last configure event
793 if (get_microseconds() - last_configure_time < 500000) {
796 have_configure_timeout = false;
797 save_ardour_state ();
803 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
805 if (have_configure_timeout) {
806 last_configure_time = get_microseconds();
808 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
809 have_configure_timeout = true;
816 ARDOUR_UI::save_session_at_its_request (std::string snapshot_name)
819 _session->save_state (snapshot_name);
824 ARDOUR_UI::autosave_session ()
826 if (g_main_depth() > 1) {
827 /* inside a recursive main loop,
828 give up because we may not be able to
834 if (!Config->get_periodic_safety_backups()) {
839 _session->maybe_write_autosave();
846 ARDOUR_UI::session_dirty_changed ()
853 ARDOUR_UI::update_autosave ()
855 if (_session && _session->dirty()) {
856 if (_autosave_connection.connected()) {
857 _autosave_connection.disconnect();
860 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
861 Config->get_periodic_safety_backup_interval() * 1000);
864 if (_autosave_connection.connected()) {
865 _autosave_connection.disconnect();
871 ARDOUR_UI::check_announcements ()
874 string _annc_filename;
877 _annc_filename = PROGRAM_NAME "_announcements_osx_";
878 #elif defined PLATFORM_WINDOWS
879 _annc_filename = PROGRAM_NAME "_announcements_windows_";
881 _annc_filename = PROGRAM_NAME "_announcements_linux_";
883 _annc_filename.append (VERSIONSTRING);
885 _announce_string = "";
887 std::string path = Glib::build_filename (user_config_directory(), _annc_filename);
888 FILE* fin = g_fopen (path.c_str(), "rb");
890 while (!feof (fin)) {
893 if ((len = fread (tmp, sizeof(char), 1024, fin)) == 0 || ferror (fin)) {
896 _announce_string.append (tmp, len);
901 pingback (VERSIONSTRING, path);
906 _hide_splash (gpointer arg)
908 ((ARDOUR_UI*)arg)->hide_splash();
913 ARDOUR_UI::starting ()
915 Application* app = Application::instance ();
917 bool brand_new_user = ArdourStartup::required ();
919 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
920 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::load_from_application_api));
922 if (ARDOUR_COMMAND_LINE::check_announcements) {
923 check_announcements ();
928 /* we need to create this early because it may need to set the
929 * audio backend end up.
933 audio_midi_setup.get (true);
935 std::cerr << "audio-midi engine setup failed."<< std::endl;
939 if ((nsm_url = g_getenv ("NSM_URL")) != 0) {
940 nsm = new NSM_Client;
941 if (!nsm->init (nsm_url)) {
942 /* the ardour executable may have different names:
944 * waf's obj.target for distro versions: eg ardour4, ardourvst4
945 * Ardour4, Mixbus3 for bundled versions + full path on OSX & windows
946 * argv[0] does not apply since we need the wrapper-script (not the binary itself)
948 * The wrapper startup script should set the environment variable 'ARDOUR_SELF'
950 const char *process_name = g_getenv ("ARDOUR_SELF");
951 nsm->announce (PROGRAM_NAME, ":dirty:", process_name ? process_name : "ardour4");
954 // wait for announce reply from nsm server
955 for ( i = 0; i < 5000; ++i) {
959 if (nsm->is_active()) {
964 error << _("NSM server did not announce itself") << endmsg;
967 // wait for open command from nsm server
968 for ( i = 0; i < 5000; ++i) {
971 if (nsm->client_id ()) {
977 error << _("NSM: no client ID provided") << endmsg;
981 if (_session && nsm) {
982 _session->set_nsm_state( nsm->is_active() );
984 error << _("NSM: no session created") << endmsg;
988 // nsm requires these actions disabled
989 vector<string> action_names;
990 action_names.push_back("SaveAs");
991 action_names.push_back("Rename");
992 action_names.push_back("New");
993 action_names.push_back("Open");
994 action_names.push_back("Recent");
995 action_names.push_back("Close");
997 for (vector<string>::const_iterator n = action_names.begin(); n != action_names.end(); ++n) {
998 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), (*n).c_str());
1000 act->set_sensitive (false);
1007 error << _("NSM: initialization failed") << endmsg;
1013 if (brand_new_user) {
1014 _initial_verbose_plugin_scan = true;
1019 _initial_verbose_plugin_scan = false;
1020 switch (s.response ()) {
1021 case Gtk::RESPONSE_OK:
1028 // TODO: maybe IFF brand_new_user
1029 if (ARDOUR::Profile->get_mixbus () && Config->get_copy_demo_sessions ()) {
1030 std::string dspd (Config->get_default_session_parent_dir());
1031 Searchpath ds (ARDOUR::ardour_data_search_path());
1032 ds.add_subdirectory_to_paths ("sessions");
1033 vector<string> demos;
1034 find_files_matching_pattern (demos, ds, "*.tar.xz");
1036 ARDOUR::RecentSessions rs;
1037 ARDOUR::read_recent_sessions (rs);
1039 for (vector<string>::iterator i = demos.begin(); i != demos.end (); ++i) {
1040 /* "demo-session" must be inside "demo-session.tar.xz"
1043 std::string name = basename_nosuffix (basename_nosuffix (*i));
1044 std::string path = Glib::build_filename (dspd, name);
1045 /* skip if session-dir already exists */
1046 if (Glib::file_test(path.c_str(), Glib::FILE_TEST_IS_DIR)) {
1049 /* skip sessions that are already in 'recent'.
1050 * eg. a new user changed <session-default-dir> shorly after installation
1052 for (ARDOUR::RecentSessions::iterator r = rs.begin(); r != rs.end(); ++r) {
1053 if ((*r).first == name) {
1058 PBD::FileArchive ar (*i);
1059 if (0 == ar.inflate (dspd)) {
1060 store_recent_sessions (name, path);
1061 info << string_compose (_("Copied Demo Session %1."), name) << endmsg;
1067 #ifdef NO_PLUGIN_STATE
1069 ARDOUR::RecentSessions rs;
1070 ARDOUR::read_recent_sessions (rs);
1072 string path = Glib::build_filename (user_config_directory(), ".iknowaboutfreeversion");
1074 if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS) && !rs.empty()) {
1076 /* already used Ardour, have sessions ... warn about plugin state */
1078 ArdourDialog d (_("Free/Demo Version Warning"), true);
1080 Button b (string_compose (_("Subscribe and support development of %1"), PROGRAM_NAME));
1081 CheckButton c (_("Don't warn me about this again"));
1083 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"),
1084 string_compose (_("This is a free/demo version of %1"), PROGRAM_NAME),
1085 _("It will not restore OR save any plugin settings"),
1086 _("If you load an existing session with plugin settings\n"
1087 "they will not be used and will be lost."),
1088 _("To get full access to updates without this limitation\n"
1089 "consider becoming a subscriber for a low cost every month.")));
1090 l.set_justify (JUSTIFY_CENTER);
1092 b.signal_clicked().connect (mem_fun(*this, &ARDOUR_UI::launch_subscribe));
1094 d.get_vbox()->pack_start (l, true, true);
1095 d.get_vbox()->pack_start (b, false, false, 12);
1096 d.get_vbox()->pack_start (c, false, false, 12);
1098 d.add_button (_("Quit now"), RESPONSE_CANCEL);
1099 d.add_button (string_compose (_("Continue using %1"), PROGRAM_NAME), RESPONSE_OK);
1103 c.signal_toggled().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (toggle_file_existence), path)));
1105 if (d.run () != RESPONSE_OK) {
1111 /* go get a session */
1113 const bool new_session_required = (ARDOUR_COMMAND_LINE::new_session || brand_new_user);
1115 if (get_session_parameters (false, new_session_required, ARDOUR_COMMAND_LINE::load_template)) {
1116 std::cerr << "Cannot get session parameters."<< std::endl;
1123 WM::Manager::instance().show_visible ();
1125 /* We have to do this here since goto_editor_window() ends up calling show_all() on the
1126 * editor window, and we may want stuff to be hidden.
1128 _status_bar_visibility.update ();
1130 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
1132 if (splash && splash->is_visible()) {
1133 // in 1 second, hide the splash screen
1134 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
1137 /* all other dialogs are created conditionally */
1143 ARDOUR_UI::check_memory_locking ()
1145 #if defined(__APPLE__) || defined(PLATFORM_WINDOWS)
1146 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
1150 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
1152 if (AudioEngine::instance()->is_realtime() && memory_warning_node == 0) {
1154 struct rlimit limits;
1156 long pages, page_size;
1158 size_t pages_len=sizeof(pages);
1159 if ((page_size = getpagesize()) < 0 ||
1160 sysctlbyname("hw.availpages", &pages, &pages_len, NULL, 0))
1162 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0)
1167 ram = (int64_t) pages * (int64_t) page_size;
1170 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
1174 if (limits.rlim_cur != RLIM_INFINITY) {
1176 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
1180 _("WARNING: Your system has a limit for maximum amount of locked memory. "
1181 "This might cause %1 to run out of memory before your system "
1182 "runs out of memory. \n\n"
1183 "You can view the memory limit with 'ulimit -l', "
1184 "and it is normally controlled by %2"),
1187 X_("/etc/login.conf")
1189 X_(" /etc/security/limits.conf")
1193 msg.set_default_response (RESPONSE_OK);
1195 VBox* vbox = msg.get_vbox();
1197 CheckButton cb (_("Do not show this window again"));
1198 hbox.pack_start (cb, true, false);
1199 vbox->pack_start (hbox);
1204 pop_back_splash (msg);
1208 if (cb.get_active()) {
1209 XMLNode node (X_("no-memory-warning"));
1210 Config->add_instant_xml (node);
1215 #endif // !__APPLE__
1220 ARDOUR_UI::queue_finish ()
1222 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
1226 ARDOUR_UI::idle_finish ()
1229 return false; /* do not call again */
1236 ARDOUR_UI::instance()->video_timeline->sync_session_state();
1238 if (_session->dirty()) {
1239 vector<string> actions;
1240 actions.push_back (_("Don't quit"));
1241 actions.push_back (_("Just quit"));
1242 actions.push_back (_("Save and quit"));
1243 switch (ask_about_saving_session(actions)) {
1248 /* use the default name */
1249 if (save_state_canfail ("")) {
1250 /* failed - don't quit */
1251 MessageDialog msg (_main_window,
1252 string_compose (_("\
1253 %1 was unable to save your session.\n\n\
1254 If you still wish to quit, please use the\n\n\
1255 \"Just quit\" option."), PROGRAM_NAME));
1256 pop_back_splash(msg);
1266 second_connection.disconnect ();
1267 point_one_second_connection.disconnect ();
1268 point_zero_something_second_connection.disconnect();
1269 fps_connection.disconnect();
1272 delete ARDOUR_UI::instance()->video_timeline;
1273 ARDOUR_UI::instance()->video_timeline = NULL;
1274 stop_video_server();
1276 /* Save state before deleting the session, as that causes some
1277 windows to be destroyed before their visible state can be
1280 save_ardour_state ();
1282 if (key_editor.get (false)) {
1283 key_editor->disconnect ();
1286 close_all_dialogs ();
1289 _session->set_clean ();
1290 _session->remove_pending_capture_state ();
1295 halt_connection.disconnect ();
1296 AudioEngine::instance()->stop ();
1297 #ifdef WINDOWS_VST_SUPPORT
1298 fst_stop_threading();
1304 ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
1306 ArdourDialog window (_("Unsaved Session"));
1307 Gtk::HBox dhbox; // the hbox for the image and text
1308 Gtk::Label prompt_label;
1309 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
1313 assert (actions.size() >= 3);
1315 window.add_button (actions[0], RESPONSE_REJECT);
1316 window.add_button (actions[1], RESPONSE_APPLY);
1317 window.add_button (actions[2], RESPONSE_ACCEPT);
1319 window.set_default_response (RESPONSE_ACCEPT);
1321 Gtk::Button noquit_button (msg);
1322 noquit_button.set_name ("EditorGTKButton");
1326 if (_session->snap_name() == _session->name()) {
1327 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?"),
1328 _session->snap_name());
1330 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?"),
1331 _session->snap_name());
1334 prompt_label.set_text (prompt);
1335 prompt_label.set_name (X_("PrompterLabel"));
1336 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
1338 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
1339 dhbox.set_homogeneous (false);
1340 dhbox.pack_start (*dimage, false, false, 5);
1341 dhbox.pack_start (prompt_label, true, false, 5);
1342 window.get_vbox()->pack_start (dhbox);
1344 window.set_name (_("Prompter"));
1345 window.set_modal (true);
1346 window.set_resizable (false);
1349 prompt_label.show();
1354 ResponseType r = (ResponseType) window.run();
1359 case RESPONSE_ACCEPT: // save and get out of here
1361 case RESPONSE_APPLY: // get out of here
1372 ARDOUR_UI::every_second ()
1375 update_xrun_count ();
1376 update_buffer_load ();
1377 update_disk_space ();
1378 update_timecode_format ();
1379 update_peak_thread_work ();
1381 if (nsm && nsm->is_active ()) {
1384 if (!_was_dirty && _session->dirty ()) {
1388 else if (_was_dirty && !_session->dirty ()){
1396 ARDOUR_UI::every_point_one_seconds ()
1398 // TODO get rid of this..
1399 // ShuttleControl is updated directly via TransportStateChange signal
1403 ARDOUR_UI::every_point_zero_something_seconds ()
1405 // august 2007: actual update frequency: 25Hz (40ms), not 100Hz
1407 if (editor_meter && UIConfiguration::instance().get_show_editor_meter() && editor_meter_peak_display.is_mapped ()) {
1408 float mpeak = editor_meter->update_meters();
1409 if (mpeak > editor_meter_max_peak) {
1410 if (mpeak >= UIConfiguration::instance().get_meter_peak()) {
1411 editor_meter_peak_display.set_active_state ( Gtkmm2ext::ExplicitActive );
1418 ARDOUR_UI::set_fps_timeout_connection ()
1420 unsigned int interval = 40;
1421 if (!_session) return;
1422 if (_session->timecode_frames_per_second() != 0) {
1423 /* ideally we'll use a select() to sleep and not accumulate
1424 * idle time to provide a regular periodic signal.
1425 * See linux_vst_gui_support.cc 'elapsed_time_ms'.
1426 * However, that'll require a dedicated thread and cross-thread
1427 * signals to the GUI Thread..
1429 interval = floor(500. /* update twice per FPS, since Glib::signal_timeout is very irregular */
1430 * _session->frame_rate() / _session->nominal_frame_rate()
1431 / _session->timecode_frames_per_second()
1433 #ifdef PLATFORM_WINDOWS
1434 // the smallest windows scheduler time-slice is ~15ms.
1435 // periodic GUI timeouts shorter than that will cause
1436 // WaitForSingleObject to spinlock (100% of one CPU Core)
1437 // and gtk never enters idle mode.
1438 // also changing timeBeginPeriod(1) does not affect that in
1439 // any beneficial way, so we just limit the max rate for now.
1440 interval = std::max(30u, interval); // at most ~33Hz.
1442 interval = std::max(8u, interval); // at most 120Hz.
1445 fps_connection.disconnect();
1446 Timers::set_fps_interval (interval);
1450 ARDOUR_UI::update_sample_rate (framecnt_t)
1454 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
1456 if (!AudioEngine::instance()->connected()) {
1458 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1462 framecnt_t rate = AudioEngine::instance()->sample_rate();
1465 /* no sample rate available */
1466 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1469 if (fmod (rate, 1000.0) != 0.0) {
1470 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
1471 (float) rate / 1000.0f,
1472 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1474 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
1476 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1480 sample_rate_label.set_markup (buf);
1484 ARDOUR_UI::update_format ()
1487 format_label.set_text ("");
1492 s << _("File:") << X_(" <span foreground=\"green\">");
1494 switch (_session->config.get_native_file_header_format ()) {
1526 switch (_session->config.get_native_file_data_format ()) {
1540 format_label.set_markup (s.str ());
1544 ARDOUR_UI::update_xrun_count ()
1548 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1549 should also be changed.
1553 const unsigned int x = _session->get_xrun_count ();
1555 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">>10K</span>"), X_("red"));
1557 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">%u</span>"), x > 0 ? X_("red") : X_("green"), x);
1560 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">?</span>"), X_("yellow"));
1562 xrun_label.set_markup (buf);
1563 set_tip (xrun_label, _("Audio dropouts. Shift+click to reset"));
1567 ARDOUR_UI::update_cpu_load ()
1571 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1572 should also be changed.
1575 double const c = AudioEngine::instance()->get_dsp_load ();
1576 snprintf (buf, sizeof (buf), _("DSP: <span foreground=\"%s\">%5.1f%%</span>"), c >= 90 ? X_("red") : X_("green"), c);
1577 cpu_load_label.set_markup (buf);
1581 ARDOUR_UI::update_peak_thread_work ()
1584 const int c = SourceFactory::peak_work_queue_length ();
1586 snprintf (buf, sizeof (buf), _("PkBld: <span foreground=\"%s\">%d</span>"), c >= 2 ? X_("red") : X_("green"), c);
1587 peak_thread_work_label.set_markup (buf);
1589 peak_thread_work_label.set_markup (X_(""));
1594 ARDOUR_UI::update_buffer_load ()
1598 uint32_t const playback = _session ? _session->playback_load () : 100;
1599 uint32_t const capture = _session ? _session->capture_load () : 100;
1601 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1602 should also be changed.
1608 _("Buffers: <span foreground=\"green\">p:</span><span foreground=\"%s\">%" PRIu32 "%%</span> "
1609 "<span foreground=\"green\">c:</span><span foreground=\"%s\">%" PRIu32 "%%</span>"),
1610 playback <= 5 ? X_("red") : X_("green"),
1612 capture <= 5 ? X_("red") : X_("green"),
1616 buffer_load_label.set_markup (buf);
1618 buffer_load_label.set_text ("");
1623 ARDOUR_UI::count_recenabled_streams (Route& route)
1625 Track* track = dynamic_cast<Track*>(&route);
1626 if (track && track->rec_enable_control()->get_value()) {
1627 rec_enabled_streams += track->n_inputs().n_total();
1632 ARDOUR_UI::update_disk_space()
1634 if (_session == 0) {
1638 boost::optional<framecnt_t> opt_frames = _session->available_capture_duration();
1640 framecnt_t fr = _session->frame_rate();
1643 /* skip update - no SR available */
1648 /* Available space is unknown */
1649 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">Unknown</span>"));
1650 } else if (opt_frames.get_value_or (0) == max_framecnt) {
1651 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">24hrs+</span>"));
1653 rec_enabled_streams = 0;
1654 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams, false);
1656 framecnt_t frames = opt_frames.get_value_or (0);
1658 if (rec_enabled_streams) {
1659 frames /= rec_enabled_streams;
1666 hrs = frames / (fr * 3600);
1669 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">>24 hrs</span>"));
1671 frames -= hrs * fr * 3600;
1672 mins = frames / (fr * 60);
1673 frames -= mins * fr * 60;
1676 bool const low = (hrs == 0 && mins <= 30);
1680 _("Disk: <span foreground=\"%s\">%02dh:%02dm:%02ds</span>"),
1681 low ? X_("red") : X_("green"),
1687 disk_space_label.set_markup (buf);
1691 ARDOUR_UI::update_timecode_format ()
1697 TimecodeSlave* tcslave;
1698 SyncSource sync_src = Config->get_sync_source();
1700 if ((sync_src == LTC || sync_src == MTC) && (tcslave = dynamic_cast<TimecodeSlave*>(_session->slave())) != 0) {
1701 matching = (tcslave->apparent_timecode_format() == _session->config.get_timecode_format());
1706 snprintf (buf, sizeof (buf), S_("Timecode|TC: <span foreground=\"%s\">%s</span>"),
1707 matching ? X_("green") : X_("red"),
1708 Timecode::timecode_format_name (_session->config.get_timecode_format()).c_str());
1710 snprintf (buf, sizeof (buf), "TC: n/a");
1713 timecode_format_label.set_markup (buf);
1717 ARDOUR_UI::update_wall_clock ()
1721 static int last_min = -1;
1724 tm_now = localtime (&now);
1725 if (last_min != tm_now->tm_min) {
1727 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1728 wall_clock_label.set_text (buf);
1729 last_min = tm_now->tm_min;
1736 ARDOUR_UI::open_recent_session ()
1738 bool can_return = (_session != 0);
1740 SessionDialog recent_session_dialog;
1744 ResponseType r = (ResponseType) recent_session_dialog.run ();
1747 case RESPONSE_ACCEPT:
1751 recent_session_dialog.hide();
1758 recent_session_dialog.hide();
1762 std::string path = recent_session_dialog.session_folder();
1763 std::string state = recent_session_dialog.session_name (should_be_new);
1765 if (should_be_new == true) {
1769 _session_is_new = false;
1771 if (load_session (path, state) == 0) {
1777 if (splash && splash->is_visible()) {
1778 // in 1 second, hide the splash screen
1779 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
1784 ARDOUR_UI::check_audioengine (Gtk::Window& parent)
1786 if (!AudioEngine::instance()->connected()) {
1787 MessageDialog msg (parent, string_compose (
1788 _("%1 is not connected to any audio backend.\n"
1789 "You cannot open or close sessions in this condition"),
1791 pop_back_splash (msg);
1799 ARDOUR_UI::open_session ()
1801 if (!check_audioengine (_main_window)) {
1805 /* ardour sessions are folders */
1806 Gtk::FileChooserDialog open_session_selector(_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1807 open_session_selector.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1808 open_session_selector.add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1809 open_session_selector.set_default_response(Gtk::RESPONSE_ACCEPT);
1812 string session_parent_dir = Glib::path_get_dirname(_session->path());
1813 open_session_selector.set_current_folder(session_parent_dir);
1815 open_session_selector.set_current_folder(Config->get_default_session_parent_dir());
1818 Gtkmm2ext::add_volume_shortcuts (open_session_selector);
1820 /* add_shortcut_folder throws an exception if the folder being added already has a shortcut */
1821 string default_session_folder = Config->get_default_session_parent_dir();
1822 open_session_selector.add_shortcut_folder (default_session_folder);
1824 catch (Glib::Error & e) {
1825 std::cerr << "open_session_selector.add_shortcut_folder() threw Glib::Error " << e.what() << std::endl;
1828 FileFilter session_filter;
1829 session_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::statefile_suffix));
1830 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1831 open_session_selector.add_filter (session_filter);
1833 FileFilter archive_filter;
1834 archive_filter.add_pattern (X_("*.tar.xz"));
1835 archive_filter.set_name (_("Session Archives"));
1837 open_session_selector.add_filter (archive_filter);
1839 open_session_selector.set_filter (session_filter);
1841 int response = open_session_selector.run();
1842 open_session_selector.hide ();
1844 if (response == Gtk::RESPONSE_CANCEL) {
1848 string session_path = open_session_selector.get_filename();
1852 if (session_path.length() > 0) {
1853 int rv = ARDOUR::inflate_session (session_path,
1854 Config->get_default_session_parent_dir(), path, name);
1856 _session_is_new = false;
1857 load_session (path, name);
1860 MessageDialog msg (_main_window,
1861 string_compose (_("Extracting session-archive failed: %1"), inflate_error (rv)));
1864 else if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1865 _session_is_new = isnew;
1866 load_session (path, name);
1872 ARDOUR_UI::session_add_vca (const string& name_template, uint32_t n)
1878 _session->vca_manager().create_vca (n, name_template);
1882 ARDOUR_UI::session_add_mixed_track (
1883 const ChanCount& input,
1884 const ChanCount& output,
1885 RouteGroup* route_group,
1887 const string& name_template,
1889 PluginInfoPtr instrument,
1890 Plugin::PresetRecord* pset,
1891 ARDOUR::PresentationInfo::order_t order)
1893 if (_session == 0) {
1894 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1898 if (Profile->get_mixbus ()) {
1903 list<boost::shared_ptr<MidiTrack> > tracks;
1904 tracks = _session->new_midi_track (input, output, strict_io, instrument, pset, route_group, how_many, name_template, order, ARDOUR::Normal);
1906 if (tracks.size() != how_many) {
1907 error << string_compose(P_("could not create %1 new mixed track", "could not create %1 new mixed tracks", how_many), how_many) << endmsg;
1912 display_insufficient_ports_message ();
1918 ARDOUR_UI::session_add_midi_bus (
1919 RouteGroup* route_group,
1921 const string& name_template,
1923 PluginInfoPtr instrument,
1924 Plugin::PresetRecord* pset,
1925 ARDOUR::PresentationInfo::order_t order)
1927 if (_session == 0) {
1928 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1932 if (Profile->get_mixbus ()) {
1938 routes = _session->new_midi_route (route_group, how_many, name_template, strict_io, instrument, pset, PresentationInfo::MidiBus, order);
1939 if (routes.size() != how_many) {
1940 error << string_compose(P_("could not create %1 new Midi Bus", "could not create %1 new Midi Busses", how_many), how_many) << endmsg;
1945 display_insufficient_ports_message ();
1951 ARDOUR_UI::session_add_midi_route (
1953 RouteGroup* route_group,
1955 const string& name_template,
1957 PluginInfoPtr instrument,
1958 Plugin::PresetRecord* pset,
1959 ARDOUR::PresentationInfo::order_t order)
1961 ChanCount one_midi_channel;
1962 one_midi_channel.set (DataType::MIDI, 1);
1965 session_add_mixed_track (one_midi_channel, one_midi_channel, route_group, how_many, name_template, strict_io, instrument, pset, order);
1967 session_add_midi_bus (route_group, how_many, name_template, strict_io, instrument, pset, order);
1972 ARDOUR_UI::session_add_audio_route (
1974 int32_t input_channels,
1975 int32_t output_channels,
1976 ARDOUR::TrackMode mode,
1977 RouteGroup* route_group,
1979 string const & name_template,
1981 ARDOUR::PresentationInfo::order_t order)
1983 list<boost::shared_ptr<AudioTrack> > tracks;
1986 if (_session == 0) {
1987 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1993 tracks = _session->new_audio_track (input_channels, output_channels, route_group, how_many, name_template, order, mode);
1995 if (tracks.size() != how_many) {
1996 error << string_compose (P_("could not create %1 new audio track", "could not create %1 new audio tracks", how_many), how_many)
2002 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template, PresentationInfo::AudioBus, order);
2004 if (routes.size() != how_many) {
2005 error << string_compose (P_("could not create %1 new audio bus", "could not create %1 new audio busses", how_many), how_many)
2012 display_insufficient_ports_message ();
2017 for (list<boost::shared_ptr<AudioTrack> >::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2018 (*i)->set_strict_io (true);
2020 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
2021 (*i)->set_strict_io (true);
2027 ARDOUR_UI::display_insufficient_ports_message ()
2029 MessageDialog msg (_main_window,
2030 string_compose (_("There are insufficient ports available\n\
2031 to create a new track or bus.\n\
2032 You should save %1, exit and\n\
2033 restart with more ports."), PROGRAM_NAME));
2034 pop_back_splash (msg);
2039 ARDOUR_UI::transport_goto_start ()
2042 _session->goto_start();
2044 /* force displayed area in editor to start no matter
2045 what "follow playhead" setting is.
2049 editor->center_screen (_session->current_start_frame ());
2055 ARDOUR_UI::transport_goto_zero ()
2058 _session->request_locate (0);
2060 /* force displayed area in editor to start no matter
2061 what "follow playhead" setting is.
2065 editor->reset_x_origin (0);
2071 ARDOUR_UI::transport_goto_wallclock ()
2073 if (_session && editor) {
2080 localtime_r (&now, &tmnow);
2082 framecnt_t frame_rate = _session->frame_rate();
2084 if (frame_rate == 0) {
2085 /* no frame rate available */
2089 frames = tmnow.tm_hour * (60 * 60 * frame_rate);
2090 frames += tmnow.tm_min * (60 * frame_rate);
2091 frames += tmnow.tm_sec * frame_rate;
2093 _session->request_locate (frames, _session->transport_rolling ());
2095 /* force displayed area in editor to start no matter
2096 what "follow playhead" setting is.
2100 editor->center_screen (frames);
2106 ARDOUR_UI::transport_goto_end ()
2109 framepos_t const frame = _session->current_end_frame();
2110 _session->request_locate (frame);
2112 /* force displayed area in editor to start no matter
2113 what "follow playhead" setting is.
2117 editor->center_screen (frame);
2123 ARDOUR_UI::transport_stop ()
2129 if (_session->is_auditioning()) {
2130 _session->cancel_audition ();
2134 _session->request_stop (false, true);
2137 /** Check if any tracks are record enabled. If none are, record enable all of them.
2138 * @return true if track record-enabled status was changed, false otherwise.
2141 ARDOUR_UI::trx_record_enable_all_tracks ()
2147 boost::shared_ptr<RouteList> rl = _session->get_tracks ();
2148 bool none_record_enabled = true;
2150 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
2151 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*r);
2154 if (t->rec_enable_control()->get_value()) {
2155 none_record_enabled = false;
2160 if (none_record_enabled) {
2161 _session->set_controls (route_list_to_control_list (rl, &Stripable::rec_enable_control), 1.0, Controllable::NoGroup);
2164 return none_record_enabled;
2168 ARDOUR_UI::transport_record (bool roll)
2171 switch (_session->record_status()) {
2172 case Session::Disabled:
2173 if (_session->ntracks() == 0) {
2174 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."));
2178 if (Profile->get_trx()) {
2179 roll = trx_record_enable_all_tracks ();
2181 _session->maybe_enable_record ();
2186 case Session::Recording:
2188 _session->request_stop();
2190 _session->disable_record (false, true);
2194 case Session::Enabled:
2195 _session->disable_record (false, true);
2201 ARDOUR_UI::transport_roll ()
2207 if (_session->is_auditioning()) {
2212 if (_session->config.get_external_sync()) {
2213 switch (Config->get_sync_source()) {
2217 /* transport controlled by the master */
2223 bool rolling = _session->transport_rolling();
2225 if (_session->get_play_loop()) {
2227 /* If loop playback is not a mode, then we should cancel
2228 it when this action is requested. If it is a mode
2229 we just leave it in place.
2232 if (!Config->get_loop_is_mode()) {
2233 /* XXX it is not possible to just leave seamless loop and keep
2234 playing at present (nov 4th 2009)
2236 if (!Config->get_seamless_loop()) {
2237 /* stop loop playback and stop rolling */
2238 _session->request_play_loop (false, true);
2239 } else if (rolling) {
2240 /* stop loop playback but keep rolling */
2241 _session->request_play_loop (false, false);
2245 } else if (_session->get_play_range () ) {
2246 /* stop playing a range if we currently are */
2247 _session->request_play_range (0, true);
2251 _session->request_transport_speed (1.0f);
2256 ARDOUR_UI::get_smart_mode() const
2258 return ( editor->get_smart_mode() );
2263 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
2269 if (_session->is_auditioning()) {
2270 _session->cancel_audition ();
2274 if (_session->config.get_external_sync()) {
2275 switch (Config->get_sync_source()) {
2279 /* transport controlled by the master */
2284 bool rolling = _session->transport_rolling();
2285 bool affect_transport = true;
2287 if (rolling && roll_out_of_bounded_mode) {
2288 /* drop out of loop/range playback but leave transport rolling */
2289 if (_session->get_play_loop()) {
2290 if (_session->actively_recording()) {
2292 /* just stop using the loop, then actually stop
2295 _session->request_play_loop (false, affect_transport);
2298 if (Config->get_seamless_loop()) {
2299 /* the disk buffers contain copies of the loop - we can't
2300 just keep playing, so stop the transport. the user
2301 can restart as they wish.
2303 affect_transport = true;
2305 /* disk buffers are normal, so we can keep playing */
2306 affect_transport = false;
2308 _session->request_play_loop (false, affect_transport);
2310 } else if (_session->get_play_range ()) {
2311 affect_transport = false;
2312 _session->request_play_range (0, true);
2316 if (affect_transport) {
2318 _session->request_stop (with_abort, true);
2320 } else if (!with_abort) { /* with_abort == true means the
2321 * command was intended to stop
2322 * transport, not start.
2325 /* the only external sync condition we can be in here
2326 * would be Engine (JACK) sync, in which case we still
2330 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
2331 _session->request_play_range (&editor->get_selection().time, true);
2332 _session->set_requested_return_frame( editor->get_selection().time.front().start ); //force an auto-return here
2334 _session->request_transport_speed (1.0f);
2340 ARDOUR_UI::toggle_session_auto_loop ()
2346 Location * looploc = _session->locations()->auto_loop_location();
2352 if (_session->get_play_loop()) {
2354 /* looping enabled, our job is to disable it */
2356 _session->request_play_loop (false);
2360 /* looping not enabled, our job is to enable it.
2362 loop-is-NOT-mode: this action always starts the transport rolling.
2363 loop-IS-mode: this action simply sets the loop play mechanism, but
2364 does not start transport.
2366 if (Config->get_loop_is_mode()) {
2367 _session->request_play_loop (true, false);
2369 _session->request_play_loop (true, true);
2373 //show the loop markers
2374 looploc->set_hidden (false, this);
2378 ARDOUR_UI::transport_play_selection ()
2384 editor->play_selection ();
2388 ARDOUR_UI::transport_play_preroll ()
2393 editor->play_with_preroll ();
2397 ARDOUR_UI::transport_rec_preroll ()
2402 editor->rec_with_preroll ();
2406 ARDOUR_UI::transport_rec_count_in ()
2411 editor->rec_with_count_in ();
2415 ARDOUR_UI::transport_rewind (int option)
2417 float current_transport_speed;
2420 current_transport_speed = _session->transport_speed();
2422 if (current_transport_speed >= 0.0f) {
2425 _session->request_transport_speed (-1.0f);
2428 _session->request_transport_speed (-4.0f);
2431 _session->request_transport_speed (-0.5f);
2436 _session->request_transport_speed (current_transport_speed * 1.5f);
2442 ARDOUR_UI::transport_forward (int option)
2448 float current_transport_speed = _session->transport_speed();
2450 if (current_transport_speed <= 0.0f) {
2453 _session->request_transport_speed (1.0f);
2456 _session->request_transport_speed (4.0f);
2459 _session->request_transport_speed (0.5f);
2464 _session->request_transport_speed (current_transport_speed * 1.5f);
2469 ARDOUR_UI::toggle_record_enable (uint16_t rid)
2475 boost::shared_ptr<Route> r;
2477 if ((r = _session->get_remote_nth_route (rid)) != 0) {
2479 boost::shared_ptr<Track> t;
2481 if ((t = boost::dynamic_pointer_cast<Track>(r)) != 0) {
2482 t->rec_enable_control()->set_value (!t->rec_enable_control()->get_value(), Controllable::UseGroup);
2488 ARDOUR_UI::map_transport_state ()
2491 auto_loop_button.unset_active_state ();
2492 play_selection_button.unset_active_state ();
2493 roll_button.unset_active_state ();
2494 stop_button.set_active_state (Gtkmm2ext::ExplicitActive);
2495 layered_button.set_sensitive (false);
2499 shuttle_box.map_transport_state ();
2501 float sp = _session->transport_speed();
2507 if (_session->get_play_range()) {
2509 play_selection_button.set_active_state (Gtkmm2ext::ExplicitActive);
2510 roll_button.unset_active_state ();
2511 auto_loop_button.unset_active_state ();
2513 } else if (_session->get_play_loop ()) {
2515 auto_loop_button.set_active (true);
2516 play_selection_button.set_active (false);
2517 if (Config->get_loop_is_mode()) {
2518 roll_button.set_active (true);
2520 roll_button.set_active (false);
2525 roll_button.set_active (true);
2526 play_selection_button.set_active (false);
2527 auto_loop_button.set_active (false);
2530 if (UIConfiguration::instance().get_follow_edits() && !_session->config.get_external_sync()) {
2531 /* light up both roll and play-selection if they are joined */
2532 roll_button.set_active (true);
2533 play_selection_button.set_active (true);
2535 layered_button.set_sensitive (!_session->actively_recording ());
2537 stop_button.set_active (false);
2541 layered_button.set_sensitive (true);
2542 stop_button.set_active (true);
2543 roll_button.set_active (false);
2544 play_selection_button.set_active (false);
2545 if (Config->get_loop_is_mode ()) {
2546 auto_loop_button.set_active (_session->get_play_loop());
2548 auto_loop_button.set_active (false);
2550 update_disk_space ();
2555 ARDOUR_UI::blink_handler (bool blink_on)
2557 transport_rec_enable_blink (blink_on);
2558 solo_blink (blink_on);
2559 sync_blink (blink_on);
2560 audition_blink (blink_on);
2561 feedback_blink (blink_on);
2562 error_blink (blink_on);
2566 ARDOUR_UI::update_clocks ()
2568 if (!_session) return;
2570 if (editor && !editor->dragging_playhead()) {
2571 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD)); /* EMIT_SIGNAL */
2576 ARDOUR_UI::start_clocking ()
2578 if (UIConfiguration::instance().get_super_rapid_clock_update()) {
2579 clock_signal_connection = Timers::fps_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2581 clock_signal_connection = Timers::rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2586 ARDOUR_UI::stop_clocking ()
2588 clock_signal_connection.disconnect ();
2592 ARDOUR_UI::save_as_progress_update (float fraction, int64_t cnt, int64_t total, Gtk::Label* label, Gtk::ProgressBar* bar)
2596 snprintf (buf, sizeof (buf), _("Copied %" PRId64 " of %" PRId64), cnt, total);
2598 label->set_text (buf);
2599 bar->set_fraction (fraction);
2601 /* process events, redraws, etc. */
2603 while (gtk_events_pending()) {
2604 gtk_main_iteration ();
2607 return true; /* continue with save-as */
2611 ARDOUR_UI::save_session_as ()
2617 if (!save_as_dialog) {
2618 save_as_dialog = new SaveAsDialog;
2621 save_as_dialog->set_name (_session->name());
2623 int response = save_as_dialog->run ();
2625 save_as_dialog->hide ();
2628 case Gtk::RESPONSE_OK:
2637 sa.new_parent_folder = save_as_dialog->new_parent_folder ();
2638 sa.new_name = save_as_dialog->new_name ();
2639 sa.switch_to = save_as_dialog->switch_to();
2640 sa.copy_media = save_as_dialog->copy_media();
2641 sa.copy_external = save_as_dialog->copy_external();
2642 sa.include_media = save_as_dialog->include_media ();
2644 /* Only bother with a progress dialog if we're going to copy
2645 media into the save-as target. Without that choice, this
2646 will be very fast because we're only talking about a few kB's to
2647 perhaps a couple of MB's of data.
2650 ArdourDialog progress_dialog (_("Save As"), true);
2652 if (sa.include_media && sa.copy_media) {
2655 Gtk::ProgressBar progress_bar;
2657 progress_dialog.get_vbox()->pack_start (label);
2658 progress_dialog.get_vbox()->pack_start (progress_bar);
2660 progress_bar.show ();
2662 /* this signal will be emitted from within this, the calling thread,
2663 * after every file is copied. It provides information on percentage
2664 * complete (in terms of total data to copy), the number of files
2665 * copied so far, and the total number to copy.
2670 sa.Progress.connect_same_thread (c, boost::bind (&ARDOUR_UI::save_as_progress_update, this, _1, _2, _3, &label, &progress_bar));
2672 progress_dialog.show_all ();
2673 progress_dialog.present ();
2676 if (_session->save_as (sa)) {
2678 MessageDialog msg (string_compose (_("Save As failed: %1"), sa.failure_message));
2682 /* the logic here may seem odd: why isn't the condition sa.switch_to ?
2683 * the trick is this: if the new session was copy with media included,
2684 * then Session::save_as() will have already done a neat trick to avoid
2685 * us having to unload and load the new state. But if the media was not
2686 * included, then this is required (it avoids us having to otherwise
2687 * drop all references to media (sources).
2690 if (!sa.include_media && sa.switch_to) {
2691 unload_session (false);
2692 load_session (sa.final_session_folder_name, sa.new_name);
2698 ARDOUR_UI::archive_session ()
2706 Glib::DateTime gdt (Glib::DateTime::create_now_local (n));
2708 SessionArchiveDialog sad;
2709 sad.set_name (_session->name() + gdt.format ("_%F_%H%M%S"));
2710 int response = sad.run ();
2712 if (response != Gtk::RESPONSE_OK) {
2717 if (_session->archive_session (sad.target_folder(), sad.name(), sad.encode_option (), sad.only_used_sources (), &sad)) {
2718 MessageDialog msg (_("Session Archiving failed."));
2724 ARDOUR_UI::quick_snapshot_session (bool switch_to_it)
2728 struct tm local_time;
2731 localtime_r (&n, &local_time);
2732 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2734 save_state (timebuf, switch_to_it);
2739 ARDOUR_UI::process_snapshot_session_prompter (ArdourPrompter& prompter, bool switch_to_it)
2743 prompter.get_result (snapname);
2745 bool do_save = (snapname.length() != 0);
2748 char illegal = Session::session_name_is_legal(snapname);
2750 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2751 "snapshot names may not contain a '%1' character"), illegal));
2757 vector<std::string> p;
2758 get_state_files_in_directory (_session->session_directory().root_path(), p);
2759 vector<string> n = get_file_names_no_extension (p);
2761 if (find (n.begin(), n.end(), snapname) != n.end()) {
2763 do_save = overwrite_file_dialog (prompter,
2764 _("Confirm Snapshot Overwrite"),
2765 _("A snapshot already exists with that name. Do you want to overwrite it?"));
2769 save_state (snapname, switch_to_it);
2779 /** Ask the user for the name of a new snapshot and then take it.
2783 ARDOUR_UI::snapshot_session (bool switch_to_it)
2785 ArdourPrompter prompter (true);
2787 prompter.set_name ("Prompter");
2788 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2790 prompter.set_title (_("Snapshot and switch"));
2791 prompter.set_prompt (_("New session name"));
2793 prompter.set_title (_("Take Snapshot"));
2794 prompter.set_prompt (_("Name of new snapshot"));
2798 prompter.set_initial_text (_session->snap_name());
2800 Glib::DateTime tm (g_date_time_new_now_local ());
2801 prompter.set_initial_text (tm.format ("%FT%H.%M.%S"));
2804 bool finished = false;
2806 switch (prompter.run()) {
2807 case RESPONSE_ACCEPT:
2809 finished = process_snapshot_session_prompter (prompter, switch_to_it);
2820 /** Ask the user for a new session name and then rename the session to it.
2824 ARDOUR_UI::rename_session ()
2830 ArdourPrompter prompter (true);
2833 prompter.set_name ("Prompter");
2834 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2835 prompter.set_title (_("Rename Session"));
2836 prompter.set_prompt (_("New session name"));
2839 switch (prompter.run()) {
2840 case RESPONSE_ACCEPT:
2842 prompter.get_result (name);
2844 bool do_rename = (name.length() != 0);
2847 char illegal = Session::session_name_is_legal (name);
2850 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2851 "session names may not contain a '%1' character"), illegal));
2856 switch (_session->rename (name)) {
2858 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
2859 msg.set_position (WIN_POS_MOUSE);
2867 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
2868 msg.set_position (WIN_POS_MOUSE);
2884 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2886 if (!_session || _session->deletion_in_progress()) {
2890 XMLNode* node = new XMLNode (X_("UI"));
2892 WM::Manager::instance().add_state (*node);
2894 node->add_child_nocopy (gui_object_state->get_state());
2896 _session->add_extra_xml (*node);
2898 if (export_video_dialog) {
2899 _session->add_extra_xml (export_video_dialog->get_state());
2902 save_state_canfail (name, switch_to_it);
2906 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2911 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2916 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2921 ARDOUR_UI::primary_clock_value_changed ()
2924 _session->request_locate (primary_clock->current_time ());
2929 ARDOUR_UI::big_clock_value_changed ()
2932 _session->request_locate (big_clock->current_time ());
2937 ARDOUR_UI::secondary_clock_value_changed ()
2940 _session->request_locate (secondary_clock->current_time ());
2945 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2947 if (_session == 0) {
2951 if (_session->step_editing()) {
2955 Session::RecordState const r = _session->record_status ();
2956 bool const h = _session->have_rec_enabled_track ();
2958 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2960 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2962 rec_button.set_active_state (Gtkmm2ext::Off);
2964 } else if (r == Session::Recording && h) {
2965 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2967 rec_button.unset_active_state ();
2972 ARDOUR_UI::process_save_template_prompter (ArdourPrompter& prompter)
2976 prompter.get_result (name);
2978 if (name.length()) {
2979 int failed = _session->save_template (name);
2981 if (failed == -2) { /* file already exists. */
2982 bool overwrite = overwrite_file_dialog (prompter,
2983 _("Confirm Template Overwrite"),
2984 _("A template already exists with that name. Do you want to overwrite it?"));
2987 _session->save_template (name, true);
2999 ARDOUR_UI::save_template ()
3001 ArdourPrompter prompter (true);
3003 if (!check_audioengine (_main_window)) {
3007 prompter.set_name (X_("Prompter"));
3008 prompter.set_title (_("Save Template"));
3009 prompter.set_prompt (_("Name for template:"));
3010 prompter.set_initial_text(_session->name() + _("-template"));
3011 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
3013 bool finished = false;
3015 switch (prompter.run()) {
3016 case RESPONSE_ACCEPT:
3017 finished = process_save_template_prompter (prompter);
3028 ARDOUR_UI::edit_metadata ()
3030 SessionMetadataEditor dialog;
3031 dialog.set_session (_session);
3032 dialog.grab_focus ();
3037 ARDOUR_UI::import_metadata ()
3039 SessionMetadataImporter dialog;
3040 dialog.set_session (_session);
3045 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
3047 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
3049 MessageDialog msg (str,
3051 Gtk::MESSAGE_WARNING,
3052 Gtk::BUTTONS_YES_NO,
3056 msg.set_name (X_("OpenExistingDialog"));
3057 msg.set_title (_("Open Existing Session"));
3058 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
3059 msg.set_position (Gtk::WIN_POS_CENTER);
3060 pop_back_splash (msg);
3062 switch (msg.run()) {
3071 ARDOUR_UI::build_session_from_dialog (SessionDialog& sd, const std::string& session_path, const std::string& session_name)
3073 BusProfile bus_profile;
3077 bus_profile.master_out_channels = 2;
3078 bus_profile.input_ac = AutoConnectPhysical;
3079 bus_profile.output_ac = AutoConnectMaster;
3080 bus_profile.requested_physical_in = 0; // use all available
3081 bus_profile.requested_physical_out = 0; // use all available
3085 /* get settings from advanced section of NSD */
3087 if (sd.create_master_bus()) {
3088 bus_profile.master_out_channels = (uint32_t) sd.master_channel_count();
3090 bus_profile.master_out_channels = 0;
3093 if (sd.connect_inputs()) {
3094 bus_profile.input_ac = AutoConnectPhysical;
3096 bus_profile.input_ac = AutoConnectOption (0);
3099 bus_profile.output_ac = AutoConnectOption (0);
3101 if (sd.connect_outputs ()) {
3102 if (sd.connect_outs_to_master()) {
3103 bus_profile.output_ac = AutoConnectMaster;
3104 } else if (sd.connect_outs_to_physical()) {
3105 bus_profile.output_ac = AutoConnectPhysical;
3109 bus_profile.requested_physical_in = (uint32_t) sd.input_limit_count();
3110 bus_profile.requested_physical_out = (uint32_t) sd.output_limit_count();
3113 if (build_session (session_path, session_name, bus_profile)) {
3121 ARDOUR_UI::load_from_application_api (const std::string& path)
3123 /* OS X El Capitan (and probably later) now somehow passes the command
3124 line arguments to an app via the openFile delegate protocol. Ardour
3125 already does its own command line processing, and having both
3126 pathways active causes crashes. So, if the command line was already
3127 set, do nothing here.
3130 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
3134 ARDOUR_COMMAND_LINE::session_name = path;
3136 /* Cancel SessionDialog if it's visible to make OSX delegates work.
3138 * ARDOUR_UI::starting connects app->ShouldLoad signal and then shows a SessionDialog
3140 * - ShouldLoad does not arrive in time, ARDOUR_COMMAND_LINE::session_name is empty:
3141 * -> ARDOUR_UI::get_session_parameters starts a SessionDialog.
3142 * - ShouldLoad signal arrives, this function is called and sets ARDOUR_COMMAND_LINE::session_name
3143 * -> SessionDialog is not displayed
3146 if (_session_dialog) {
3147 std::string session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3148 std::string session_path = path;
3149 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_REGULAR)) {
3150 session_path = Glib::path_get_dirname (session_path);
3152 // signal the existing dialog in ARDOUR_UI::get_session_parameters()
3153 _session_dialog->set_provided_session (session_name, session_path);
3154 _session_dialog->response (RESPONSE_NONE);
3155 _session_dialog->hide();
3160 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
3161 /* /path/to/foo => /path/to/foo, foo */
3162 rv = load_session (path, basename_nosuffix (path));
3164 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
3165 rv =load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
3168 // if load_session fails -> pop up SessionDialog.
3170 ARDOUR_COMMAND_LINE::session_name = "";
3172 if (get_session_parameters (true, false)) {
3178 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
3180 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
3182 string session_name;
3183 string session_path;
3184 string template_name;
3186 bool likely_new = false;
3187 bool cancel_not_quit;
3189 /* deal with any existing DIRTY session now, rather than later. don't
3190 * treat a non-dirty session this way, so that it stays visible
3191 * as we bring up the new session dialog.
3194 if (_session && ARDOUR_UI::instance()->video_timeline) {
3195 ARDOUR_UI::instance()->video_timeline->sync_session_state();
3198 /* if there is already a session, relabel the button
3199 on the SessionDialog so that we don't Quit directly
3201 cancel_not_quit = (_session != 0);
3203 if (_session && _session->dirty()) {
3204 if (unload_session (false)) {
3205 /* unload cancelled by user */
3208 ARDOUR_COMMAND_LINE::session_name = "";
3211 if (!load_template.empty()) {
3212 should_be_new = true;
3213 template_name = load_template;
3216 session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3217 session_path = ARDOUR_COMMAND_LINE::session_name;
3219 if (!session_path.empty()) {
3220 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_EXISTS)) {
3221 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_IS_REGULAR)) {
3222 /* session/snapshot file, change path to be dir */
3223 session_path = Glib::path_get_dirname (session_path);
3228 SessionDialog session_dialog (should_be_new, session_name, session_path, load_template, cancel_not_quit);
3230 _session_dialog = &session_dialog;
3233 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
3235 /* if they named a specific statefile, use it, otherwise they are
3236 just giving a session folder, and we want to use it as is
3237 to find the session.
3240 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
3242 if (suffix != string::npos) {
3243 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
3244 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
3245 session_name = Glib::path_get_basename (session_name);
3247 session_path = ARDOUR_COMMAND_LINE::session_name;
3248 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
3253 session_dialog.clear_given ();
3256 if (should_be_new || session_name.empty()) {
3257 /* need the dialog to get info from user */
3259 cerr << "run dialog\n";
3261 switch (session_dialog.run()) {
3262 case RESPONSE_ACCEPT:
3265 /* this is used for async * app->ShouldLoad(). */
3266 continue; // while loop
3269 if (quit_on_cancel) {
3270 // JE - Currently (July 2014) this section can only get reached if the
3271 // user quits from the main 'Session Setup' dialog (i.e. reaching this
3272 // point does NOT indicate an abnormal termination). Therefore, let's
3273 // behave gracefully (i.e. let's do some cleanup) before we call exit()
3275 pthread_cancel_all ();
3283 session_dialog.hide ();
3286 /* if we run the startup dialog again, offer more than just "new session" */
3288 should_be_new = false;
3290 session_name = session_dialog.session_name (likely_new);
3291 session_path = session_dialog.session_folder ();
3298 int rv = ARDOUR::inflate_session (session_name,
3299 Config->get_default_session_parent_dir(), session_path, session_name);
3301 MessageDialog msg (session_dialog,
3302 string_compose (_("Extracting session-archive failed: %1"), inflate_error (rv)));
3307 session_dialog.set_provided_session (session_name, session_path);
3311 // XXX check archive, inflate
3312 string::size_type suffix = session_name.find (statefile_suffix);
3314 if (suffix != string::npos) {
3315 session_name = session_name.substr (0, suffix);
3318 /* this shouldn't happen, but we catch it just in case it does */
3320 if (session_name.empty()) {
3324 if (session_dialog.use_session_template()) {
3325 template_name = session_dialog.session_template_name();
3326 _session_is_new = true;
3329 if (session_name[0] == G_DIR_SEPARATOR ||
3330 #ifdef PLATFORM_WINDOWS
3331 (session_name.length() > 3 && session_name[1] == ':' && session_name[2] == G_DIR_SEPARATOR)
3333 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
3334 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)
3339 /* absolute path or cwd-relative path specified for session name: infer session folder
3340 from what was given.
3343 session_path = Glib::path_get_dirname (session_name);
3344 session_name = Glib::path_get_basename (session_name);
3348 session_path = session_dialog.session_folder();
3350 char illegal = Session::session_name_is_legal (session_name);
3353 MessageDialog msg (session_dialog,
3354 string_compose (_("To ensure compatibility with various systems\n"
3355 "session names may not contain a '%1' character"),
3358 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3363 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
3366 if (likely_new && !nsm) {
3368 std::string existing = Glib::build_filename (session_path, session_name);
3370 if (!ask_about_loading_existing_session (existing)) {
3371 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3376 _session_is_new = false;
3381 pop_back_splash (session_dialog);
3382 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
3384 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3388 char illegal = Session::session_name_is_legal(session_name);
3391 pop_back_splash (session_dialog);
3392 MessageDialog msg (session_dialog, string_compose(_("To ensure compatibility with various systems\n"
3393 "session names may not contain a '%1' character"), illegal));
3395 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3399 _session_is_new = true;
3402 if (likely_new && template_name.empty()) {
3404 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3408 ret = load_session (session_path, session_name, template_name);
3411 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
3415 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
3416 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
3420 /* clear this to avoid endless attempts to load the
3424 ARDOUR_COMMAND_LINE::session_name = "";
3428 _session_dialog = NULL;
3434 ARDOUR_UI::close_session()
3436 if (!check_audioengine (_main_window)) {
3440 if (unload_session (true)) {
3444 ARDOUR_COMMAND_LINE::session_name = "";
3446 if (get_session_parameters (true, false)) {
3449 if (splash && splash->is_visible()) {
3450 // in 1 second, hide the splash screen
3451 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
3455 /** @param snap_name Snapshot name (without .ardour suffix).
3456 * @return -2 if the load failed because we are not connected to the AudioEngine.
3459 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
3461 Session *new_session;
3466 unload_status = unload_session ();
3468 if (unload_status < 0) {
3470 } else if (unload_status > 0) {
3476 session_loaded = false;
3478 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
3481 new_session = new Session (*AudioEngine::instance(), path, snap_name, 0, mix_template);
3484 /* this one is special */
3486 catch (AudioEngine::PortRegistrationFailure& err) {
3488 MessageDialog msg (err.what(),
3491 Gtk::BUTTONS_CLOSE);
3493 msg.set_title (_("Port Registration Error"));
3494 msg.set_secondary_text (_("Click the Close button to try again."));
3495 msg.set_position (Gtk::WIN_POS_CENTER);
3496 pop_back_splash (msg);
3499 int response = msg.run ();
3504 case RESPONSE_CANCEL:
3511 catch (SessionException e) {
3512 MessageDialog msg (string_compose(
3513 _("Session \"%1 (snapshot %2)\" did not load successfully: %3"),
3514 path, snap_name, e.what()),
3519 msg.set_title (_("Loading Error"));
3520 msg.set_position (Gtk::WIN_POS_CENTER);
3521 pop_back_splash (msg);
3533 MessageDialog msg (string_compose(
3534 _("Session \"%1 (snapshot %2)\" did not load successfully"),
3540 msg.set_title (_("Loading Error"));
3541 msg.set_position (Gtk::WIN_POS_CENTER);
3542 pop_back_splash (msg);
3554 list<string> const u = new_session->unknown_processors ();
3556 MissingPluginDialog d (_session, u);
3561 if (!new_session->writable()) {
3562 MessageDialog msg (_("This session has been opened in read-only mode.\n\nYou will not be able to record or save."),
3567 msg.set_title (_("Read-only Session"));
3568 msg.set_position (Gtk::WIN_POS_CENTER);
3569 pop_back_splash (msg);
3575 set_session (new_session);
3577 session_loaded = true;
3580 _session->set_clean ();
3583 #ifdef WINDOWS_VST_SUPPORT
3584 fst_stop_threading();
3588 Timers::TimerSuspender t;
3592 #ifdef WINDOWS_VST_SUPPORT
3593 fst_start_threading();
3602 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
3604 Session *new_session;
3607 session_loaded = false;
3608 x = unload_session ();
3616 _session_is_new = true;
3619 new_session = new Session (*AudioEngine::instance(), path, snap_name, &bus_profile);
3622 catch (SessionException e) {
3623 cerr << "Here are the errors associated with this failed session:\n";
3625 cerr << "---------\n";
3626 MessageDialog msg (string_compose(_("Could not create session in \"%1\": %2"), path, e.what()));
3627 msg.set_title (_("Loading Error"));
3628 msg.set_position (Gtk::WIN_POS_CENTER);
3629 pop_back_splash (msg);
3634 cerr << "Here are the errors associated with this failed session:\n";
3636 cerr << "---------\n";
3637 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
3638 msg.set_title (_("Loading Error"));
3639 msg.set_position (Gtk::WIN_POS_CENTER);
3640 pop_back_splash (msg);
3645 /* Give the new session the default GUI state, if such things exist */
3648 n = Config->instant_xml (X_("Editor"));
3650 n->remove_nodes_and_delete ("Selection"); // no not apply selection to new sessions.
3651 new_session->add_instant_xml (*n, false);
3653 n = Config->instant_xml (X_("Mixer"));
3655 new_session->add_instant_xml (*n, false);
3658 n = Config->instant_xml (X_("Preferences"));
3660 new_session->add_instant_xml (*n, false);
3663 /* Put the playhead at 0 and scroll fully left */
3664 n = new_session->instant_xml (X_("Editor"));
3666 n->add_property (X_("playhead"), X_("0"));
3667 n->add_property (X_("left-frame"), X_("0"));
3670 set_session (new_session);
3672 session_loaded = true;
3674 new_session->save_state(new_session->name());
3680 ARDOUR_UI::launch_chat ()
3682 MessageDialog dialog(_("<b>Just ask and wait for an answer.\nIt may take from minutes to hours.</b>"), true);
3684 dialog.set_title (_("About the Chat"));
3685 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."));
3687 switch (dialog.run()) {
3690 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
3691 #elif defined PLATFORM_WINDOWS
3692 open_uri("http://webchat.freenode.net/?channels=ardour-windows");
3694 open_uri("http://webchat.freenode.net/?channels=ardour");
3703 ARDOUR_UI::launch_manual ()
3705 PBD::open_uri (Config->get_tutorial_manual_url());
3709 ARDOUR_UI::launch_reference ()
3711 PBD::open_uri (Config->get_reference_manual_url());
3715 ARDOUR_UI::launch_tracker ()
3717 PBD::open_uri ("http://tracker.ardour.org");
3721 ARDOUR_UI::launch_subscribe ()
3723 PBD::open_uri ("https://community.ardour.org/s/subscribe");
3727 ARDOUR_UI::launch_cheat_sheet ()
3730 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheat_sheet_osx.pdf");
3732 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheatsheet.pdf");
3737 ARDOUR_UI::launch_website ()
3739 PBD::open_uri ("http://ardour.org");
3743 ARDOUR_UI::launch_website_dev ()
3745 PBD::open_uri ("http://ardour.org/development.html");
3749 ARDOUR_UI::launch_forums ()
3751 PBD::open_uri ("https://community.ardour.org/forums");
3755 ARDOUR_UI::launch_howto_report ()
3757 PBD::open_uri ("http://ardour.org/reporting_bugs");
3761 ARDOUR_UI::loading_message (const std::string& msg)
3763 if (ARDOUR_COMMAND_LINE::no_splash) {
3771 splash->message (msg);
3775 ARDOUR_UI::show_splash ()
3779 splash = new Splash;
3789 ARDOUR_UI::hide_splash ()
3796 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title, const bool msg_delete)
3800 removed = rep.paths.size();
3803 MessageDialog msgd (_main_window,
3804 _("No files were ready for clean-up"),
3808 msgd.set_title (_("Clean-up"));
3809 msgd.set_secondary_text (_("If this seems suprising, \n\
3810 check for any existing snapshots.\n\
3811 These may still include regions that\n\
3812 require some unused files to continue to exist."));
3818 ArdourDialog results (_("Clean-up"), true, false);
3820 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
3821 CleanupResultsModelColumns() {
3825 Gtk::TreeModelColumn<std::string> visible_name;
3826 Gtk::TreeModelColumn<std::string> fullpath;
3830 CleanupResultsModelColumns results_columns;
3831 Glib::RefPtr<Gtk::ListStore> results_model;
3832 Gtk::TreeView results_display;
3834 results_model = ListStore::create (results_columns);
3835 results_display.set_model (results_model);
3836 results_display.append_column (list_title, results_columns.visible_name);
3838 results_display.set_name ("CleanupResultsList");
3839 results_display.set_headers_visible (true);
3840 results_display.set_headers_clickable (false);
3841 results_display.set_reorderable (false);
3843 Gtk::ScrolledWindow list_scroller;
3846 Gtk::HBox dhbox; // the hbox for the image and text
3847 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
3848 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
3850 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
3852 const string dead_directory = _session->session_directory().dead_path();
3855 %1 - number of files removed
3856 %2 - location of "dead"
3857 %3 - size of files affected
3858 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
3861 const char* bprefix;
3862 double space_adjusted = 0;
3864 if (rep.space < 1000) {
3866 space_adjusted = rep.space;
3867 } else if (rep.space < 1000000) {
3868 bprefix = _("kilo");
3869 space_adjusted = floorf((float)rep.space / 1000.0);
3870 } else if (rep.space < 1000000 * 1000) {
3871 bprefix = _("mega");
3872 space_adjusted = floorf((float)rep.space / (1000.0 * 1000.0));
3874 bprefix = _("giga");
3875 space_adjusted = floorf((float)rep.space / (1000.0 * 1000 * 1000.0));
3879 txt.set_markup (string_compose (P_("\
3880 The following file was deleted from %2,\n\
3881 releasing %3 %4bytes of disk space", "\
3882 The following %1 files were deleted from %2,\n\
3883 releasing %3 %4bytes of disk space", removed),
3884 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3886 txt.set_markup (string_compose (P_("\
3887 The following file was not in use and \n\
3888 has been moved to: %2\n\n\
3889 After a restart of %5\n\n\
3890 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3891 will release an additional %3 %4bytes of disk space.\n", "\
3892 The following %1 files were not in use and \n\
3893 have been moved to: %2\n\n\
3894 After a restart of %5\n\n\
3895 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3896 will release an additional %3 %4bytes of disk space.\n", removed),
3897 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3900 dhbox.pack_start (*dimage, true, false, 5);
3901 dhbox.pack_start (txt, true, false, 5);
3903 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
3904 TreeModel::Row row = *(results_model->append());
3905 row[results_columns.visible_name] = *i;
3906 row[results_columns.fullpath] = *i;
3909 list_scroller.add (results_display);
3910 list_scroller.set_size_request (-1, 150);
3911 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
3913 dvbox.pack_start (dhbox, true, false, 5);
3914 dvbox.pack_start (list_scroller, true, false, 5);
3915 ddhbox.pack_start (dvbox, true, false, 5);
3917 results.get_vbox()->pack_start (ddhbox, true, false, 5);
3918 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
3919 results.set_default_response (RESPONSE_CLOSE);
3920 results.set_position (Gtk::WIN_POS_MOUSE);
3922 results_display.show();
3923 list_scroller.show();
3930 //results.get_vbox()->show();
3931 results.set_resizable (false);
3938 ARDOUR_UI::cleanup ()
3940 if (_session == 0) {
3941 /* shouldn't happen: menu item is insensitive */
3946 MessageDialog checker (_("Are you sure you want to clean-up?"),
3948 Gtk::MESSAGE_QUESTION,
3951 checker.set_title (_("Clean-up"));
3953 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
3954 ALL undo/redo information will be lost if you clean-up.\n\
3955 Clean-up will move all unused files to a \"dead\" location."));
3957 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3958 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
3959 checker.set_default_response (RESPONSE_CANCEL);
3961 checker.set_name (_("CleanupDialog"));
3962 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3963 checker.set_position (Gtk::WIN_POS_MOUSE);
3965 switch (checker.run()) {
3966 case RESPONSE_ACCEPT:
3972 ARDOUR::CleanupReport rep;
3974 editor->prepare_for_cleanup ();
3976 /* do not allow flush until a session is reloaded */
3978 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3980 act->set_sensitive (false);
3983 if (_session->cleanup_sources (rep)) {
3984 editor->finish_cleanup ();
3988 editor->finish_cleanup ();
3991 display_cleanup_results (rep, _("Cleaned Files"), false);
3995 ARDOUR_UI::flush_trash ()
3997 if (_session == 0) {
3998 /* shouldn't happen: menu item is insensitive */
4002 ARDOUR::CleanupReport rep;
4004 if (_session->cleanup_trash_sources (rep)) {
4008 display_cleanup_results (rep, _("deleted file"), true);
4012 ARDOUR_UI::cleanup_peakfiles ()
4014 if (_session == 0) {
4015 /* shouldn't happen: menu item is insensitive */
4019 if (! _session->can_cleanup_peakfiles ()) {
4023 // get all region-views in this session
4025 TrackViewList empty;
4027 editor->get_regions_after(rs, (framepos_t) 0, empty);
4028 std::list<RegionView*> views = rs.by_layer();
4030 // remove displayed audio-region-views waveforms
4031 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
4032 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
4033 if (!arv) { continue ; }
4034 arv->delete_waves();
4037 // cleanup peak files:
4038 // - stop pending peakfile threads
4039 // - close peakfiles if any
4040 // - remove peak dir in session
4041 // - setup peakfiles (background thread)
4042 _session->cleanup_peakfiles ();
4044 // re-add waves to ARV
4045 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
4046 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
4047 if (!arv) { continue ; }
4048 arv->create_waves();
4052 PresentationInfo::order_t
4053 ARDOUR_UI::translate_order (RouteDialogs::InsertAt place)
4055 if (editor->get_selection().tracks.empty()) {
4056 return PresentationInfo::max_order;
4059 PresentationInfo::order_t order_hint = PresentationInfo::max_order;
4062 we want the new routes to have their order keys set starting from
4063 the highest order key in the selection + 1 (if available).
4066 if (place == RouteDialogs::AfterSelection) {
4067 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.back());
4069 order_hint = rtav->route()->presentation_info().order();
4072 } else if (place == RouteDialogs::BeforeSelection) {
4073 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.front());
4075 order_hint = rtav->route()->presentation_info().order();
4077 } else if (place == RouteDialogs::First) {
4080 /* leave order_hint at max_order */
4087 ARDOUR_UI::start_duplicate_routes ()
4089 if (!duplicate_routes_dialog) {
4090 duplicate_routes_dialog = new DuplicateRouteDialog;
4093 if (duplicate_routes_dialog->restart (_session)) {
4097 duplicate_routes_dialog->present ();
4101 ARDOUR_UI::add_route ()
4103 if (!add_route_dialog.get (false)) {
4104 add_route_dialog->signal_response().connect (sigc::mem_fun (*this, &ARDOUR_UI::add_route_dialog_finished));
4111 if (add_route_dialog->is_visible()) {
4112 /* we're already doing this */
4116 add_route_dialog->set_position (WIN_POS_MOUSE);
4117 add_route_dialog->present();
4121 ARDOUR_UI::add_route_dialog_finished (int r)
4125 add_route_dialog->hide();
4128 case RESPONSE_ACCEPT:
4135 if ((count = add_route_dialog->count()) <= 0) {
4139 PresentationInfo::order_t order = translate_order (add_route_dialog->insert_at());
4140 string template_path = add_route_dialog->track_template();
4141 DisplaySuspender ds;
4143 if (!template_path.empty()) {
4144 if (add_route_dialog->name_template_is_default()) {
4145 _session->new_route_from_template (count, order, template_path, string());
4147 _session->new_route_from_template (count, order, template_path, add_route_dialog->name_template());
4152 ChanCount input_chan= add_route_dialog->channels ();
4153 ChanCount output_chan;
4154 string name_template = add_route_dialog->name_template ();
4155 PluginInfoPtr instrument = add_route_dialog->requested_instrument ();
4156 RouteGroup* route_group = add_route_dialog->route_group ();
4157 AutoConnectOption oac = Config->get_output_auto_connect();
4158 bool strict_io = add_route_dialog->use_strict_io ();
4160 if (oac & AutoConnectMaster) {
4161 output_chan.set (DataType::AUDIO, (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan.n_audio()));
4162 output_chan.set (DataType::MIDI, 0);
4164 output_chan = input_chan;
4167 /* XXX do something with name template */
4169 Session::ProcessorChangeBlocker pcb (_session);
4171 switch (add_route_dialog->type_wanted()) {
4172 case AddRouteDialog::AudioTrack:
4173 session_add_audio_track (input_chan.n_audio(), output_chan.n_audio(), add_route_dialog->mode(), route_group, count, name_template, strict_io, order);
4175 case AddRouteDialog::MidiTrack:
4176 session_add_midi_track (route_group, count, name_template, strict_io, instrument, 0, order);
4178 case AddRouteDialog::MixedTrack:
4179 session_add_mixed_track (input_chan, output_chan, route_group, count, name_template, strict_io, instrument, 0, order);
4181 case AddRouteDialog::AudioBus:
4182 session_add_audio_bus (input_chan.n_audio(), output_chan.n_audio(), route_group, count, name_template, strict_io, order);
4184 case AddRouteDialog::MidiBus:
4185 session_add_midi_bus (route_group, count, name_template, strict_io, instrument, 0, order);
4187 case AddRouteDialog::VCAMaster:
4188 session_add_vca (name_template, count);
4194 ARDOUR_UI::stop_video_server (bool ask_confirm)
4196 if (!video_server_process && ask_confirm) {
4197 warning << string_compose (_("Video-Server was not launched by %1. The request to stop it is ignored."), PROGRAM_NAME) << endmsg;
4199 if (video_server_process) {
4201 ArdourDialog confirm (_("Stop Video-Server"), true);
4202 Label m (_("Do you really want to stop the Video Server?"));
4203 confirm.get_vbox()->pack_start (m, true, true);
4204 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
4205 confirm.add_button (_("Yes, Stop It"), Gtk::RESPONSE_ACCEPT);
4206 confirm.show_all ();
4207 if (confirm.run() == RESPONSE_CANCEL) {
4211 delete video_server_process;
4212 video_server_process =0;
4217 ARDOUR_UI::start_video_server_menu (Gtk::Window* float_window)
4219 ARDOUR_UI::start_video_server( float_window, true);
4223 ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg)
4229 if (ARDOUR_UI::instance()->video_timeline->check_server()) {
4230 if (video_server_process) {
4231 popup_error(_("The Video Server is already started."));
4233 popup_error(_("An external Video Server is configured and can be reached. Not starting a new instance."));
4239 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4241 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4243 VideoServerDialog *video_server_dialog = new VideoServerDialog (_session);
4245 video_server_dialog->set_transient_for (*float_window);
4248 if (!Config->get_show_video_server_dialog() && firsttime < 2) {
4249 video_server_dialog->hide();
4251 ResponseType r = (ResponseType) video_server_dialog->run ();
4252 video_server_dialog->hide();
4253 if (r != RESPONSE_ACCEPT) { return false; }
4254 if (video_server_dialog->show_again()) {
4255 Config->set_show_video_server_dialog(false);
4259 std::string icsd_exec = video_server_dialog->get_exec_path();
4260 std::string icsd_docroot = video_server_dialog->get_docroot();
4261 #ifndef PLATFORM_WINDOWS
4262 if (icsd_docroot.empty()) {
4263 icsd_docroot = VideoUtils::video_get_docroot (Config);
4268 #ifdef PLATFORM_WINDOWS
4269 if (VideoUtils::harvid_version >= 0x000802 && icsd_docroot.empty()) {
4270 /* OK, allow all drive letters */
4273 if (g_lstat (icsd_docroot.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode)) {
4274 warning << _("Specified docroot is not an existing directory.") << endmsg;
4277 #ifndef PLATFORM_WINDOWS
4278 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4279 || (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0 ) {
4280 warning << _("Given Video Server is not an executable file.") << endmsg;
4284 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4285 || (sb.st_mode & (S_IXUSR)) == 0 ) {
4286 warning << _("Given Video Server is not an executable file.") << endmsg;
4292 argp=(char**) calloc(9,sizeof(char*));
4293 argp[0] = strdup(icsd_exec.c_str());
4294 argp[1] = strdup("-P");
4295 argp[2] = (char*) calloc(16,sizeof(char)); snprintf(argp[2], 16, "%s", video_server_dialog->get_listenaddr().c_str());
4296 argp[3] = strdup("-p");
4297 argp[4] = (char*) calloc(6,sizeof(char)); snprintf(argp[4], 6, "%i", video_server_dialog->get_listenport());
4298 argp[5] = strdup("-C");
4299 argp[6] = (char*) calloc(6,sizeof(char)); snprintf(argp[6], 6, "%i", video_server_dialog->get_cachesize());
4300 argp[7] = strdup(icsd_docroot.c_str());
4302 stop_video_server();
4304 #ifdef PLATFORM_WINDOWS
4305 if (VideoUtils::harvid_version >= 0x000802 && icsd_docroot.empty()) {
4306 /* OK, allow all drive letters */
4309 if (icsd_docroot == X_("/") || icsd_docroot == X_("C:\\")) {
4310 Config->set_video_advanced_setup(false);
4312 std::ostringstream osstream;
4313 osstream << "http://127.0.0.1:" << video_server_dialog->get_listenport() << "/";
4314 Config->set_video_server_url(osstream.str());
4315 Config->set_video_server_docroot(icsd_docroot);
4316 Config->set_video_advanced_setup(true);
4319 if (video_server_process) {
4320 delete video_server_process;
4323 video_server_process = new ARDOUR::SystemExec(icsd_exec, argp);
4324 if (video_server_process->start()) {
4325 warning << _("Cannot launch the video-server") << endmsg;
4328 int timeout = 120; // 6 sec
4329 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4330 Glib::usleep (50000);
4332 if (--timeout <= 0 || !video_server_process->is_running()) break;
4335 warning << _("Video-server was started but does not respond to requests...") << endmsg;
4337 if (!ARDOUR_UI::instance()->video_timeline->check_server_docroot()) {
4338 delete video_server_process;
4339 video_server_process = 0;
4347 ARDOUR_UI::add_video (Gtk::Window* float_window)
4353 if (!start_video_server(float_window, false)) {
4354 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4359 add_video_dialog->set_transient_for (*float_window);
4362 if (add_video_dialog->is_visible()) {
4363 /* we're already doing this */
4367 ResponseType r = (ResponseType) add_video_dialog->run ();
4368 add_video_dialog->hide();
4369 if (r != RESPONSE_ACCEPT) { return; }
4371 bool local_file, orig_local_file;
4372 std::string path = add_video_dialog->file_name(local_file);
4374 std::string orig_path = path;
4375 orig_local_file = local_file;
4377 bool auto_set_session_fps = add_video_dialog->auto_set_session_fps();
4379 if (local_file && !Glib::file_test(path, Glib::FILE_TEST_EXISTS)) {
4380 warning << string_compose(_("could not open %1"), path) << endmsg;
4383 if (!local_file && path.length() == 0) {
4384 warning << _("no video-file selected") << endmsg;
4388 std::string audio_from_video;
4389 bool detect_ltc = false;
4391 switch (add_video_dialog->import_option()) {
4392 case VTL_IMPORT_TRANSCODE:
4394 TranscodeVideoDialog *transcode_video_dialog;
4395 transcode_video_dialog = new TranscodeVideoDialog (_session, path);
4396 ResponseType r = (ResponseType) transcode_video_dialog->run ();
4397 transcode_video_dialog->hide();
4398 if (r != RESPONSE_ACCEPT) {
4399 delete transcode_video_dialog;
4403 audio_from_video = transcode_video_dialog->get_audiofile();
4405 if (!audio_from_video.empty() && transcode_video_dialog->detect_ltc()) {
4408 else if (!audio_from_video.empty()) {
4409 editor->embed_audio_from_video(
4411 video_timeline->get_offset(),
4412 (transcode_video_dialog->import_option() != VTL_IMPORT_NO_VIDEO)
4415 switch (transcode_video_dialog->import_option()) {
4416 case VTL_IMPORT_TRANSCODED:
4417 path = transcode_video_dialog->get_filename();
4420 case VTL_IMPORT_REFERENCE:
4423 delete transcode_video_dialog;
4426 delete transcode_video_dialog;
4430 case VTL_IMPORT_NONE:
4434 /* strip _session->session_directory().video_path() from video file if possible */
4435 if (local_file && !path.compare(0, _session->session_directory().video_path().size(), _session->session_directory().video_path())) {
4436 path=path.substr(_session->session_directory().video_path().size());
4437 if (path.at(0) == G_DIR_SEPARATOR) {
4438 path=path.substr(1);
4442 video_timeline->set_update_session_fps(auto_set_session_fps);
4444 if (video_timeline->video_file_info(path, local_file)) {
4445 XMLNode* node = new XMLNode(X_("Videotimeline"));
4446 node->add_property (X_("Filename"), path);
4447 node->add_property (X_("AutoFPS"), auto_set_session_fps?X_("1"):X_("0"));
4448 node->add_property (X_("LocalFile"), local_file?X_("1"):X_("0"));
4449 if (orig_local_file) {
4450 node->add_property (X_("OriginalVideoFile"), orig_path);
4452 node->remove_property (X_("OriginalVideoFile"));
4454 _session->add_extra_xml (*node);
4455 _session->set_dirty ();
4457 if (!audio_from_video.empty() && detect_ltc) {
4458 std::vector<LTCFileReader::LTCMap> ltc_seq;
4461 /* TODO ask user about TV standard (LTC alignment if any) */
4462 LTCFileReader ltcr (audio_from_video, video_timeline->get_video_file_fps());
4463 /* TODO ASK user which channel: 0 .. ltcr->channels() - 1 */
4465 ltc_seq = ltcr.read_ltc (/*channel*/ 0, /*max LTC frames to decode*/ 15);
4467 /* TODO seek near end of file, and read LTC until end.
4468 * if it fails to find any LTC frames, scan complete file
4470 * calculate drift of LTC compared to video-duration,
4471 * ask user for reference (timecode from start/mid/end)
4474 // LTCFileReader will have written error messages
4477 ::g_unlink(audio_from_video.c_str());
4479 if (ltc_seq.size() == 0) {
4480 PBD::error << _("No LTC detected, video will not be aligned.") << endmsg;
4482 /* the very first TC in the file is somteimes not aligned properly */
4483 int i = ltc_seq.size() -1;
4484 ARDOUR::frameoffset_t video_start_offset =
4485 _session->nominal_frame_rate() * (ltc_seq[i].timecode_sec - ltc_seq[i].framepos_sec);
4486 PBD::info << string_compose (_("Align video-start to %1 [samples]"), video_start_offset) << endmsg;
4487 video_timeline->set_offset(video_start_offset);
4491 _session->maybe_update_session_range(
4492 std::max(video_timeline->get_offset(), (ARDOUR::frameoffset_t) 0),
4493 std::max(video_timeline->get_offset() + video_timeline->get_duration(), (ARDOUR::frameoffset_t) 0));
4496 if (add_video_dialog->launch_xjadeo() && local_file) {
4497 editor->set_xjadeo_sensitive(true);
4498 editor->toggle_xjadeo_proc(1);
4500 editor->toggle_xjadeo_proc(0);
4502 editor->toggle_ruler_video(true);
4507 ARDOUR_UI::remove_video ()
4509 video_timeline->close_session();
4510 editor->toggle_ruler_video(false);
4513 video_timeline->set_offset_locked(false);
4514 video_timeline->set_offset(0);
4516 /* delete session state */
4517 XMLNode* node = new XMLNode(X_("Videotimeline"));
4518 _session->add_extra_xml(*node);
4519 node = new XMLNode(X_("Videomonitor"));
4520 _session->add_extra_xml(*node);
4521 node = new XMLNode(X_("Videoexport"));
4522 _session->add_extra_xml(*node);
4523 stop_video_server();
4527 ARDOUR_UI::flush_videotimeline_cache (bool localcacheonly)
4529 if (localcacheonly) {
4530 video_timeline->vmon_update();
4532 video_timeline->flush_cache();
4534 editor->queue_visual_videotimeline_update();
4538 ARDOUR_UI::export_video (bool range)
4540 if (ARDOUR::Config->get_show_video_export_info()) {
4541 ExportVideoInfobox infobox (_session);
4542 Gtk::ResponseType rv = (Gtk::ResponseType) infobox.run();
4543 if (infobox.show_again()) {
4544 ARDOUR::Config->set_show_video_export_info(false);
4547 case GTK_RESPONSE_YES:
4548 PBD::open_uri (ARDOUR::Config->get_reference_manual_url() + "/video-timeline/operations/#export");
4554 export_video_dialog->set_session (_session);
4555 export_video_dialog->apply_state(editor->get_selection().time, range);
4556 export_video_dialog->run ();
4557 export_video_dialog->hide ();
4561 ARDOUR_UI::preferences_settings () const
4566 node = _session->instant_xml(X_("Preferences"));
4568 node = Config->instant_xml(X_("Preferences"));
4572 node = new XMLNode (X_("Preferences"));
4579 ARDOUR_UI::mixer_settings () const
4584 node = _session->instant_xml(X_("Mixer"));
4586 node = Config->instant_xml(X_("Mixer"));
4590 node = new XMLNode (X_("Mixer"));
4597 ARDOUR_UI::main_window_settings () const
4602 node = _session->instant_xml(X_("Main"));
4604 node = Config->instant_xml(X_("Main"));
4608 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4609 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4614 node = new XMLNode (X_("Main"));
4621 ARDOUR_UI::editor_settings () const
4626 node = _session->instant_xml(X_("Editor"));
4628 node = Config->instant_xml(X_("Editor"));
4632 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4633 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4638 node = new XMLNode (X_("Editor"));
4645 ARDOUR_UI::keyboard_settings () const
4649 node = Config->extra_xml(X_("Keyboard"));
4652 node = new XMLNode (X_("Keyboard"));
4659 ARDOUR_UI::create_xrun_marker (framepos_t where)
4662 Location *location = new Location (*_session, where, where, _("xrun"), Location::IsMark, 0);
4663 _session->locations()->add (location);
4668 ARDOUR_UI::halt_on_xrun_message ()
4670 cerr << "HALT on xrun\n";
4671 MessageDialog msg (_main_window, _("Recording was stopped because your system could not keep up."));
4676 ARDOUR_UI::xrun_handler (framepos_t where)
4682 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
4684 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
4685 create_xrun_marker(where);
4688 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
4689 halt_on_xrun_message ();
4694 ARDOUR_UI::disk_overrun_handler ()
4696 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
4698 if (!have_disk_speed_dialog_displayed) {
4699 have_disk_speed_dialog_displayed = true;
4700 MessageDialog* msg = new MessageDialog (_main_window, string_compose (_("\
4701 The disk system on your computer\n\
4702 was not able to keep up with %1.\n\
4704 Specifically, it failed to write data to disk\n\
4705 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
4706 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4712 /* TODO: this is getting elaborate enough to warrant being split into a dedicated class */
4713 static MessageDialog *scan_dlg = NULL;
4714 static ProgressBar *scan_pbar = NULL;
4715 static HBox *scan_tbox = NULL;
4716 static Gtk::Button *scan_timeout_button;
4719 ARDOUR_UI::cancel_plugin_scan ()
4721 PluginManager::instance().cancel_plugin_scan();
4725 ARDOUR_UI::cancel_plugin_timeout ()
4727 PluginManager::instance().cancel_plugin_timeout();
4728 scan_timeout_button->set_sensitive (false);
4732 ARDOUR_UI::plugin_scan_timeout (int timeout)
4734 if (!scan_dlg || !scan_dlg->is_mapped() || !scan_pbar) {
4738 scan_pbar->set_sensitive (false);
4739 scan_timeout_button->set_sensitive (true);
4740 scan_pbar->set_fraction ((float) timeout / (float) Config->get_vst_scan_timeout());
4743 scan_pbar->set_sensitive (false);
4744 scan_timeout_button->set_sensitive (false);
4750 ARDOUR_UI::plugin_scan_dialog (std::string type, std::string plugin, bool can_cancel)
4752 if (type == X_("closeme") && !(scan_dlg && scan_dlg->is_mapped())) {
4756 const bool cancelled = PluginManager::instance().cancelled();
4757 if (type != X_("closeme") && (!UIConfiguration::instance().get_show_plugin_scan_window()) && !_initial_verbose_plugin_scan) {
4758 if (cancelled && scan_dlg->is_mapped()) {
4763 if (cancelled || !can_cancel) {
4768 static Gtk::Button *cancel_button;
4770 scan_dlg = new MessageDialog("", false, MESSAGE_INFO, BUTTONS_NONE); // TODO manage
4771 VBox* vbox = scan_dlg->get_vbox();
4772 vbox->set_size_request(400,-1);
4773 scan_dlg->set_title (_("Scanning for plugins"));
4775 cancel_button = manage(new Gtk::Button(_("Cancel plugin scan")));
4776 cancel_button->set_name ("EditorGTKButton");
4777 cancel_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_scan) );
4778 cancel_button->show();
4780 scan_dlg->get_vbox()->pack_start ( *cancel_button, PACK_SHRINK);
4782 scan_tbox = manage( new HBox() );
4784 scan_timeout_button = manage(new Gtk::Button(_("Stop Timeout")));
4785 scan_timeout_button->set_name ("EditorGTKButton");
4786 scan_timeout_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_timeout) );
4787 scan_timeout_button->show();
4789 scan_pbar = manage(new ProgressBar());
4790 scan_pbar->set_orientation(Gtk::PROGRESS_RIGHT_TO_LEFT);
4791 scan_pbar->set_text(_("Scan Timeout"));
4794 scan_tbox->pack_start (*scan_pbar, PACK_EXPAND_WIDGET, 4);
4795 scan_tbox->pack_start (*scan_timeout_button, PACK_SHRINK, 4);
4797 scan_dlg->get_vbox()->pack_start (*scan_tbox, PACK_SHRINK, 4);
4800 assert(scan_dlg && scan_tbox && cancel_button);
4802 if (type == X_("closeme")) {
4806 scan_dlg->set_message(type + ": " + Glib::path_get_basename(plugin));
4809 if (!can_cancel || !cancelled) {
4810 scan_timeout_button->set_sensitive(false);
4812 cancel_button->set_sensitive(can_cancel && !cancelled);
4818 ARDOUR_UI::gui_idle_handler ()
4821 /* due to idle calls, gtk_events_pending() may always return true */
4822 while (gtk_events_pending() && --timeout) {
4823 gtk_main_iteration ();
4828 ARDOUR_UI::disk_underrun_handler ()
4830 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
4832 if (!have_disk_speed_dialog_displayed) {
4833 have_disk_speed_dialog_displayed = true;
4834 MessageDialog* msg = new MessageDialog (
4835 _main_window, string_compose (_("The disk system on your computer\n\
4836 was not able to keep up with %1.\n\
4838 Specifically, it failed to read data from disk\n\
4839 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
4840 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4846 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
4848 have_disk_speed_dialog_displayed = false;
4853 ARDOUR_UI::session_dialog (std::string msg)
4855 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
4859 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
4866 ARDOUR_UI::pending_state_dialog ()
4868 HBox* hbox = manage (new HBox());
4869 Image* image = manage (new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG));
4870 ArdourDialog dialog (_("Crash Recovery"), true);
4871 Label message (string_compose (_("\
4872 This session appears to have been in the\n\
4873 middle of recording when %1 or\n\
4874 the computer was shutdown.\n\
4876 %1 can recover any captured audio for\n\
4877 you, or it can ignore it. Please decide\n\
4878 what you would like to do.\n"), PROGRAM_NAME));
4879 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4880 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4881 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4882 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4883 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
4884 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
4885 dialog.set_default_response (RESPONSE_ACCEPT);
4886 dialog.set_position (WIN_POS_CENTER);
4891 switch (dialog.run ()) {
4892 case RESPONSE_ACCEPT:
4900 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
4902 HBox* hbox = new HBox();
4903 Image* image = new Image (Stock::DIALOG_WARNING, ICON_SIZE_DIALOG);
4904 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
4905 Label message (string_compose (_("\
4906 This session was created with a sample rate of %1 Hz, but\n\
4907 %2 is currently running at %3 Hz. If you load this session,\n\
4908 audio may be played at the wrong sample rate.\n"), desired, PROGRAM_NAME, actual));
4910 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4911 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4912 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4913 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4914 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
4915 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
4916 dialog.set_default_response (RESPONSE_ACCEPT);
4917 dialog.set_position (WIN_POS_CENTER);
4922 switch (dialog.run()) {
4923 case RESPONSE_ACCEPT:
4933 ARDOUR_UI::sr_mismatch_message (framecnt_t desired, framecnt_t actual)
4935 MessageDialog msg (string_compose (_("\
4936 This session was created with a sample rate of %1 Hz, but\n\
4937 %2 is currently running at %3 Hz.\n\
4938 Audio will be recorded and played at the wrong sample rate.\n\
4939 Re-Configure the Audio Engine in\n\
4940 Menu > Window > Audio/Midi Setup"),
4941 desired, PROGRAM_NAME, actual),
4943 Gtk::MESSAGE_WARNING);
4948 ARDOUR_UI::use_config ()
4953 ARDOUR_UI::update_transport_clocks (framepos_t pos)
4955 if (UIConfiguration::instance().get_primary_clock_delta_edit_cursor()) {
4956 primary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
4958 primary_clock->set (pos);
4961 if (UIConfiguration::instance().get_secondary_clock_delta_edit_cursor()) {
4962 secondary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
4964 secondary_clock->set (pos);
4967 if (big_clock_window) {
4968 big_clock->set (pos);
4970 ARDOUR_UI::instance()->video_timeline->manual_seek_video_monitor(pos);
4974 ARDOUR_UI::step_edit_status_change (bool yn)
4976 // XXX should really store pre-step edit status of things
4977 // we make insensitive
4980 rec_button.set_active_state (Gtkmm2ext::ImplicitActive);
4981 rec_button.set_sensitive (false);
4983 rec_button.unset_active_state ();;
4984 rec_button.set_sensitive (true);
4989 ARDOUR_UI::record_state_changed ()
4991 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
4994 /* why bother - the clock isn't visible */
4998 ActionManager::set_sensitive (ActionManager::rec_sensitive_actions, !_session->actively_recording());
5000 if (big_clock_window) {
5001 if (_session->record_status () == Session::Recording && _session->have_rec_enabled_track ()) {
5002 big_clock->set_active (true);
5004 big_clock->set_active (false);
5011 ARDOUR_UI::first_idle ()
5014 _session->allow_auto_play (true);
5018 editor->first_idle();
5021 Keyboard::set_can_save_keybindings (true);
5026 ARDOUR_UI::store_clock_modes ()
5028 XMLNode* node = new XMLNode(X_("ClockModes"));
5030 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
5031 XMLNode* child = new XMLNode (X_("Clock"));
5033 child->add_property (X_("name"), (*x)->name());
5034 child->add_property (X_("mode"), enum_2_string ((*x)->mode()));
5035 child->add_property (X_("on"), ((*x)->off() ? X_("no") : X_("yes")));
5037 node->add_child_nocopy (*child);
5040 _session->add_extra_xml (*node);
5041 _session->set_dirty ();
5045 ARDOUR_UI::setup_profile ()
5047 if (gdk_screen_width() < 1200 || getenv ("ARDOUR_NARROW_SCREEN")) {
5048 Profile->set_small_screen ();
5051 if (g_getenv ("TRX")) {
5052 Profile->set_trx ();
5055 if (g_getenv ("MIXBUS")) {
5056 Profile->set_mixbus ();
5061 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
5063 MissingFileDialog dialog (s, str, type);
5068 int result = dialog.run ();
5075 return 1; // quit entire session load
5078 result = dialog.get_action ();
5084 ARDOUR_UI::ambiguous_file (std::string file, std::vector<std::string> hits)
5086 AmbiguousFileDialog dialog (file, hits);
5093 return dialog.get_which ();
5096 /** Allocate our thread-local buffers */
5098 ARDOUR_UI::get_process_buffers ()
5100 _process_thread->get_buffers ();
5103 /** Drop our thread-local buffers */
5105 ARDOUR_UI::drop_process_buffers ()
5107 _process_thread->drop_buffers ();
5111 ARDOUR_UI::feedback_detected ()
5113 _feedback_exists = true;
5117 ARDOUR_UI::successful_graph_sort ()
5119 _feedback_exists = false;
5123 ARDOUR_UI::midi_panic ()
5126 _session->midi_panic();
5131 ARDOUR_UI::session_format_mismatch (std::string xml_path, std::string backup_path)
5133 const char* start_big = "<span size=\"x-large\" weight=\"bold\">";
5134 const char* end_big = "</span>";
5135 const char* start_mono = "<tt>";
5136 const char* end_mono = "</tt>";
5138 MessageDialog msg (string_compose (_("%4This is a session from an older version of %3%5\n\n"
5139 "%3 has copied the old session file\n\n%6%1%7\n\nto\n\n%6%2%7\n\n"
5140 "From now on, use the backup copy with older versions of %3"),
5141 xml_path, backup_path, PROGRAM_NAME,
5143 start_mono, end_mono), true);
5150 ARDOUR_UI::reset_peak_display ()
5152 if (!_session || !_session->master_out() || !editor_meter) return;
5153 editor_meter->clear_meters();
5154 editor_meter_max_peak = -INFINITY;
5155 editor_meter_peak_display.set_active_state ( Gtkmm2ext::Off );
5159 ARDOUR_UI::reset_group_peak_display (RouteGroup* group)
5161 if (!_session || !_session->master_out()) return;
5162 if (group == _session->master_out()->route_group()) {
5163 reset_peak_display ();
5168 ARDOUR_UI::reset_route_peak_display (Route* route)
5170 if (!_session || !_session->master_out()) return;
5171 if (_session->master_out().get() == route) {
5172 reset_peak_display ();
5177 ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate)
5179 audio_midi_setup->set_desired_sample_rate (desired_sample_rate);
5180 audio_midi_setup->set_position (WIN_POS_CENTER);
5182 if (Config->get_try_autostart_engine () || getenv ("TRY_AUTOSTART_ENGINE")) {
5183 audio_midi_setup->try_autostart ();
5184 if (ARDOUR::AudioEngine::instance()->running()) {
5190 int response = audio_midi_setup->run();
5191 printf("RESPONSE %d\n", response);
5193 case Gtk::RESPONSE_DELETE_EVENT:
5196 if (!AudioEngine::instance()->running()) {
5199 audio_midi_setup->hide ();
5207 ARDOUR_UI::transport_numpad_timeout ()
5209 _numpad_locate_happening = false;
5210 if (_numpad_timeout_connection.connected() )
5211 _numpad_timeout_connection.disconnect();
5216 ARDOUR_UI::transport_numpad_decimal ()
5218 _numpad_timeout_connection.disconnect();
5220 if (_numpad_locate_happening) {
5221 if (editor) editor->goto_nth_marker(_pending_locate_num - 1);
5222 _numpad_locate_happening = false;
5224 _pending_locate_num = 0;
5225 _numpad_locate_happening = true;
5226 _numpad_timeout_connection = Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::transport_numpad_timeout), 2*1000);
5231 ARDOUR_UI::transport_numpad_event (int num)
5233 if ( _numpad_locate_happening ) {
5234 _pending_locate_num = _pending_locate_num*10 + num;
5237 case 0: toggle_roll(false, false); break;
5238 case 1: transport_rewind(1); break;
5239 case 2: transport_forward(1); break;
5240 case 3: transport_record(true); break;
5241 case 4: toggle_session_auto_loop(); break;
5242 case 5: transport_record(false); toggle_session_auto_loop(); break;
5243 case 6: toggle_punch(); break;
5244 case 7: toggle_click(); break;
5245 case 8: toggle_auto_return(); break;
5246 case 9: toggle_follow_edits(); break;
5252 ARDOUR_UI::set_flat_buttons ()
5254 CairoWidget::set_flat_buttons( UIConfiguration::instance().get_flat_buttons() );
5258 ARDOUR_UI::audioengine_became_silent ()
5260 MessageDialog msg (string_compose (_("This is a free/demo copy of %1. It has just switched to silent mode."), PROGRAM_NAME),
5262 Gtk::MESSAGE_WARNING,
5266 msg.set_title (string_compose (_("%1 is now silent"), PROGRAM_NAME));
5268 Gtk::Label pay_label (string_compose (_("Please consider paying for a copy of %1 - you can pay whatever you want."), PROGRAM_NAME));
5269 Gtk::Label subscribe_label (_("Better yet become a subscriber - subscriptions start at US$1 per month."));
5270 Gtk::Button pay_button (_("Pay for a copy (via the web)"));
5271 Gtk::Button subscribe_button (_("Become a subscriber (via the web)"));
5272 Gtk::HBox pay_button_box;
5273 Gtk::HBox subscribe_button_box;
5275 pay_button_box.pack_start (pay_button, true, false);
5276 subscribe_button_box.pack_start (subscribe_button, true, false);
5278 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 */
5280 pay_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://ardour.org/download")));
5281 subscribe_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://community.ardour.org/s/subscribe")));
5283 msg.get_vbox()->pack_start (pay_label);
5284 msg.get_vbox()->pack_start (pay_button_box);
5285 msg.get_vbox()->pack_start (subscribe_label);
5286 msg.get_vbox()->pack_start (subscribe_button_box);
5288 msg.get_vbox()->show_all ();
5290 msg.add_button (_("Remain silent"), Gtk::RESPONSE_CANCEL);
5291 msg.add_button (_("Save and quit"), Gtk::RESPONSE_NO);
5292 msg.add_button (_("Give me more time"), Gtk::RESPONSE_YES);
5297 case Gtk::RESPONSE_YES:
5298 AudioEngine::instance()->reset_silence_countdown ();
5301 case Gtk::RESPONSE_NO:
5303 save_state_canfail ("");
5307 case Gtk::RESPONSE_CANCEL:
5309 /* don't reset, save session and exit */
5315 ARDOUR_UI::hide_application ()
5317 Application::instance ()-> hide ();
5321 ARDOUR_UI::setup_toplevel_window (Gtk::Window& window, const string& name, void* owner)
5323 /* icons, titles, WM stuff */
5325 static list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
5327 if (window_icons.empty()) {
5328 Glib::RefPtr<Gdk::Pixbuf> icon;
5329 if ((icon = ::get_icon (PROGRAM_NAME "-icon_16px"))) {
5330 window_icons.push_back (icon);
5332 if ((icon = ::get_icon (PROGRAM_NAME "-icon_22px"))) {
5333 window_icons.push_back (icon);
5335 if ((icon = ::get_icon (PROGRAM_NAME "-icon_32px"))) {
5336 window_icons.push_back (icon);
5338 if ((icon = ::get_icon (PROGRAM_NAME "-icon_48px"))) {
5339 window_icons.push_back (icon);
5343 if (!window_icons.empty()) {
5344 window.set_default_icon_list (window_icons);
5347 Gtkmm2ext::WindowTitle title (Glib::get_application_name());
5349 if (!name.empty()) {
5353 window.set_title (title.get_string());
5354 window.set_wmclass (string_compose (X_("%1_%1"), downcase (std::string(PROGRAM_NAME)), downcase (name)), PROGRAM_NAME);
5356 window.set_flags (CAN_FOCUS);
5357 window.add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
5359 /* This is a hack to ensure that GTK-accelerators continue to
5360 * work. Once we switch over to entirely native bindings, this will be
5361 * unnecessary and should be removed
5363 window.add_accel_group (ActionManager::ui_manager->get_accel_group());
5365 window.signal_configure_event().connect (sigc::mem_fun (*this, &ARDOUR_UI::configure_handler));
5366 window.signal_window_state_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::tabbed_window_state_event_handler), owner));
5367 window.signal_key_press_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5368 window.signal_key_release_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5372 ARDOUR_UI::key_event_handler (GdkEventKey* ev, Gtk::Window* event_window)
5374 Gtkmm2ext::Bindings* bindings = 0;
5375 Gtk::Window* window = 0;
5377 /* until we get ardour bindings working, we are not handling key
5381 if (ev->type != GDK_KEY_PRESS) {
5385 if (event_window == &_main_window) {
5387 window = event_window;
5389 /* find current tab contents */
5391 Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page());
5393 /* see if it uses the ardour binding system */
5396 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(w->get_data ("ardour-bindings"));
5399 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("main window key event, bindings = %1, global = %2\n", bindings, &global_bindings));
5403 window = event_window;
5405 /* see if window uses ardour binding system */
5407 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(window->get_data ("ardour-bindings"));
5410 /* An empty binding set is treated as if it doesn't exist */
5412 if (bindings && bindings->empty()) {
5416 return key_press_focus_accelerator_handler (*window, ev, bindings);
5419 static Gtkmm2ext::Bindings*
5420 get_bindings_from_widget_heirarchy (GtkWidget** w)
5425 if ((p = g_object_get_data (G_OBJECT(*w), "ardour-bindings")) != 0) {
5428 *w = gtk_widget_get_parent (*w);
5431 return reinterpret_cast<Gtkmm2ext::Bindings*> (p);
5435 ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev, Gtkmm2ext::Bindings* bindings)
5437 GtkWindow* win = window.gobj();
5438 GtkWidget* focus = gtk_window_get_focus (win);
5439 GtkWidget* binding_widget = focus;
5440 bool special_handling_of_unmodified_accelerators = false;
5441 const guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK));
5445 /* some widget has keyboard focus */
5447 if (GTK_IS_ENTRY(focus) || Keyboard::some_magic_widget_has_focus()) {
5449 /* A particular kind of focusable widget currently has keyboard
5450 * focus. All unmodified key events should go to that widget
5451 * first and not be used as an accelerator by default
5454 special_handling_of_unmodified_accelerators = true;
5458 Gtkmm2ext::Bindings* focus_bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5459 if (focus_bindings) {
5460 bindings = focus_bindings;
5461 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Switch bindings based on focus widget, now using %1\n", bindings->name()));
5466 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",
5469 Gtkmm2ext::show_gdk_event_state (ev->state),
5470 special_handling_of_unmodified_accelerators,
5471 Keyboard::some_magic_widget_has_focus(),
5473 (focus ? gtk_widget_get_name (focus) : "no focus widget"),
5474 ((ev->state & mask) ? "yes" : "no"),
5475 window.get_title()));
5477 /* This exists to allow us to override the way GTK handles
5478 key events. The normal sequence is:
5480 a) event is delivered to a GtkWindow
5481 b) accelerators/mnemonics are activated
5482 c) if (b) didn't handle the event, propagate to
5483 the focus widget and/or focus chain
5485 The problem with this is that if the accelerators include
5486 keys without modifiers, such as the space bar or the
5487 letter "e", then pressing the key while typing into
5488 a text entry widget results in the accelerator being
5489 activated, instead of the desired letter appearing
5492 There is no good way of fixing this, but this
5493 represents a compromise. The idea is that
5494 key events involving modifiers (not Shift)
5495 get routed into the activation pathway first, then
5496 get propagated to the focus widget if necessary.
5498 If the key event doesn't involve modifiers,
5499 we deliver to the focus widget first, thus allowing
5500 it to get "normal text" without interference
5503 Of course, this can also be problematic: if there
5504 is a widget with focus, then it will swallow
5505 all "normal text" accelerators.
5509 if (!special_handling_of_unmodified_accelerators || (ev->state & mask)) {
5511 /* no special handling or there are modifiers in effect: accelerate first */
5513 DEBUG_TRACE (DEBUG::Accelerators, "\tactivate, then propagate\n");
5514 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tevent send-event:%1 time:%2 length:%3 name %7 string:%4 hardware_keycode:%5 group:%6\n",
5515 ev->send_event, ev->time, ev->length, ev->string, ev->hardware_keycode, ev->group, gdk_keyval_name (ev->keyval)));
5517 DEBUG_TRACE (DEBUG::Accelerators, "\tsending to window\n");
5518 KeyboardKey k (ev->state, ev->keyval);
5522 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tusing Ardour bindings %1 @ %2 for this event\n", bindings->name(), bindings));
5524 if (bindings->activate (k, Bindings::Press)) {
5525 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5529 if (binding_widget) {
5530 binding_widget = gtk_widget_get_parent (binding_widget);
5531 if (binding_widget) {
5532 bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5541 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5543 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5544 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5548 DEBUG_TRACE (DEBUG::Accelerators, "\tnot accelerated, now propagate\n");
5550 if (gtk_window_propagate_key_event (win, ev)) {
5551 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate handled\n");
5557 /* no modifiers, propagate first */
5559 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate, then activate\n");
5561 if (gtk_window_propagate_key_event (win, ev)) {
5562 DEBUG_TRACE (DEBUG::Accelerators, "\thandled by propagate\n");
5566 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagation didn't handle, so activate\n");
5567 KeyboardKey k (ev->state, ev->keyval);
5571 DEBUG_TRACE (DEBUG::Accelerators, "\tusing Ardour bindings for this window\n");
5574 if (bindings->activate (k, Bindings::Press)) {
5575 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5579 if (binding_widget) {
5580 binding_widget = gtk_widget_get_parent (binding_widget);
5581 if (binding_widget) {
5582 bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5591 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5593 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5594 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5599 DEBUG_TRACE (DEBUG::Accelerators, "\tnot handled\n");
5604 ARDOUR_UI::load_bindings ()
5606 if ((global_bindings = Bindings::get_bindings (X_("Global"), global_actions)) == 0) {
5607 error << _("Global keybindings are missing") << endmsg;
5612 ARDOUR_UI::cancel_solo ()
5615 _session->cancel_all_solo ();
5620 ARDOUR_UI::reset_focus (Gtk::Widget* w)
5622 /* this resets focus to the first focusable parent of the given widget,
5623 * or, if there is no focusable parent, cancels focus in the toplevel
5624 * window that the given widget is packed into (if there is one).
5631 Gtk::Widget* top = w->get_toplevel();
5633 if (!top || !top->is_toplevel()) {
5637 w = w->get_parent ();
5641 if (w->is_toplevel()) {
5642 /* Setting the focus widget to a Gtk::Window causes all
5643 * subsequent calls to ::has_focus() on the nominal
5644 * focus widget in that window to return
5645 * false. Workaround: never set focus to the toplevel
5651 if (w->get_can_focus ()) {
5652 Gtk::Window* win = dynamic_cast<Gtk::Window*> (top);
5653 win->set_focus (*w);
5656 w = w->get_parent ();
5659 if (top == &_main_window) {
5663 /* no focusable parent found, cancel focus in top level window.
5664 C++ API cannot be used for this. Thanks, references.
5667 gtk_window_set_focus (GTK_WINDOW(top->gobj()), 0);