2 Copyright (C) 1999-2013 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include "gtk2ardour-config.h"
22 #include "gtk2ardour-version.h"
32 #ifndef PLATFORM_WINDOWS
33 #include <sys/resource.h>
37 #include <sys/types.h>
38 #include <sys/sysctl.h>
48 #include "pbd/gstdio_compat.h"
50 #include <gtkmm/messagedialog.h>
51 #include <gtkmm/accelmap.h>
52 #include <gtkmm/stock.h>
54 #include "pbd/error.h"
55 #include "pbd/basename.h"
56 #include "pbd/compose.h"
57 #include "pbd/convert.h"
58 #include "pbd/failed_constructor.h"
59 #include "pbd/enumwriter.h"
60 #include "pbd/memento_command.h"
61 #include "pbd/openuri.h"
62 #include "pbd/stl_delete.h"
63 #include "pbd/file_utils.h"
64 #include "pbd/localtime_r.h"
65 #include "pbd/pthread_utils.h"
66 #include "pbd/replace_all.h"
67 #include "pbd/xml++.h"
69 #include "gtkmm2ext/application.h"
70 #include "gtkmm2ext/bindings.h"
71 #include "gtkmm2ext/gtk_ui.h"
72 #include "gtkmm2ext/utils.h"
73 #include "gtkmm2ext/click_box.h"
74 #include "gtkmm2ext/fastmeter.h"
75 #include "gtkmm2ext/popup.h"
76 #include "gtkmm2ext/window_title.h"
78 #include "ardour/ardour.h"
79 #include "ardour/audio_backend.h"
80 #include "ardour/audio_track.h"
81 #include "ardour/audioengine.h"
82 #include "ardour/audiofilesource.h"
83 #include "ardour/automation_watch.h"
84 #include "ardour/diskstream.h"
85 #include "ardour/filename_extensions.h"
86 #include "ardour/filesystem_paths.h"
87 #include "ardour/ltc_file_reader.h"
88 #include "ardour/midi_track.h"
89 #include "ardour/port.h"
90 #include "ardour/plugin_manager.h"
91 #include "ardour/process_thread.h"
92 #include "ardour/profile.h"
93 #include "ardour/recent_sessions.h"
94 #include "ardour/record_enable_control.h"
95 #include "ardour/session_directory.h"
96 #include "ardour/session_route.h"
97 #include "ardour/session_state_utils.h"
98 #include "ardour/session_utils.h"
99 #include "ardour/source_factory.h"
100 #include "ardour/slave.h"
101 #include "ardour/system_exec.h"
102 #include "ardour/track.h"
103 #include "ardour/vca_manager.h"
104 #include "ardour/utils.h"
106 #include "LuaBridge/LuaBridge.h"
108 #ifdef WINDOWS_VST_SUPPORT
111 #ifdef AUDIOUNIT_SUPPORT
112 #include "ardour/audio_unit.h"
115 // fix for OSX (nsm.h has a check function, AU/Apple defines check)
120 #include "timecode/time.h"
122 typedef uint64_t microseconds_t;
127 #include "add_route_dialog.h"
128 #include "ambiguous_file_dialog.h"
129 #include "ardour_ui.h"
130 #include "audio_clock.h"
131 #include "audio_region_view.h"
132 #include "big_clock_window.h"
133 #include "bundle_manager.h"
134 #include "duplicate_routes_dialog.h"
136 #include "engine_dialog.h"
137 #include "export_video_dialog.h"
138 #include "export_video_infobox.h"
139 #include "gain_meter.h"
140 #include "global_port_matrix.h"
141 #include "gui_object.h"
142 #include "gui_thread.h"
143 #include "keyboard.h"
144 #include "keyeditor.h"
145 #include "location_ui.h"
146 #include "lua_script_manager.h"
147 #include "luawindow.h"
148 #include "main_clock.h"
149 #include "missing_file_dialog.h"
150 #include "missing_plugin_dialog.h"
151 #include "mixer_ui.h"
152 #include "meterbridge.h"
153 #include "mouse_cursors.h"
156 #include "pingback.h"
157 #include "processor_box.h"
158 #include "prompter.h"
159 #include "public_editor.h"
160 #include "rc_option_editor.h"
161 #include "route_time_axis.h"
162 #include "route_params_ui.h"
163 #include "save_as_dialog.h"
164 #include "script_selector.h"
165 #include "session_dialog.h"
166 #include "session_metadata_dialog.h"
167 #include "session_option_editor.h"
168 #include "shuttle_control.h"
169 #include "speaker_dialog.h"
172 #include "theme_manager.h"
173 #include "time_axis_view_item.h"
176 #include "video_server_dialog.h"
177 #include "add_video_dialog.h"
178 #include "transcode_video_dialog.h"
182 using namespace ARDOUR;
183 using namespace ARDOUR_UI_UTILS;
185 using namespace Gtkmm2ext;
188 using namespace Editing;
190 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
192 sigc::signal<void, framepos_t, bool, framepos_t> ARDOUR_UI::Clock;
193 sigc::signal<void> ARDOUR_UI::CloseAllDialogs;
196 ask_about_configuration_copy (string const & old_dir, string const & new_dir, int version)
198 MessageDialog msg (string_compose (_("%1 %2.x has discovered configuration files from %1 %3.x.\n\n"
199 "Would you like these files to be copied and used for %1 %2.x?\n\n"
200 "(This will require you to restart %1.)"),
201 PROGRAM_NAME, PROGRAM_VERSION, version),
202 false, /* no markup */
205 true /* modal, though it hardly matters since it is the only window */
208 msg.set_default_response (Gtk::RESPONSE_YES);
211 return (msg.run() == Gtk::RESPONSE_YES);
215 libxml_generic_error_func (void* /* parsing_context*/,
223 vsnprintf (buf, sizeof (buf), msg, ap);
224 error << buf << endmsg;
229 libxml_structured_error_func (void* /* parsing_context*/,
237 replace_all (msg, "\n", "");
240 if (err->file && err->line) {
241 error << X_("XML error: ") << msg << " in " << err->file << " at line " << err->line;
244 error << ':' << err->int2;
249 error << X_("XML error: ") << msg << endmsg;
255 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
256 : Gtkmm2ext::UI (PROGRAM_NAME, X_("gui"), argcp, argvp)
257 , session_loaded (false)
258 , gui_object_state (new GUIObjectState)
259 , primary_clock (new MainClock (X_("primary"), X_("transport"), true ))
260 , secondary_clock (new MainClock (X_("secondary"), X_("secondary"), false))
261 , big_clock (new AudioClock (X_("bigclock"), false, "big", true, true, false, false))
263 , global_actions (X_("global"))
264 , ignore_dual_punch (false)
265 , main_window_visibility (0)
270 , _mixer_on_top (false)
271 , _initial_verbose_plugin_scan (false)
272 , first_time_engine_run (true)
273 , roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll))
274 , stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop))
275 , goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart))
276 , goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd))
277 , auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop))
278 , play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection))
279 , rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable))
280 , auto_return_button (ArdourButton::led_default_elements)
281 , follow_edits_button (ArdourButton::led_default_elements)
282 , auto_input_button (ArdourButton::led_default_elements)
283 , auditioning_alert_button (_("Audition"))
284 , solo_alert_button (_("Solo"))
285 , feedback_alert_button (_("Feedback"))
286 , error_alert_button ( ArdourButton::just_led_default_elements )
288 , editor_meter_peak_display()
289 , _numpad_locate_happening (false)
290 , _session_is_new (false)
291 , last_key_press_time (0)
295 , rc_option_editor (0)
296 , speaker_config_window (X_("speaker-config"), _("Speaker Configuration"))
297 , add_route_dialog (X_("add-routes"), _("Add Tracks/Busses"))
298 , about (X_("about"), _("About"))
299 , location_ui (X_("locations"), S_("Ranges|Locations"))
300 , route_params (X_("inspector"), _("Tracks and Busses"))
301 , audio_midi_setup (X_("audio-midi-setup"), _("Audio/MIDI Setup"))
302 , export_video_dialog (X_("video-export"), _("Video Export Dialog"))
303 , lua_script_window (X_("script-manager"), _("Script Manager"))
304 , session_option_editor (X_("session-options-editor"), _("Properties"), boost::bind (&ARDOUR_UI::create_session_option_editor, this))
305 , add_video_dialog (X_("add-video"), _("Add Video"), boost::bind (&ARDOUR_UI::create_add_video_dialog, this))
306 , bundle_manager (X_("bundle-manager"), _("Bundle Manager"), boost::bind (&ARDOUR_UI::create_bundle_manager, this))
307 , big_clock_window (X_("big-clock"), _("Big Clock"), boost::bind (&ARDOUR_UI::create_big_clock_window, this))
308 , audio_port_matrix (X_("audio-connection-manager"), _("Audio Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::AUDIO))
309 , midi_port_matrix (X_("midi-connection-manager"), _("MIDI Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::MIDI))
310 , key_editor (X_("key-editor"), _("Bindings Editor"), boost::bind (&ARDOUR_UI::create_key_editor, this))
311 , video_server_process (0)
313 , have_configure_timeout (false)
314 , last_configure_time (0)
316 , have_disk_speed_dialog_displayed (false)
317 , _status_bar_visibility (X_("status-bar"))
318 , _feedback_exists (false)
319 , _log_not_acknowledged (LogLevelNone)
320 , duplicate_routes_dialog (0)
321 , editor_visibility_button (S_("Window|Editor"))
322 , mixer_visibility_button (S_("Window|Mixer"))
323 , prefs_visibility_button (S_("Window|Preferences"))
325 Gtkmm2ext::init (localedir);
327 UIConfiguration::instance().post_gui_init ();
329 if (ARDOUR::handle_old_configuration_files (boost::bind (ask_about_configuration_copy, _1, _2, _3))) {
330 MessageDialog msg (string_compose (_("Your configuration files were copied. You can now restart %1."), PROGRAM_NAME), true);
332 /* configuration was modified, exit immediately */
337 if (string (VERSIONSTRING).find (".pre") != string::npos) {
338 /* check this is not being run from ./ardev etc. */
339 if (!running_from_source_tree ()) {
340 pre_release_dialog ();
344 if (theArdourUI == 0) {
348 /* track main window visibility */
350 main_window_visibility = new VisibilityTracker (_main_window);
352 /* stop libxml from spewing to stdout/stderr */
354 xmlSetGenericErrorFunc (this, libxml_generic_error_func);
355 xmlSetStructuredErrorFunc (this, libxml_structured_error_func);
357 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::parameter_changed));
358 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
359 UIConfiguration::instance().map_parameters (pc);
361 roll_button.set_controllable (roll_controllable);
362 stop_button.set_controllable (stop_controllable);
363 goto_start_button.set_controllable (goto_start_controllable);
364 goto_end_button.set_controllable (goto_end_controllable);
365 auto_loop_button.set_controllable (auto_loop_controllable);
366 play_selection_button.set_controllable (play_selection_controllable);
367 rec_button.set_controllable (rec_controllable);
369 roll_button.set_name ("transport button");
370 stop_button.set_name ("transport button");
371 goto_start_button.set_name ("transport button");
372 goto_end_button.set_name ("transport button");
373 auto_loop_button.set_name ("transport button");
374 play_selection_button.set_name ("transport button");
375 rec_button.set_name ("transport recenable button");
376 midi_panic_button.set_name ("transport button");
378 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
379 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
381 ARDOUR::Session::VersionMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_format_mismatch, this, _1, _2), gui_context());
383 /* handle dialog requests */
385 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
387 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
389 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
391 /* handle Audio/MIDI setup when session requires it */
393 ARDOUR::Session::AudioEngineSetupRequired.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::do_audio_midi_setup, this, _1));
395 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
397 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
399 /* handle sr mismatch with a dialog - cross-thread from engine */
400 ARDOUR::Session::NotifyAboutSampleRateMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::sr_mismatch_message, this, _1, _2), gui_context ());
402 /* handle requests to quit (coming from JACK session) */
404 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::finish, this), gui_context ());
406 /* tell the user about feedback */
408 ARDOUR::Session::FeedbackDetected.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::feedback_detected, this), gui_context ());
409 ARDOUR::Session::SuccessfulGraphSort.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::successful_graph_sort, this), gui_context ());
411 /* handle requests to deal with missing files */
413 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
415 /* and ambiguous files */
417 ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2));
419 /* also plugin scan messages */
420 ARDOUR::PluginScanMessage.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_dialog, this, _1, _2, _3), gui_context());
421 ARDOUR::PluginScanTimeout.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_timeout, this, _1), gui_context());
423 ARDOUR::GUIIdle.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::gui_idle_handler, this), gui_context());
425 Config->ParameterChanged.connect ( forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::set_flat_buttons, this), gui_context() );
428 /* lets get this party started */
430 setup_gtk_ardour_enums ();
433 SessionEvent::create_per_thread_pool ("GUI", 4096);
435 /* we like keyboards */
437 keyboard = new ArdourKeyboard(*this);
439 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
441 keyboard->set_state (*node, Stateful::loading_state_version);
444 UIConfiguration::instance().reset_dpi ();
446 TimeAxisViewItem::set_constant_heights ();
448 /* Set this up so that our window proxies can register actions */
450 ActionManager::init ();
452 /* The following must happen after ARDOUR::init() so that Config is set up */
454 const XMLNode* ui_xml = Config->extra_xml (X_("UI"));
457 key_editor.set_state (*ui_xml, 0);
458 session_option_editor.set_state (*ui_xml, 0);
459 speaker_config_window.set_state (*ui_xml, 0);
460 about.set_state (*ui_xml, 0);
461 add_route_dialog.set_state (*ui_xml, 0);
462 add_video_dialog.set_state (*ui_xml, 0);
463 route_params.set_state (*ui_xml, 0);
464 bundle_manager.set_state (*ui_xml, 0);
465 location_ui.set_state (*ui_xml, 0);
466 big_clock_window.set_state (*ui_xml, 0);
467 audio_port_matrix.set_state (*ui_xml, 0);
468 midi_port_matrix.set_state (*ui_xml, 0);
469 export_video_dialog.set_state (*ui_xml, 0);
470 lua_script_window.set_state (*ui_xml, 0);
473 /* Separate windows */
475 WM::Manager::instance().register_window (&key_editor);
476 WM::Manager::instance().register_window (&session_option_editor);
477 WM::Manager::instance().register_window (&speaker_config_window);
478 WM::Manager::instance().register_window (&about);
479 WM::Manager::instance().register_window (&add_route_dialog);
480 WM::Manager::instance().register_window (&add_video_dialog);
481 WM::Manager::instance().register_window (&route_params);
482 WM::Manager::instance().register_window (&audio_midi_setup);
483 WM::Manager::instance().register_window (&export_video_dialog);
484 WM::Manager::instance().register_window (&lua_script_window);
485 WM::Manager::instance().register_window (&bundle_manager);
486 WM::Manager::instance().register_window (&location_ui);
487 WM::Manager::instance().register_window (&big_clock_window);
488 WM::Manager::instance().register_window (&audio_port_matrix);
489 WM::Manager::instance().register_window (&midi_port_matrix);
491 /* do not retain position for add route dialog */
492 add_route_dialog.set_state_mask (WindowProxy::Size);
494 _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 ()
4008 if (!add_route_dialog.get (false)) {
4009 add_route_dialog->signal_response().connect (sigc::mem_fun (*this, &ARDOUR_UI::add_route_dialog_finished));
4016 if (add_route_dialog->is_visible()) {
4017 /* we're already doing this */
4021 add_route_dialog->set_position (WIN_POS_MOUSE);
4022 add_route_dialog->present();
4026 ARDOUR_UI::add_route_dialog_finished (int r)
4030 add_route_dialog->hide();
4033 case RESPONSE_ACCEPT:
4040 if ((count = add_route_dialog->count()) <= 0) {
4044 PresentationInfo::order_t order = translate_order (add_route_dialog->insert_at());
4045 string template_path = add_route_dialog->track_template();
4046 DisplaySuspender ds;
4048 if (!template_path.empty()) {
4049 if (add_route_dialog->name_template_is_default()) {
4050 _session->new_route_from_template (count, template_path, string());
4052 _session->new_route_from_template (count, template_path, add_route_dialog->name_template());
4057 ChanCount input_chan= add_route_dialog->channels ();
4058 ChanCount output_chan;
4059 string name_template = add_route_dialog->name_template ();
4060 PluginInfoPtr instrument = add_route_dialog->requested_instrument ();
4061 RouteGroup* route_group = add_route_dialog->route_group ();
4062 AutoConnectOption oac = Config->get_output_auto_connect();
4063 bool strict_io = add_route_dialog->use_strict_io ();
4065 if (oac & AutoConnectMaster) {
4066 output_chan.set (DataType::AUDIO, (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan.n_audio()));
4067 output_chan.set (DataType::MIDI, 0);
4069 output_chan = input_chan;
4072 /* XXX do something with name template */
4074 switch (add_route_dialog->type_wanted()) {
4075 case AddRouteDialog::AudioTrack:
4076 session_add_audio_track (input_chan.n_audio(), output_chan.n_audio(), add_route_dialog->mode(), route_group, count, name_template, strict_io, order);
4078 case AddRouteDialog::MidiTrack:
4079 session_add_midi_track (route_group, count, name_template, strict_io, instrument, 0, order);
4081 case AddRouteDialog::MixedTrack:
4082 session_add_mixed_track (input_chan, output_chan, route_group, count, name_template, strict_io, instrument, 0, order);
4084 case AddRouteDialog::AudioBus:
4085 session_add_audio_bus (input_chan.n_audio(), output_chan.n_audio(), route_group, count, name_template, strict_io, order);
4087 case AddRouteDialog::MidiBus:
4088 session_add_midi_bus (route_group, count, name_template, strict_io, instrument, 0, order);
4090 case AddRouteDialog::VCAMaster:
4091 session_add_vca (name_template, count);
4097 ARDOUR_UI::add_lua_script ()
4103 LuaScriptInfoPtr spi;
4104 ScriptSelector ss ("Add Lua Session Script", LuaScriptInfo::Session);
4105 switch (ss.run ()) {
4106 case Gtk::RESPONSE_ACCEPT:
4114 std::string script = "";
4117 script = Glib::file_get_contents (spi->path);
4118 } catch (Glib::FileError e) {
4119 string msg = string_compose (_("Cannot read session script '%1': %2"), spi->path, e.what());
4120 MessageDialog am (msg);
4125 LuaScriptParamList lsp = LuaScriptParams::script_params (spi, "sess_params");
4126 std::vector<std::string> reg = _session->registered_lua_functions ();
4128 ScriptParameterDialog spd (_("Set Script Parameters"), spi, reg, lsp);
4129 switch (spd.run ()) {
4130 case Gtk::RESPONSE_ACCEPT:
4137 _session->register_lua_function (spd.name(), script, lsp);
4138 } catch (luabridge::LuaException const& e) {
4139 string msg = string_compose (_("Session script '%1' instantiation failed: %2"), spd.name(), e.what ());
4140 MessageDialog am (msg);
4142 } catch (SessionException e) {
4143 string msg = string_compose (_("Loading Session script '%1' failed: %2"), spd.name(), e.what ());
4144 MessageDialog am (msg);
4150 ARDOUR_UI::remove_lua_script ()
4155 if (_session->registered_lua_function_count () == 0) {
4156 string msg = _("There are no active Lua session scripts present in this session.");
4157 MessageDialog am (msg);
4162 std::vector<std::string> reg = _session->registered_lua_functions ();
4163 SessionScriptManager sm ("Remove Lua Session Script", reg);
4164 switch (sm.run ()) {
4165 case Gtk::RESPONSE_ACCEPT:
4171 _session->unregister_lua_function (sm.name());
4172 } catch (luabridge::LuaException const& e) {
4173 string msg = string_compose (_("Session script '%1' removal failed: %2"), sm.name(), e.what ());
4174 MessageDialog am (msg);
4180 ARDOUR_UI::stop_video_server (bool ask_confirm)
4182 if (!video_server_process && ask_confirm) {
4183 warning << string_compose (_("Video-Server was not launched by %1. The request to stop it is ignored."), PROGRAM_NAME) << endmsg;
4185 if (video_server_process) {
4187 ArdourDialog confirm (_("Stop Video-Server"), true);
4188 Label m (_("Do you really want to stop the Video Server?"));
4189 confirm.get_vbox()->pack_start (m, true, true);
4190 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
4191 confirm.add_button (_("Yes, Stop It"), Gtk::RESPONSE_ACCEPT);
4192 confirm.show_all ();
4193 if (confirm.run() == RESPONSE_CANCEL) {
4197 delete video_server_process;
4198 video_server_process =0;
4203 ARDOUR_UI::start_video_server_menu (Gtk::Window* float_window)
4205 ARDOUR_UI::start_video_server( float_window, true);
4209 ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg)
4215 if (ARDOUR_UI::instance()->video_timeline->check_server()) {
4216 if (video_server_process) {
4217 popup_error(_("The Video Server is already started."));
4219 popup_error(_("An external Video Server is configured and can be reached. Not starting a new instance."));
4225 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4227 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4229 VideoServerDialog *video_server_dialog = new VideoServerDialog (_session);
4231 video_server_dialog->set_transient_for (*float_window);
4234 if (!Config->get_show_video_server_dialog() && firsttime < 2) {
4235 video_server_dialog->hide();
4237 ResponseType r = (ResponseType) video_server_dialog->run ();
4238 video_server_dialog->hide();
4239 if (r != RESPONSE_ACCEPT) { return false; }
4240 if (video_server_dialog->show_again()) {
4241 Config->set_show_video_server_dialog(false);
4245 std::string icsd_exec = video_server_dialog->get_exec_path();
4246 std::string icsd_docroot = video_server_dialog->get_docroot();
4247 if (icsd_docroot.empty()) {
4248 #ifndef PLATFORM_WINDOWS
4249 icsd_docroot = X_("/");
4251 icsd_docroot = X_("C:\\");
4256 if (g_lstat (icsd_docroot.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode)) {
4257 warning << _("Specified docroot is not an existing directory.") << endmsg;
4260 #ifndef PLATFORM_WINDOWS
4261 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4262 || (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0 ) {
4263 warning << _("Given Video Server is not an executable file.") << endmsg;
4267 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4268 || (sb.st_mode & (S_IXUSR)) == 0 ) {
4269 warning << _("Given Video Server is not an executable file.") << endmsg;
4275 argp=(char**) calloc(9,sizeof(char*));
4276 argp[0] = strdup(icsd_exec.c_str());
4277 argp[1] = strdup("-P");
4278 argp[2] = (char*) calloc(16,sizeof(char)); snprintf(argp[2], 16, "%s", video_server_dialog->get_listenaddr().c_str());
4279 argp[3] = strdup("-p");
4280 argp[4] = (char*) calloc(6,sizeof(char)); snprintf(argp[4], 6, "%i", video_server_dialog->get_listenport());
4281 argp[5] = strdup("-C");
4282 argp[6] = (char*) calloc(6,sizeof(char)); snprintf(argp[6], 6, "%i", video_server_dialog->get_cachesize());
4283 argp[7] = strdup(icsd_docroot.c_str());
4285 stop_video_server();
4287 if (icsd_docroot == X_("/") || icsd_docroot == X_("C:\\")) {
4288 Config->set_video_advanced_setup(false);
4290 std::ostringstream osstream;
4291 osstream << "http://127.0.0.1:" << video_server_dialog->get_listenport() << "/";
4292 Config->set_video_server_url(osstream.str());
4293 Config->set_video_server_docroot(icsd_docroot);
4294 Config->set_video_advanced_setup(true);
4297 if (video_server_process) {
4298 delete video_server_process;
4301 video_server_process = new ARDOUR::SystemExec(icsd_exec, argp);
4302 if (video_server_process->start()) {
4303 warning << _("Cannot launch the video-server") << endmsg;
4306 int timeout = 120; // 6 sec
4307 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4308 Glib::usleep (50000);
4310 if (--timeout <= 0 || !video_server_process->is_running()) break;
4313 warning << _("Video-server was started but does not respond to requests...") << endmsg;
4315 if (!ARDOUR_UI::instance()->video_timeline->check_server_docroot()) {
4316 delete video_server_process;
4317 video_server_process = 0;
4325 ARDOUR_UI::add_video (Gtk::Window* float_window)
4331 if (!start_video_server(float_window, false)) {
4332 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4337 add_video_dialog->set_transient_for (*float_window);
4340 if (add_video_dialog->is_visible()) {
4341 /* we're already doing this */
4345 ResponseType r = (ResponseType) add_video_dialog->run ();
4346 add_video_dialog->hide();
4347 if (r != RESPONSE_ACCEPT) { return; }
4349 bool local_file, orig_local_file;
4350 std::string path = add_video_dialog->file_name(local_file);
4352 std::string orig_path = path;
4353 orig_local_file = local_file;
4355 bool auto_set_session_fps = add_video_dialog->auto_set_session_fps();
4357 if (local_file && !Glib::file_test(path, Glib::FILE_TEST_EXISTS)) {
4358 warning << string_compose(_("could not open %1"), path) << endmsg;
4361 if (!local_file && path.length() == 0) {
4362 warning << _("no video-file selected") << endmsg;
4366 std::string audio_from_video;
4367 bool detect_ltc = false;
4369 switch (add_video_dialog->import_option()) {
4370 case VTL_IMPORT_TRANSCODE:
4372 TranscodeVideoDialog *transcode_video_dialog;
4373 transcode_video_dialog = new TranscodeVideoDialog (_session, path);
4374 ResponseType r = (ResponseType) transcode_video_dialog->run ();
4375 transcode_video_dialog->hide();
4376 if (r != RESPONSE_ACCEPT) {
4377 delete transcode_video_dialog;
4381 audio_from_video = transcode_video_dialog->get_audiofile();
4383 if (!audio_from_video.empty() && transcode_video_dialog->detect_ltc()) {
4386 else if (!audio_from_video.empty()) {
4387 editor->embed_audio_from_video(
4389 video_timeline->get_offset(),
4390 (transcode_video_dialog->import_option() != VTL_IMPORT_NO_VIDEO)
4393 switch (transcode_video_dialog->import_option()) {
4394 case VTL_IMPORT_TRANSCODED:
4395 path = transcode_video_dialog->get_filename();
4398 case VTL_IMPORT_REFERENCE:
4401 delete transcode_video_dialog;
4404 delete transcode_video_dialog;
4408 case VTL_IMPORT_NONE:
4412 /* strip _session->session_directory().video_path() from video file if possible */
4413 if (local_file && !path.compare(0, _session->session_directory().video_path().size(), _session->session_directory().video_path())) {
4414 path=path.substr(_session->session_directory().video_path().size());
4415 if (path.at(0) == G_DIR_SEPARATOR) {
4416 path=path.substr(1);
4420 video_timeline->set_update_session_fps(auto_set_session_fps);
4422 if (video_timeline->video_file_info(path, local_file)) {
4423 XMLNode* node = new XMLNode(X_("Videotimeline"));
4424 node->add_property (X_("Filename"), path);
4425 node->add_property (X_("AutoFPS"), auto_set_session_fps?X_("1"):X_("0"));
4426 node->add_property (X_("LocalFile"), local_file?X_("1"):X_("0"));
4427 if (orig_local_file) {
4428 node->add_property (X_("OriginalVideoFile"), orig_path);
4430 node->remove_property (X_("OriginalVideoFile"));
4432 _session->add_extra_xml (*node);
4433 _session->set_dirty ();
4435 if (!audio_from_video.empty() && detect_ltc) {
4436 std::vector<LTCFileReader::LTCMap> ltc_seq;
4439 /* TODO ask user about TV standard (LTC alignment if any) */
4440 LTCFileReader ltcr (audio_from_video, video_timeline->get_video_file_fps());
4441 /* TODO ASK user which channel: 0 .. ltcr->channels() - 1 */
4443 ltc_seq = ltcr.read_ltc (/*channel*/ 0, /*max LTC frames to decode*/ 15);
4445 /* TODO seek near end of file, and read LTC until end.
4446 * if it fails to find any LTC frames, scan complete file
4448 * calculate drift of LTC compared to video-duration,
4449 * ask user for reference (timecode from start/mid/end)
4452 // LTCFileReader will have written error messages
4455 ::g_unlink(audio_from_video.c_str());
4457 if (ltc_seq.size() == 0) {
4458 PBD::error << _("No LTC detected, video will not be aligned.") << endmsg;
4460 /* the very first TC in the file is somteimes not aligned properly */
4461 int i = ltc_seq.size() -1;
4462 ARDOUR::frameoffset_t video_start_offset =
4463 _session->nominal_frame_rate() * (ltc_seq[i].timecode_sec - ltc_seq[i].framepos_sec);
4464 PBD::info << string_compose (_("Align video-start to %1 [samples]"), video_start_offset) << endmsg;
4465 video_timeline->set_offset(video_start_offset);
4469 _session->maybe_update_session_range(
4470 std::max(video_timeline->get_offset(), (ARDOUR::frameoffset_t) 0),
4471 std::max(video_timeline->get_offset() + video_timeline->get_duration(), (ARDOUR::frameoffset_t) 0));
4474 if (add_video_dialog->launch_xjadeo() && local_file) {
4475 editor->set_xjadeo_sensitive(true);
4476 editor->toggle_xjadeo_proc(1);
4478 editor->toggle_xjadeo_proc(0);
4480 editor->toggle_ruler_video(true);
4485 ARDOUR_UI::remove_video ()
4487 video_timeline->close_session();
4488 editor->toggle_ruler_video(false);
4491 video_timeline->set_offset_locked(false);
4492 video_timeline->set_offset(0);
4494 /* delete session state */
4495 XMLNode* node = new XMLNode(X_("Videotimeline"));
4496 _session->add_extra_xml(*node);
4497 node = new XMLNode(X_("Videomonitor"));
4498 _session->add_extra_xml(*node);
4499 node = new XMLNode(X_("Videoexport"));
4500 _session->add_extra_xml(*node);
4501 stop_video_server();
4505 ARDOUR_UI::flush_videotimeline_cache (bool localcacheonly)
4507 if (localcacheonly) {
4508 video_timeline->vmon_update();
4510 video_timeline->flush_cache();
4512 editor->queue_visual_videotimeline_update();
4516 ARDOUR_UI::export_video (bool range)
4518 if (ARDOUR::Config->get_show_video_export_info()) {
4519 ExportVideoInfobox infobox (_session);
4520 Gtk::ResponseType rv = (Gtk::ResponseType) infobox.run();
4521 if (infobox.show_again()) {
4522 ARDOUR::Config->set_show_video_export_info(false);
4525 case GTK_RESPONSE_YES:
4526 PBD::open_uri (ARDOUR::Config->get_reference_manual_url() + "/video-timeline/operations/#export");
4532 export_video_dialog->set_session (_session);
4533 export_video_dialog->apply_state(editor->get_selection().time, range);
4534 export_video_dialog->run ();
4535 export_video_dialog->hide ();
4539 ARDOUR_UI::mixer_settings () const
4544 node = _session->instant_xml(X_("Mixer"));
4546 node = Config->instant_xml(X_("Mixer"));
4550 node = new XMLNode (X_("Mixer"));
4557 ARDOUR_UI::main_window_settings () const
4562 node = _session->instant_xml(X_("Main"));
4564 node = Config->instant_xml(X_("Main"));
4568 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4569 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4574 node = new XMLNode (X_("Main"));
4581 ARDOUR_UI::editor_settings () const
4586 node = _session->instant_xml(X_("Editor"));
4588 node = Config->instant_xml(X_("Editor"));
4592 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4593 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4598 node = new XMLNode (X_("Editor"));
4605 ARDOUR_UI::keyboard_settings () const
4609 node = Config->extra_xml(X_("Keyboard"));
4612 node = new XMLNode (X_("Keyboard"));
4619 ARDOUR_UI::create_xrun_marker (framepos_t where)
4622 Location *location = new Location (*_session, where, where, _("xrun"), Location::IsMark);
4623 _session->locations()->add (location);
4628 ARDOUR_UI::halt_on_xrun_message ()
4630 cerr << "HALT on xrun\n";
4631 MessageDialog msg (_main_window, _("Recording was stopped because your system could not keep up."));
4636 ARDOUR_UI::xrun_handler (framepos_t where)
4642 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
4644 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
4645 create_xrun_marker(where);
4648 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
4649 halt_on_xrun_message ();
4654 ARDOUR_UI::disk_overrun_handler ()
4656 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
4658 if (!have_disk_speed_dialog_displayed) {
4659 have_disk_speed_dialog_displayed = true;
4660 MessageDialog* msg = new MessageDialog (_main_window, string_compose (_("\
4661 The disk system on your computer\n\
4662 was not able to keep up with %1.\n\
4664 Specifically, it failed to write data to disk\n\
4665 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
4666 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4672 /* TODO: this is getting elaborate enough to warrant being split into a dedicated class */
4673 static MessageDialog *scan_dlg = NULL;
4674 static ProgressBar *scan_pbar = NULL;
4675 static HBox *scan_tbox = NULL;
4676 static Gtk::Button *scan_timeout_button;
4679 ARDOUR_UI::cancel_plugin_scan ()
4681 PluginManager::instance().cancel_plugin_scan();
4685 ARDOUR_UI::cancel_plugin_timeout ()
4687 PluginManager::instance().cancel_plugin_timeout();
4688 scan_timeout_button->set_sensitive (false);
4692 ARDOUR_UI::plugin_scan_timeout (int timeout)
4694 if (!scan_dlg || !scan_dlg->is_mapped() || !scan_pbar) {
4698 scan_pbar->set_sensitive (false);
4699 scan_timeout_button->set_sensitive (true);
4700 scan_pbar->set_fraction ((float) timeout / (float) Config->get_vst_scan_timeout());
4703 scan_pbar->set_sensitive (false);
4704 scan_timeout_button->set_sensitive (false);
4710 ARDOUR_UI::plugin_scan_dialog (std::string type, std::string plugin, bool can_cancel)
4712 if (type == X_("closeme") && !(scan_dlg && scan_dlg->is_mapped())) {
4716 const bool cancelled = PluginManager::instance().cancelled();
4717 if (type != X_("closeme") && (!UIConfiguration::instance().get_show_plugin_scan_window()) && !_initial_verbose_plugin_scan) {
4718 if (cancelled && scan_dlg->is_mapped()) {
4723 if (cancelled || !can_cancel) {
4728 static Gtk::Button *cancel_button;
4730 scan_dlg = new MessageDialog("", false, MESSAGE_INFO, BUTTONS_NONE); // TODO manage
4731 VBox* vbox = scan_dlg->get_vbox();
4732 vbox->set_size_request(400,-1);
4733 scan_dlg->set_title (_("Scanning for plugins"));
4735 cancel_button = manage(new Gtk::Button(_("Cancel plugin scan")));
4736 cancel_button->set_name ("EditorGTKButton");
4737 cancel_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_scan) );
4738 cancel_button->show();
4740 scan_dlg->get_vbox()->pack_start ( *cancel_button, PACK_SHRINK);
4742 scan_tbox = manage( new HBox() );
4744 scan_timeout_button = manage(new Gtk::Button(_("Stop Timeout")));
4745 scan_timeout_button->set_name ("EditorGTKButton");
4746 scan_timeout_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_timeout) );
4747 scan_timeout_button->show();
4749 scan_pbar = manage(new ProgressBar());
4750 scan_pbar->set_orientation(Gtk::PROGRESS_RIGHT_TO_LEFT);
4751 scan_pbar->set_text(_("Scan Timeout"));
4754 scan_tbox->pack_start (*scan_pbar, PACK_EXPAND_WIDGET, 4);
4755 scan_tbox->pack_start (*scan_timeout_button, PACK_SHRINK, 4);
4757 scan_dlg->get_vbox()->pack_start (*scan_tbox, PACK_SHRINK, 4);
4760 assert(scan_dlg && scan_tbox && cancel_button);
4762 if (type == X_("closeme")) {
4766 scan_dlg->set_message(type + ": " + Glib::path_get_basename(plugin));
4769 if (!can_cancel || !cancelled) {
4770 scan_timeout_button->set_sensitive(false);
4772 cancel_button->set_sensitive(can_cancel && !cancelled);
4778 ARDOUR_UI::gui_idle_handler ()
4781 /* due to idle calls, gtk_events_pending() may always return true */
4782 while (gtk_events_pending() && --timeout) {
4783 gtk_main_iteration ();
4788 ARDOUR_UI::disk_underrun_handler ()
4790 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
4792 if (!have_disk_speed_dialog_displayed) {
4793 have_disk_speed_dialog_displayed = true;
4794 MessageDialog* msg = new MessageDialog (
4795 _main_window, string_compose (_("The disk system on your computer\n\
4796 was not able to keep up with %1.\n\
4798 Specifically, it failed to read data from disk\n\
4799 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
4800 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4806 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
4808 have_disk_speed_dialog_displayed = false;
4813 ARDOUR_UI::session_dialog (std::string msg)
4815 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
4819 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
4826 ARDOUR_UI::pending_state_dialog ()
4828 HBox* hbox = manage (new HBox());
4829 Image* image = manage (new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG));
4830 ArdourDialog dialog (_("Crash Recovery"), true);
4831 Label message (string_compose (_("\
4832 This session appears to have been in the\n\
4833 middle of recording when %1 or\n\
4834 the computer was shutdown.\n\
4836 %1 can recover any captured audio for\n\
4837 you, or it can ignore it. Please decide\n\
4838 what you would like to do.\n"), PROGRAM_NAME));
4839 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4840 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4841 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4842 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4843 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
4844 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
4845 dialog.set_default_response (RESPONSE_ACCEPT);
4846 dialog.set_position (WIN_POS_CENTER);
4851 switch (dialog.run ()) {
4852 case RESPONSE_ACCEPT:
4860 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
4862 HBox* hbox = new HBox();
4863 Image* image = new Image (Stock::DIALOG_WARNING, ICON_SIZE_DIALOG);
4864 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
4865 Label message (string_compose (_("\
4866 This session was created with a sample rate of %1 Hz, but\n\
4867 %2 is currently running at %3 Hz. If you load this session,\n\
4868 audio may be played at the wrong sample rate.\n"), desired, PROGRAM_NAME, actual));
4870 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4871 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4872 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4873 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4874 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
4875 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
4876 dialog.set_default_response (RESPONSE_ACCEPT);
4877 dialog.set_position (WIN_POS_CENTER);
4882 switch (dialog.run()) {
4883 case RESPONSE_ACCEPT:
4893 ARDOUR_UI::sr_mismatch_message (framecnt_t desired, framecnt_t actual)
4895 MessageDialog msg (string_compose (_("\
4896 This session was created with a sample rate of %1 Hz, but\n\
4897 %2 is currently running at %3 Hz.\n\
4898 Audio will be recorded and played at the wrong sample rate.\n\
4899 Re-Configure the Audio Engine in\n\
4900 Menu > Window > Audio/Midi Setup"),
4901 desired, PROGRAM_NAME, actual),
4903 Gtk::MESSAGE_WARNING);
4908 ARDOUR_UI::use_config ()
4910 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
4912 set_transport_controllable_state (*node);
4917 ARDOUR_UI::update_transport_clocks (framepos_t pos)
4919 if (UIConfiguration::instance().get_primary_clock_delta_edit_cursor()) {
4920 primary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
4922 primary_clock->set (pos);
4925 if (UIConfiguration::instance().get_secondary_clock_delta_edit_cursor()) {
4926 secondary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
4928 secondary_clock->set (pos);
4931 if (big_clock_window) {
4932 big_clock->set (pos);
4934 ARDOUR_UI::instance()->video_timeline->manual_seek_video_monitor(pos);
4938 ARDOUR_UI::step_edit_status_change (bool yn)
4940 // XXX should really store pre-step edit status of things
4941 // we make insensitive
4944 rec_button.set_active_state (Gtkmm2ext::ImplicitActive);
4945 rec_button.set_sensitive (false);
4947 rec_button.unset_active_state ();;
4948 rec_button.set_sensitive (true);
4953 ARDOUR_UI::record_state_changed ()
4955 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
4957 if (!_session || !big_clock_window) {
4958 /* why bother - the clock isn't visible */
4962 if (_session->record_status () == Session::Recording && _session->have_rec_enabled_track ()) {
4963 big_clock->set_active (true);
4965 big_clock->set_active (false);
4970 ARDOUR_UI::first_idle ()
4973 _session->allow_auto_play (true);
4977 editor->first_idle();
4980 Keyboard::set_can_save_keybindings (true);
4985 ARDOUR_UI::store_clock_modes ()
4987 XMLNode* node = new XMLNode(X_("ClockModes"));
4989 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
4990 XMLNode* child = new XMLNode (X_("Clock"));
4992 child->add_property (X_("name"), (*x)->name());
4993 child->add_property (X_("mode"), enum_2_string ((*x)->mode()));
4994 child->add_property (X_("on"), ((*x)->off() ? X_("no") : X_("yes")));
4996 node->add_child_nocopy (*child);
4999 _session->add_extra_xml (*node);
5000 _session->set_dirty ();
5003 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
5004 : Controllable (name), ui (u), type(tp)
5010 ARDOUR_UI::TransportControllable::set_value (double val, PBD::Controllable::GroupControlDisposition /*group_override*/)
5013 /* do nothing: these are radio-style actions */
5017 const char *action = 0;
5021 action = X_("Roll");
5024 action = X_("Stop");
5027 action = X_("GotoStart");
5030 action = X_("GotoEnd");
5033 action = X_("Loop");
5036 action = X_("PlaySelection");
5039 action = X_("Record");
5049 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
5057 ARDOUR_UI::TransportControllable::get_value (void) const
5084 ARDOUR_UI::setup_profile ()
5086 if (gdk_screen_width() < 1200 || getenv ("ARDOUR_NARROW_SCREEN")) {
5087 Profile->set_small_screen ();
5090 if (g_getenv ("TRX")) {
5091 Profile->set_trx ();
5094 if (g_getenv ("MIXBUS")) {
5095 Profile->set_mixbus ();
5100 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
5102 MissingFileDialog dialog (s, str, type);
5107 int result = dialog.run ();
5114 return 1; // quit entire session load
5117 result = dialog.get_action ();
5123 ARDOUR_UI::ambiguous_file (std::string file, std::vector<std::string> hits)
5125 AmbiguousFileDialog dialog (file, hits);
5132 return dialog.get_which ();
5135 /** Allocate our thread-local buffers */
5137 ARDOUR_UI::get_process_buffers ()
5139 _process_thread->get_buffers ();
5142 /** Drop our thread-local buffers */
5144 ARDOUR_UI::drop_process_buffers ()
5146 _process_thread->drop_buffers ();
5150 ARDOUR_UI::feedback_detected ()
5152 _feedback_exists = true;
5156 ARDOUR_UI::successful_graph_sort ()
5158 _feedback_exists = false;
5162 ARDOUR_UI::midi_panic ()
5165 _session->midi_panic();
5170 ARDOUR_UI::session_format_mismatch (std::string xml_path, std::string backup_path)
5172 const char* start_big = "<span size=\"x-large\" weight=\"bold\">";
5173 const char* end_big = "</span>";
5174 const char* start_mono = "<tt>";
5175 const char* end_mono = "</tt>";
5177 MessageDialog msg (string_compose (_("%4This is a session from an older version of %3%5\n\n"
5178 "%3 has copied the old session file\n\n%6%1%7\n\nto\n\n%6%2%7\n\n"
5179 "From now on, use the backup copy with older versions of %3"),
5180 xml_path, backup_path, PROGRAM_NAME,
5182 start_mono, end_mono), true);
5189 ARDOUR_UI::reset_peak_display ()
5191 if (!_session || !_session->master_out() || !editor_meter) return;
5192 editor_meter->clear_meters();
5193 editor_meter_max_peak = -INFINITY;
5194 editor_meter_peak_display.set_active_state ( Gtkmm2ext::Off );
5198 ARDOUR_UI::reset_group_peak_display (RouteGroup* group)
5200 if (!_session || !_session->master_out()) return;
5201 if (group == _session->master_out()->route_group()) {
5202 reset_peak_display ();
5207 ARDOUR_UI::reset_route_peak_display (Route* route)
5209 if (!_session || !_session->master_out()) return;
5210 if (_session->master_out().get() == route) {
5211 reset_peak_display ();
5216 ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate)
5218 audio_midi_setup->set_desired_sample_rate (desired_sample_rate);
5219 audio_midi_setup->set_position (WIN_POS_CENTER);
5221 if (Config->get_try_autostart_engine () || getenv ("TRY_AUTOSTART_ENGINE")) {
5222 audio_midi_setup->try_autostart ();
5223 if (ARDOUR::AudioEngine::instance()->running()) {
5229 int response = audio_midi_setup->run();
5231 case Gtk::RESPONSE_OK:
5232 if (!AudioEngine::instance()->running()) {
5246 ARDOUR_UI::transport_numpad_timeout ()
5248 _numpad_locate_happening = false;
5249 if (_numpad_timeout_connection.connected() )
5250 _numpad_timeout_connection.disconnect();
5255 ARDOUR_UI::transport_numpad_decimal ()
5257 _numpad_timeout_connection.disconnect();
5259 if (_numpad_locate_happening) {
5260 if (editor) editor->goto_nth_marker(_pending_locate_num - 1);
5261 _numpad_locate_happening = false;
5263 _pending_locate_num = 0;
5264 _numpad_locate_happening = true;
5265 _numpad_timeout_connection = Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::transport_numpad_timeout), 2*1000);
5270 ARDOUR_UI::transport_numpad_event (int num)
5272 if ( _numpad_locate_happening ) {
5273 _pending_locate_num = _pending_locate_num*10 + num;
5276 case 0: toggle_roll(false, false); break;
5277 case 1: transport_rewind(1); break;
5278 case 2: transport_forward(1); break;
5279 case 3: transport_record(true); break;
5280 case 4: toggle_session_auto_loop(); break;
5281 case 5: transport_record(false); toggle_session_auto_loop(); break;
5282 case 6: toggle_punch(); break;
5283 case 7: toggle_click(); break;
5284 case 8: toggle_auto_return(); break;
5285 case 9: toggle_follow_edits(); break;
5291 ARDOUR_UI::set_flat_buttons ()
5293 CairoWidget::set_flat_buttons( UIConfiguration::instance().get_flat_buttons() );
5297 ARDOUR_UI::audioengine_became_silent ()
5299 MessageDialog msg (string_compose (_("This is a free/demo copy of %1. It has just switched to silent mode."), PROGRAM_NAME),
5301 Gtk::MESSAGE_WARNING,
5305 msg.set_title (string_compose (_("%1 is now silent"), PROGRAM_NAME));
5307 Gtk::Label pay_label (string_compose (_("Please consider paying for a copy of %1 - you can pay whatever you want."), PROGRAM_NAME));
5308 Gtk::Label subscribe_label (_("Better yet become a subscriber - subscriptions start at US$1 per month."));
5309 Gtk::Button pay_button (_("Pay for a copy (via the web)"));
5310 Gtk::Button subscribe_button (_("Become a subscriber (via the web)"));
5311 Gtk::HBox pay_button_box;
5312 Gtk::HBox subscribe_button_box;
5314 pay_button_box.pack_start (pay_button, true, false);
5315 subscribe_button_box.pack_start (subscribe_button, true, false);
5317 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 */
5319 pay_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://ardour.org/download")));
5320 subscribe_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://community.ardour.org/s/subscribe")));
5322 msg.get_vbox()->pack_start (pay_label);
5323 msg.get_vbox()->pack_start (pay_button_box);
5324 msg.get_vbox()->pack_start (subscribe_label);
5325 msg.get_vbox()->pack_start (subscribe_button_box);
5327 msg.get_vbox()->show_all ();
5329 msg.add_button (_("Remain silent"), Gtk::RESPONSE_CANCEL);
5330 msg.add_button (_("Save and quit"), Gtk::RESPONSE_NO);
5331 msg.add_button (_("Give me more time"), Gtk::RESPONSE_YES);
5336 case Gtk::RESPONSE_YES:
5337 AudioEngine::instance()->reset_silence_countdown ();
5340 case Gtk::RESPONSE_NO:
5342 save_state_canfail ("");
5346 case Gtk::RESPONSE_CANCEL:
5348 /* don't reset, save session and exit */
5354 ARDOUR_UI::hide_application ()
5356 Application::instance ()-> hide ();
5360 ARDOUR_UI::setup_toplevel_window (Gtk::Window& window, const string& name, void* owner)
5362 /* icons, titles, WM stuff */
5364 static list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
5366 if (window_icons.empty()) {
5367 Glib::RefPtr<Gdk::Pixbuf> icon;
5368 if ((icon = ::get_icon (PROGRAM_NAME "-icon_16px")) != 0) {
5369 window_icons.push_back (icon);
5371 if ((icon = ::get_icon (PROGRAM_NAME "-icon_22px")) != 0) {
5372 window_icons.push_back (icon);
5374 if ((icon = ::get_icon (PROGRAM_NAME "-icon_32px")) != 0) {
5375 window_icons.push_back (icon);
5377 if ((icon = ::get_icon (PROGRAM_NAME "-icon_48px")) != 0) {
5378 window_icons.push_back (icon);
5382 if (!window_icons.empty()) {
5383 window.set_default_icon_list (window_icons);
5386 Gtkmm2ext::WindowTitle title (Glib::get_application_name());
5388 if (!name.empty()) {
5392 window.set_title (title.get_string());
5393 window.set_wmclass (string_compose (X_("%1_%1"), downcase (PROGRAM_NAME), downcase (name)), PROGRAM_NAME);
5395 window.set_flags (CAN_FOCUS);
5396 window.add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
5398 /* This is a hack to ensure that GTK-accelerators continue to
5399 * work. Once we switch over to entirely native bindings, this will be
5400 * unnecessary and should be removed
5402 window.add_accel_group (ActionManager::ui_manager->get_accel_group());
5404 window.signal_configure_event().connect (sigc::mem_fun (*this, &ARDOUR_UI::configure_handler));
5405 window.signal_window_state_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::tabbed_window_state_event_handler), owner));
5406 window.signal_key_press_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5407 window.signal_key_release_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5411 ARDOUR_UI::key_event_handler (GdkEventKey* ev, Gtk::Window* event_window)
5413 Gtkmm2ext::Bindings* bindings = 0;
5414 Gtk::Window* window = 0;
5416 /* until we get ardour bindings working, we are not handling key
5420 if (ev->type != GDK_KEY_PRESS) {
5424 if (event_window == &_main_window) {
5426 window = event_window;
5428 /* find current tab contents */
5430 Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page());
5432 /* see if it uses the ardour binding system */
5435 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(w->get_data ("ardour-bindings"));
5438 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("main window key event, bindings = %1, global = %2\n", bindings, &global_bindings));
5442 window = event_window;
5444 /* see if window uses ardour binding system */
5446 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(window->get_data ("ardour-bindings"));
5449 /* An empty binding set is treated as if it doesn't exist */
5451 if (bindings && bindings->empty()) {
5455 return key_press_focus_accelerator_handler (*window, ev, bindings);
5458 static Gtkmm2ext::Bindings*
5459 get_bindings_from_widget_heirarchy (GtkWidget* w)
5464 if ((p = g_object_get_data (G_OBJECT(w), "ardour-bindings")) != 0) {
5467 w = gtk_widget_get_parent (w);
5470 return reinterpret_cast<Gtkmm2ext::Bindings*> (p);
5474 ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev, Gtkmm2ext::Bindings* bindings)
5476 GtkWindow* win = window.gobj();
5477 GtkWidget* focus = gtk_window_get_focus (win);
5478 bool special_handling_of_unmodified_accelerators = false;
5479 const guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK));
5483 /* some widget has keyboard focus */
5485 if (GTK_IS_ENTRY(focus) || Keyboard::some_magic_widget_has_focus()) {
5487 /* A particular kind of focusable widget currently has keyboard
5488 * focus. All unmodified key events should go to that widget
5489 * first and not be used as an accelerator by default
5492 special_handling_of_unmodified_accelerators = true;
5496 Gtkmm2ext::Bindings* focus_bindings = get_bindings_from_widget_heirarchy (focus);
5497 if (focus_bindings) {
5498 bindings = focus_bindings;
5499 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Switch bindings based on focus widget, now using %1\n", bindings->name()));
5504 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",
5507 show_gdk_event_state (ev->state),
5508 special_handling_of_unmodified_accelerators,
5509 Keyboard::some_magic_widget_has_focus(),
5511 (focus ? gtk_widget_get_name (focus) : "no focus widget"),
5512 ((ev->state & mask) ? "yes" : "no"),
5513 window.get_title()));
5515 /* This exists to allow us to override the way GTK handles
5516 key events. The normal sequence is:
5518 a) event is delivered to a GtkWindow
5519 b) accelerators/mnemonics are activated
5520 c) if (b) didn't handle the event, propagate to
5521 the focus widget and/or focus chain
5523 The problem with this is that if the accelerators include
5524 keys without modifiers, such as the space bar or the
5525 letter "e", then pressing the key while typing into
5526 a text entry widget results in the accelerator being
5527 activated, instead of the desired letter appearing
5530 There is no good way of fixing this, but this
5531 represents a compromise. The idea is that
5532 key events involving modifiers (not Shift)
5533 get routed into the activation pathway first, then
5534 get propagated to the focus widget if necessary.
5536 If the key event doesn't involve modifiers,
5537 we deliver to the focus widget first, thus allowing
5538 it to get "normal text" without interference
5541 Of course, this can also be problematic: if there
5542 is a widget with focus, then it will swallow
5543 all "normal text" accelerators.
5547 if (!special_handling_of_unmodified_accelerators || (ev->state & mask)) {
5549 /* no special handling or there are modifiers in effect: accelerate first */
5551 DEBUG_TRACE (DEBUG::Accelerators, "\tactivate, then propagate\n");
5552 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tevent send-event:%1 time:%2 length:%3 name %7 string:%4 hardware_keycode:%5 group:%6\n",
5553 ev->send_event, ev->time, ev->length, ev->string, ev->hardware_keycode, ev->group, gdk_keyval_name (ev->keyval)));
5555 DEBUG_TRACE (DEBUG::Accelerators, "\tsending to window\n");
5556 KeyboardKey k (ev->state, ev->keyval);
5560 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tusing Ardour bindings %1 @ %2 for this event\n", bindings->name(), bindings));
5562 if (bindings->activate (k, Bindings::Press)) {
5563 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5568 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5570 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5571 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5575 DEBUG_TRACE (DEBUG::Accelerators, "\tnot accelerated, now propagate\n");
5577 if (gtk_window_propagate_key_event (win, ev)) {
5578 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate handled\n");
5584 /* no modifiers, propagate first */
5586 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate, then activate\n");
5588 if (gtk_window_propagate_key_event (win, ev)) {
5589 DEBUG_TRACE (DEBUG::Accelerators, "\thandled by propagate\n");
5593 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagation didn't handle, so activate\n");
5594 KeyboardKey k (ev->state, ev->keyval);
5598 DEBUG_TRACE (DEBUG::Accelerators, "\tusing Ardour bindings for this window\n");
5601 if (bindings->activate (k, Bindings::Press)) {
5602 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5608 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5610 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5611 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5616 DEBUG_TRACE (DEBUG::Accelerators, "\tnot handled\n");
5621 ARDOUR_UI::load_bindings ()
5623 if ((global_bindings = Bindings::get_bindings (X_("Global"), global_actions)) == 0) {
5624 error << _("Global keybindings are missing") << endmsg;
5629 ARDOUR_UI::cancel_solo ()
5633 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_control), 0.0, Controllable::NoGroup);
5635 _session->clear_all_solo_state (_session->get_routes()); // safeguard, ideally this won't do anything, check the log-window