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>
43 #include "pbd/gstdio_compat.h"
45 #include <gtkmm/messagedialog.h>
46 #include <gtkmm/accelmap.h>
47 #include <gtkmm/stock.h>
49 #include "pbd/error.h"
50 #include "pbd/basename.h"
51 #include "pbd/compose.h"
52 #include "pbd/convert.h"
53 #include "pbd/failed_constructor.h"
54 #include "pbd/enumwriter.h"
55 #include "pbd/memento_command.h"
56 #include "pbd/openuri.h"
57 #include "pbd/stl_delete.h"
58 #include "pbd/file_utils.h"
59 #include "pbd/localtime_r.h"
60 #include "pbd/pthread_utils.h"
61 #include "pbd/replace_all.h"
62 #include "pbd/xml++.h"
64 #include "gtkmm2ext/application.h"
65 #include "gtkmm2ext/bindings.h"
66 #include "gtkmm2ext/gtk_ui.h"
67 #include "gtkmm2ext/utils.h"
68 #include "gtkmm2ext/click_box.h"
69 #include "gtkmm2ext/fastmeter.h"
70 #include "gtkmm2ext/popup.h"
71 #include "gtkmm2ext/window_title.h"
73 #include "ardour/ardour.h"
74 #include "ardour/audio_backend.h"
75 #include "ardour/audio_track.h"
76 #include "ardour/audioengine.h"
77 #include "ardour/audiofilesource.h"
78 #include "ardour/automation_watch.h"
79 #include "ardour/diskstream.h"
80 #include "ardour/filename_extensions.h"
81 #include "ardour/filesystem_paths.h"
82 #include "ardour/ltc_file_reader.h"
83 #include "ardour/midi_track.h"
84 #include "ardour/port.h"
85 #include "ardour/plugin_manager.h"
86 #include "ardour/process_thread.h"
87 #include "ardour/profile.h"
88 #include "ardour/recent_sessions.h"
89 #include "ardour/record_enable_control.h"
90 #include "ardour/session_directory.h"
91 #include "ardour/session_route.h"
92 #include "ardour/session_state_utils.h"
93 #include "ardour/session_utils.h"
94 #include "ardour/source_factory.h"
95 #include "ardour/slave.h"
96 #include "ardour/system_exec.h"
97 #include "ardour/track.h"
98 #include "ardour/vca_manager.h"
99 #include "ardour/utils.h"
101 #include "LuaBridge/LuaBridge.h"
103 #ifdef WINDOWS_VST_SUPPORT
106 #ifdef AUDIOUNIT_SUPPORT
107 #include "ardour/audio_unit.h"
110 // fix for OSX (nsm.h has a check function, AU/Apple defines check)
115 #include "timecode/time.h"
117 typedef uint64_t microseconds_t;
122 #include "add_route_dialog.h"
123 #include "ambiguous_file_dialog.h"
124 #include "ardour_ui.h"
125 #include "audio_clock.h"
126 #include "audio_region_view.h"
127 #include "big_clock_window.h"
128 #include "bundle_manager.h"
129 #include "duplicate_routes_dialog.h"
131 #include "engine_dialog.h"
132 #include "export_video_dialog.h"
133 #include "export_video_infobox.h"
134 #include "gain_meter.h"
135 #include "global_port_matrix.h"
136 #include "gui_object.h"
137 #include "gui_thread.h"
138 #include "keyboard.h"
139 #include "keyeditor.h"
140 #include "location_ui.h"
141 #include "lua_script_manager.h"
142 #include "luawindow.h"
143 #include "main_clock.h"
144 #include "missing_file_dialog.h"
145 #include "missing_plugin_dialog.h"
146 #include "mixer_ui.h"
147 #include "meterbridge.h"
148 #include "mouse_cursors.h"
151 #include "pingback.h"
152 #include "processor_box.h"
153 #include "prompter.h"
154 #include "public_editor.h"
155 #include "rc_option_editor.h"
156 #include "route_time_axis.h"
157 #include "route_params_ui.h"
158 #include "save_as_dialog.h"
159 #include "script_selector.h"
160 #include "session_dialog.h"
161 #include "session_metadata_dialog.h"
162 #include "session_option_editor.h"
163 #include "shuttle_control.h"
164 #include "speaker_dialog.h"
167 #include "theme_manager.h"
168 #include "time_axis_view_item.h"
171 #include "video_server_dialog.h"
172 #include "add_video_dialog.h"
173 #include "transcode_video_dialog.h"
177 using namespace ARDOUR;
178 using namespace ARDOUR_UI_UTILS;
180 using namespace Gtkmm2ext;
183 using namespace Editing;
185 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
187 sigc::signal<void, framepos_t, bool, framepos_t> ARDOUR_UI::Clock;
188 sigc::signal<void> ARDOUR_UI::CloseAllDialogs;
191 ask_about_configuration_copy (string const & old_dir, string const & new_dir, int version)
193 MessageDialog msg (string_compose (_("%1 %2.x has discovered configuration files from %1 %3.x.\n\n"
194 "Would you like these files to be copied and used for %1 %2.x?\n\n"
195 "(This will require you to restart %1.)"),
196 PROGRAM_NAME, PROGRAM_VERSION, version),
197 false, /* no markup */
200 true /* modal, though it hardly matters since it is the only window */
203 msg.set_default_response (Gtk::RESPONSE_YES);
206 return (msg.run() == Gtk::RESPONSE_YES);
210 libxml_generic_error_func (void* /* parsing_context*/,
218 vsnprintf (buf, sizeof (buf), msg, ap);
219 error << buf << endmsg;
224 libxml_structured_error_func (void* /* parsing_context*/,
232 replace_all (msg, "\n", "");
235 if (err->file && err->line) {
236 error << X_("XML error: ") << msg << " in " << err->file << " at line " << err->line;
239 error << ':' << err->int2;
244 error << X_("XML error: ") << msg << endmsg;
250 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
251 : Gtkmm2ext::UI (PROGRAM_NAME, X_("gui"), argcp, argvp)
252 , session_loaded (false)
253 , gui_object_state (new GUIObjectState)
254 , primary_clock (new MainClock (X_("primary"), X_("transport"), true ))
255 , secondary_clock (new MainClock (X_("secondary"), X_("secondary"), false))
256 , big_clock (new AudioClock (X_("bigclock"), false, "big", true, true, false, false))
258 , global_actions (X_("global"))
259 , ignore_dual_punch (false)
260 , main_window_visibility (0)
265 , _mixer_on_top (false)
266 , _initial_verbose_plugin_scan (false)
267 , first_time_engine_run (true)
268 , roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll))
269 , stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop))
270 , goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart))
271 , goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd))
272 , auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop))
273 , play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection))
274 , rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable))
275 , auto_return_button (ArdourButton::led_default_elements)
276 , follow_edits_button (ArdourButton::led_default_elements)
277 , auto_input_button (ArdourButton::led_default_elements)
278 , auditioning_alert_button (_("Audition"))
279 , solo_alert_button (_("Solo"))
280 , feedback_alert_button (_("Feedback"))
281 , error_alert_button ( ArdourButton::just_led_default_elements )
283 , editor_meter_peak_display()
284 , _numpad_locate_happening (false)
285 , _session_is_new (false)
286 , last_key_press_time (0)
290 , rc_option_editor (0)
291 , speaker_config_window (X_("speaker-config"), _("Speaker Configuration"))
292 , add_route_dialog (X_("add-routes"), _("Add Tracks/Busses"))
293 , about (X_("about"), _("About"))
294 , location_ui (X_("locations"), _("Locations"))
295 , route_params (X_("inspector"), _("Tracks and Busses"))
296 , audio_midi_setup (X_("audio-midi-setup"), _("Audio/MIDI Setup"))
297 , export_video_dialog (X_("video-export"), _("Video Export Dialog"))
298 , lua_script_window (X_("script-manager"), _("Script Manager"))
299 , session_option_editor (X_("session-options-editor"), _("Properties"), boost::bind (&ARDOUR_UI::create_session_option_editor, this))
300 , add_video_dialog (X_("add-video"), _("Add Video"), boost::bind (&ARDOUR_UI::create_add_video_dialog, this))
301 , bundle_manager (X_("bundle-manager"), _("Bundle Manager"), boost::bind (&ARDOUR_UI::create_bundle_manager, this))
302 , big_clock_window (X_("big-clock"), _("Big Clock"), boost::bind (&ARDOUR_UI::create_big_clock_window, this))
303 , audio_port_matrix (X_("audio-connection-manager"), _("Audio Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::AUDIO))
304 , midi_port_matrix (X_("midi-connection-manager"), _("MIDI Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::MIDI))
305 , key_editor (X_("key-editor"), _("Bindings Editor"), boost::bind (&ARDOUR_UI::create_key_editor, this))
306 , video_server_process (0)
308 , have_configure_timeout (false)
309 , last_configure_time (0)
311 , have_disk_speed_dialog_displayed (false)
312 , _status_bar_visibility (X_("status-bar"))
313 , _feedback_exists (false)
314 , _log_not_acknowledged (LogLevelNone)
315 , duplicate_routes_dialog (0)
316 , editor_visibility_button (S_("Window|Editor"))
317 , mixer_visibility_button (S_("Window|Mixer"))
318 , prefs_visibility_button (S_("Window|Preferences"))
320 Gtkmm2ext::init (localedir);
322 UIConfiguration::instance().post_gui_init ();
324 if (ARDOUR::handle_old_configuration_files (boost::bind (ask_about_configuration_copy, _1, _2, _3))) {
325 MessageDialog msg (string_compose (_("Your configuration files were copied. You can now restart %1."), PROGRAM_NAME), true);
327 /* configuration was modified, exit immediately */
332 if (string (VERSIONSTRING).find (".pre") != string::npos) {
333 /* check this is not being run from ./ardev etc. */
334 gchar const *x = g_getenv ("ARDOUR_THEMES_PATH");
335 if (!x || string (x).find ("gtk2_ardour") == string::npos) {
336 pre_release_dialog ();
340 if (theArdourUI == 0) {
344 /* track main window visibility */
346 main_window_visibility = new VisibilityTracker (_main_window);
348 /* stop libxml from spewing to stdout/stderr */
350 xmlSetGenericErrorFunc (this, libxml_generic_error_func);
351 xmlSetStructuredErrorFunc (this, libxml_structured_error_func);
353 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::parameter_changed));
354 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
355 UIConfiguration::instance().map_parameters (pc);
357 roll_button.set_controllable (roll_controllable);
358 stop_button.set_controllable (stop_controllable);
359 goto_start_button.set_controllable (goto_start_controllable);
360 goto_end_button.set_controllable (goto_end_controllable);
361 auto_loop_button.set_controllable (auto_loop_controllable);
362 play_selection_button.set_controllable (play_selection_controllable);
363 rec_button.set_controllable (rec_controllable);
365 roll_button.set_name ("transport button");
366 stop_button.set_name ("transport button");
367 goto_start_button.set_name ("transport button");
368 goto_end_button.set_name ("transport button");
369 auto_loop_button.set_name ("transport button");
370 play_selection_button.set_name ("transport button");
371 rec_button.set_name ("transport recenable button");
372 midi_panic_button.set_name ("transport button");
374 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
375 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
377 ARDOUR::Session::VersionMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_format_mismatch, this, _1, _2), gui_context());
379 /* handle dialog requests */
381 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
383 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
385 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
387 /* handle Audio/MIDI setup when session requires it */
389 ARDOUR::Session::AudioEngineSetupRequired.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::do_audio_midi_setup, this, _1));
391 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
393 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
395 /* handle sr mismatch with a dialog - cross-thread from engine */
396 ARDOUR::Session::NotifyAboutSampleRateMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::sr_mismatch_message, this, _1, _2), gui_context ());
398 /* handle requests to quit (coming from JACK session) */
400 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::finish, this), gui_context ());
402 /* tell the user about feedback */
404 ARDOUR::Session::FeedbackDetected.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::feedback_detected, this), gui_context ());
405 ARDOUR::Session::SuccessfulGraphSort.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::successful_graph_sort, this), gui_context ());
407 /* handle requests to deal with missing files */
409 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
411 /* and ambiguous files */
413 ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2));
415 /* also plugin scan messages */
416 ARDOUR::PluginScanMessage.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_dialog, this, _1, _2, _3), gui_context());
417 ARDOUR::PluginScanTimeout.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_timeout, this, _1), gui_context());
419 ARDOUR::GUIIdle.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::gui_idle_handler, this), gui_context());
421 Config->ParameterChanged.connect ( forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::set_flat_buttons, this), gui_context() );
424 /* lets get this party started */
426 setup_gtk_ardour_enums ();
429 SessionEvent::create_per_thread_pool ("GUI", 4096);
431 /* we like keyboards */
433 keyboard = new ArdourKeyboard(*this);
435 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
437 keyboard->set_state (*node, Stateful::loading_state_version);
440 UIConfiguration::instance().reset_dpi ();
442 TimeAxisViewItem::set_constant_heights ();
444 /* Set this up so that our window proxies can register actions */
446 ActionManager::init ();
448 /* The following must happen after ARDOUR::init() so that Config is set up */
450 const XMLNode* ui_xml = Config->extra_xml (X_("UI"));
453 key_editor.set_state (*ui_xml, 0);
454 session_option_editor.set_state (*ui_xml, 0);
455 speaker_config_window.set_state (*ui_xml, 0);
456 about.set_state (*ui_xml, 0);
457 add_route_dialog.set_state (*ui_xml, 0);
458 add_video_dialog.set_state (*ui_xml, 0);
459 route_params.set_state (*ui_xml, 0);
460 bundle_manager.set_state (*ui_xml, 0);
461 location_ui.set_state (*ui_xml, 0);
462 big_clock_window.set_state (*ui_xml, 0);
463 audio_port_matrix.set_state (*ui_xml, 0);
464 midi_port_matrix.set_state (*ui_xml, 0);
465 export_video_dialog.set_state (*ui_xml, 0);
466 lua_script_window.set_state (*ui_xml, 0);
469 /* Separate windows */
471 WM::Manager::instance().register_window (&key_editor);
472 WM::Manager::instance().register_window (&session_option_editor);
473 WM::Manager::instance().register_window (&speaker_config_window);
474 WM::Manager::instance().register_window (&about);
475 WM::Manager::instance().register_window (&add_route_dialog);
476 WM::Manager::instance().register_window (&add_video_dialog);
477 WM::Manager::instance().register_window (&route_params);
478 WM::Manager::instance().register_window (&audio_midi_setup);
479 WM::Manager::instance().register_window (&export_video_dialog);
480 WM::Manager::instance().register_window (&lua_script_window);
481 WM::Manager::instance().register_window (&bundle_manager);
482 WM::Manager::instance().register_window (&location_ui);
483 WM::Manager::instance().register_window (&big_clock_window);
484 WM::Manager::instance().register_window (&audio_port_matrix);
485 WM::Manager::instance().register_window (&midi_port_matrix);
487 /* do not retain position for add route dialog */
488 add_route_dialog.set_state_mask (WindowProxy::Size);
490 /* Trigger setting up the color scheme and loading the GTK RC file */
492 UIConfiguration::instance().load_rc_file (false);
494 _process_thread = new ProcessThread ();
495 _process_thread->init ();
497 UIConfiguration::instance().DPIReset.connect (sigc::mem_fun (*this, &ARDOUR_UI::resize_text_widgets));
503 ARDOUR_UI::pre_release_dialog ()
505 ArdourDialog d (_("Pre-Release Warning"), true, false);
506 d.add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
508 Label* label = manage (new Label);
509 label->set_markup (string_compose (_("<b>Welcome to this pre-release build of %1 %2</b>\n\n\
510 There are still several issues and bugs to be worked on,\n\
511 as well as general workflow improvements, before this can be considered\n\
512 release software. So, a few guidelines:\n\
514 1) Please do <b>NOT</b> use this software with the expectation that it is stable or reliable\n\
515 though it may be so, depending on your workflow.\n\
516 2) Please wait for a helpful writeup of new features.\n\
517 3) <b>Please do NOT use the forums at ardour.org to report issues</b>.\n\
518 4) Please <b>DO</b> use the bugtracker at http://tracker.ardour.org/ to report issues\n\
519 making sure to note the product version number as 5.0-pre.\n\
520 5) Please <b>DO</b> use the ardour-users mailing list to discuss ideas and pass on comments.\n\
521 6) Please <b>DO</b> join us on IRC for real time discussions about %1 %2. You\n\
522 can get there directly from within the program via the Help->Chat menu option.\n\
524 Full information on all the above can be found on the support page at\n\
526 http://ardour.org/support\n\
527 "), PROGRAM_NAME, VERSIONSTRING));
529 d.get_vbox()->set_border_width (12);
530 d.get_vbox()->pack_start (*label, false, false, 12);
531 d.get_vbox()->show_all ();
536 GlobalPortMatrixWindow*
537 ARDOUR_UI::create_global_port_matrix (ARDOUR::DataType type)
542 return new GlobalPortMatrixWindow (_session, type);
546 ARDOUR_UI::attach_to_engine ()
548 AudioEngine::instance()->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
549 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
553 ARDOUR_UI::engine_stopped ()
555 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
556 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
557 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
558 update_sample_rate (0);
563 ARDOUR_UI::engine_running ()
565 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
566 if (first_time_engine_run) {
568 first_time_engine_run = false;
572 _session->reset_xrun_count ();
574 update_disk_space ();
576 update_xrun_count ();
577 update_sample_rate (AudioEngine::instance()->sample_rate());
578 update_timecode_format ();
579 update_peak_thread_work ();
580 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, true);
581 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, false);
585 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
587 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
588 /* we can't rely on the original string continuing to exist when we are called
589 again in the GUI thread, so make a copy and note that we need to
592 char *copy = strdup (reason);
593 Gtkmm2ext::UI::instance()->call_slot (MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
597 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
598 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
600 update_sample_rate (0);
604 /* if the reason is a non-empty string, it means that the backend was shutdown
605 rather than just Ardour.
608 if (strlen (reason)) {
609 msgstr = string_compose (_("The audio backend was shutdown because:\n\n%1"), reason);
611 msgstr = string_compose (_("\
612 The audio backend has either been shutdown or it\n\
613 disconnected %1 because %1\n\
614 was not fast enough. Try to restart\n\
615 the audio backend and save the session."), PROGRAM_NAME);
618 MessageDialog msg (_main_window, msgstr);
619 pop_back_splash (msg);
623 free (const_cast<char*> (reason));
628 ARDOUR_UI::post_engine ()
630 /* Things to be done once (and once ONLY) after we have a backend running in the AudioEngine
632 #ifdef AUDIOUNIT_SUPPORT
634 if (AUPluginInfo::au_get_crashlog(au_msg)) {
635 popup_error(_("Audio Unit Plugin Scan Failed. Automatic AU scanning has been disabled. Please see the log window for further details."));
636 error << _("Audio Unit Plugin Scan Failed:") << endmsg;
637 info << au_msg << endmsg;
641 ARDOUR::init_post_engine ();
643 /* connect to important signals */
645 AudioEngine::instance()->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
646 AudioEngine::instance()->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
647 AudioEngine::instance()->BufferSizeChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
648 AudioEngine::instance()->Halted.connect_same_thread (halt_connection, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
649 AudioEngine::instance()->BecameSilent.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::audioengine_became_silent, this), gui_context());
651 if (setup_windows ()) {
652 throw failed_constructor ();
655 /* Do this after setup_windows (), as that's when the _status_bar_visibility is created */
656 XMLNode* n = Config->extra_xml (X_("UI"));
658 _status_bar_visibility.set_state (*n);
661 check_memory_locking();
663 /* this is the first point at which all the possible actions are
664 * available, because some of the available actions are dependent on
665 * aspects of the engine/backend.
668 if (ARDOUR_COMMAND_LINE::show_key_actions) {
671 vector<string> paths;
672 vector<string> labels;
673 vector<string> tooltips;
675 vector<Glib::RefPtr<Gtk::Action> > actions;
677 Gtkmm2ext::ActionMap::get_all_actions (paths, labels, tooltips, keys, actions);
679 vector<string>::iterator k;
680 vector<string>::iterator p;
682 for (p = paths.begin(), k = keys.begin(); p != paths.end(); ++k, ++p) {
687 cout << *p << " => " << *k << endl;
691 halt_connection.disconnect ();
692 AudioEngine::instance()->stop ();
696 /* this being a GUI and all, we want peakfiles */
698 AudioFileSource::set_build_peakfiles (true);
699 AudioFileSource::set_build_missing_peakfiles (true);
701 /* set default clock modes */
703 primary_clock->set_mode (AudioClock::Timecode);
704 secondary_clock->set_mode (AudioClock::BBT);
706 /* start the time-of-day-clock */
709 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
710 update_wall_clock ();
711 Glib::signal_timeout().connect_seconds (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 1);
716 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
717 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
718 Config->map_parameters (pc);
720 UIConfiguration::instance().map_parameters (pc);
724 ARDOUR_UI::~ARDOUR_UI ()
726 UIConfiguration::instance().save_state();
730 if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
731 // don't bother at 'real' exit. the OS cleans up for us.
732 delete big_clock; big_clock = 0;
733 delete primary_clock; primary_clock = 0;
734 delete secondary_clock; secondary_clock = 0;
735 delete _process_thread; _process_thread = 0;
736 delete meterbridge; meterbridge = 0;
737 delete luawindow; luawindow = 0;
738 delete editor; editor = 0;
739 delete mixer; mixer = 0;
741 delete gui_object_state; gui_object_state = 0;
742 delete main_window_visibility;
743 FastMeter::flush_pattern_cache ();
744 PixFader::flush_pattern_cache ();
748 /* Small trick to flush main-thread event pool.
749 * Other thread-pools are destroyed at pthread_exit(),
750 * but tmain thread termination is too late to trigger Pool::~Pool()
752 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.
753 delete ev->event_pool();
758 ARDOUR_UI::pop_back_splash (Gtk::Window& win)
760 if (Splash::instance()) {
761 Splash::instance()->pop_back_for (win);
766 ARDOUR_UI::configure_timeout ()
768 if (last_configure_time == 0) {
769 /* no configure events yet */
773 /* force a gap of 0.5 seconds since the last configure event
776 if (get_microseconds() - last_configure_time < 500000) {
779 have_configure_timeout = false;
780 save_ardour_state ();
786 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
788 if (have_configure_timeout) {
789 last_configure_time = get_microseconds();
791 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
792 have_configure_timeout = true;
799 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
801 XMLProperty const * prop;
803 if ((prop = node.property ("roll")) != 0) {
804 roll_controllable->set_id (prop->value());
806 if ((prop = node.property ("stop")) != 0) {
807 stop_controllable->set_id (prop->value());
809 if ((prop = node.property ("goto-start")) != 0) {
810 goto_start_controllable->set_id (prop->value());
812 if ((prop = node.property ("goto-end")) != 0) {
813 goto_end_controllable->set_id (prop->value());
815 if ((prop = node.property ("auto-loop")) != 0) {
816 auto_loop_controllable->set_id (prop->value());
818 if ((prop = node.property ("play-selection")) != 0) {
819 play_selection_controllable->set_id (prop->value());
821 if ((prop = node.property ("rec")) != 0) {
822 rec_controllable->set_id (prop->value());
824 if ((prop = node.property ("shuttle")) != 0) {
825 shuttle_box->controllable()->set_id (prop->value());
830 ARDOUR_UI::get_transport_controllable_state ()
832 XMLNode* node = new XMLNode(X_("TransportControllables"));
835 roll_controllable->id().print (buf, sizeof (buf));
836 node->add_property (X_("roll"), buf);
837 stop_controllable->id().print (buf, sizeof (buf));
838 node->add_property (X_("stop"), buf);
839 goto_start_controllable->id().print (buf, sizeof (buf));
840 node->add_property (X_("goto_start"), buf);
841 goto_end_controllable->id().print (buf, sizeof (buf));
842 node->add_property (X_("goto_end"), buf);
843 auto_loop_controllable->id().print (buf, sizeof (buf));
844 node->add_property (X_("auto_loop"), buf);
845 play_selection_controllable->id().print (buf, sizeof (buf));
846 node->add_property (X_("play_selection"), buf);
847 rec_controllable->id().print (buf, sizeof (buf));
848 node->add_property (X_("rec"), buf);
849 shuttle_box->controllable()->id().print (buf, sizeof (buf));
850 node->add_property (X_("shuttle"), buf);
856 ARDOUR_UI::save_session_at_its_request (std::string snapshot_name)
859 _session->save_state (snapshot_name);
864 ARDOUR_UI::autosave_session ()
866 if (g_main_depth() > 1) {
867 /* inside a recursive main loop,
868 give up because we may not be able to
874 if (!Config->get_periodic_safety_backups()) {
879 _session->maybe_write_autosave();
886 ARDOUR_UI::session_dirty_changed ()
893 ARDOUR_UI::update_autosave ()
895 if (_session && _session->dirty()) {
896 if (_autosave_connection.connected()) {
897 _autosave_connection.disconnect();
900 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
901 Config->get_periodic_safety_backup_interval() * 1000);
904 if (_autosave_connection.connected()) {
905 _autosave_connection.disconnect();
911 ARDOUR_UI::check_announcements ()
914 string _annc_filename;
917 _annc_filename = PROGRAM_NAME "_announcements_osx_";
918 #elif defined PLATFORM_WINDOWS
919 _annc_filename = PROGRAM_NAME "_announcements_windows_";
921 _annc_filename = PROGRAM_NAME "_announcements_linux_";
923 _annc_filename.append (VERSIONSTRING);
925 _announce_string = "";
927 std::string path = Glib::build_filename (user_config_directory(), _annc_filename);
928 FILE* fin = g_fopen (path.c_str(), "rb");
930 while (!feof (fin)) {
933 if ((len = fread (tmp, sizeof(char), 1024, fin)) == 0 || ferror (fin)) {
936 _announce_string.append (tmp, len);
941 pingback (VERSIONSTRING, path);
946 _hide_splash (gpointer arg)
948 ((ARDOUR_UI*)arg)->hide_splash();
953 ARDOUR_UI::starting ()
955 Application* app = Application::instance ();
957 bool brand_new_user = ArdourStartup::required ();
959 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
960 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::load_from_application_api));
962 if (ARDOUR_COMMAND_LINE::check_announcements) {
963 check_announcements ();
968 /* we need to create this early because it may need to set the
969 * audio backend end up.
973 audio_midi_setup.get (true);
975 std::cerr << "audio-midi engine setup failed."<< std::endl;
979 if ((nsm_url = g_getenv ("NSM_URL")) != 0) {
980 nsm = new NSM_Client;
981 if (!nsm->init (nsm_url)) {
982 /* the ardour executable may have different names:
984 * waf's obj.target for distro versions: eg ardour4, ardourvst4
985 * Ardour4, Mixbus3 for bundled versions + full path on OSX & windows
986 * argv[0] does not apply since we need the wrapper-script (not the binary itself)
988 * The wrapper startup script should set the environment variable 'ARDOUR_SELF'
990 const char *process_name = g_getenv ("ARDOUR_SELF");
991 nsm->announce (PROGRAM_NAME, ":dirty:", process_name ? process_name : "ardour4");
994 // wait for announce reply from nsm server
995 for ( i = 0; i < 5000; ++i) {
999 if (nsm->is_active()) {
1004 error << _("NSM server did not announce itself") << endmsg;
1007 // wait for open command from nsm server
1008 for ( i = 0; i < 5000; ++i) {
1010 Glib::usleep (1000);
1011 if (nsm->client_id ()) {
1017 error << _("NSM: no client ID provided") << endmsg;
1021 if (_session && nsm) {
1022 _session->set_nsm_state( nsm->is_active() );
1024 error << _("NSM: no session created") << endmsg;
1028 // nsm requires these actions disabled
1029 vector<string> action_names;
1030 action_names.push_back("SaveAs");
1031 action_names.push_back("Rename");
1032 action_names.push_back("New");
1033 action_names.push_back("Open");
1034 action_names.push_back("Recent");
1035 action_names.push_back("Close");
1037 for (vector<string>::const_iterator n = action_names.begin(); n != action_names.end(); ++n) {
1038 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), (*n).c_str());
1040 act->set_sensitive (false);
1047 error << _("NSM: initialization failed") << endmsg;
1053 if (brand_new_user) {
1054 _initial_verbose_plugin_scan = true;
1059 _initial_verbose_plugin_scan = false;
1060 switch (s.response ()) {
1061 case Gtk::RESPONSE_OK:
1068 #ifdef NO_PLUGIN_STATE
1070 ARDOUR::RecentSessions rs;
1071 ARDOUR::read_recent_sessions (rs);
1073 string path = Glib::build_filename (user_config_directory(), ".iknowaboutfreeversion");
1075 if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS) && !rs.empty()) {
1077 /* already used Ardour, have sessions ... warn about plugin state */
1079 ArdourDialog d (_("Free/Demo Version Warning"), true);
1081 Button b (string_compose (_("Subscribe and support development of %1"), PROGRAM_NAME));
1082 CheckButton c (_("Don't warn me about this again"));
1084 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"),
1085 string_compose (_("This is a free/demo version of %1"), PROGRAM_NAME),
1086 _("It will not restore OR save any plugin settings"),
1087 _("If you load an existing session with plugin settings\n"
1088 "they will not be used and will be lost."),
1089 _("To get full access to updates without this limitation\n"
1090 "consider becoming a subscriber for a low cost every month.")));
1091 l.set_justify (JUSTIFY_CENTER);
1093 b.signal_clicked().connect (mem_fun(*this, &ARDOUR_UI::launch_subscribe));
1095 d.get_vbox()->pack_start (l, true, true);
1096 d.get_vbox()->pack_start (b, false, false, 12);
1097 d.get_vbox()->pack_start (c, false, false, 12);
1099 d.add_button (_("Quit now"), RESPONSE_CANCEL);
1100 d.add_button (string_compose (_("Continue using %1"), PROGRAM_NAME), RESPONSE_OK);
1104 c.signal_toggled().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (toggle_file_existence), path)));
1106 if (d.run () != RESPONSE_OK) {
1112 /* go get a session */
1114 const bool new_session_required = (ARDOUR_COMMAND_LINE::new_session || brand_new_user);
1116 if (get_session_parameters (false, new_session_required, ARDOUR_COMMAND_LINE::load_template)) {
1117 std::cerr << "Cannot get session parameters."<< std::endl;
1124 WM::Manager::instance().show_visible ();
1126 /* We have to do this here since goto_editor_window() ends up calling show_all() on the
1127 * editor window, and we may want stuff to be hidden.
1129 _status_bar_visibility.update ();
1131 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
1133 if (splash && splash->is_visible()) {
1134 // in 1 second, hide the splash screen
1135 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
1138 /* all other dialogs are created conditionally */
1144 ARDOUR_UI::check_memory_locking ()
1146 #if defined(__APPLE__) || defined(PLATFORM_WINDOWS)
1147 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
1151 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
1153 if (AudioEngine::instance()->is_realtime() && memory_warning_node == 0) {
1155 struct rlimit limits;
1157 long pages, page_size;
1159 size_t pages_len=sizeof(pages);
1160 if ((page_size = getpagesize()) < 0 ||
1161 sysctlbyname("hw.availpages", &pages, &pages_len, NULL, 0))
1163 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0)
1168 ram = (int64_t) pages * (int64_t) page_size;
1171 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
1175 if (limits.rlim_cur != RLIM_INFINITY) {
1177 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
1181 _("WARNING: Your system has a limit for maximum amount of locked memory. "
1182 "This might cause %1 to run out of memory before your system "
1183 "runs out of memory. \n\n"
1184 "You can view the memory limit with 'ulimit -l', "
1185 "and it is normally controlled by %2"),
1188 X_("/etc/login.conf")
1190 X_(" /etc/security/limits.conf")
1194 msg.set_default_response (RESPONSE_OK);
1196 VBox* vbox = msg.get_vbox();
1198 CheckButton cb (_("Do not show this window again"));
1199 hbox.pack_start (cb, true, false);
1200 vbox->pack_start (hbox);
1205 pop_back_splash (msg);
1209 if (cb.get_active()) {
1210 XMLNode node (X_("no-memory-warning"));
1211 Config->add_instant_xml (node);
1216 #endif // !__APPLE__
1221 ARDOUR_UI::queue_finish ()
1223 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
1227 ARDOUR_UI::idle_finish ()
1230 return false; /* do not call again */
1237 ARDOUR_UI::instance()->video_timeline->sync_session_state();
1239 if (_session->dirty()) {
1240 vector<string> actions;
1241 actions.push_back (_("Don't quit"));
1242 actions.push_back (_("Just quit"));
1243 actions.push_back (_("Save and quit"));
1244 switch (ask_about_saving_session(actions)) {
1249 /* use the default name */
1250 if (save_state_canfail ("")) {
1251 /* failed - don't quit */
1252 MessageDialog msg (_main_window,
1253 string_compose (_("\
1254 %1 was unable to save your session.\n\n\
1255 If you still wish to quit, please use the\n\n\
1256 \"Just quit\" option."), PROGRAM_NAME));
1257 pop_back_splash(msg);
1267 second_connection.disconnect ();
1268 point_one_second_connection.disconnect ();
1269 point_zero_something_second_connection.disconnect();
1270 fps_connection.disconnect();
1273 delete ARDOUR_UI::instance()->video_timeline;
1274 ARDOUR_UI::instance()->video_timeline = NULL;
1275 stop_video_server();
1277 /* Save state before deleting the session, as that causes some
1278 windows to be destroyed before their visible state can be
1281 save_ardour_state ();
1283 close_all_dialogs ();
1286 _session->set_clean ();
1287 _session->remove_pending_capture_state ();
1292 halt_connection.disconnect ();
1293 AudioEngine::instance()->stop ();
1294 #ifdef WINDOWS_VST_SUPPORT
1295 fst_stop_threading();
1301 ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
1303 ArdourDialog window (_("Unsaved Session"));
1304 Gtk::HBox dhbox; // the hbox for the image and text
1305 Gtk::Label prompt_label;
1306 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
1310 assert (actions.size() >= 3);
1312 window.add_button (actions[0], RESPONSE_REJECT);
1313 window.add_button (actions[1], RESPONSE_APPLY);
1314 window.add_button (actions[2], RESPONSE_ACCEPT);
1316 window.set_default_response (RESPONSE_ACCEPT);
1318 Gtk::Button noquit_button (msg);
1319 noquit_button.set_name ("EditorGTKButton");
1323 if (_session->snap_name() == _session->name()) {
1324 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?"),
1325 _session->snap_name());
1327 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?"),
1328 _session->snap_name());
1331 prompt_label.set_text (prompt);
1332 prompt_label.set_name (X_("PrompterLabel"));
1333 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
1335 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
1336 dhbox.set_homogeneous (false);
1337 dhbox.pack_start (*dimage, false, false, 5);
1338 dhbox.pack_start (prompt_label, true, false, 5);
1339 window.get_vbox()->pack_start (dhbox);
1341 window.set_name (_("Prompter"));
1342 window.set_modal (true);
1343 window.set_resizable (false);
1346 prompt_label.show();
1351 ResponseType r = (ResponseType) window.run();
1356 case RESPONSE_ACCEPT: // save and get out of here
1358 case RESPONSE_APPLY: // get out of here
1369 ARDOUR_UI::every_second ()
1372 update_xrun_count ();
1373 update_buffer_load ();
1374 update_disk_space ();
1375 update_timecode_format ();
1376 update_peak_thread_work ();
1378 if (nsm && nsm->is_active ()) {
1381 if (!_was_dirty && _session->dirty ()) {
1385 else if (_was_dirty && !_session->dirty ()){
1393 ARDOUR_UI::every_point_one_seconds ()
1395 // TODO get rid of this..
1396 // ShuttleControl is updated directly via TransportStateChange signal
1400 ARDOUR_UI::every_point_zero_something_seconds ()
1402 // august 2007: actual update frequency: 25Hz (40ms), not 100Hz
1404 if (editor_meter && UIConfiguration::instance().get_show_editor_meter()) {
1405 float mpeak = editor_meter->update_meters();
1406 if (mpeak > editor_meter_max_peak) {
1407 if (mpeak >= UIConfiguration::instance().get_meter_peak()) {
1408 editor_meter_peak_display.set_active_state ( Gtkmm2ext::ExplicitActive );
1415 ARDOUR_UI::set_fps_timeout_connection ()
1417 unsigned int interval = 40;
1418 if (!_session) return;
1419 if (_session->timecode_frames_per_second() != 0) {
1420 /* ideally we'll use a select() to sleep and not accumulate
1421 * idle time to provide a regular periodic signal.
1422 * See linux_vst_gui_support.cc 'elapsed_time_ms'.
1423 * However, that'll require a dedicated thread and cross-thread
1424 * signals to the GUI Thread..
1426 interval = floor(500. /* update twice per FPS, since Glib::signal_timeout is very irregular */
1427 * _session->frame_rate() / _session->nominal_frame_rate()
1428 / _session->timecode_frames_per_second()
1430 #ifdef PLATFORM_WINDOWS
1431 // the smallest windows scheduler time-slice is ~15ms.
1432 // periodic GUI timeouts shorter than that will cause
1433 // WaitForSingleObject to spinlock (100% of one CPU Core)
1434 // and gtk never enters idle mode.
1435 // also changing timeBeginPeriod(1) does not affect that in
1436 // any beneficial way, so we just limit the max rate for now.
1437 interval = std::max(30u, interval); // at most ~33Hz.
1439 interval = std::max(8u, interval); // at most 120Hz.
1442 fps_connection.disconnect();
1443 Timers::set_fps_interval (interval);
1447 ARDOUR_UI::update_sample_rate (framecnt_t)
1451 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
1453 if (!AudioEngine::instance()->connected()) {
1455 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1459 framecnt_t rate = AudioEngine::instance()->sample_rate();
1462 /* no sample rate available */
1463 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1466 if (fmod (rate, 1000.0) != 0.0) {
1467 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
1468 (float) rate / 1000.0f,
1469 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1471 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
1473 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1477 sample_rate_label.set_markup (buf);
1481 ARDOUR_UI::update_format ()
1484 format_label.set_text ("");
1489 s << _("File:") << X_(" <span foreground=\"green\">");
1491 switch (_session->config.get_native_file_header_format ()) {
1523 switch (_session->config.get_native_file_data_format ()) {
1537 format_label.set_markup (s.str ());
1541 ARDOUR_UI::update_xrun_count ()
1545 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1546 should also be changed.
1550 const unsigned int x = _session->get_xrun_count ();
1552 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">>10K</span>"), X_("red"));
1554 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">%u</span>"), x > 0 ? X_("red") : X_("green"), x);
1557 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">?</span>"), X_("yellow"));
1559 xrun_label.set_markup (buf);
1560 set_tip (xrun_label, _("Audio dropouts. Shift+click to reset"));
1564 ARDOUR_UI::update_cpu_load ()
1568 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1569 should also be changed.
1572 double const c = AudioEngine::instance()->get_dsp_load ();
1573 snprintf (buf, sizeof (buf), _("DSP: <span foreground=\"%s\">%5.1f%%</span>"), c >= 90 ? X_("red") : X_("green"), c);
1574 cpu_load_label.set_markup (buf);
1578 ARDOUR_UI::update_peak_thread_work ()
1581 const int c = SourceFactory::peak_work_queue_length ();
1583 snprintf (buf, sizeof (buf), _("PkBld: <span foreground=\"%s\">%d</span>"), c >= 2 ? X_("red") : X_("green"), c);
1584 peak_thread_work_label.set_markup (buf);
1586 peak_thread_work_label.set_markup (X_(""));
1591 ARDOUR_UI::update_buffer_load ()
1595 uint32_t const playback = _session ? _session->playback_load () : 100;
1596 uint32_t const capture = _session ? _session->capture_load () : 100;
1598 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1599 should also be changed.
1605 _("Buffers: <span foreground=\"green\">p:</span><span foreground=\"%s\">%" PRIu32 "%%</span> "
1606 "<span foreground=\"green\">c:</span><span foreground=\"%s\">%" PRIu32 "%%</span>"),
1607 playback <= 5 ? X_("red") : X_("green"),
1609 capture <= 5 ? X_("red") : X_("green"),
1613 buffer_load_label.set_markup (buf);
1615 buffer_load_label.set_text ("");
1620 ARDOUR_UI::count_recenabled_streams (Route& route)
1622 Track* track = dynamic_cast<Track*>(&route);
1623 if (track && track->rec_enable_control()->get_value()) {
1624 rec_enabled_streams += track->n_inputs().n_total();
1629 ARDOUR_UI::update_disk_space()
1631 if (_session == 0) {
1635 boost::optional<framecnt_t> opt_frames = _session->available_capture_duration();
1637 framecnt_t fr = _session->frame_rate();
1640 /* skip update - no SR available */
1645 /* Available space is unknown */
1646 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">Unknown</span>"));
1647 } else if (opt_frames.get_value_or (0) == max_framecnt) {
1648 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">24hrs+</span>"));
1650 rec_enabled_streams = 0;
1651 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams, false);
1653 framecnt_t frames = opt_frames.get_value_or (0);
1655 if (rec_enabled_streams) {
1656 frames /= rec_enabled_streams;
1663 hrs = frames / (fr * 3600);
1666 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">>24 hrs</span>"));
1668 frames -= hrs * fr * 3600;
1669 mins = frames / (fr * 60);
1670 frames -= mins * fr * 60;
1673 bool const low = (hrs == 0 && mins <= 30);
1677 _("Disk: <span foreground=\"%s\">%02dh:%02dm:%02ds</span>"),
1678 low ? X_("red") : X_("green"),
1684 disk_space_label.set_markup (buf);
1688 ARDOUR_UI::update_timecode_format ()
1694 TimecodeSlave* tcslave;
1695 SyncSource sync_src = Config->get_sync_source();
1697 if ((sync_src == LTC || sync_src == MTC) && (tcslave = dynamic_cast<TimecodeSlave*>(_session->slave())) != 0) {
1698 matching = (tcslave->apparent_timecode_format() == _session->config.get_timecode_format());
1703 snprintf (buf, sizeof (buf), S_("Timecode|TC: <span foreground=\"%s\">%s</span>"),
1704 matching ? X_("green") : X_("red"),
1705 Timecode::timecode_format_name (_session->config.get_timecode_format()).c_str());
1707 snprintf (buf, sizeof (buf), "TC: n/a");
1710 timecode_format_label.set_markup (buf);
1714 ARDOUR_UI::update_wall_clock ()
1718 static int last_min = -1;
1721 tm_now = localtime (&now);
1722 if (last_min != tm_now->tm_min) {
1724 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1725 wall_clock_label.set_text (buf);
1726 last_min = tm_now->tm_min;
1733 ARDOUR_UI::open_recent_session ()
1735 bool can_return = (_session != 0);
1737 SessionDialog recent_session_dialog;
1741 ResponseType r = (ResponseType) recent_session_dialog.run ();
1744 case RESPONSE_ACCEPT:
1748 recent_session_dialog.hide();
1755 recent_session_dialog.hide();
1759 std::string path = recent_session_dialog.session_folder();
1760 std::string state = recent_session_dialog.session_name (should_be_new);
1762 if (should_be_new == true) {
1766 _session_is_new = false;
1768 if (load_session (path, state) == 0) {
1774 if (splash && splash->is_visible()) {
1775 // in 1 second, hide the splash screen
1776 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
1781 ARDOUR_UI::check_audioengine (Gtk::Window& parent)
1783 if (!AudioEngine::instance()->connected()) {
1784 MessageDialog msg (parent, string_compose (
1785 _("%1 is not connected to any audio backend.\n"
1786 "You cannot open or close sessions in this condition"),
1788 pop_back_splash (msg);
1796 ARDOUR_UI::open_session ()
1798 if (!check_audioengine (_main_window)) {
1802 /* ardour sessions are folders */
1803 Gtk::FileChooserDialog open_session_selector(_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1804 open_session_selector.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1805 open_session_selector.add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1806 open_session_selector.set_default_response(Gtk::RESPONSE_ACCEPT);
1809 string session_parent_dir = Glib::path_get_dirname(_session->path());
1810 open_session_selector.set_current_folder(session_parent_dir);
1812 open_session_selector.set_current_folder(Config->get_default_session_parent_dir());
1815 Gtkmm2ext::add_volume_shortcuts (open_session_selector);
1817 /* add_shortcut_folder throws an exception if the folder being added already has a shortcut */
1818 string default_session_folder = Config->get_default_session_parent_dir();
1819 open_session_selector.add_shortcut_folder (default_session_folder);
1821 catch (Glib::Error & e) {
1822 std::cerr << "open_session_selector.add_shortcut_folder() threw Glib::Error " << e.what() << std::endl;
1825 FileFilter session_filter;
1826 session_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::statefile_suffix));
1827 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1828 open_session_selector.add_filter (session_filter);
1829 open_session_selector.set_filter (session_filter);
1831 int response = open_session_selector.run();
1832 open_session_selector.hide ();
1834 if (response == Gtk::RESPONSE_CANCEL) {
1838 string session_path = open_session_selector.get_filename();
1842 if (session_path.length() > 0) {
1843 if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1844 _session_is_new = isnew;
1845 load_session (path, name);
1851 ARDOUR_UI::session_add_vca (const string& name_template, uint32_t n)
1857 _session->vca_manager().create_vca (n, name_template);
1861 ARDOUR_UI::session_add_mixed_track (
1862 const ChanCount& input,
1863 const ChanCount& output,
1864 RouteGroup* route_group,
1866 const string& name_template,
1868 PluginInfoPtr instrument,
1869 Plugin::PresetRecord* pset,
1870 ARDOUR::PresentationInfo::order_t order)
1872 list<boost::shared_ptr<MidiTrack> > tracks;
1874 if (_session == 0) {
1875 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1880 tracks = _session->new_midi_track (input, output, instrument, pset, route_group, how_many, name_template, order, ARDOUR::Normal);
1882 if (tracks.size() != how_many) {
1883 error << string_compose(P_("could not create %1 new mixed track", "could not create %1 new mixed tracks", how_many), how_many) << endmsg;
1888 display_insufficient_ports_message ();
1893 for (list<boost::shared_ptr<MidiTrack> >::iterator i = tracks.begin(); i != tracks.end(); ++i) {
1894 (*i)->set_strict_io (true);
1900 ARDOUR_UI::session_add_midi_bus (
1901 RouteGroup* route_group,
1903 const string& name_template,
1905 PluginInfoPtr instrument,
1906 Plugin::PresetRecord* pset,
1907 ARDOUR::PresentationInfo::order_t order)
1911 if (_session == 0) {
1912 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1918 routes = _session->new_midi_route (route_group, how_many, name_template, instrument, pset, PresentationInfo::MidiBus, order);
1919 if (routes.size() != how_many) {
1920 error << string_compose(P_("could not create %1 new Midi Bus", "could not create %1 new Midi Busses", how_many), how_many) << endmsg;
1925 display_insufficient_ports_message ();
1930 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
1931 (*i)->set_strict_io (true);
1937 ARDOUR_UI::session_add_midi_route (
1939 RouteGroup* route_group,
1941 const string& name_template,
1943 PluginInfoPtr instrument,
1944 Plugin::PresetRecord* pset,
1945 ARDOUR::PresentationInfo::order_t order)
1947 ChanCount one_midi_channel;
1948 one_midi_channel.set (DataType::MIDI, 1);
1951 session_add_mixed_track (one_midi_channel, one_midi_channel, route_group, how_many, name_template, strict_io, instrument, pset, order);
1953 session_add_midi_bus (route_group, how_many, name_template, strict_io, instrument, pset, order);
1958 ARDOUR_UI::session_add_audio_route (
1960 int32_t input_channels,
1961 int32_t output_channels,
1962 ARDOUR::TrackMode mode,
1963 RouteGroup* route_group,
1965 string const & name_template,
1967 ARDOUR::PresentationInfo::order_t order)
1969 list<boost::shared_ptr<AudioTrack> > tracks;
1972 if (_session == 0) {
1973 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1979 tracks = _session->new_audio_track (input_channels, output_channels, route_group, how_many, name_template, order, mode);
1981 if (tracks.size() != how_many) {
1982 error << string_compose (P_("could not create %1 new audio track", "could not create %1 new audio tracks", how_many), how_many)
1988 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template, PresentationInfo::AudioBus, order);
1990 if (routes.size() != how_many) {
1991 error << string_compose (P_("could not create %1 new audio bus", "could not create %1 new audio busses", how_many), how_many)
1998 display_insufficient_ports_message ();
2003 for (list<boost::shared_ptr<AudioTrack> >::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2004 (*i)->set_strict_io (true);
2006 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
2007 (*i)->set_strict_io (true);
2013 ARDOUR_UI::display_insufficient_ports_message ()
2015 MessageDialog msg (_main_window,
2016 string_compose (_("There are insufficient ports available\n\
2017 to create a new track or bus.\n\
2018 You should save %1, exit and\n\
2019 restart with more ports."), PROGRAM_NAME));
2020 pop_back_splash (msg);
2025 ARDOUR_UI::transport_goto_start ()
2028 _session->goto_start();
2030 /* force displayed area in editor to start no matter
2031 what "follow playhead" setting is.
2035 editor->center_screen (_session->current_start_frame ());
2041 ARDOUR_UI::transport_goto_zero ()
2044 _session->request_locate (0);
2046 /* force displayed area in editor to start no matter
2047 what "follow playhead" setting is.
2051 editor->reset_x_origin (0);
2057 ARDOUR_UI::transport_goto_wallclock ()
2059 if (_session && editor) {
2066 localtime_r (&now, &tmnow);
2068 framecnt_t frame_rate = _session->frame_rate();
2070 if (frame_rate == 0) {
2071 /* no frame rate available */
2075 frames = tmnow.tm_hour * (60 * 60 * frame_rate);
2076 frames += tmnow.tm_min * (60 * frame_rate);
2077 frames += tmnow.tm_sec * frame_rate;
2079 _session->request_locate (frames, _session->transport_rolling ());
2081 /* force displayed area in editor to start no matter
2082 what "follow playhead" setting is.
2086 editor->center_screen (frames);
2092 ARDOUR_UI::transport_goto_end ()
2095 framepos_t const frame = _session->current_end_frame();
2096 _session->request_locate (frame);
2098 /* force displayed area in editor to start no matter
2099 what "follow playhead" setting is.
2103 editor->center_screen (frame);
2109 ARDOUR_UI::transport_stop ()
2115 if (_session->is_auditioning()) {
2116 _session->cancel_audition ();
2120 _session->request_stop (false, true);
2123 /** Check if any tracks are record enabled. If none are, record enable all of them.
2124 * @return true if track record-enabled status was changed, false otherwise.
2127 ARDOUR_UI::trx_record_enable_all_tracks ()
2133 boost::shared_ptr<RouteList> rl = _session->get_tracks ();
2134 bool none_record_enabled = true;
2136 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
2137 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*r);
2140 if (t->rec_enable_control()->get_value()) {
2141 none_record_enabled = false;
2146 if (none_record_enabled) {
2147 _session->set_controls (route_list_to_control_list (rl, &Stripable::rec_enable_control), 1.0, Controllable::NoGroup);
2150 return none_record_enabled;
2154 ARDOUR_UI::transport_record (bool roll)
2157 switch (_session->record_status()) {
2158 case Session::Disabled:
2159 if (_session->ntracks() == 0) {
2160 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."));
2164 if (Profile->get_trx()) {
2165 roll = trx_record_enable_all_tracks ();
2167 _session->maybe_enable_record ();
2172 case Session::Recording:
2174 _session->request_stop();
2176 _session->disable_record (false, true);
2180 case Session::Enabled:
2181 _session->disable_record (false, true);
2187 ARDOUR_UI::transport_roll ()
2193 if (_session->is_auditioning()) {
2198 if (_session->config.get_external_sync()) {
2199 switch (Config->get_sync_source()) {
2203 /* transport controlled by the master */
2209 bool rolling = _session->transport_rolling();
2211 if (_session->get_play_loop()) {
2213 /* If loop playback is not a mode, then we should cancel
2214 it when this action is requested. If it is a mode
2215 we just leave it in place.
2218 if (!Config->get_loop_is_mode()) {
2219 /* XXX it is not possible to just leave seamless loop and keep
2220 playing at present (nov 4th 2009)
2222 if (!Config->get_seamless_loop()) {
2223 /* stop loop playback and stop rolling */
2224 _session->request_play_loop (false, true);
2225 } else if (rolling) {
2226 /* stop loop playback but keep rolling */
2227 _session->request_play_loop (false, false);
2231 } else if (_session->get_play_range () ) {
2232 /* stop playing a range if we currently are */
2233 _session->request_play_range (0, true);
2237 _session->request_transport_speed (1.0f);
2242 ARDOUR_UI::get_smart_mode() const
2244 return ( editor->get_smart_mode() );
2249 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
2255 if (_session->is_auditioning()) {
2256 _session->cancel_audition ();
2260 if (_session->config.get_external_sync()) {
2261 switch (Config->get_sync_source()) {
2265 /* transport controlled by the master */
2270 bool rolling = _session->transport_rolling();
2271 bool affect_transport = true;
2273 if (rolling && roll_out_of_bounded_mode) {
2274 /* drop out of loop/range playback but leave transport rolling */
2275 if (_session->get_play_loop()) {
2276 if (_session->actively_recording()) {
2278 /* just stop using the loop, then actually stop
2281 _session->request_play_loop (false, affect_transport);
2284 if (Config->get_seamless_loop()) {
2285 /* the disk buffers contain copies of the loop - we can't
2286 just keep playing, so stop the transport. the user
2287 can restart as they wish.
2289 affect_transport = true;
2291 /* disk buffers are normal, so we can keep playing */
2292 affect_transport = false;
2294 _session->request_play_loop (false, affect_transport);
2296 } else if (_session->get_play_range ()) {
2297 affect_transport = false;
2298 _session->request_play_range (0, true);
2302 if (affect_transport) {
2304 _session->request_stop (with_abort, true);
2306 /* the only external sync condition we can be in here
2307 * would be Engine (JACK) sync, in which case we still
2311 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
2312 _session->request_play_range (&editor->get_selection().time, true);
2313 _session->set_requested_return_frame( editor->get_selection().time.front().start ); //force an auto-return here
2315 _session->request_transport_speed (1.0f);
2321 ARDOUR_UI::toggle_session_auto_loop ()
2327 Location * looploc = _session->locations()->auto_loop_location();
2333 if (_session->get_play_loop()) {
2335 /* looping enabled, our job is to disable it */
2337 _session->request_play_loop (false);
2341 /* looping not enabled, our job is to enable it.
2343 loop-is-NOT-mode: this action always starts the transport rolling.
2344 loop-IS-mode: this action simply sets the loop play mechanism, but
2345 does not start transport.
2347 if (Config->get_loop_is_mode()) {
2348 _session->request_play_loop (true, false);
2350 _session->request_play_loop (true, true);
2354 //show the loop markers
2355 looploc->set_hidden (false, this);
2359 ARDOUR_UI::transport_play_selection ()
2365 editor->play_selection ();
2369 ARDOUR_UI::transport_play_preroll ()
2374 editor->play_with_preroll ();
2378 ARDOUR_UI::transport_rewind (int option)
2380 float current_transport_speed;
2383 current_transport_speed = _session->transport_speed();
2385 if (current_transport_speed >= 0.0f) {
2388 _session->request_transport_speed (-1.0f);
2391 _session->request_transport_speed (-4.0f);
2394 _session->request_transport_speed (-0.5f);
2399 _session->request_transport_speed (current_transport_speed * 1.5f);
2405 ARDOUR_UI::transport_forward (int option)
2411 float current_transport_speed = _session->transport_speed();
2413 if (current_transport_speed <= 0.0f) {
2416 _session->request_transport_speed (1.0f);
2419 _session->request_transport_speed (4.0f);
2422 _session->request_transport_speed (0.5f);
2427 _session->request_transport_speed (current_transport_speed * 1.5f);
2432 ARDOUR_UI::toggle_record_enable (uint16_t rid)
2438 boost::shared_ptr<Route> r;
2440 if ((r = _session->get_remote_nth_route (rid)) != 0) {
2442 boost::shared_ptr<Track> t;
2444 if ((t = boost::dynamic_pointer_cast<Track>(r)) != 0) {
2445 t->rec_enable_control()->set_value (!t->rec_enable_control()->get_value(), Controllable::UseGroup);
2451 ARDOUR_UI::map_transport_state ()
2454 auto_loop_button.unset_active_state ();
2455 play_selection_button.unset_active_state ();
2456 roll_button.unset_active_state ();
2457 stop_button.set_active_state (Gtkmm2ext::ExplicitActive);
2461 shuttle_box->map_transport_state ();
2463 float sp = _session->transport_speed();
2469 if (_session->get_play_range()) {
2471 play_selection_button.set_active_state (Gtkmm2ext::ExplicitActive);
2472 roll_button.unset_active_state ();
2473 auto_loop_button.unset_active_state ();
2475 } else if (_session->get_play_loop ()) {
2477 auto_loop_button.set_active (true);
2478 play_selection_button.set_active (false);
2479 if (Config->get_loop_is_mode()) {
2480 roll_button.set_active (true);
2482 roll_button.set_active (false);
2487 roll_button.set_active (true);
2488 play_selection_button.set_active (false);
2489 auto_loop_button.set_active (false);
2492 if (UIConfiguration::instance().get_follow_edits() && !_session->config.get_external_sync()) {
2493 /* light up both roll and play-selection if they are joined */
2494 roll_button.set_active (true);
2495 play_selection_button.set_active (true);
2498 stop_button.set_active (false);
2502 stop_button.set_active (true);
2503 roll_button.set_active (false);
2504 play_selection_button.set_active (false);
2505 if (Config->get_loop_is_mode ()) {
2506 auto_loop_button.set_active (_session->get_play_loop());
2508 auto_loop_button.set_active (false);
2510 update_disk_space ();
2515 ARDOUR_UI::blink_handler (bool blink_on)
2517 transport_rec_enable_blink (blink_on);
2518 solo_blink (blink_on);
2519 sync_blink (blink_on);
2520 audition_blink (blink_on);
2521 feedback_blink (blink_on);
2522 error_blink (blink_on);
2526 ARDOUR_UI::update_clocks ()
2528 if (!_session) return;
2530 if (editor && !editor->dragging_playhead()) {
2531 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD)); /* EMIT_SIGNAL */
2536 ARDOUR_UI::start_clocking ()
2538 if (UIConfiguration::instance().get_super_rapid_clock_update()) {
2539 clock_signal_connection = Timers::fps_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2541 clock_signal_connection = Timers::rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2546 ARDOUR_UI::stop_clocking ()
2548 clock_signal_connection.disconnect ();
2552 ARDOUR_UI::save_as_progress_update (float fraction, int64_t cnt, int64_t total, Gtk::Label* label, Gtk::ProgressBar* bar)
2556 snprintf (buf, sizeof (buf), _("Copied %" PRId64 " of %" PRId64), cnt, total);
2558 label->set_text (buf);
2559 bar->set_fraction (fraction);
2561 /* process events, redraws, etc. */
2563 while (gtk_events_pending()) {
2564 gtk_main_iteration ();
2567 return true; /* continue with save-as */
2571 ARDOUR_UI::save_session_as ()
2577 if (!save_as_dialog) {
2578 save_as_dialog = new SaveAsDialog;
2581 save_as_dialog->set_name (_session->name());
2583 int response = save_as_dialog->run ();
2585 save_as_dialog->hide ();
2588 case Gtk::RESPONSE_OK:
2597 sa.new_parent_folder = save_as_dialog->new_parent_folder ();
2598 sa.new_name = save_as_dialog->new_name ();
2599 sa.switch_to = save_as_dialog->switch_to();
2600 sa.copy_media = save_as_dialog->copy_media();
2601 sa.copy_external = save_as_dialog->copy_external();
2602 sa.include_media = save_as_dialog->include_media ();
2604 /* Only bother with a progress dialog if we're going to copy
2605 media into the save-as target. Without that choice, this
2606 will be very fast because we're only talking about a few kB's to
2607 perhaps a couple of MB's of data.
2610 ArdourDialog progress_dialog (_("Save As"), true);
2612 if (sa.include_media && sa.copy_media) {
2615 Gtk::ProgressBar progress_bar;
2617 progress_dialog.get_vbox()->pack_start (label);
2618 progress_dialog.get_vbox()->pack_start (progress_bar);
2620 progress_bar.show ();
2622 /* this signal will be emitted from within this, the calling thread,
2623 * after every file is copied. It provides information on percentage
2624 * complete (in terms of total data to copy), the number of files
2625 * copied so far, and the total number to copy.
2630 sa.Progress.connect_same_thread (c, boost::bind (&ARDOUR_UI::save_as_progress_update, this, _1, _2, _3, &label, &progress_bar));
2632 progress_dialog.show_all ();
2633 progress_dialog.present ();
2636 if (_session->save_as (sa)) {
2638 MessageDialog msg (string_compose (_("Save As failed: %1"), sa.failure_message));
2642 if (!sa.include_media) {
2643 unload_session (false);
2644 load_session (sa.final_session_folder_name, sa.new_name);
2649 ARDOUR_UI::quick_snapshot_session (bool switch_to_it)
2653 struct tm local_time;
2656 localtime_r (&n, &local_time);
2657 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2659 save_state (timebuf, switch_to_it);
2664 ARDOUR_UI::process_snapshot_session_prompter (ArdourPrompter& prompter, bool switch_to_it)
2668 prompter.get_result (snapname);
2670 bool do_save = (snapname.length() != 0);
2673 char illegal = Session::session_name_is_legal(snapname);
2675 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2676 "snapshot names may not contain a '%1' character"), illegal));
2682 vector<std::string> p;
2683 get_state_files_in_directory (_session->session_directory().root_path(), p);
2684 vector<string> n = get_file_names_no_extension (p);
2686 if (find (n.begin(), n.end(), snapname) != n.end()) {
2688 do_save = overwrite_file_dialog (prompter,
2689 _("Confirm Snapshot Overwrite"),
2690 _("A snapshot already exists with that name. Do you want to overwrite it?"));
2694 save_state (snapname, switch_to_it);
2704 /** Ask the user for the name of a new snapshot and then take it.
2708 ARDOUR_UI::snapshot_session (bool switch_to_it)
2710 ArdourPrompter prompter (true);
2712 prompter.set_name ("Prompter");
2713 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2715 prompter.set_title (_("Snapshot and switch"));
2716 prompter.set_prompt (_("New session name"));
2718 prompter.set_title (_("Take Snapshot"));
2719 prompter.set_prompt (_("Name of new snapshot"));
2723 prompter.set_initial_text (_session->snap_name());
2727 struct tm local_time;
2730 localtime_r (&n, &local_time);
2731 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2732 prompter.set_initial_text (timebuf);
2735 bool finished = false;
2737 switch (prompter.run()) {
2738 case RESPONSE_ACCEPT:
2740 finished = process_snapshot_session_prompter (prompter, switch_to_it);
2751 /** Ask the user for a new session name and then rename the session to it.
2755 ARDOUR_UI::rename_session ()
2761 ArdourPrompter prompter (true);
2764 prompter.set_name ("Prompter");
2765 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2766 prompter.set_title (_("Rename Session"));
2767 prompter.set_prompt (_("New session name"));
2770 switch (prompter.run()) {
2771 case RESPONSE_ACCEPT:
2773 prompter.get_result (name);
2775 bool do_rename = (name.length() != 0);
2778 char illegal = Session::session_name_is_legal (name);
2781 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2782 "session names may not contain a '%1' character"), illegal));
2787 switch (_session->rename (name)) {
2789 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
2790 msg.set_position (WIN_POS_MOUSE);
2798 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
2799 msg.set_position (WIN_POS_MOUSE);
2815 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2817 if (!_session || _session->deletion_in_progress()) {
2821 XMLNode* node = new XMLNode (X_("UI"));
2823 WM::Manager::instance().add_state (*node);
2825 node->add_child_nocopy (gui_object_state->get_state());
2827 _session->add_extra_xml (*node);
2829 if (export_video_dialog) {
2830 _session->add_extra_xml (export_video_dialog->get_state());
2833 save_state_canfail (name, switch_to_it);
2837 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2842 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2847 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2852 ARDOUR_UI::primary_clock_value_changed ()
2855 _session->request_locate (primary_clock->current_time ());
2860 ARDOUR_UI::big_clock_value_changed ()
2863 _session->request_locate (big_clock->current_time ());
2868 ARDOUR_UI::secondary_clock_value_changed ()
2871 _session->request_locate (secondary_clock->current_time ());
2876 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2878 if (_session == 0) {
2882 if (_session->step_editing()) {
2886 Session::RecordState const r = _session->record_status ();
2887 bool const h = _session->have_rec_enabled_track ();
2889 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2891 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2893 rec_button.set_active_state (Gtkmm2ext::Off);
2895 } else if (r == Session::Recording && h) {
2896 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2898 rec_button.unset_active_state ();
2903 ARDOUR_UI::process_save_template_prompter (ArdourPrompter& prompter)
2907 prompter.get_result (name);
2909 if (name.length()) {
2910 int failed = _session->save_template (name);
2912 if (failed == -2) { /* file already exists. */
2913 bool overwrite = overwrite_file_dialog (prompter,
2914 _("Confirm Template Overwrite"),
2915 _("A template already exists with that name. Do you want to overwrite it?"));
2918 _session->save_template (name, true);
2930 ARDOUR_UI::save_template ()
2932 ArdourPrompter prompter (true);
2934 if (!check_audioengine (_main_window)) {
2938 prompter.set_name (X_("Prompter"));
2939 prompter.set_title (_("Save Template"));
2940 prompter.set_prompt (_("Name for template:"));
2941 prompter.set_initial_text(_session->name() + _("-template"));
2942 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2944 bool finished = false;
2946 switch (prompter.run()) {
2947 case RESPONSE_ACCEPT:
2948 finished = process_save_template_prompter (prompter);
2959 ARDOUR_UI::edit_metadata ()
2961 SessionMetadataEditor dialog;
2962 dialog.set_session (_session);
2963 dialog.grab_focus ();
2968 ARDOUR_UI::import_metadata ()
2970 SessionMetadataImporter dialog;
2971 dialog.set_session (_session);
2976 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
2978 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2980 MessageDialog msg (str,
2982 Gtk::MESSAGE_WARNING,
2983 Gtk::BUTTONS_YES_NO,
2987 msg.set_name (X_("OpenExistingDialog"));
2988 msg.set_title (_("Open Existing Session"));
2989 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
2990 msg.set_position (Gtk::WIN_POS_CENTER);
2991 pop_back_splash (msg);
2993 switch (msg.run()) {
3002 ARDOUR_UI::build_session_from_dialog (SessionDialog& sd, const std::string& session_path, const std::string& session_name)
3004 BusProfile bus_profile;
3008 bus_profile.master_out_channels = 2;
3009 bus_profile.input_ac = AutoConnectPhysical;
3010 bus_profile.output_ac = AutoConnectMaster;
3011 bus_profile.requested_physical_in = 0; // use all available
3012 bus_profile.requested_physical_out = 0; // use all available
3016 /* get settings from advanced section of NSD */
3018 if (sd.create_master_bus()) {
3019 bus_profile.master_out_channels = (uint32_t) sd.master_channel_count();
3021 bus_profile.master_out_channels = 0;
3024 if (sd.connect_inputs()) {
3025 bus_profile.input_ac = AutoConnectPhysical;
3027 bus_profile.input_ac = AutoConnectOption (0);
3030 bus_profile.output_ac = AutoConnectOption (0);
3032 if (sd.connect_outputs ()) {
3033 if (sd.connect_outs_to_master()) {
3034 bus_profile.output_ac = AutoConnectMaster;
3035 } else if (sd.connect_outs_to_physical()) {
3036 bus_profile.output_ac = AutoConnectPhysical;
3040 bus_profile.requested_physical_in = (uint32_t) sd.input_limit_count();
3041 bus_profile.requested_physical_out = (uint32_t) sd.output_limit_count();
3044 if (build_session (session_path, session_name, bus_profile)) {
3052 ARDOUR_UI::load_from_application_api (const std::string& path)
3054 ARDOUR_COMMAND_LINE::session_name = path;
3055 /* Cancel SessionDialog if it's visible to make OSX delegates work.
3057 * ARDOUR_UI::starting connects app->ShouldLoad signal and then shows a SessionDialog
3059 * - ShouldLoad does not arrive in time, ARDOUR_COMMAND_LINE::session_name is empty:
3060 * -> ARDOUR_UI::get_session_parameters starts a SessionDialog.
3061 * - ShouldLoad signal arrives, this function is called and sets ARDOUR_COMMAND_LINE::session_name
3062 * -> SessionDialog is not displayed
3065 if (_session_dialog) {
3066 std::string session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3067 std::string session_path = path;
3068 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_REGULAR)) {
3069 session_path = Glib::path_get_dirname (session_path);
3071 // signal the existing dialog in ARDOUR_UI::get_session_parameters()
3072 _session_dialog->set_provided_session (session_name, session_path);
3073 _session_dialog->response (RESPONSE_NONE);
3074 _session_dialog->hide();
3079 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
3080 /* /path/to/foo => /path/to/foo, foo */
3081 rv = load_session (path, basename_nosuffix (path));
3083 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
3084 rv =load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
3087 // if load_session fails -> pop up SessionDialog.
3089 ARDOUR_COMMAND_LINE::session_name = "";
3091 if (get_session_parameters (true, false)) {
3097 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
3099 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
3101 string session_name;
3102 string session_path;
3103 string template_name;
3105 bool likely_new = false;
3106 bool cancel_not_quit;
3108 /* deal with any existing DIRTY session now, rather than later. don't
3109 * treat a non-dirty session this way, so that it stays visible
3110 * as we bring up the new session dialog.
3113 if (_session && ARDOUR_UI::instance()->video_timeline) {
3114 ARDOUR_UI::instance()->video_timeline->sync_session_state();
3117 /* if there is already a session, relabel the button
3118 on the SessionDialog so that we don't Quit directly
3120 cancel_not_quit = (_session != 0);
3122 if (_session && _session->dirty()) {
3123 if (unload_session (false)) {
3124 /* unload cancelled by user */
3127 ARDOUR_COMMAND_LINE::session_name = "";
3130 if (!load_template.empty()) {
3131 should_be_new = true;
3132 template_name = load_template;
3135 session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3136 session_path = ARDOUR_COMMAND_LINE::session_name;
3138 if (!session_path.empty()) {
3139 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_EXISTS)) {
3140 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_IS_REGULAR)) {
3141 /* session/snapshot file, change path to be dir */
3142 session_path = Glib::path_get_dirname (session_path);
3147 SessionDialog session_dialog (should_be_new, session_name, session_path, load_template, cancel_not_quit);
3149 _session_dialog = &session_dialog;
3152 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
3154 /* if they named a specific statefile, use it, otherwise they are
3155 just giving a session folder, and we want to use it as is
3156 to find the session.
3159 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
3161 if (suffix != string::npos) {
3162 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
3163 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
3164 session_name = Glib::path_get_basename (session_name);
3166 session_path = ARDOUR_COMMAND_LINE::session_name;
3167 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
3172 session_dialog.clear_given ();
3175 if (should_be_new || session_name.empty()) {
3176 /* need the dialog to get info from user */
3178 cerr << "run dialog\n";
3180 switch (session_dialog.run()) {
3181 case RESPONSE_ACCEPT:
3184 /* this is used for async * app->ShouldLoad(). */
3185 continue; // while loop
3188 if (quit_on_cancel) {
3189 // JE - Currently (July 2014) this section can only get reached if the
3190 // user quits from the main 'Session Setup' dialog (i.e. reaching this
3191 // point does NOT indicate an abnormal termination). Therefore, let's
3192 // behave gracefully (i.e. let's do some cleanup) before we call exit()
3194 pthread_cancel_all ();
3202 session_dialog.hide ();
3205 /* if we run the startup dialog again, offer more than just "new session" */
3207 should_be_new = false;
3209 session_name = session_dialog.session_name (likely_new);
3210 session_path = session_dialog.session_folder ();
3216 string::size_type suffix = session_name.find (statefile_suffix);
3218 if (suffix != string::npos) {
3219 session_name = session_name.substr (0, suffix);
3222 /* this shouldn't happen, but we catch it just in case it does */
3224 if (session_name.empty()) {
3228 if (session_dialog.use_session_template()) {
3229 template_name = session_dialog.session_template_name();
3230 _session_is_new = true;
3233 if (session_name[0] == G_DIR_SEPARATOR ||
3234 #ifdef PLATFORM_WINDOWS
3235 (session_name.length() > 3 && session_name[1] == ':' && session_name[2] == G_DIR_SEPARATOR)
3237 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
3238 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)
3243 /* absolute path or cwd-relative path specified for session name: infer session folder
3244 from what was given.
3247 session_path = Glib::path_get_dirname (session_name);
3248 session_name = Glib::path_get_basename (session_name);
3252 session_path = session_dialog.session_folder();
3254 char illegal = Session::session_name_is_legal (session_name);
3257 MessageDialog msg (session_dialog,
3258 string_compose (_("To ensure compatibility with various systems\n"
3259 "session names may not contain a '%1' character"),
3262 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3267 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
3270 if (likely_new && !nsm) {
3272 std::string existing = Glib::build_filename (session_path, session_name);
3274 if (!ask_about_loading_existing_session (existing)) {
3275 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3280 _session_is_new = false;
3285 pop_back_splash (session_dialog);
3286 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
3288 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3292 char illegal = Session::session_name_is_legal(session_name);
3295 pop_back_splash (session_dialog);
3296 MessageDialog msg (session_dialog, string_compose(_("To ensure compatibility with various systems\n"
3297 "session names may not contain a '%1' character"), illegal));
3299 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3303 _session_is_new = true;
3306 if (likely_new && template_name.empty()) {
3308 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3312 ret = load_session (session_path, session_name, template_name);
3315 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
3319 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
3320 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
3324 /* clear this to avoid endless attempts to load the
3328 ARDOUR_COMMAND_LINE::session_name = "";
3332 _session_dialog = NULL;
3338 ARDOUR_UI::close_session()
3340 if (!check_audioengine (_main_window)) {
3344 if (unload_session (true)) {
3348 ARDOUR_COMMAND_LINE::session_name = "";
3350 if (get_session_parameters (true, false)) {
3353 if (splash && splash->is_visible()) {
3354 // in 1 second, hide the splash screen
3355 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
3359 /** @param snap_name Snapshot name (without .ardour suffix).
3360 * @return -2 if the load failed because we are not connected to the AudioEngine.
3363 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
3365 Session *new_session;
3370 unload_status = unload_session ();
3372 if (unload_status < 0) {
3374 } else if (unload_status > 0) {
3380 session_loaded = false;
3382 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
3385 new_session = new Session (*AudioEngine::instance(), path, snap_name, 0, mix_template);
3388 /* this one is special */
3390 catch (AudioEngine::PortRegistrationFailure& err) {
3392 MessageDialog msg (err.what(),
3395 Gtk::BUTTONS_CLOSE);
3397 msg.set_title (_("Port Registration Error"));
3398 msg.set_secondary_text (_("Click the Close button to try again."));
3399 msg.set_position (Gtk::WIN_POS_CENTER);
3400 pop_back_splash (msg);
3403 int response = msg.run ();
3408 case RESPONSE_CANCEL:
3415 catch (SessionException e) {
3416 MessageDialog msg (string_compose(
3417 _("Session \"%1 (snapshot %2)\" did not load successfully: %3"),
3418 path, snap_name, e.what()),
3423 msg.set_title (_("Loading Error"));
3424 msg.set_position (Gtk::WIN_POS_CENTER);
3425 pop_back_splash (msg);
3437 MessageDialog msg (string_compose(
3438 _("Session \"%1 (snapshot %2)\" did not load successfully"),
3444 msg.set_title (_("Loading Error"));
3445 msg.set_position (Gtk::WIN_POS_CENTER);
3446 pop_back_splash (msg);
3458 list<string> const u = new_session->unknown_processors ();
3460 MissingPluginDialog d (_session, u);
3465 if (!new_session->writable()) {
3466 MessageDialog msg (_("This session has been opened in read-only mode.\n\nYou will not be able to record or save."),
3471 msg.set_title (_("Read-only Session"));
3472 msg.set_position (Gtk::WIN_POS_CENTER);
3473 pop_back_splash (msg);
3480 /* Now the session been created, add the transport controls */
3481 new_session->add_controllable(roll_controllable);
3482 new_session->add_controllable(stop_controllable);
3483 new_session->add_controllable(goto_start_controllable);
3484 new_session->add_controllable(goto_end_controllable);
3485 new_session->add_controllable(auto_loop_controllable);
3486 new_session->add_controllable(play_selection_controllable);
3487 new_session->add_controllable(rec_controllable);
3489 set_session (new_session);
3491 session_loaded = true;
3494 _session->set_clean ();
3497 #ifdef WINDOWS_VST_SUPPORT
3498 fst_stop_threading();
3502 Timers::TimerSuspender t;
3506 #ifdef WINDOWS_VST_SUPPORT
3507 fst_start_threading();
3516 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
3518 Session *new_session;
3521 session_loaded = false;
3522 x = unload_session ();
3530 _session_is_new = true;
3533 new_session = new Session (*AudioEngine::instance(), path, snap_name, &bus_profile);
3536 catch (SessionException e) {
3538 MessageDialog msg (string_compose(_("Could not create session in \"%1\": %2"), path, e.what()));
3539 msg.set_title (_("Loading Error"));
3540 msg.set_position (Gtk::WIN_POS_CENTER);
3541 pop_back_splash (msg);
3547 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
3548 msg.set_title (_("Loading Error"));
3549 msg.set_position (Gtk::WIN_POS_CENTER);
3550 pop_back_splash (msg);
3555 /* Give the new session the default GUI state, if such things exist */
3558 n = Config->instant_xml (X_("Editor"));
3560 n->remove_nodes_and_delete ("Selection"); // no not apply selection to new sessions.
3561 new_session->add_instant_xml (*n, false);
3563 n = Config->instant_xml (X_("Mixer"));
3565 new_session->add_instant_xml (*n, false);
3568 /* Put the playhead at 0 and scroll fully left */
3569 n = new_session->instant_xml (X_("Editor"));
3571 n->add_property (X_("playhead"), X_("0"));
3572 n->add_property (X_("left-frame"), X_("0"));
3575 set_session (new_session);
3577 session_loaded = true;
3579 new_session->save_state(new_session->name());
3585 ARDOUR_UI::launch_chat ()
3587 MessageDialog dialog(_("<b>Just ask and wait for an answer.\nIt may take from minutes to hours.</b>"), true);
3589 dialog.set_title (_("About the Chat"));
3590 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."));
3592 switch (dialog.run()) {
3595 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
3596 #elif defined PLATFORM_WINDOWS
3597 open_uri("http://webchat.freenode.net/?channels=ardour-windows");
3599 open_uri("http://webchat.freenode.net/?channels=ardour");
3608 ARDOUR_UI::launch_manual ()
3610 PBD::open_uri (Config->get_tutorial_manual_url());
3614 ARDOUR_UI::launch_reference ()
3616 PBD::open_uri (Config->get_reference_manual_url());
3620 ARDOUR_UI::launch_tracker ()
3622 PBD::open_uri ("http://tracker.ardour.org");
3626 ARDOUR_UI::launch_subscribe ()
3628 PBD::open_uri ("https://community.ardour.org/s/subscribe");
3632 ARDOUR_UI::launch_cheat_sheet ()
3635 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheat_sheet_osx.pdf");
3637 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheatsheet.pdf");
3642 ARDOUR_UI::launch_website ()
3644 PBD::open_uri ("http://ardour.org");
3648 ARDOUR_UI::launch_website_dev ()
3650 PBD::open_uri ("http://ardour.org/development.html");
3654 ARDOUR_UI::launch_forums ()
3656 PBD::open_uri ("https://community.ardour.org/forums");
3660 ARDOUR_UI::launch_howto_report ()
3662 PBD::open_uri ("http://ardour.org/reporting_bugs");
3666 ARDOUR_UI::loading_message (const std::string& msg)
3668 if (ARDOUR_COMMAND_LINE::no_splash) {
3676 splash->message (msg);
3680 ARDOUR_UI::show_splash ()
3684 splash = new Splash;
3694 ARDOUR_UI::hide_splash ()
3701 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title, const bool msg_delete)
3705 removed = rep.paths.size();
3708 MessageDialog msgd (_main_window,
3709 _("No files were ready for clean-up"),
3713 msgd.set_title (_("Clean-up"));
3714 msgd.set_secondary_text (_("If this seems suprising, \n\
3715 check for any existing snapshots.\n\
3716 These may still include regions that\n\
3717 require some unused files to continue to exist."));
3723 ArdourDialog results (_("Clean-up"), true, false);
3725 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
3726 CleanupResultsModelColumns() {
3730 Gtk::TreeModelColumn<std::string> visible_name;
3731 Gtk::TreeModelColumn<std::string> fullpath;
3735 CleanupResultsModelColumns results_columns;
3736 Glib::RefPtr<Gtk::ListStore> results_model;
3737 Gtk::TreeView results_display;
3739 results_model = ListStore::create (results_columns);
3740 results_display.set_model (results_model);
3741 results_display.append_column (list_title, results_columns.visible_name);
3743 results_display.set_name ("CleanupResultsList");
3744 results_display.set_headers_visible (true);
3745 results_display.set_headers_clickable (false);
3746 results_display.set_reorderable (false);
3748 Gtk::ScrolledWindow list_scroller;
3751 Gtk::HBox dhbox; // the hbox for the image and text
3752 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
3753 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
3755 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
3757 const string dead_directory = _session->session_directory().dead_path();
3760 %1 - number of files removed
3761 %2 - location of "dead"
3762 %3 - size of files affected
3763 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
3766 const char* bprefix;
3767 double space_adjusted = 0;
3769 if (rep.space < 1000) {
3771 space_adjusted = rep.space;
3772 } else if (rep.space < 1000000) {
3773 bprefix = _("kilo");
3774 space_adjusted = floorf((float)rep.space / 1000.0);
3775 } else if (rep.space < 1000000 * 1000) {
3776 bprefix = _("mega");
3777 space_adjusted = floorf((float)rep.space / (1000.0 * 1000.0));
3779 bprefix = _("giga");
3780 space_adjusted = floorf((float)rep.space / (1000.0 * 1000 * 1000.0));
3784 txt.set_markup (string_compose (P_("\
3785 The following file was deleted from %2,\n\
3786 releasing %3 %4bytes of disk space", "\
3787 The following %1 files were deleted from %2,\n\
3788 releasing %3 %4bytes of disk space", removed),
3789 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3791 txt.set_markup (string_compose (P_("\
3792 The following file was not in use and \n\
3793 has been moved to: %2\n\n\
3794 After a restart of %5\n\n\
3795 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3796 will release an additional %3 %4bytes of disk space.\n", "\
3797 The following %1 files were not in use and \n\
3798 have been moved to: %2\n\n\
3799 After a restart of %5\n\n\
3800 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3801 will release an additional %3 %4bytes of disk space.\n", removed),
3802 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3805 dhbox.pack_start (*dimage, true, false, 5);
3806 dhbox.pack_start (txt, true, false, 5);
3808 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
3809 TreeModel::Row row = *(results_model->append());
3810 row[results_columns.visible_name] = *i;
3811 row[results_columns.fullpath] = *i;
3814 list_scroller.add (results_display);
3815 list_scroller.set_size_request (-1, 150);
3816 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
3818 dvbox.pack_start (dhbox, true, false, 5);
3819 dvbox.pack_start (list_scroller, true, false, 5);
3820 ddhbox.pack_start (dvbox, true, false, 5);
3822 results.get_vbox()->pack_start (ddhbox, true, false, 5);
3823 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
3824 results.set_default_response (RESPONSE_CLOSE);
3825 results.set_position (Gtk::WIN_POS_MOUSE);
3827 results_display.show();
3828 list_scroller.show();
3835 //results.get_vbox()->show();
3836 results.set_resizable (false);
3843 ARDOUR_UI::cleanup ()
3845 if (_session == 0) {
3846 /* shouldn't happen: menu item is insensitive */
3851 MessageDialog checker (_("Are you sure you want to clean-up?"),
3853 Gtk::MESSAGE_QUESTION,
3856 checker.set_title (_("Clean-up"));
3858 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
3859 ALL undo/redo information will be lost if you clean-up.\n\
3860 Clean-up will move all unused files to a \"dead\" location."));
3862 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3863 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
3864 checker.set_default_response (RESPONSE_CANCEL);
3866 checker.set_name (_("CleanupDialog"));
3867 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3868 checker.set_position (Gtk::WIN_POS_MOUSE);
3870 switch (checker.run()) {
3871 case RESPONSE_ACCEPT:
3877 ARDOUR::CleanupReport rep;
3879 editor->prepare_for_cleanup ();
3881 /* do not allow flush until a session is reloaded */
3883 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3885 act->set_sensitive (false);
3888 if (_session->cleanup_sources (rep)) {
3889 editor->finish_cleanup ();
3893 editor->finish_cleanup ();
3896 display_cleanup_results (rep, _("Cleaned Files"), false);
3900 ARDOUR_UI::flush_trash ()
3902 if (_session == 0) {
3903 /* shouldn't happen: menu item is insensitive */
3907 ARDOUR::CleanupReport rep;
3909 if (_session->cleanup_trash_sources (rep)) {
3913 display_cleanup_results (rep, _("deleted file"), true);
3917 ARDOUR_UI::cleanup_peakfiles ()
3919 if (_session == 0) {
3920 /* shouldn't happen: menu item is insensitive */
3924 if (! _session->can_cleanup_peakfiles ()) {
3928 // get all region-views in this session
3930 TrackViewList empty;
3932 editor->get_regions_after(rs, (framepos_t) 0, empty);
3933 std::list<RegionView*> views = rs.by_layer();
3935 // remove displayed audio-region-views waveforms
3936 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
3937 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
3938 if (!arv) { continue ; }
3939 arv->delete_waves();
3942 // cleanup peak files:
3943 // - stop pending peakfile threads
3944 // - close peakfiles if any
3945 // - remove peak dir in session
3946 // - setup peakfiles (background thread)
3947 _session->cleanup_peakfiles ();
3949 // re-add waves to ARV
3950 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
3951 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
3952 if (!arv) { continue ; }
3953 arv->create_waves();
3957 PresentationInfo::order_t
3958 ARDOUR_UI::translate_order (AddRouteDialog::InsertAt place)
3960 if (editor->get_selection().tracks.empty()) {
3961 return PresentationInfo::max_order;
3964 PresentationInfo::order_t order_hint = PresentationInfo::max_order;
3967 we want the new routes to have their order keys set starting from
3968 the highest order key in the selection + 1 (if available).
3971 if (place == AddRouteDialog::AfterSelection) {
3972 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.back());
3974 order_hint = rtav->route()->presentation_info().order();
3977 } else if (place == AddRouteDialog::BeforeSelection) {
3978 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.front());
3980 order_hint = rtav->route()->presentation_info().order();
3982 } else if (place == AddRouteDialog::First) {
3985 /* leave order_hint at max_order */
3992 ARDOUR_UI::start_duplicate_routes ()
3994 if (!duplicate_routes_dialog) {
3995 duplicate_routes_dialog = new DuplicateRouteDialog;
3998 if (duplicate_routes_dialog->restart (_session)) {
4002 duplicate_routes_dialog->present ();
4006 ARDOUR_UI::add_route ()
4014 if (add_route_dialog->is_visible()) {
4015 /* we're already doing this */
4019 ResponseType r = (ResponseType) add_route_dialog->run ();
4021 add_route_dialog->hide();
4024 case RESPONSE_ACCEPT:
4031 if ((count = add_route_dialog->count()) <= 0) {
4035 PresentationInfo::order_t order = translate_order (add_route_dialog->insert_at());
4036 string template_path = add_route_dialog->track_template();
4037 DisplaySuspender ds;
4039 if (!template_path.empty()) {
4040 if (add_route_dialog->name_template_is_default()) {
4041 _session->new_route_from_template (count, template_path, string());
4043 _session->new_route_from_template (count, template_path, add_route_dialog->name_template());
4048 ChanCount input_chan= add_route_dialog->channels ();
4049 ChanCount output_chan;
4050 string name_template = add_route_dialog->name_template ();
4051 PluginInfoPtr instrument = add_route_dialog->requested_instrument ();
4052 RouteGroup* route_group = add_route_dialog->route_group ();
4053 AutoConnectOption oac = Config->get_output_auto_connect();
4054 bool strict_io = add_route_dialog->use_strict_io ();
4056 if (oac & AutoConnectMaster) {
4057 output_chan.set (DataType::AUDIO, (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan.n_audio()));
4058 output_chan.set (DataType::MIDI, 0);
4060 output_chan = input_chan;
4063 /* XXX do something with name template */
4065 switch (add_route_dialog->type_wanted()) {
4066 case AddRouteDialog::AudioTrack:
4067 session_add_audio_track (input_chan.n_audio(), output_chan.n_audio(), add_route_dialog->mode(), route_group, count, name_template, strict_io, order);
4069 case AddRouteDialog::MidiTrack:
4070 session_add_midi_track (route_group, count, name_template, strict_io, instrument, 0, order);
4072 case AddRouteDialog::MixedTrack:
4073 session_add_mixed_track (input_chan, output_chan, route_group, count, name_template, strict_io, instrument, 0, order);
4075 case AddRouteDialog::AudioBus:
4076 session_add_audio_bus (input_chan.n_audio(), output_chan.n_audio(), route_group, count, name_template, strict_io, order);
4078 case AddRouteDialog::MidiBus:
4079 session_add_midi_bus (route_group, count, name_template, strict_io, instrument, 0, order);
4081 case AddRouteDialog::VCAMaster:
4082 session_add_vca (name_template, count);
4088 ARDOUR_UI::add_lua_script ()
4094 LuaScriptInfoPtr spi;
4095 ScriptSelector ss ("Add Lua Session Script", LuaScriptInfo::Session);
4096 switch (ss.run ()) {
4097 case Gtk::RESPONSE_ACCEPT:
4105 std::string script = "";
4108 script = Glib::file_get_contents (spi->path);
4109 } catch (Glib::FileError e) {
4110 string msg = string_compose (_("Cannot read session script '%1': %2"), spi->path, e.what());
4111 MessageDialog am (msg);
4116 LuaScriptParamList lsp = LuaScriptParams::script_params (spi, "sess_params");
4117 std::vector<std::string> reg = _session->registered_lua_functions ();
4119 ScriptParameterDialog spd (_("Set Script Parameters"), spi, reg, lsp);
4120 switch (spd.run ()) {
4121 case Gtk::RESPONSE_ACCEPT:
4128 _session->register_lua_function (spd.name(), script, lsp);
4129 } catch (luabridge::LuaException const& e) {
4130 string msg = string_compose (_("Session script '%1' instantiation failed: %2"), spd.name(), e.what ());
4131 MessageDialog am (msg);
4133 } catch (SessionException e) {
4134 string msg = string_compose (_("Loading Session script '%1' failed: %2"), spd.name(), e.what ());
4135 MessageDialog am (msg);
4141 ARDOUR_UI::remove_lua_script ()
4146 if (_session->registered_lua_function_count () == 0) {
4147 string msg = _("There are no active Lua session scripts present in this session.");
4148 MessageDialog am (msg);
4153 std::vector<std::string> reg = _session->registered_lua_functions ();
4154 SessionScriptManager sm ("Remove Lua Session Script", reg);
4155 switch (sm.run ()) {
4156 case Gtk::RESPONSE_ACCEPT:
4162 _session->unregister_lua_function (sm.name());
4163 } catch (luabridge::LuaException const& e) {
4164 string msg = string_compose (_("Session script '%1' removal failed: %2"), sm.name(), e.what ());
4165 MessageDialog am (msg);
4171 ARDOUR_UI::stop_video_server (bool ask_confirm)
4173 if (!video_server_process && ask_confirm) {
4174 warning << string_compose (_("Video-Server was not launched by %1. The request to stop it is ignored."), PROGRAM_NAME) << endmsg;
4176 if (video_server_process) {
4178 ArdourDialog confirm (_("Stop Video-Server"), true);
4179 Label m (_("Do you really want to stop the Video Server?"));
4180 confirm.get_vbox()->pack_start (m, true, true);
4181 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
4182 confirm.add_button (_("Yes, Stop It"), Gtk::RESPONSE_ACCEPT);
4183 confirm.show_all ();
4184 if (confirm.run() == RESPONSE_CANCEL) {
4188 delete video_server_process;
4189 video_server_process =0;
4194 ARDOUR_UI::start_video_server_menu (Gtk::Window* float_window)
4196 ARDOUR_UI::start_video_server( float_window, true);
4200 ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg)
4206 if (ARDOUR_UI::instance()->video_timeline->check_server()) {
4207 if (video_server_process) {
4208 popup_error(_("The Video Server is already started."));
4210 popup_error(_("An external Video Server is configured and can be reached. Not starting a new instance."));
4216 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4218 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4220 VideoServerDialog *video_server_dialog = new VideoServerDialog (_session);
4222 video_server_dialog->set_transient_for (*float_window);
4225 if (!Config->get_show_video_server_dialog() && firsttime < 2) {
4226 video_server_dialog->hide();
4228 ResponseType r = (ResponseType) video_server_dialog->run ();
4229 video_server_dialog->hide();
4230 if (r != RESPONSE_ACCEPT) { return false; }
4231 if (video_server_dialog->show_again()) {
4232 Config->set_show_video_server_dialog(false);
4236 std::string icsd_exec = video_server_dialog->get_exec_path();
4237 std::string icsd_docroot = video_server_dialog->get_docroot();
4238 if (icsd_docroot.empty()) {
4239 #ifndef PLATFORM_WINDOWS
4240 icsd_docroot = X_("/");
4242 icsd_docroot = X_("C:\\");
4247 if (g_lstat (icsd_docroot.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode)) {
4248 warning << _("Specified docroot is not an existing directory.") << endmsg;
4251 #ifndef PLATFORM_WINDOWS
4252 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4253 || (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0 ) {
4254 warning << _("Given Video Server is not an executable file.") << endmsg;
4258 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4259 || (sb.st_mode & (S_IXUSR)) == 0 ) {
4260 warning << _("Given Video Server is not an executable file.") << endmsg;
4266 argp=(char**) calloc(9,sizeof(char*));
4267 argp[0] = strdup(icsd_exec.c_str());
4268 argp[1] = strdup("-P");
4269 argp[2] = (char*) calloc(16,sizeof(char)); snprintf(argp[2], 16, "%s", video_server_dialog->get_listenaddr().c_str());
4270 argp[3] = strdup("-p");
4271 argp[4] = (char*) calloc(6,sizeof(char)); snprintf(argp[4], 6, "%i", video_server_dialog->get_listenport());
4272 argp[5] = strdup("-C");
4273 argp[6] = (char*) calloc(6,sizeof(char)); snprintf(argp[6], 6, "%i", video_server_dialog->get_cachesize());
4274 argp[7] = strdup(icsd_docroot.c_str());
4276 stop_video_server();
4278 if (icsd_docroot == X_("/") || icsd_docroot == X_("C:\\")) {
4279 Config->set_video_advanced_setup(false);
4281 std::ostringstream osstream;
4282 osstream << "http://127.0.0.1:" << video_server_dialog->get_listenport() << "/";
4283 Config->set_video_server_url(osstream.str());
4284 Config->set_video_server_docroot(icsd_docroot);
4285 Config->set_video_advanced_setup(true);
4288 if (video_server_process) {
4289 delete video_server_process;
4292 video_server_process = new ARDOUR::SystemExec(icsd_exec, argp);
4293 if (video_server_process->start()) {
4294 warning << _("Cannot launch the video-server") << endmsg;
4297 int timeout = 120; // 6 sec
4298 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4299 Glib::usleep (50000);
4301 if (--timeout <= 0 || !video_server_process->is_running()) break;
4304 warning << _("Video-server was started but does not respond to requests...") << endmsg;
4306 if (!ARDOUR_UI::instance()->video_timeline->check_server_docroot()) {
4307 delete video_server_process;
4308 video_server_process = 0;
4316 ARDOUR_UI::add_video (Gtk::Window* float_window)
4322 if (!start_video_server(float_window, false)) {
4323 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4328 add_video_dialog->set_transient_for (*float_window);
4331 if (add_video_dialog->is_visible()) {
4332 /* we're already doing this */
4336 ResponseType r = (ResponseType) add_video_dialog->run ();
4337 add_video_dialog->hide();
4338 if (r != RESPONSE_ACCEPT) { return; }
4340 bool local_file, orig_local_file;
4341 std::string path = add_video_dialog->file_name(local_file);
4343 std::string orig_path = path;
4344 orig_local_file = local_file;
4346 bool auto_set_session_fps = add_video_dialog->auto_set_session_fps();
4348 if (local_file && !Glib::file_test(path, Glib::FILE_TEST_EXISTS)) {
4349 warning << string_compose(_("could not open %1"), path) << endmsg;
4352 if (!local_file && path.length() == 0) {
4353 warning << _("no video-file selected") << endmsg;
4357 std::string audio_from_video;
4358 bool detect_ltc = false;
4360 switch (add_video_dialog->import_option()) {
4361 case VTL_IMPORT_TRANSCODE:
4363 TranscodeVideoDialog *transcode_video_dialog;
4364 transcode_video_dialog = new TranscodeVideoDialog (_session, path);
4365 ResponseType r = (ResponseType) transcode_video_dialog->run ();
4366 transcode_video_dialog->hide();
4367 if (r != RESPONSE_ACCEPT) {
4368 delete transcode_video_dialog;
4372 audio_from_video = transcode_video_dialog->get_audiofile();
4374 if (!audio_from_video.empty() && transcode_video_dialog->detect_ltc()) {
4377 else if (!audio_from_video.empty()) {
4378 editor->embed_audio_from_video(
4380 video_timeline->get_offset(),
4381 (transcode_video_dialog->import_option() != VTL_IMPORT_NO_VIDEO)
4384 switch (transcode_video_dialog->import_option()) {
4385 case VTL_IMPORT_TRANSCODED:
4386 path = transcode_video_dialog->get_filename();
4389 case VTL_IMPORT_REFERENCE:
4392 delete transcode_video_dialog;
4395 delete transcode_video_dialog;
4399 case VTL_IMPORT_NONE:
4403 /* strip _session->session_directory().video_path() from video file if possible */
4404 if (local_file && !path.compare(0, _session->session_directory().video_path().size(), _session->session_directory().video_path())) {
4405 path=path.substr(_session->session_directory().video_path().size());
4406 if (path.at(0) == G_DIR_SEPARATOR) {
4407 path=path.substr(1);
4411 video_timeline->set_update_session_fps(auto_set_session_fps);
4413 if (video_timeline->video_file_info(path, local_file)) {
4414 XMLNode* node = new XMLNode(X_("Videotimeline"));
4415 node->add_property (X_("Filename"), path);
4416 node->add_property (X_("AutoFPS"), auto_set_session_fps?X_("1"):X_("0"));
4417 node->add_property (X_("LocalFile"), local_file?X_("1"):X_("0"));
4418 if (orig_local_file) {
4419 node->add_property (X_("OriginalVideoFile"), orig_path);
4421 node->remove_property (X_("OriginalVideoFile"));
4423 _session->add_extra_xml (*node);
4424 _session->set_dirty ();
4426 if (!audio_from_video.empty() && detect_ltc) {
4427 std::vector<LTCFileReader::LTCMap> ltc_seq;
4430 /* TODO ask user about TV standard (LTC alignment if any) */
4431 LTCFileReader ltcr (audio_from_video, video_timeline->get_video_file_fps());
4432 /* TODO ASK user which channel: 0 .. ltcr->channels() - 1 */
4434 ltc_seq = ltcr.read_ltc (/*channel*/ 0, /*max LTC frames to decode*/ 15);
4436 /* TODO seek near end of file, and read LTC until end.
4437 * if it fails to find any LTC frames, scan complete file
4439 * calculate drift of LTC compared to video-duration,
4440 * ask user for reference (timecode from start/mid/end)
4443 // LTCFileReader will have written error messages
4446 ::g_unlink(audio_from_video.c_str());
4448 if (ltc_seq.size() == 0) {
4449 PBD::error << _("No LTC detected, video will not be aligned.") << endmsg;
4451 /* the very first TC in the file is somteimes not aligned properly */
4452 int i = ltc_seq.size() -1;
4453 ARDOUR::frameoffset_t video_start_offset =
4454 _session->nominal_frame_rate() * (ltc_seq[i].timecode_sec - ltc_seq[i].framepos_sec);
4455 PBD::info << string_compose (_("Align video-start to %1 [samples]"), video_start_offset) << endmsg;
4456 video_timeline->set_offset(video_start_offset);
4460 _session->maybe_update_session_range(
4461 std::max(video_timeline->get_offset(), (ARDOUR::frameoffset_t) 0),
4462 std::max(video_timeline->get_offset() + video_timeline->get_duration(), (ARDOUR::frameoffset_t) 0));
4465 if (add_video_dialog->launch_xjadeo() && local_file) {
4466 editor->set_xjadeo_sensitive(true);
4467 editor->toggle_xjadeo_proc(1);
4469 editor->toggle_xjadeo_proc(0);
4471 editor->toggle_ruler_video(true);
4476 ARDOUR_UI::remove_video ()
4478 video_timeline->close_session();
4479 editor->toggle_ruler_video(false);
4482 video_timeline->set_offset_locked(false);
4483 video_timeline->set_offset(0);
4485 /* delete session state */
4486 XMLNode* node = new XMLNode(X_("Videotimeline"));
4487 _session->add_extra_xml(*node);
4488 node = new XMLNode(X_("Videomonitor"));
4489 _session->add_extra_xml(*node);
4490 node = new XMLNode(X_("Videoexport"));
4491 _session->add_extra_xml(*node);
4492 stop_video_server();
4496 ARDOUR_UI::flush_videotimeline_cache (bool localcacheonly)
4498 if (localcacheonly) {
4499 video_timeline->vmon_update();
4501 video_timeline->flush_cache();
4503 editor->queue_visual_videotimeline_update();
4507 ARDOUR_UI::export_video (bool range)
4509 if (ARDOUR::Config->get_show_video_export_info()) {
4510 ExportVideoInfobox infobox (_session);
4511 Gtk::ResponseType rv = (Gtk::ResponseType) infobox.run();
4512 if (infobox.show_again()) {
4513 ARDOUR::Config->set_show_video_export_info(false);
4516 case GTK_RESPONSE_YES:
4517 PBD::open_uri (ARDOUR::Config->get_reference_manual_url() + "/video-timeline/operations/#export");
4523 export_video_dialog->set_session (_session);
4524 export_video_dialog->apply_state(editor->get_selection().time, range);
4525 export_video_dialog->run ();
4526 export_video_dialog->hide ();
4530 ARDOUR_UI::mixer_settings () const
4535 node = _session->instant_xml(X_("Mixer"));
4537 node = Config->instant_xml(X_("Mixer"));
4541 node = new XMLNode (X_("Mixer"));
4548 ARDOUR_UI::main_window_settings () const
4553 node = _session->instant_xml(X_("Main"));
4555 node = Config->instant_xml(X_("Main"));
4559 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4560 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4565 node = new XMLNode (X_("Main"));
4572 ARDOUR_UI::editor_settings () const
4577 node = _session->instant_xml(X_("Editor"));
4579 node = Config->instant_xml(X_("Editor"));
4583 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4584 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4589 node = new XMLNode (X_("Editor"));
4596 ARDOUR_UI::keyboard_settings () const
4600 node = Config->extra_xml(X_("Keyboard"));
4603 node = new XMLNode (X_("Keyboard"));
4610 ARDOUR_UI::create_xrun_marker (framepos_t where)
4613 Location *location = new Location (*_session, where, where, _("xrun"), Location::IsMark);
4614 _session->locations()->add (location);
4619 ARDOUR_UI::halt_on_xrun_message ()
4621 cerr << "HALT on xrun\n";
4622 MessageDialog msg (_main_window, _("Recording was stopped because your system could not keep up."));
4627 ARDOUR_UI::xrun_handler (framepos_t where)
4633 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
4635 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
4636 create_xrun_marker(where);
4639 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
4640 halt_on_xrun_message ();
4645 ARDOUR_UI::disk_overrun_handler ()
4647 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
4649 if (!have_disk_speed_dialog_displayed) {
4650 have_disk_speed_dialog_displayed = true;
4651 MessageDialog* msg = new MessageDialog (_main_window, string_compose (_("\
4652 The disk system on your computer\n\
4653 was not able to keep up with %1.\n\
4655 Specifically, it failed to write data to disk\n\
4656 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
4657 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4663 /* TODO: this is getting elaborate enough to warrant being split into a dedicated class */
4664 static MessageDialog *scan_dlg = NULL;
4665 static ProgressBar *scan_pbar = NULL;
4666 static HBox *scan_tbox = NULL;
4667 static Gtk::Button *scan_timeout_button;
4670 ARDOUR_UI::cancel_plugin_scan ()
4672 PluginManager::instance().cancel_plugin_scan();
4676 ARDOUR_UI::cancel_plugin_timeout ()
4678 PluginManager::instance().cancel_plugin_timeout();
4679 scan_timeout_button->set_sensitive (false);
4683 ARDOUR_UI::plugin_scan_timeout (int timeout)
4685 if (!scan_dlg || !scan_dlg->is_mapped() || !scan_pbar) {
4689 scan_pbar->set_sensitive (false);
4690 scan_timeout_button->set_sensitive (true);
4691 scan_pbar->set_fraction ((float) timeout / (float) Config->get_vst_scan_timeout());
4694 scan_pbar->set_sensitive (false);
4695 scan_timeout_button->set_sensitive (false);
4701 ARDOUR_UI::plugin_scan_dialog (std::string type, std::string plugin, bool can_cancel)
4703 if (type == X_("closeme") && !(scan_dlg && scan_dlg->is_mapped())) {
4707 const bool cancelled = PluginManager::instance().cancelled();
4708 if (type != X_("closeme") && (!UIConfiguration::instance().get_show_plugin_scan_window()) && !_initial_verbose_plugin_scan) {
4709 if (cancelled && scan_dlg->is_mapped()) {
4714 if (cancelled || !can_cancel) {
4719 static Gtk::Button *cancel_button;
4721 scan_dlg = new MessageDialog("", false, MESSAGE_INFO, BUTTONS_NONE); // TODO manage
4722 VBox* vbox = scan_dlg->get_vbox();
4723 vbox->set_size_request(400,-1);
4724 scan_dlg->set_title (_("Scanning for plugins"));
4726 cancel_button = manage(new Gtk::Button(_("Cancel plugin scan")));
4727 cancel_button->set_name ("EditorGTKButton");
4728 cancel_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_scan) );
4729 cancel_button->show();
4731 scan_dlg->get_vbox()->pack_start ( *cancel_button, PACK_SHRINK);
4733 scan_tbox = manage( new HBox() );
4735 scan_timeout_button = manage(new Gtk::Button(_("Stop Timeout")));
4736 scan_timeout_button->set_name ("EditorGTKButton");
4737 scan_timeout_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_timeout) );
4738 scan_timeout_button->show();
4740 scan_pbar = manage(new ProgressBar());
4741 scan_pbar->set_orientation(Gtk::PROGRESS_RIGHT_TO_LEFT);
4742 scan_pbar->set_text(_("Scan Timeout"));
4745 scan_tbox->pack_start (*scan_pbar, PACK_EXPAND_WIDGET, 4);
4746 scan_tbox->pack_start (*scan_timeout_button, PACK_SHRINK, 4);
4748 scan_dlg->get_vbox()->pack_start (*scan_tbox, PACK_SHRINK, 4);
4751 assert(scan_dlg && scan_tbox && cancel_button);
4753 if (type == X_("closeme")) {
4757 scan_dlg->set_message(type + ": " + Glib::path_get_basename(plugin));
4760 if (!can_cancel || !cancelled) {
4761 scan_timeout_button->set_sensitive(false);
4763 cancel_button->set_sensitive(can_cancel && !cancelled);
4769 ARDOUR_UI::gui_idle_handler ()
4772 /* due to idle calls, gtk_events_pending() may always return true */
4773 while (gtk_events_pending() && --timeout) {
4774 gtk_main_iteration ();
4779 ARDOUR_UI::disk_underrun_handler ()
4781 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
4783 if (!have_disk_speed_dialog_displayed) {
4784 have_disk_speed_dialog_displayed = true;
4785 MessageDialog* msg = new MessageDialog (
4786 _main_window, string_compose (_("The disk system on your computer\n\
4787 was not able to keep up with %1.\n\
4789 Specifically, it failed to read data from disk\n\
4790 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
4791 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4797 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
4799 have_disk_speed_dialog_displayed = false;
4804 ARDOUR_UI::session_dialog (std::string msg)
4806 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
4810 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
4817 ARDOUR_UI::pending_state_dialog ()
4819 HBox* hbox = manage (new HBox());
4820 Image* image = manage (new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG));
4821 ArdourDialog dialog (_("Crash Recovery"), true);
4822 Label message (string_compose (_("\
4823 This session appears to have been in the\n\
4824 middle of recording when %1 or\n\
4825 the computer was shutdown.\n\
4827 %1 can recover any captured audio for\n\
4828 you, or it can ignore it. Please decide\n\
4829 what you would like to do.\n"), PROGRAM_NAME));
4830 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4831 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4832 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4833 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4834 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
4835 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
4836 dialog.set_default_response (RESPONSE_ACCEPT);
4837 dialog.set_position (WIN_POS_CENTER);
4842 switch (dialog.run ()) {
4843 case RESPONSE_ACCEPT:
4851 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
4853 HBox* hbox = new HBox();
4854 Image* image = new Image (Stock::DIALOG_WARNING, ICON_SIZE_DIALOG);
4855 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
4856 Label message (string_compose (_("\
4857 This session was created with a sample rate of %1 Hz, but\n\
4858 %2 is currently running at %3 Hz. If you load this session,\n\
4859 audio may be played at the wrong sample rate.\n"), desired, PROGRAM_NAME, actual));
4861 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4862 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4863 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4864 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4865 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
4866 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
4867 dialog.set_default_response (RESPONSE_ACCEPT);
4868 dialog.set_position (WIN_POS_CENTER);
4873 switch (dialog.run()) {
4874 case RESPONSE_ACCEPT:
4884 ARDOUR_UI::sr_mismatch_message (framecnt_t desired, framecnt_t actual)
4886 MessageDialog msg (string_compose (_("\
4887 This session was created with a sample rate of %1 Hz, but\n\
4888 %2 is currently running at %3 Hz.\n\
4889 Audio will be recorded and played at the wrong sample rate.\n\
4890 Re-Configure the Audio Engine in\n\
4891 Menu > Window > Audio/Midi Setup"),
4892 desired, PROGRAM_NAME, actual),
4894 Gtk::MESSAGE_WARNING);
4899 ARDOUR_UI::use_config ()
4901 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
4903 set_transport_controllable_state (*node);
4908 ARDOUR_UI::update_transport_clocks (framepos_t pos)
4910 if (UIConfiguration::instance().get_primary_clock_delta_edit_cursor()) {
4911 primary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
4913 primary_clock->set (pos);
4916 if (UIConfiguration::instance().get_secondary_clock_delta_edit_cursor()) {
4917 secondary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
4919 secondary_clock->set (pos);
4922 if (big_clock_window) {
4923 big_clock->set (pos);
4925 ARDOUR_UI::instance()->video_timeline->manual_seek_video_monitor(pos);
4929 ARDOUR_UI::step_edit_status_change (bool yn)
4931 // XXX should really store pre-step edit status of things
4932 // we make insensitive
4935 rec_button.set_active_state (Gtkmm2ext::ImplicitActive);
4936 rec_button.set_sensitive (false);
4938 rec_button.unset_active_state ();;
4939 rec_button.set_sensitive (true);
4944 ARDOUR_UI::record_state_changed ()
4946 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
4948 if (!_session || !big_clock_window) {
4949 /* why bother - the clock isn't visible */
4953 if (_session->record_status () == Session::Recording && _session->have_rec_enabled_track ()) {
4954 big_clock->set_active (true);
4956 big_clock->set_active (false);
4961 ARDOUR_UI::first_idle ()
4964 _session->allow_auto_play (true);
4968 editor->first_idle();
4971 Keyboard::set_can_save_keybindings (true);
4976 ARDOUR_UI::store_clock_modes ()
4978 XMLNode* node = new XMLNode(X_("ClockModes"));
4980 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
4981 XMLNode* child = new XMLNode (X_("Clock"));
4983 child->add_property (X_("name"), (*x)->name());
4984 child->add_property (X_("mode"), enum_2_string ((*x)->mode()));
4985 child->add_property (X_("on"), ((*x)->off() ? X_("no") : X_("yes")));
4987 node->add_child_nocopy (*child);
4990 _session->add_extra_xml (*node);
4991 _session->set_dirty ();
4994 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
4995 : Controllable (name), ui (u), type(tp)
5001 ARDOUR_UI::TransportControllable::set_value (double val, PBD::Controllable::GroupControlDisposition /*group_override*/)
5004 /* do nothing: these are radio-style actions */
5008 const char *action = 0;
5012 action = X_("Roll");
5015 action = X_("Stop");
5018 action = X_("GotoStart");
5021 action = X_("GotoEnd");
5024 action = X_("Loop");
5027 action = X_("PlaySelection");
5030 action = X_("Record");
5040 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
5048 ARDOUR_UI::TransportControllable::get_value (void) const
5075 ARDOUR_UI::setup_profile ()
5077 if (gdk_screen_width() < 1200 || getenv ("ARDOUR_NARROW_SCREEN")) {
5078 Profile->set_small_screen ();
5081 if (g_getenv ("TRX")) {
5082 Profile->set_trx ();
5085 if (g_getenv ("MIXBUS")) {
5086 Profile->set_mixbus ();
5091 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
5093 MissingFileDialog dialog (s, str, type);
5098 int result = dialog.run ();
5105 return 1; // quit entire session load
5108 result = dialog.get_action ();
5114 ARDOUR_UI::ambiguous_file (std::string file, std::vector<std::string> hits)
5116 AmbiguousFileDialog dialog (file, hits);
5123 return dialog.get_which ();
5126 /** Allocate our thread-local buffers */
5128 ARDOUR_UI::get_process_buffers ()
5130 _process_thread->get_buffers ();
5133 /** Drop our thread-local buffers */
5135 ARDOUR_UI::drop_process_buffers ()
5137 _process_thread->drop_buffers ();
5141 ARDOUR_UI::feedback_detected ()
5143 _feedback_exists = true;
5147 ARDOUR_UI::successful_graph_sort ()
5149 _feedback_exists = false;
5153 ARDOUR_UI::midi_panic ()
5156 _session->midi_panic();
5161 ARDOUR_UI::session_format_mismatch (std::string xml_path, std::string backup_path)
5163 const char* start_big = "<span size=\"x-large\" weight=\"bold\">";
5164 const char* end_big = "</span>";
5165 const char* start_mono = "<tt>";
5166 const char* end_mono = "</tt>";
5168 MessageDialog msg (string_compose (_("%4This is a session from an older version of %3%5\n\n"
5169 "%3 has copied the old session file\n\n%6%1%7\n\nto\n\n%6%2%7\n\n"
5170 "From now on, use the backup copy with older versions of %3"),
5171 xml_path, backup_path, PROGRAM_NAME,
5173 start_mono, end_mono), true);
5180 ARDOUR_UI::reset_peak_display ()
5182 if (!_session || !_session->master_out() || !editor_meter) return;
5183 editor_meter->clear_meters();
5184 editor_meter_max_peak = -INFINITY;
5185 editor_meter_peak_display.set_active_state ( Gtkmm2ext::Off );
5189 ARDOUR_UI::reset_group_peak_display (RouteGroup* group)
5191 if (!_session || !_session->master_out()) return;
5192 if (group == _session->master_out()->route_group()) {
5193 reset_peak_display ();
5198 ARDOUR_UI::reset_route_peak_display (Route* route)
5200 if (!_session || !_session->master_out()) return;
5201 if (_session->master_out().get() == route) {
5202 reset_peak_display ();
5207 ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate)
5209 audio_midi_setup->set_desired_sample_rate (desired_sample_rate);
5210 audio_midi_setup->set_position (WIN_POS_CENTER);
5212 if (Config->get_try_autostart_engine () || getenv ("TRY_AUTOSTART_ENGINE")) {
5213 audio_midi_setup->try_autostart ();
5214 if (ARDOUR::AudioEngine::instance()->running()) {
5220 int response = audio_midi_setup->run();
5222 case Gtk::RESPONSE_OK:
5223 if (!AudioEngine::instance()->running()) {
5237 ARDOUR_UI::transport_numpad_timeout ()
5239 _numpad_locate_happening = false;
5240 if (_numpad_timeout_connection.connected() )
5241 _numpad_timeout_connection.disconnect();
5246 ARDOUR_UI::transport_numpad_decimal ()
5248 _numpad_timeout_connection.disconnect();
5250 if (_numpad_locate_happening) {
5251 if (editor) editor->goto_nth_marker(_pending_locate_num - 1);
5252 _numpad_locate_happening = false;
5254 _pending_locate_num = 0;
5255 _numpad_locate_happening = true;
5256 _numpad_timeout_connection = Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::transport_numpad_timeout), 2*1000);
5261 ARDOUR_UI::transport_numpad_event (int num)
5263 if ( _numpad_locate_happening ) {
5264 _pending_locate_num = _pending_locate_num*10 + num;
5267 case 0: toggle_roll(false, false); break;
5268 case 1: transport_rewind(1); break;
5269 case 2: transport_forward(1); break;
5270 case 3: transport_record(true); break;
5271 case 4: toggle_session_auto_loop(); break;
5272 case 5: transport_record(false); toggle_session_auto_loop(); break;
5273 case 6: toggle_punch(); break;
5274 case 7: toggle_click(); break;
5275 case 8: toggle_auto_return(); break;
5276 case 9: toggle_follow_edits(); break;
5282 ARDOUR_UI::set_flat_buttons ()
5284 CairoWidget::set_flat_buttons( UIConfiguration::instance().get_flat_buttons() );
5288 ARDOUR_UI::audioengine_became_silent ()
5290 MessageDialog msg (string_compose (_("This is a free/demo copy of %1. It has just switched to silent mode."), PROGRAM_NAME),
5292 Gtk::MESSAGE_WARNING,
5296 msg.set_title (string_compose (_("%1 is now silent"), PROGRAM_NAME));
5298 Gtk::Label pay_label (string_compose (_("Please consider paying for a copy of %1 - you can pay whatever you want."), PROGRAM_NAME));
5299 Gtk::Label subscribe_label (_("Better yet become a subscriber - subscriptions start at US$1 per month."));
5300 Gtk::Button pay_button (_("Pay for a copy (via the web)"));
5301 Gtk::Button subscribe_button (_("Become a subscriber (via the web)"));
5302 Gtk::HBox pay_button_box;
5303 Gtk::HBox subscribe_button_box;
5305 pay_button_box.pack_start (pay_button, true, false);
5306 subscribe_button_box.pack_start (subscribe_button, true, false);
5308 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 */
5310 pay_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://ardour.org/download")));
5311 subscribe_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://community.ardour.org/s/subscribe")));
5313 msg.get_vbox()->pack_start (pay_label);
5314 msg.get_vbox()->pack_start (pay_button_box);
5315 msg.get_vbox()->pack_start (subscribe_label);
5316 msg.get_vbox()->pack_start (subscribe_button_box);
5318 msg.get_vbox()->show_all ();
5320 msg.add_button (_("Remain silent"), Gtk::RESPONSE_CANCEL);
5321 msg.add_button (_("Save and quit"), Gtk::RESPONSE_NO);
5322 msg.add_button (_("Give me more time"), Gtk::RESPONSE_YES);
5327 case Gtk::RESPONSE_YES:
5328 AudioEngine::instance()->reset_silence_countdown ();
5331 case Gtk::RESPONSE_NO:
5333 save_state_canfail ("");
5337 case Gtk::RESPONSE_CANCEL:
5339 /* don't reset, save session and exit */
5345 ARDOUR_UI::hide_application ()
5347 Application::instance ()-> hide ();
5351 ARDOUR_UI::setup_toplevel_window (Gtk::Window& window, const string& name, void* owner)
5353 /* icons, titles, WM stuff */
5355 static list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
5357 if (window_icons.empty()) {
5358 Glib::RefPtr<Gdk::Pixbuf> icon;
5359 if ((icon = ::get_icon (PROGRAM_NAME "-icon_16px")) != 0) {
5360 window_icons.push_back (icon);
5362 if ((icon = ::get_icon (PROGRAM_NAME "-icon_22px")) != 0) {
5363 window_icons.push_back (icon);
5365 if ((icon = ::get_icon (PROGRAM_NAME "-icon_32px")) != 0) {
5366 window_icons.push_back (icon);
5368 if ((icon = ::get_icon (PROGRAM_NAME "-icon_48px")) != 0) {
5369 window_icons.push_back (icon);
5373 if (!window_icons.empty()) {
5374 window.set_default_icon_list (window_icons);
5377 Gtkmm2ext::WindowTitle title (Glib::get_application_name());
5379 if (!name.empty()) {
5383 window.set_title (title.get_string());
5384 window.set_wmclass (string_compose (X_("%1_%1"), downcase (PROGRAM_NAME), downcase (name)), PROGRAM_NAME);
5386 window.set_flags (CAN_FOCUS);
5387 window.add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
5389 /* This is a hack to ensure that GTK-accelerators continue to
5390 * work. Once we switch over to entirely native bindings, this will be
5391 * unnecessary and should be removed
5393 window.add_accel_group (ActionManager::ui_manager->get_accel_group());
5395 window.signal_configure_event().connect (sigc::mem_fun (*this, &ARDOUR_UI::configure_handler));
5396 window.signal_window_state_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::tabbed_window_state_event_handler), owner));
5397 window.signal_key_press_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5398 window.signal_key_release_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5402 ARDOUR_UI::key_event_handler (GdkEventKey* ev, Gtk::Window* event_window)
5404 Gtkmm2ext::Bindings* bindings = 0;
5405 Gtk::Window* window = 0;
5407 /* until we get ardour bindings working, we are not handling key
5411 if (ev->type != GDK_KEY_PRESS) {
5415 if (event_window == &_main_window) {
5417 window = event_window;
5419 /* find current tab contents */
5421 Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page());
5423 /* see if it uses the ardour binding system */
5426 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(w->get_data ("ardour-bindings"));
5429 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("main window key event, bindings = %1, global = %2\n", bindings, &global_bindings));
5433 window = event_window;
5435 /* see if window uses ardour binding system */
5437 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(window->get_data ("ardour-bindings"));
5440 /* An empty binding set is treated as if it doesn't exist */
5442 if (bindings && bindings->empty()) {
5446 return key_press_focus_accelerator_handler (*window, ev, bindings);
5449 static Gtkmm2ext::Bindings*
5450 get_bindings_from_widget_heirarchy (GtkWidget* w)
5455 if ((p = g_object_get_data (G_OBJECT(w), "ardour-bindings")) != 0) {
5458 w = gtk_widget_get_parent (w);
5461 return reinterpret_cast<Gtkmm2ext::Bindings*> (p);
5465 ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev, Gtkmm2ext::Bindings* bindings)
5467 GtkWindow* win = window.gobj();
5468 GtkWidget* focus = gtk_window_get_focus (win);
5469 bool special_handling_of_unmodified_accelerators = false;
5470 const guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK));
5474 /* some widget has keyboard focus */
5476 if (GTK_IS_ENTRY(focus) || Keyboard::some_magic_widget_has_focus()) {
5478 /* A particular kind of focusable widget currently has keyboard
5479 * focus. All unmodified key events should go to that widget
5480 * first and not be used as an accelerator by default
5483 special_handling_of_unmodified_accelerators = true;
5487 Gtkmm2ext::Bindings* focus_bindings = get_bindings_from_widget_heirarchy (focus);
5488 if (focus_bindings) {
5489 bindings = focus_bindings;
5490 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Switch bindings based on focus widget, now using %1\n", bindings->name()));
5495 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",
5498 show_gdk_event_state (ev->state),
5499 special_handling_of_unmodified_accelerators,
5500 Keyboard::some_magic_widget_has_focus(),
5502 (focus ? gtk_widget_get_name (focus) : "no focus widget"),
5503 ((ev->state & mask) ? "yes" : "no"),
5504 window.get_title()));
5506 /* This exists to allow us to override the way GTK handles
5507 key events. The normal sequence is:
5509 a) event is delivered to a GtkWindow
5510 b) accelerators/mnemonics are activated
5511 c) if (b) didn't handle the event, propagate to
5512 the focus widget and/or focus chain
5514 The problem with this is that if the accelerators include
5515 keys without modifiers, such as the space bar or the
5516 letter "e", then pressing the key while typing into
5517 a text entry widget results in the accelerator being
5518 activated, instead of the desired letter appearing
5521 There is no good way of fixing this, but this
5522 represents a compromise. The idea is that
5523 key events involving modifiers (not Shift)
5524 get routed into the activation pathway first, then
5525 get propagated to the focus widget if necessary.
5527 If the key event doesn't involve modifiers,
5528 we deliver to the focus widget first, thus allowing
5529 it to get "normal text" without interference
5532 Of course, this can also be problematic: if there
5533 is a widget with focus, then it will swallow
5534 all "normal text" accelerators.
5538 if (!special_handling_of_unmodified_accelerators || (ev->state & mask)) {
5540 /* no special handling or there are modifiers in effect: accelerate first */
5542 DEBUG_TRACE (DEBUG::Accelerators, "\tactivate, then propagate\n");
5543 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tevent send-event:%1 time:%2 length:%3 name %7 string:%4 hardware_keycode:%5 group:%6\n",
5544 ev->send_event, ev->time, ev->length, ev->string, ev->hardware_keycode, ev->group, gdk_keyval_name (ev->keyval)));
5546 DEBUG_TRACE (DEBUG::Accelerators, "\tsending to window\n");
5547 KeyboardKey k (ev->state, ev->keyval);
5551 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tusing Ardour bindings %1 @ %2 for this event\n", bindings->name(), bindings));
5553 if (bindings->activate (k, Bindings::Press)) {
5554 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5559 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5561 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5562 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5566 DEBUG_TRACE (DEBUG::Accelerators, "\tnot accelerated, now propagate\n");
5568 if (gtk_window_propagate_key_event (win, ev)) {
5569 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate handled\n");
5575 /* no modifiers, propagate first */
5577 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate, then activate\n");
5579 if (gtk_window_propagate_key_event (win, ev)) {
5580 DEBUG_TRACE (DEBUG::Accelerators, "\thandled by propagate\n");
5584 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagation didn't handle, so activate\n");
5585 KeyboardKey k (ev->state, ev->keyval);
5589 DEBUG_TRACE (DEBUG::Accelerators, "\tusing Ardour bindings for this window\n");
5592 if (bindings->activate (k, Bindings::Press)) {
5593 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5599 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5601 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5602 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5607 DEBUG_TRACE (DEBUG::Accelerators, "\tnot handled\n");
5612 ARDOUR_UI::load_bindings ()
5614 if ((global_bindings = Bindings::get_bindings (X_("Global"), global_actions)) == 0) {
5615 error << _("Global keybindings are missing") << endmsg;
5620 ARDOUR_UI::cancel_solo ()
5624 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_control), 0.0, Controllable::NoGroup);
5626 _session->clear_all_solo_state (_session->get_routes()); // safeguard, ideally this won't do anything, check the log-window