2 Copyright (C) 1999-2013 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include "gtk2ardour-config.h"
22 #include "gtk2ardour-version.h"
32 #ifndef PLATFORM_WINDOWS
33 #include <sys/resource.h>
43 #include "pbd/gstdio_compat.h"
45 #include <gtkmm/messagedialog.h>
46 #include <gtkmm/accelmap.h>
47 #include <gtkmm/stock.h>
49 #include "pbd/error.h"
50 #include "pbd/basename.h"
51 #include "pbd/compose.h"
52 #include "pbd/convert.h"
53 #include "pbd/failed_constructor.h"
54 #include "pbd/enumwriter.h"
55 #include "pbd/memento_command.h"
56 #include "pbd/openuri.h"
57 #include "pbd/stl_delete.h"
58 #include "pbd/file_utils.h"
59 #include "pbd/localtime_r.h"
60 #include "pbd/pthread_utils.h"
61 #include "pbd/replace_all.h"
62 #include "pbd/xml++.h"
64 #include "gtkmm2ext/application.h"
65 #include "gtkmm2ext/bindings.h"
66 #include "gtkmm2ext/gtk_ui.h"
67 #include "gtkmm2ext/utils.h"
68 #include "gtkmm2ext/click_box.h"
69 #include "gtkmm2ext/fastmeter.h"
70 #include "gtkmm2ext/popup.h"
71 #include "gtkmm2ext/window_title.h"
73 #include "ardour/ardour.h"
74 #include "ardour/audio_backend.h"
75 #include "ardour/audio_track.h"
76 #include "ardour/audioengine.h"
77 #include "ardour/audiofilesource.h"
78 #include "ardour/automation_watch.h"
79 #include "ardour/diskstream.h"
80 #include "ardour/filename_extensions.h"
81 #include "ardour/filesystem_paths.h"
82 #include "ardour/ltc_file_reader.h"
83 #include "ardour/midi_track.h"
84 #include "ardour/port.h"
85 #include "ardour/plugin_manager.h"
86 #include "ardour/process_thread.h"
87 #include "ardour/profile.h"
88 #include "ardour/recent_sessions.h"
89 #include "ardour/record_enable_control.h"
90 #include "ardour/session_directory.h"
91 #include "ardour/session_route.h"
92 #include "ardour/session_state_utils.h"
93 #include "ardour/session_utils.h"
94 #include "ardour/source_factory.h"
95 #include "ardour/slave.h"
96 #include "ardour/system_exec.h"
97 #include "ardour/track.h"
98 #include "ardour/vca_manager.h"
99 #include "ardour/utils.h"
101 #include "LuaBridge/LuaBridge.h"
103 #ifdef WINDOWS_VST_SUPPORT
106 #ifdef AUDIOUNIT_SUPPORT
107 #include "ardour/audio_unit.h"
110 // fix for OSX (nsm.h has a check function, AU/Apple defines check)
115 #include "timecode/time.h"
117 typedef uint64_t microseconds_t;
122 #include "add_route_dialog.h"
123 #include "ambiguous_file_dialog.h"
124 #include "ardour_ui.h"
125 #include "audio_clock.h"
126 #include "audio_region_view.h"
127 #include "big_clock_window.h"
128 #include "bundle_manager.h"
129 #include "duplicate_routes_dialog.h"
131 #include "engine_dialog.h"
132 #include "export_video_dialog.h"
133 #include "export_video_infobox.h"
134 #include "gain_meter.h"
135 #include "global_port_matrix.h"
136 #include "gui_object.h"
137 #include "gui_thread.h"
138 #include "keyboard.h"
139 #include "keyeditor.h"
140 #include "location_ui.h"
141 #include "lua_script_manager.h"
142 #include "luawindow.h"
143 #include "main_clock.h"
144 #include "missing_file_dialog.h"
145 #include "missing_plugin_dialog.h"
146 #include "mixer_ui.h"
147 #include "meterbridge.h"
148 #include "mouse_cursors.h"
151 #include "pingback.h"
152 #include "processor_box.h"
153 #include "prompter.h"
154 #include "public_editor.h"
155 #include "rc_option_editor.h"
156 #include "route_time_axis.h"
157 #include "route_params_ui.h"
158 #include "save_as_dialog.h"
159 #include "script_selector.h"
160 #include "session_dialog.h"
161 #include "session_metadata_dialog.h"
162 #include "session_option_editor.h"
163 #include "shuttle_control.h"
164 #include "speaker_dialog.h"
167 #include "theme_manager.h"
168 #include "time_axis_view_item.h"
171 #include "video_server_dialog.h"
172 #include "add_video_dialog.h"
173 #include "transcode_video_dialog.h"
177 using namespace ARDOUR;
178 using namespace ARDOUR_UI_UTILS;
180 using namespace Gtkmm2ext;
183 using namespace Editing;
185 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
187 sigc::signal<void, framepos_t, bool, framepos_t> ARDOUR_UI::Clock;
188 sigc::signal<void> ARDOUR_UI::CloseAllDialogs;
191 ask_about_configuration_copy (string const & old_dir, string const & new_dir, int version)
193 MessageDialog msg (string_compose (_("%1 %2.x has discovered configuration files from %1 %3.x.\n\n"
194 "Would you like these files to be copied and used for %1 %2.x?\n\n"
195 "(This will require you to restart %1.)"),
196 PROGRAM_NAME, PROGRAM_VERSION, version),
197 false, /* no markup */
200 true /* modal, though it hardly matters since it is the only window */
203 msg.set_default_response (Gtk::RESPONSE_YES);
206 return (msg.run() == Gtk::RESPONSE_YES);
210 libxml_generic_error_func (void* /* parsing_context*/,
218 vsnprintf (buf, sizeof (buf), msg, ap);
219 error << buf << endmsg;
224 libxml_structured_error_func (void* /* parsing_context*/,
232 replace_all (msg, "\n", "");
235 if (err->file && err->line) {
236 error << X_("XML error: ") << msg << " in " << err->file << " at line " << err->line;
239 error << ':' << err->int2;
244 error << X_("XML error: ") << msg << endmsg;
250 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
251 : Gtkmm2ext::UI (PROGRAM_NAME, X_("gui"), argcp, argvp)
252 , session_loaded (false)
253 , gui_object_state (new GUIObjectState)
254 , primary_clock (new MainClock (X_("primary"), X_("transport"), true ))
255 , secondary_clock (new MainClock (X_("secondary"), X_("secondary"), false))
256 , big_clock (new AudioClock (X_("bigclock"), false, "big", true, true, false, false))
258 , global_actions (X_("global"))
259 , ignore_dual_punch (false)
260 , main_window_visibility (0)
265 , _mixer_on_top (false)
266 , _initial_verbose_plugin_scan (false)
267 , first_time_engine_run (true)
268 , roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll))
269 , stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop))
270 , goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart))
271 , goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd))
272 , auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop))
273 , play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection))
274 , rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable))
275 , auto_return_button (ArdourButton::led_default_elements)
276 , follow_edits_button (ArdourButton::led_default_elements)
277 , auto_input_button (ArdourButton::led_default_elements)
278 , auditioning_alert_button (_("Audition"))
279 , solo_alert_button (_("Solo"))
280 , feedback_alert_button (_("Feedback"))
281 , error_alert_button ( ArdourButton::just_led_default_elements )
283 , editor_meter_peak_display()
284 , _numpad_locate_happening (false)
285 , _session_is_new (false)
286 , last_key_press_time (0)
290 , rc_option_editor (0)
291 , speaker_config_window (X_("speaker-config"), _("Speaker Configuration"))
292 , add_route_dialog (X_("add-routes"), _("Add Tracks/Busses"))
293 , about (X_("about"), _("About"))
294 , location_ui (X_("locations"), S_("Ranges|Locations"))
295 , route_params (X_("inspector"), _("Tracks and Busses"))
296 , audio_midi_setup (X_("audio-midi-setup"), _("Audio/MIDI Setup"))
297 , export_video_dialog (X_("video-export"), _("Video Export Dialog"))
298 , lua_script_window (X_("script-manager"), _("Script Manager"))
299 , session_option_editor (X_("session-options-editor"), _("Properties"), boost::bind (&ARDOUR_UI::create_session_option_editor, this))
300 , add_video_dialog (X_("add-video"), _("Add Video"), boost::bind (&ARDOUR_UI::create_add_video_dialog, this))
301 , bundle_manager (X_("bundle-manager"), _("Bundle Manager"), boost::bind (&ARDOUR_UI::create_bundle_manager, this))
302 , big_clock_window (X_("big-clock"), _("Big Clock"), boost::bind (&ARDOUR_UI::create_big_clock_window, this))
303 , audio_port_matrix (X_("audio-connection-manager"), _("Audio Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::AUDIO))
304 , midi_port_matrix (X_("midi-connection-manager"), _("MIDI Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::MIDI))
305 , key_editor (X_("key-editor"), _("Bindings Editor"), boost::bind (&ARDOUR_UI::create_key_editor, this))
306 , video_server_process (0)
308 , have_configure_timeout (false)
309 , last_configure_time (0)
311 , have_disk_speed_dialog_displayed (false)
312 , _status_bar_visibility (X_("status-bar"))
313 , _feedback_exists (false)
314 , _log_not_acknowledged (LogLevelNone)
315 , duplicate_routes_dialog (0)
316 , editor_visibility_button (S_("Window|Editor"))
317 , mixer_visibility_button (S_("Window|Mixer"))
318 , prefs_visibility_button (S_("Window|Preferences"))
320 Gtkmm2ext::init (localedir);
322 UIConfiguration::instance().post_gui_init ();
324 if (ARDOUR::handle_old_configuration_files (boost::bind (ask_about_configuration_copy, _1, _2, _3))) {
325 MessageDialog msg (string_compose (_("Your configuration files were copied. You can now restart %1."), PROGRAM_NAME), true);
327 /* configuration was modified, exit immediately */
332 if (string (VERSIONSTRING).find (".pre") != string::npos) {
333 /* check this is not being run from ./ardev etc. */
334 if (!running_from_source_tree ()) {
335 pre_release_dialog ();
339 if (theArdourUI == 0) {
343 /* track main window visibility */
345 main_window_visibility = new VisibilityTracker (_main_window);
347 /* stop libxml from spewing to stdout/stderr */
349 xmlSetGenericErrorFunc (this, libxml_generic_error_func);
350 xmlSetStructuredErrorFunc (this, libxml_structured_error_func);
352 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::parameter_changed));
353 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
354 UIConfiguration::instance().map_parameters (pc);
356 roll_button.set_controllable (roll_controllable);
357 stop_button.set_controllable (stop_controllable);
358 goto_start_button.set_controllable (goto_start_controllable);
359 goto_end_button.set_controllable (goto_end_controllable);
360 auto_loop_button.set_controllable (auto_loop_controllable);
361 play_selection_button.set_controllable (play_selection_controllable);
362 rec_button.set_controllable (rec_controllable);
364 roll_button.set_name ("transport button");
365 stop_button.set_name ("transport button");
366 goto_start_button.set_name ("transport button");
367 goto_end_button.set_name ("transport button");
368 auto_loop_button.set_name ("transport button");
369 play_selection_button.set_name ("transport button");
370 rec_button.set_name ("transport recenable button");
371 midi_panic_button.set_name ("transport button");
373 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
374 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
376 ARDOUR::Session::VersionMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_format_mismatch, this, _1, _2), gui_context());
378 /* handle dialog requests */
380 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
382 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
384 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
386 /* handle Audio/MIDI setup when session requires it */
388 ARDOUR::Session::AudioEngineSetupRequired.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::do_audio_midi_setup, this, _1));
390 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
392 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
394 /* handle sr mismatch with a dialog - cross-thread from engine */
395 ARDOUR::Session::NotifyAboutSampleRateMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::sr_mismatch_message, this, _1, _2), gui_context ());
397 /* handle requests to quit (coming from JACK session) */
399 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::finish, this), gui_context ());
401 /* tell the user about feedback */
403 ARDOUR::Session::FeedbackDetected.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::feedback_detected, this), gui_context ());
404 ARDOUR::Session::SuccessfulGraphSort.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::successful_graph_sort, this), gui_context ());
406 /* handle requests to deal with missing files */
408 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
410 /* and ambiguous files */
412 ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2));
414 /* also plugin scan messages */
415 ARDOUR::PluginScanMessage.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_dialog, this, _1, _2, _3), gui_context());
416 ARDOUR::PluginScanTimeout.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_timeout, this, _1), gui_context());
418 ARDOUR::GUIIdle.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::gui_idle_handler, this), gui_context());
420 Config->ParameterChanged.connect ( forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::set_flat_buttons, this), gui_context() );
423 /* lets get this party started */
425 setup_gtk_ardour_enums ();
428 SessionEvent::create_per_thread_pool ("GUI", 4096);
430 /* we like keyboards */
432 keyboard = new ArdourKeyboard(*this);
434 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
436 keyboard->set_state (*node, Stateful::loading_state_version);
439 UIConfiguration::instance().reset_dpi ();
441 TimeAxisViewItem::set_constant_heights ();
443 /* Set this up so that our window proxies can register actions */
445 ActionManager::init ();
447 /* The following must happen after ARDOUR::init() so that Config is set up */
449 const XMLNode* ui_xml = Config->extra_xml (X_("UI"));
452 key_editor.set_state (*ui_xml, 0);
453 session_option_editor.set_state (*ui_xml, 0);
454 speaker_config_window.set_state (*ui_xml, 0);
455 about.set_state (*ui_xml, 0);
456 add_route_dialog.set_state (*ui_xml, 0);
457 add_video_dialog.set_state (*ui_xml, 0);
458 route_params.set_state (*ui_xml, 0);
459 bundle_manager.set_state (*ui_xml, 0);
460 location_ui.set_state (*ui_xml, 0);
461 big_clock_window.set_state (*ui_xml, 0);
462 audio_port_matrix.set_state (*ui_xml, 0);
463 midi_port_matrix.set_state (*ui_xml, 0);
464 export_video_dialog.set_state (*ui_xml, 0);
465 lua_script_window.set_state (*ui_xml, 0);
468 /* Separate windows */
470 WM::Manager::instance().register_window (&key_editor);
471 WM::Manager::instance().register_window (&session_option_editor);
472 WM::Manager::instance().register_window (&speaker_config_window);
473 WM::Manager::instance().register_window (&about);
474 WM::Manager::instance().register_window (&add_route_dialog);
475 WM::Manager::instance().register_window (&add_video_dialog);
476 WM::Manager::instance().register_window (&route_params);
477 WM::Manager::instance().register_window (&audio_midi_setup);
478 WM::Manager::instance().register_window (&export_video_dialog);
479 WM::Manager::instance().register_window (&lua_script_window);
480 WM::Manager::instance().register_window (&bundle_manager);
481 WM::Manager::instance().register_window (&location_ui);
482 WM::Manager::instance().register_window (&big_clock_window);
483 WM::Manager::instance().register_window (&audio_port_matrix);
484 WM::Manager::instance().register_window (&midi_port_matrix);
486 /* do not retain position for add route dialog */
487 add_route_dialog.set_state_mask (WindowProxy::Size);
489 /* Trigger setting up the color scheme and loading the GTK RC file */
491 UIConfiguration::instance().load_rc_file (false);
493 _process_thread = new ProcessThread ();
494 _process_thread->init ();
496 UIConfiguration::instance().DPIReset.connect (sigc::mem_fun (*this, &ARDOUR_UI::resize_text_widgets));
502 ARDOUR_UI::pre_release_dialog ()
504 ArdourDialog d (_("Pre-Release Warning"), true, false);
505 d.add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
507 Label* label = manage (new Label);
508 label->set_markup (string_compose (_("<b>Welcome to this pre-release build of %1 %2</b>\n\n\
509 There are still several issues and bugs to be worked on,\n\
510 as well as general workflow improvements, before this can be considered\n\
511 release software. So, a few guidelines:\n\
513 1) Please do <b>NOT</b> use this software with the expectation that it is stable or reliable\n\
514 though it may be so, depending on your workflow.\n\
515 2) Please wait for a helpful writeup of new features.\n\
516 3) <b>Please do NOT use the forums at ardour.org to report issues</b>.\n\
517 4) Please <b>DO</b> use the bugtracker at http://tracker.ardour.org/ to report issues\n\
518 making sure to note the product version number as 5.0-pre.\n\
519 5) Please <b>DO</b> use the ardour-users mailing list to discuss ideas and pass on comments.\n\
520 6) Please <b>DO</b> join us on IRC for real time discussions about %1 %2. You\n\
521 can get there directly from within the program via the Help->Chat menu option.\n\
523 Full information on all the above can be found on the support page at\n\
525 http://ardour.org/support\n\
526 "), PROGRAM_NAME, VERSIONSTRING));
528 d.get_vbox()->set_border_width (12);
529 d.get_vbox()->pack_start (*label, false, false, 12);
530 d.get_vbox()->show_all ();
535 GlobalPortMatrixWindow*
536 ARDOUR_UI::create_global_port_matrix (ARDOUR::DataType type)
541 return new GlobalPortMatrixWindow (_session, type);
545 ARDOUR_UI::attach_to_engine ()
547 AudioEngine::instance()->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
548 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
552 ARDOUR_UI::engine_stopped ()
554 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
555 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
556 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
557 update_sample_rate (0);
562 ARDOUR_UI::engine_running ()
564 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
565 if (first_time_engine_run) {
567 first_time_engine_run = false;
571 _session->reset_xrun_count ();
573 update_disk_space ();
575 update_xrun_count ();
576 update_sample_rate (AudioEngine::instance()->sample_rate());
577 update_timecode_format ();
578 update_peak_thread_work ();
579 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, true);
580 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, false);
584 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
586 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
587 /* we can't rely on the original string continuing to exist when we are called
588 again in the GUI thread, so make a copy and note that we need to
591 char *copy = strdup (reason);
592 Gtkmm2ext::UI::instance()->call_slot (MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
596 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
597 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
599 update_sample_rate (0);
603 /* if the reason is a non-empty string, it means that the backend was shutdown
604 rather than just Ardour.
607 if (strlen (reason)) {
608 msgstr = string_compose (_("The audio backend was shutdown because:\n\n%1"), reason);
610 msgstr = string_compose (_("\
611 The audio backend has either been shutdown or it\n\
612 disconnected %1 because %1\n\
613 was not fast enough. Try to restart\n\
614 the audio backend and save the session."), PROGRAM_NAME);
617 MessageDialog msg (_main_window, msgstr);
618 pop_back_splash (msg);
622 free (const_cast<char*> (reason));
627 ARDOUR_UI::post_engine ()
629 /* Things to be done once (and once ONLY) after we have a backend running in the AudioEngine
631 #ifdef AUDIOUNIT_SUPPORT
633 if (AUPluginInfo::au_get_crashlog(au_msg)) {
634 popup_error(_("Audio Unit Plugin Scan Failed. Automatic AU scanning has been disabled. Please see the log window for further details."));
635 error << _("Audio Unit Plugin Scan Failed:") << endmsg;
636 info << au_msg << endmsg;
640 ARDOUR::init_post_engine ();
642 /* connect to important signals */
644 AudioEngine::instance()->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
645 AudioEngine::instance()->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
646 AudioEngine::instance()->BufferSizeChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
647 AudioEngine::instance()->Halted.connect_same_thread (halt_connection, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
648 AudioEngine::instance()->BecameSilent.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::audioengine_became_silent, this), gui_context());
650 if (setup_windows ()) {
651 throw failed_constructor ();
654 /* Do this after setup_windows (), as that's when the _status_bar_visibility is created */
655 XMLNode* n = Config->extra_xml (X_("UI"));
657 _status_bar_visibility.set_state (*n);
660 check_memory_locking();
662 /* this is the first point at which all the possible actions are
663 * available, because some of the available actions are dependent on
664 * aspects of the engine/backend.
667 if (ARDOUR_COMMAND_LINE::show_key_actions) {
670 vector<string> paths;
671 vector<string> labels;
672 vector<string> tooltips;
674 vector<Glib::RefPtr<Gtk::Action> > actions;
676 Gtkmm2ext::ActionMap::get_all_actions (paths, labels, tooltips, keys, actions);
678 vector<string>::iterator k;
679 vector<string>::iterator p;
681 for (p = paths.begin(), k = keys.begin(); p != paths.end(); ++k, ++p) {
686 cout << *p << " => " << *k << endl;
690 halt_connection.disconnect ();
691 AudioEngine::instance()->stop ();
695 /* this being a GUI and all, we want peakfiles */
697 AudioFileSource::set_build_peakfiles (true);
698 AudioFileSource::set_build_missing_peakfiles (true);
700 /* set default clock modes */
702 primary_clock->set_mode (AudioClock::Timecode);
703 secondary_clock->set_mode (AudioClock::BBT);
705 /* start the time-of-day-clock */
708 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
709 update_wall_clock ();
710 Glib::signal_timeout().connect_seconds (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 1);
715 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
716 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
717 Config->map_parameters (pc);
719 UIConfiguration::instance().map_parameters (pc);
723 ARDOUR_UI::~ARDOUR_UI ()
725 UIConfiguration::instance().save_state();
729 if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
730 // don't bother at 'real' exit. the OS cleans up for us.
731 delete big_clock; big_clock = 0;
732 delete primary_clock; primary_clock = 0;
733 delete secondary_clock; secondary_clock = 0;
734 delete _process_thread; _process_thread = 0;
735 delete meterbridge; meterbridge = 0;
736 delete luawindow; luawindow = 0;
737 delete editor; editor = 0;
738 delete mixer; mixer = 0;
740 delete gui_object_state; gui_object_state = 0;
741 delete main_window_visibility;
742 FastMeter::flush_pattern_cache ();
743 PixFader::flush_pattern_cache ();
747 /* Small trick to flush main-thread event pool.
748 * Other thread-pools are destroyed at pthread_exit(),
749 * but tmain thread termination is too late to trigger Pool::~Pool()
751 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.
752 delete ev->event_pool();
757 ARDOUR_UI::pop_back_splash (Gtk::Window& win)
759 if (Splash::instance()) {
760 Splash::instance()->pop_back_for (win);
765 ARDOUR_UI::configure_timeout ()
767 if (last_configure_time == 0) {
768 /* no configure events yet */
772 /* force a gap of 0.5 seconds since the last configure event
775 if (get_microseconds() - last_configure_time < 500000) {
778 have_configure_timeout = false;
779 save_ardour_state ();
785 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
787 if (have_configure_timeout) {
788 last_configure_time = get_microseconds();
790 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
791 have_configure_timeout = true;
798 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
800 XMLProperty const * prop;
802 if ((prop = node.property ("roll")) != 0) {
803 roll_controllable->set_id (prop->value());
805 if ((prop = node.property ("stop")) != 0) {
806 stop_controllable->set_id (prop->value());
808 if ((prop = node.property ("goto-start")) != 0) {
809 goto_start_controllable->set_id (prop->value());
811 if ((prop = node.property ("goto-end")) != 0) {
812 goto_end_controllable->set_id (prop->value());
814 if ((prop = node.property ("auto-loop")) != 0) {
815 auto_loop_controllable->set_id (prop->value());
817 if ((prop = node.property ("play-selection")) != 0) {
818 play_selection_controllable->set_id (prop->value());
820 if ((prop = node.property ("rec")) != 0) {
821 rec_controllable->set_id (prop->value());
823 if ((prop = node.property ("shuttle")) != 0) {
824 shuttle_box->controllable()->set_id (prop->value());
829 ARDOUR_UI::get_transport_controllable_state ()
831 XMLNode* node = new XMLNode(X_("TransportControllables"));
834 roll_controllable->id().print (buf, sizeof (buf));
835 node->add_property (X_("roll"), buf);
836 stop_controllable->id().print (buf, sizeof (buf));
837 node->add_property (X_("stop"), buf);
838 goto_start_controllable->id().print (buf, sizeof (buf));
839 node->add_property (X_("goto_start"), buf);
840 goto_end_controllable->id().print (buf, sizeof (buf));
841 node->add_property (X_("goto_end"), buf);
842 auto_loop_controllable->id().print (buf, sizeof (buf));
843 node->add_property (X_("auto_loop"), buf);
844 play_selection_controllable->id().print (buf, sizeof (buf));
845 node->add_property (X_("play_selection"), buf);
846 rec_controllable->id().print (buf, sizeof (buf));
847 node->add_property (X_("rec"), buf);
848 shuttle_box->controllable()->id().print (buf, sizeof (buf));
849 node->add_property (X_("shuttle"), buf);
855 ARDOUR_UI::save_session_at_its_request (std::string snapshot_name)
858 _session->save_state (snapshot_name);
863 ARDOUR_UI::autosave_session ()
865 if (g_main_depth() > 1) {
866 /* inside a recursive main loop,
867 give up because we may not be able to
873 if (!Config->get_periodic_safety_backups()) {
878 _session->maybe_write_autosave();
885 ARDOUR_UI::session_dirty_changed ()
892 ARDOUR_UI::update_autosave ()
894 if (_session && _session->dirty()) {
895 if (_autosave_connection.connected()) {
896 _autosave_connection.disconnect();
899 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
900 Config->get_periodic_safety_backup_interval() * 1000);
903 if (_autosave_connection.connected()) {
904 _autosave_connection.disconnect();
910 ARDOUR_UI::check_announcements ()
913 string _annc_filename;
916 _annc_filename = PROGRAM_NAME "_announcements_osx_";
917 #elif defined PLATFORM_WINDOWS
918 _annc_filename = PROGRAM_NAME "_announcements_windows_";
920 _annc_filename = PROGRAM_NAME "_announcements_linux_";
922 _annc_filename.append (VERSIONSTRING);
924 _announce_string = "";
926 std::string path = Glib::build_filename (user_config_directory(), _annc_filename);
927 FILE* fin = g_fopen (path.c_str(), "rb");
929 while (!feof (fin)) {
932 if ((len = fread (tmp, sizeof(char), 1024, fin)) == 0 || ferror (fin)) {
935 _announce_string.append (tmp, len);
940 pingback (VERSIONSTRING, path);
945 _hide_splash (gpointer arg)
947 ((ARDOUR_UI*)arg)->hide_splash();
952 ARDOUR_UI::starting ()
954 Application* app = Application::instance ();
956 bool brand_new_user = ArdourStartup::required ();
958 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
959 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::load_from_application_api));
961 if (ARDOUR_COMMAND_LINE::check_announcements) {
962 check_announcements ();
967 /* we need to create this early because it may need to set the
968 * audio backend end up.
972 audio_midi_setup.get (true);
974 std::cerr << "audio-midi engine setup failed."<< std::endl;
978 if ((nsm_url = g_getenv ("NSM_URL")) != 0) {
979 nsm = new NSM_Client;
980 if (!nsm->init (nsm_url)) {
981 /* the ardour executable may have different names:
983 * waf's obj.target for distro versions: eg ardour4, ardourvst4
984 * Ardour4, Mixbus3 for bundled versions + full path on OSX & windows
985 * argv[0] does not apply since we need the wrapper-script (not the binary itself)
987 * The wrapper startup script should set the environment variable 'ARDOUR_SELF'
989 const char *process_name = g_getenv ("ARDOUR_SELF");
990 nsm->announce (PROGRAM_NAME, ":dirty:", process_name ? process_name : "ardour4");
993 // wait for announce reply from nsm server
994 for ( i = 0; i < 5000; ++i) {
998 if (nsm->is_active()) {
1003 error << _("NSM server did not announce itself") << endmsg;
1006 // wait for open command from nsm server
1007 for ( i = 0; i < 5000; ++i) {
1009 Glib::usleep (1000);
1010 if (nsm->client_id ()) {
1016 error << _("NSM: no client ID provided") << endmsg;
1020 if (_session && nsm) {
1021 _session->set_nsm_state( nsm->is_active() );
1023 error << _("NSM: no session created") << endmsg;
1027 // nsm requires these actions disabled
1028 vector<string> action_names;
1029 action_names.push_back("SaveAs");
1030 action_names.push_back("Rename");
1031 action_names.push_back("New");
1032 action_names.push_back("Open");
1033 action_names.push_back("Recent");
1034 action_names.push_back("Close");
1036 for (vector<string>::const_iterator n = action_names.begin(); n != action_names.end(); ++n) {
1037 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), (*n).c_str());
1039 act->set_sensitive (false);
1046 error << _("NSM: initialization failed") << endmsg;
1052 if (brand_new_user) {
1053 _initial_verbose_plugin_scan = true;
1058 _initial_verbose_plugin_scan = false;
1059 switch (s.response ()) {
1060 case Gtk::RESPONSE_OK:
1067 #ifdef NO_PLUGIN_STATE
1069 ARDOUR::RecentSessions rs;
1070 ARDOUR::read_recent_sessions (rs);
1072 string path = Glib::build_filename (user_config_directory(), ".iknowaboutfreeversion");
1074 if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS) && !rs.empty()) {
1076 /* already used Ardour, have sessions ... warn about plugin state */
1078 ArdourDialog d (_("Free/Demo Version Warning"), true);
1080 Button b (string_compose (_("Subscribe and support development of %1"), PROGRAM_NAME));
1081 CheckButton c (_("Don't warn me about this again"));
1083 l.set_markup (string_compose (_("<span weight=\"bold\" size=\"large\">%1</span>\n\n<b>%2</b>\n\n<i>%3</i>\n\n%4"),
1084 string_compose (_("This is a free/demo version of %1"), PROGRAM_NAME),
1085 _("It will not restore OR save any plugin settings"),
1086 _("If you load an existing session with plugin settings\n"
1087 "they will not be used and will be lost."),
1088 _("To get full access to updates without this limitation\n"
1089 "consider becoming a subscriber for a low cost every month.")));
1090 l.set_justify (JUSTIFY_CENTER);
1092 b.signal_clicked().connect (mem_fun(*this, &ARDOUR_UI::launch_subscribe));
1094 d.get_vbox()->pack_start (l, true, true);
1095 d.get_vbox()->pack_start (b, false, false, 12);
1096 d.get_vbox()->pack_start (c, false, false, 12);
1098 d.add_button (_("Quit now"), RESPONSE_CANCEL);
1099 d.add_button (string_compose (_("Continue using %1"), PROGRAM_NAME), RESPONSE_OK);
1103 c.signal_toggled().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (toggle_file_existence), path)));
1105 if (d.run () != RESPONSE_OK) {
1111 /* go get a session */
1113 const bool new_session_required = (ARDOUR_COMMAND_LINE::new_session || brand_new_user);
1115 if (get_session_parameters (false, new_session_required, ARDOUR_COMMAND_LINE::load_template)) {
1116 std::cerr << "Cannot get session parameters."<< std::endl;
1123 WM::Manager::instance().show_visible ();
1125 /* We have to do this here since goto_editor_window() ends up calling show_all() on the
1126 * editor window, and we may want stuff to be hidden.
1128 _status_bar_visibility.update ();
1130 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
1132 if (splash && splash->is_visible()) {
1133 // in 1 second, hide the splash screen
1134 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
1137 /* all other dialogs are created conditionally */
1143 ARDOUR_UI::check_memory_locking ()
1145 #if defined(__APPLE__) || defined(PLATFORM_WINDOWS)
1146 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
1150 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
1152 if (AudioEngine::instance()->is_realtime() && memory_warning_node == 0) {
1154 struct rlimit limits;
1156 long pages, page_size;
1158 size_t pages_len=sizeof(pages);
1159 if ((page_size = getpagesize()) < 0 ||
1160 sysctlbyname("hw.availpages", &pages, &pages_len, NULL, 0))
1162 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0)
1167 ram = (int64_t) pages * (int64_t) page_size;
1170 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
1174 if (limits.rlim_cur != RLIM_INFINITY) {
1176 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
1180 _("WARNING: Your system has a limit for maximum amount of locked memory. "
1181 "This might cause %1 to run out of memory before your system "
1182 "runs out of memory. \n\n"
1183 "You can view the memory limit with 'ulimit -l', "
1184 "and it is normally controlled by %2"),
1187 X_("/etc/login.conf")
1189 X_(" /etc/security/limits.conf")
1193 msg.set_default_response (RESPONSE_OK);
1195 VBox* vbox = msg.get_vbox();
1197 CheckButton cb (_("Do not show this window again"));
1198 hbox.pack_start (cb, true, false);
1199 vbox->pack_start (hbox);
1204 pop_back_splash (msg);
1208 if (cb.get_active()) {
1209 XMLNode node (X_("no-memory-warning"));
1210 Config->add_instant_xml (node);
1215 #endif // !__APPLE__
1220 ARDOUR_UI::queue_finish ()
1222 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
1226 ARDOUR_UI::idle_finish ()
1229 return false; /* do not call again */
1236 ARDOUR_UI::instance()->video_timeline->sync_session_state();
1238 if (_session->dirty()) {
1239 vector<string> actions;
1240 actions.push_back (_("Don't quit"));
1241 actions.push_back (_("Just quit"));
1242 actions.push_back (_("Save and quit"));
1243 switch (ask_about_saving_session(actions)) {
1248 /* use the default name */
1249 if (save_state_canfail ("")) {
1250 /* failed - don't quit */
1251 MessageDialog msg (_main_window,
1252 string_compose (_("\
1253 %1 was unable to save your session.\n\n\
1254 If you still wish to quit, please use the\n\n\
1255 \"Just quit\" option."), PROGRAM_NAME));
1256 pop_back_splash(msg);
1266 second_connection.disconnect ();
1267 point_one_second_connection.disconnect ();
1268 point_zero_something_second_connection.disconnect();
1269 fps_connection.disconnect();
1272 delete ARDOUR_UI::instance()->video_timeline;
1273 ARDOUR_UI::instance()->video_timeline = NULL;
1274 stop_video_server();
1276 /* Save state before deleting the session, as that causes some
1277 windows to be destroyed before their visible state can be
1280 save_ardour_state ();
1282 close_all_dialogs ();
1285 _session->set_clean ();
1286 _session->remove_pending_capture_state ();
1291 halt_connection.disconnect ();
1292 AudioEngine::instance()->stop ();
1293 #ifdef WINDOWS_VST_SUPPORT
1294 fst_stop_threading();
1300 ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
1302 ArdourDialog window (_("Unsaved Session"));
1303 Gtk::HBox dhbox; // the hbox for the image and text
1304 Gtk::Label prompt_label;
1305 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
1309 assert (actions.size() >= 3);
1311 window.add_button (actions[0], RESPONSE_REJECT);
1312 window.add_button (actions[1], RESPONSE_APPLY);
1313 window.add_button (actions[2], RESPONSE_ACCEPT);
1315 window.set_default_response (RESPONSE_ACCEPT);
1317 Gtk::Button noquit_button (msg);
1318 noquit_button.set_name ("EditorGTKButton");
1322 if (_session->snap_name() == _session->name()) {
1323 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?"),
1324 _session->snap_name());
1326 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?"),
1327 _session->snap_name());
1330 prompt_label.set_text (prompt);
1331 prompt_label.set_name (X_("PrompterLabel"));
1332 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
1334 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
1335 dhbox.set_homogeneous (false);
1336 dhbox.pack_start (*dimage, false, false, 5);
1337 dhbox.pack_start (prompt_label, true, false, 5);
1338 window.get_vbox()->pack_start (dhbox);
1340 window.set_name (_("Prompter"));
1341 window.set_modal (true);
1342 window.set_resizable (false);
1345 prompt_label.show();
1350 ResponseType r = (ResponseType) window.run();
1355 case RESPONSE_ACCEPT: // save and get out of here
1357 case RESPONSE_APPLY: // get out of here
1368 ARDOUR_UI::every_second ()
1371 update_xrun_count ();
1372 update_buffer_load ();
1373 update_disk_space ();
1374 update_timecode_format ();
1375 update_peak_thread_work ();
1377 if (nsm && nsm->is_active ()) {
1380 if (!_was_dirty && _session->dirty ()) {
1384 else if (_was_dirty && !_session->dirty ()){
1392 ARDOUR_UI::every_point_one_seconds ()
1394 // TODO get rid of this..
1395 // ShuttleControl is updated directly via TransportStateChange signal
1399 ARDOUR_UI::every_point_zero_something_seconds ()
1401 // august 2007: actual update frequency: 25Hz (40ms), not 100Hz
1403 if (editor_meter && UIConfiguration::instance().get_show_editor_meter()) {
1404 float mpeak = editor_meter->update_meters();
1405 if (mpeak > editor_meter_max_peak) {
1406 if (mpeak >= UIConfiguration::instance().get_meter_peak()) {
1407 editor_meter_peak_display.set_active_state ( Gtkmm2ext::ExplicitActive );
1414 ARDOUR_UI::set_fps_timeout_connection ()
1416 unsigned int interval = 40;
1417 if (!_session) return;
1418 if (_session->timecode_frames_per_second() != 0) {
1419 /* ideally we'll use a select() to sleep and not accumulate
1420 * idle time to provide a regular periodic signal.
1421 * See linux_vst_gui_support.cc 'elapsed_time_ms'.
1422 * However, that'll require a dedicated thread and cross-thread
1423 * signals to the GUI Thread..
1425 interval = floor(500. /* update twice per FPS, since Glib::signal_timeout is very irregular */
1426 * _session->frame_rate() / _session->nominal_frame_rate()
1427 / _session->timecode_frames_per_second()
1429 #ifdef PLATFORM_WINDOWS
1430 // the smallest windows scheduler time-slice is ~15ms.
1431 // periodic GUI timeouts shorter than that will cause
1432 // WaitForSingleObject to spinlock (100% of one CPU Core)
1433 // and gtk never enters idle mode.
1434 // also changing timeBeginPeriod(1) does not affect that in
1435 // any beneficial way, so we just limit the max rate for now.
1436 interval = std::max(30u, interval); // at most ~33Hz.
1438 interval = std::max(8u, interval); // at most 120Hz.
1441 fps_connection.disconnect();
1442 Timers::set_fps_interval (interval);
1446 ARDOUR_UI::update_sample_rate (framecnt_t)
1450 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
1452 if (!AudioEngine::instance()->connected()) {
1454 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1458 framecnt_t rate = AudioEngine::instance()->sample_rate();
1461 /* no sample rate available */
1462 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1465 if (fmod (rate, 1000.0) != 0.0) {
1466 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
1467 (float) rate / 1000.0f,
1468 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1470 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
1472 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1476 sample_rate_label.set_markup (buf);
1480 ARDOUR_UI::update_format ()
1483 format_label.set_text ("");
1488 s << _("File:") << X_(" <span foreground=\"green\">");
1490 switch (_session->config.get_native_file_header_format ()) {
1522 switch (_session->config.get_native_file_data_format ()) {
1536 format_label.set_markup (s.str ());
1540 ARDOUR_UI::update_xrun_count ()
1544 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1545 should also be changed.
1549 const unsigned int x = _session->get_xrun_count ();
1551 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">>10K</span>"), X_("red"));
1553 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">%u</span>"), x > 0 ? X_("red") : X_("green"), x);
1556 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">?</span>"), X_("yellow"));
1558 xrun_label.set_markup (buf);
1559 set_tip (xrun_label, _("Audio dropouts. Shift+click to reset"));
1563 ARDOUR_UI::update_cpu_load ()
1567 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1568 should also be changed.
1571 double const c = AudioEngine::instance()->get_dsp_load ();
1572 snprintf (buf, sizeof (buf), _("DSP: <span foreground=\"%s\">%5.1f%%</span>"), c >= 90 ? X_("red") : X_("green"), c);
1573 cpu_load_label.set_markup (buf);
1577 ARDOUR_UI::update_peak_thread_work ()
1580 const int c = SourceFactory::peak_work_queue_length ();
1582 snprintf (buf, sizeof (buf), _("PkBld: <span foreground=\"%s\">%d</span>"), c >= 2 ? X_("red") : X_("green"), c);
1583 peak_thread_work_label.set_markup (buf);
1585 peak_thread_work_label.set_markup (X_(""));
1590 ARDOUR_UI::update_buffer_load ()
1594 uint32_t const playback = _session ? _session->playback_load () : 100;
1595 uint32_t const capture = _session ? _session->capture_load () : 100;
1597 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1598 should also be changed.
1604 _("Buffers: <span foreground=\"green\">p:</span><span foreground=\"%s\">%" PRIu32 "%%</span> "
1605 "<span foreground=\"green\">c:</span><span foreground=\"%s\">%" PRIu32 "%%</span>"),
1606 playback <= 5 ? X_("red") : X_("green"),
1608 capture <= 5 ? X_("red") : X_("green"),
1612 buffer_load_label.set_markup (buf);
1614 buffer_load_label.set_text ("");
1619 ARDOUR_UI::count_recenabled_streams (Route& route)
1621 Track* track = dynamic_cast<Track*>(&route);
1622 if (track && track->rec_enable_control()->get_value()) {
1623 rec_enabled_streams += track->n_inputs().n_total();
1628 ARDOUR_UI::update_disk_space()
1630 if (_session == 0) {
1634 boost::optional<framecnt_t> opt_frames = _session->available_capture_duration();
1636 framecnt_t fr = _session->frame_rate();
1639 /* skip update - no SR available */
1644 /* Available space is unknown */
1645 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">Unknown</span>"));
1646 } else if (opt_frames.get_value_or (0) == max_framecnt) {
1647 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">24hrs+</span>"));
1649 rec_enabled_streams = 0;
1650 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams, false);
1652 framecnt_t frames = opt_frames.get_value_or (0);
1654 if (rec_enabled_streams) {
1655 frames /= rec_enabled_streams;
1662 hrs = frames / (fr * 3600);
1665 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">>24 hrs</span>"));
1667 frames -= hrs * fr * 3600;
1668 mins = frames / (fr * 60);
1669 frames -= mins * fr * 60;
1672 bool const low = (hrs == 0 && mins <= 30);
1676 _("Disk: <span foreground=\"%s\">%02dh:%02dm:%02ds</span>"),
1677 low ? X_("red") : X_("green"),
1683 disk_space_label.set_markup (buf);
1687 ARDOUR_UI::update_timecode_format ()
1693 TimecodeSlave* tcslave;
1694 SyncSource sync_src = Config->get_sync_source();
1696 if ((sync_src == LTC || sync_src == MTC) && (tcslave = dynamic_cast<TimecodeSlave*>(_session->slave())) != 0) {
1697 matching = (tcslave->apparent_timecode_format() == _session->config.get_timecode_format());
1702 snprintf (buf, sizeof (buf), S_("Timecode|TC: <span foreground=\"%s\">%s</span>"),
1703 matching ? X_("green") : X_("red"),
1704 Timecode::timecode_format_name (_session->config.get_timecode_format()).c_str());
1706 snprintf (buf, sizeof (buf), "TC: n/a");
1709 timecode_format_label.set_markup (buf);
1713 ARDOUR_UI::update_wall_clock ()
1717 static int last_min = -1;
1720 tm_now = localtime (&now);
1721 if (last_min != tm_now->tm_min) {
1723 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1724 wall_clock_label.set_text (buf);
1725 last_min = tm_now->tm_min;
1732 ARDOUR_UI::open_recent_session ()
1734 bool can_return = (_session != 0);
1736 SessionDialog recent_session_dialog;
1740 ResponseType r = (ResponseType) recent_session_dialog.run ();
1743 case RESPONSE_ACCEPT:
1747 recent_session_dialog.hide();
1754 recent_session_dialog.hide();
1758 std::string path = recent_session_dialog.session_folder();
1759 std::string state = recent_session_dialog.session_name (should_be_new);
1761 if (should_be_new == true) {
1765 _session_is_new = false;
1767 if (load_session (path, state) == 0) {
1773 if (splash && splash->is_visible()) {
1774 // in 1 second, hide the splash screen
1775 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
1780 ARDOUR_UI::check_audioengine (Gtk::Window& parent)
1782 if (!AudioEngine::instance()->connected()) {
1783 MessageDialog msg (parent, string_compose (
1784 _("%1 is not connected to any audio backend.\n"
1785 "You cannot open or close sessions in this condition"),
1787 pop_back_splash (msg);
1795 ARDOUR_UI::open_session ()
1797 if (!check_audioengine (_main_window)) {
1801 /* ardour sessions are folders */
1802 Gtk::FileChooserDialog open_session_selector(_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1803 open_session_selector.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1804 open_session_selector.add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1805 open_session_selector.set_default_response(Gtk::RESPONSE_ACCEPT);
1808 string session_parent_dir = Glib::path_get_dirname(_session->path());
1809 open_session_selector.set_current_folder(session_parent_dir);
1811 open_session_selector.set_current_folder(Config->get_default_session_parent_dir());
1814 Gtkmm2ext::add_volume_shortcuts (open_session_selector);
1816 /* add_shortcut_folder throws an exception if the folder being added already has a shortcut */
1817 string default_session_folder = Config->get_default_session_parent_dir();
1818 open_session_selector.add_shortcut_folder (default_session_folder);
1820 catch (Glib::Error & e) {
1821 std::cerr << "open_session_selector.add_shortcut_folder() threw Glib::Error " << e.what() << std::endl;
1824 FileFilter session_filter;
1825 session_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::statefile_suffix));
1826 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1827 open_session_selector.add_filter (session_filter);
1828 open_session_selector.set_filter (session_filter);
1830 int response = open_session_selector.run();
1831 open_session_selector.hide ();
1833 if (response == Gtk::RESPONSE_CANCEL) {
1837 string session_path = open_session_selector.get_filename();
1841 if (session_path.length() > 0) {
1842 if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1843 _session_is_new = isnew;
1844 load_session (path, name);
1850 ARDOUR_UI::session_add_vca (const string& name_template, uint32_t n)
1856 _session->vca_manager().create_vca (n, name_template);
1860 ARDOUR_UI::session_add_mixed_track (
1861 const ChanCount& input,
1862 const ChanCount& output,
1863 RouteGroup* route_group,
1865 const string& name_template,
1867 PluginInfoPtr instrument,
1868 Plugin::PresetRecord* pset,
1869 ARDOUR::PresentationInfo::order_t order)
1871 list<boost::shared_ptr<MidiTrack> > tracks;
1873 if (_session == 0) {
1874 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1879 tracks = _session->new_midi_track (input, output, instrument, pset, route_group, how_many, name_template, order, ARDOUR::Normal);
1881 if (tracks.size() != how_many) {
1882 error << string_compose(P_("could not create %1 new mixed track", "could not create %1 new mixed tracks", how_many), how_many) << endmsg;
1887 display_insufficient_ports_message ();
1892 for (list<boost::shared_ptr<MidiTrack> >::iterator i = tracks.begin(); i != tracks.end(); ++i) {
1893 (*i)->set_strict_io (true);
1899 ARDOUR_UI::session_add_midi_bus (
1900 RouteGroup* route_group,
1902 const string& name_template,
1904 PluginInfoPtr instrument,
1905 Plugin::PresetRecord* pset,
1906 ARDOUR::PresentationInfo::order_t order)
1910 if (_session == 0) {
1911 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1917 routes = _session->new_midi_route (route_group, how_many, name_template, instrument, pset, PresentationInfo::MidiBus, order);
1918 if (routes.size() != how_many) {
1919 error << string_compose(P_("could not create %1 new Midi Bus", "could not create %1 new Midi Busses", how_many), how_many) << endmsg;
1924 display_insufficient_ports_message ();
1929 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
1930 (*i)->set_strict_io (true);
1936 ARDOUR_UI::session_add_midi_route (
1938 RouteGroup* route_group,
1940 const string& name_template,
1942 PluginInfoPtr instrument,
1943 Plugin::PresetRecord* pset,
1944 ARDOUR::PresentationInfo::order_t order)
1946 ChanCount one_midi_channel;
1947 one_midi_channel.set (DataType::MIDI, 1);
1950 session_add_mixed_track (one_midi_channel, one_midi_channel, route_group, how_many, name_template, strict_io, instrument, pset, order);
1952 session_add_midi_bus (route_group, how_many, name_template, strict_io, instrument, pset, order);
1957 ARDOUR_UI::session_add_audio_route (
1959 int32_t input_channels,
1960 int32_t output_channels,
1961 ARDOUR::TrackMode mode,
1962 RouteGroup* route_group,
1964 string const & name_template,
1966 ARDOUR::PresentationInfo::order_t order)
1968 list<boost::shared_ptr<AudioTrack> > tracks;
1971 if (_session == 0) {
1972 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1978 tracks = _session->new_audio_track (input_channels, output_channels, route_group, how_many, name_template, order, mode);
1980 if (tracks.size() != how_many) {
1981 error << string_compose (P_("could not create %1 new audio track", "could not create %1 new audio tracks", how_many), how_many)
1987 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template, PresentationInfo::AudioBus, order);
1989 if (routes.size() != how_many) {
1990 error << string_compose (P_("could not create %1 new audio bus", "could not create %1 new audio busses", how_many), how_many)
1997 display_insufficient_ports_message ();
2002 for (list<boost::shared_ptr<AudioTrack> >::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2003 (*i)->set_strict_io (true);
2005 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
2006 (*i)->set_strict_io (true);
2012 ARDOUR_UI::display_insufficient_ports_message ()
2014 MessageDialog msg (_main_window,
2015 string_compose (_("There are insufficient ports available\n\
2016 to create a new track or bus.\n\
2017 You should save %1, exit and\n\
2018 restart with more ports."), PROGRAM_NAME));
2019 pop_back_splash (msg);
2024 ARDOUR_UI::transport_goto_start ()
2027 _session->goto_start();
2029 /* force displayed area in editor to start no matter
2030 what "follow playhead" setting is.
2034 editor->center_screen (_session->current_start_frame ());
2040 ARDOUR_UI::transport_goto_zero ()
2043 _session->request_locate (0);
2045 /* force displayed area in editor to start no matter
2046 what "follow playhead" setting is.
2050 editor->reset_x_origin (0);
2056 ARDOUR_UI::transport_goto_wallclock ()
2058 if (_session && editor) {
2065 localtime_r (&now, &tmnow);
2067 framecnt_t frame_rate = _session->frame_rate();
2069 if (frame_rate == 0) {
2070 /* no frame rate available */
2074 frames = tmnow.tm_hour * (60 * 60 * frame_rate);
2075 frames += tmnow.tm_min * (60 * frame_rate);
2076 frames += tmnow.tm_sec * frame_rate;
2078 _session->request_locate (frames, _session->transport_rolling ());
2080 /* force displayed area in editor to start no matter
2081 what "follow playhead" setting is.
2085 editor->center_screen (frames);
2091 ARDOUR_UI::transport_goto_end ()
2094 framepos_t const frame = _session->current_end_frame();
2095 _session->request_locate (frame);
2097 /* force displayed area in editor to start no matter
2098 what "follow playhead" setting is.
2102 editor->center_screen (frame);
2108 ARDOUR_UI::transport_stop ()
2114 if (_session->is_auditioning()) {
2115 _session->cancel_audition ();
2119 _session->request_stop (false, true);
2122 /** Check if any tracks are record enabled. If none are, record enable all of them.
2123 * @return true if track record-enabled status was changed, false otherwise.
2126 ARDOUR_UI::trx_record_enable_all_tracks ()
2132 boost::shared_ptr<RouteList> rl = _session->get_tracks ();
2133 bool none_record_enabled = true;
2135 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
2136 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*r);
2139 if (t->rec_enable_control()->get_value()) {
2140 none_record_enabled = false;
2145 if (none_record_enabled) {
2146 _session->set_controls (route_list_to_control_list (rl, &Stripable::rec_enable_control), 1.0, Controllable::NoGroup);
2149 return none_record_enabled;
2153 ARDOUR_UI::transport_record (bool roll)
2156 switch (_session->record_status()) {
2157 case Session::Disabled:
2158 if (_session->ntracks() == 0) {
2159 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."));
2163 if (Profile->get_trx()) {
2164 roll = trx_record_enable_all_tracks ();
2166 _session->maybe_enable_record ();
2171 case Session::Recording:
2173 _session->request_stop();
2175 _session->disable_record (false, true);
2179 case Session::Enabled:
2180 _session->disable_record (false, true);
2186 ARDOUR_UI::transport_roll ()
2192 if (_session->is_auditioning()) {
2197 if (_session->config.get_external_sync()) {
2198 switch (Config->get_sync_source()) {
2202 /* transport controlled by the master */
2208 bool rolling = _session->transport_rolling();
2210 if (_session->get_play_loop()) {
2212 /* If loop playback is not a mode, then we should cancel
2213 it when this action is requested. If it is a mode
2214 we just leave it in place.
2217 if (!Config->get_loop_is_mode()) {
2218 /* XXX it is not possible to just leave seamless loop and keep
2219 playing at present (nov 4th 2009)
2221 if (!Config->get_seamless_loop()) {
2222 /* stop loop playback and stop rolling */
2223 _session->request_play_loop (false, true);
2224 } else if (rolling) {
2225 /* stop loop playback but keep rolling */
2226 _session->request_play_loop (false, false);
2230 } else if (_session->get_play_range () ) {
2231 /* stop playing a range if we currently are */
2232 _session->request_play_range (0, true);
2236 _session->request_transport_speed (1.0f);
2241 ARDOUR_UI::get_smart_mode() const
2243 return ( editor->get_smart_mode() );
2248 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
2254 if (_session->is_auditioning()) {
2255 _session->cancel_audition ();
2259 if (_session->config.get_external_sync()) {
2260 switch (Config->get_sync_source()) {
2264 /* transport controlled by the master */
2269 bool rolling = _session->transport_rolling();
2270 bool affect_transport = true;
2272 if (rolling && roll_out_of_bounded_mode) {
2273 /* drop out of loop/range playback but leave transport rolling */
2274 if (_session->get_play_loop()) {
2275 if (_session->actively_recording()) {
2277 /* just stop using the loop, then actually stop
2280 _session->request_play_loop (false, affect_transport);
2283 if (Config->get_seamless_loop()) {
2284 /* the disk buffers contain copies of the loop - we can't
2285 just keep playing, so stop the transport. the user
2286 can restart as they wish.
2288 affect_transport = true;
2290 /* disk buffers are normal, so we can keep playing */
2291 affect_transport = false;
2293 _session->request_play_loop (false, affect_transport);
2295 } else if (_session->get_play_range ()) {
2296 affect_transport = false;
2297 _session->request_play_range (0, true);
2301 if (affect_transport) {
2303 _session->request_stop (with_abort, true);
2305 /* the only external sync condition we can be in here
2306 * would be Engine (JACK) sync, in which case we still
2310 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
2311 _session->request_play_range (&editor->get_selection().time, true);
2312 _session->set_requested_return_frame( editor->get_selection().time.front().start ); //force an auto-return here
2314 _session->request_transport_speed (1.0f);
2320 ARDOUR_UI::toggle_session_auto_loop ()
2326 Location * looploc = _session->locations()->auto_loop_location();
2332 if (_session->get_play_loop()) {
2334 /* looping enabled, our job is to disable it */
2336 _session->request_play_loop (false);
2340 /* looping not enabled, our job is to enable it.
2342 loop-is-NOT-mode: this action always starts the transport rolling.
2343 loop-IS-mode: this action simply sets the loop play mechanism, but
2344 does not start transport.
2346 if (Config->get_loop_is_mode()) {
2347 _session->request_play_loop (true, false);
2349 _session->request_play_loop (true, true);
2353 //show the loop markers
2354 looploc->set_hidden (false, this);
2358 ARDOUR_UI::transport_play_selection ()
2364 editor->play_selection ();
2368 ARDOUR_UI::transport_play_preroll ()
2373 editor->play_with_preroll ();
2377 ARDOUR_UI::transport_rewind (int option)
2379 float current_transport_speed;
2382 current_transport_speed = _session->transport_speed();
2384 if (current_transport_speed >= 0.0f) {
2387 _session->request_transport_speed (-1.0f);
2390 _session->request_transport_speed (-4.0f);
2393 _session->request_transport_speed (-0.5f);
2398 _session->request_transport_speed (current_transport_speed * 1.5f);
2404 ARDOUR_UI::transport_forward (int option)
2410 float current_transport_speed = _session->transport_speed();
2412 if (current_transport_speed <= 0.0f) {
2415 _session->request_transport_speed (1.0f);
2418 _session->request_transport_speed (4.0f);
2421 _session->request_transport_speed (0.5f);
2426 _session->request_transport_speed (current_transport_speed * 1.5f);
2431 ARDOUR_UI::toggle_record_enable (uint16_t rid)
2437 boost::shared_ptr<Route> r;
2439 if ((r = _session->get_remote_nth_route (rid)) != 0) {
2441 boost::shared_ptr<Track> t;
2443 if ((t = boost::dynamic_pointer_cast<Track>(r)) != 0) {
2444 t->rec_enable_control()->set_value (!t->rec_enable_control()->get_value(), Controllable::UseGroup);
2450 ARDOUR_UI::map_transport_state ()
2453 auto_loop_button.unset_active_state ();
2454 play_selection_button.unset_active_state ();
2455 roll_button.unset_active_state ();
2456 stop_button.set_active_state (Gtkmm2ext::ExplicitActive);
2460 shuttle_box->map_transport_state ();
2462 float sp = _session->transport_speed();
2468 if (_session->get_play_range()) {
2470 play_selection_button.set_active_state (Gtkmm2ext::ExplicitActive);
2471 roll_button.unset_active_state ();
2472 auto_loop_button.unset_active_state ();
2474 } else if (_session->get_play_loop ()) {
2476 auto_loop_button.set_active (true);
2477 play_selection_button.set_active (false);
2478 if (Config->get_loop_is_mode()) {
2479 roll_button.set_active (true);
2481 roll_button.set_active (false);
2486 roll_button.set_active (true);
2487 play_selection_button.set_active (false);
2488 auto_loop_button.set_active (false);
2491 if (UIConfiguration::instance().get_follow_edits() && !_session->config.get_external_sync()) {
2492 /* light up both roll and play-selection if they are joined */
2493 roll_button.set_active (true);
2494 play_selection_button.set_active (true);
2497 stop_button.set_active (false);
2501 stop_button.set_active (true);
2502 roll_button.set_active (false);
2503 play_selection_button.set_active (false);
2504 if (Config->get_loop_is_mode ()) {
2505 auto_loop_button.set_active (_session->get_play_loop());
2507 auto_loop_button.set_active (false);
2509 update_disk_space ();
2514 ARDOUR_UI::blink_handler (bool blink_on)
2516 transport_rec_enable_blink (blink_on);
2517 solo_blink (blink_on);
2518 sync_blink (blink_on);
2519 audition_blink (blink_on);
2520 feedback_blink (blink_on);
2521 error_blink (blink_on);
2525 ARDOUR_UI::update_clocks ()
2527 if (!_session) return;
2529 if (editor && !editor->dragging_playhead()) {
2530 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD)); /* EMIT_SIGNAL */
2535 ARDOUR_UI::start_clocking ()
2537 if (UIConfiguration::instance().get_super_rapid_clock_update()) {
2538 clock_signal_connection = Timers::fps_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2540 clock_signal_connection = Timers::rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2545 ARDOUR_UI::stop_clocking ()
2547 clock_signal_connection.disconnect ();
2551 ARDOUR_UI::save_as_progress_update (float fraction, int64_t cnt, int64_t total, Gtk::Label* label, Gtk::ProgressBar* bar)
2555 snprintf (buf, sizeof (buf), _("Copied %" PRId64 " of %" PRId64), cnt, total);
2557 label->set_text (buf);
2558 bar->set_fraction (fraction);
2560 /* process events, redraws, etc. */
2562 while (gtk_events_pending()) {
2563 gtk_main_iteration ();
2566 return true; /* continue with save-as */
2570 ARDOUR_UI::save_session_as ()
2576 if (!save_as_dialog) {
2577 save_as_dialog = new SaveAsDialog;
2580 save_as_dialog->set_name (_session->name());
2582 int response = save_as_dialog->run ();
2584 save_as_dialog->hide ();
2587 case Gtk::RESPONSE_OK:
2596 sa.new_parent_folder = save_as_dialog->new_parent_folder ();
2597 sa.new_name = save_as_dialog->new_name ();
2598 sa.switch_to = save_as_dialog->switch_to();
2599 sa.copy_media = save_as_dialog->copy_media();
2600 sa.copy_external = save_as_dialog->copy_external();
2601 sa.include_media = save_as_dialog->include_media ();
2603 /* Only bother with a progress dialog if we're going to copy
2604 media into the save-as target. Without that choice, this
2605 will be very fast because we're only talking about a few kB's to
2606 perhaps a couple of MB's of data.
2609 ArdourDialog progress_dialog (_("Save As"), true);
2611 if (sa.include_media && sa.copy_media) {
2614 Gtk::ProgressBar progress_bar;
2616 progress_dialog.get_vbox()->pack_start (label);
2617 progress_dialog.get_vbox()->pack_start (progress_bar);
2619 progress_bar.show ();
2621 /* this signal will be emitted from within this, the calling thread,
2622 * after every file is copied. It provides information on percentage
2623 * complete (in terms of total data to copy), the number of files
2624 * copied so far, and the total number to copy.
2629 sa.Progress.connect_same_thread (c, boost::bind (&ARDOUR_UI::save_as_progress_update, this, _1, _2, _3, &label, &progress_bar));
2631 progress_dialog.show_all ();
2632 progress_dialog.present ();
2635 if (_session->save_as (sa)) {
2637 MessageDialog msg (string_compose (_("Save As failed: %1"), sa.failure_message));
2641 if (!sa.include_media) {
2642 unload_session (false);
2643 load_session (sa.final_session_folder_name, sa.new_name);
2648 ARDOUR_UI::quick_snapshot_session (bool switch_to_it)
2652 struct tm local_time;
2655 localtime_r (&n, &local_time);
2656 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2658 save_state (timebuf, switch_to_it);
2663 ARDOUR_UI::process_snapshot_session_prompter (ArdourPrompter& prompter, bool switch_to_it)
2667 prompter.get_result (snapname);
2669 bool do_save = (snapname.length() != 0);
2672 char illegal = Session::session_name_is_legal(snapname);
2674 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2675 "snapshot names may not contain a '%1' character"), illegal));
2681 vector<std::string> p;
2682 get_state_files_in_directory (_session->session_directory().root_path(), p);
2683 vector<string> n = get_file_names_no_extension (p);
2685 if (find (n.begin(), n.end(), snapname) != n.end()) {
2687 do_save = overwrite_file_dialog (prompter,
2688 _("Confirm Snapshot Overwrite"),
2689 _("A snapshot already exists with that name. Do you want to overwrite it?"));
2693 save_state (snapname, switch_to_it);
2703 /** Ask the user for the name of a new snapshot and then take it.
2707 ARDOUR_UI::snapshot_session (bool switch_to_it)
2709 ArdourPrompter prompter (true);
2711 prompter.set_name ("Prompter");
2712 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2714 prompter.set_title (_("Snapshot and switch"));
2715 prompter.set_prompt (_("New session name"));
2717 prompter.set_title (_("Take Snapshot"));
2718 prompter.set_prompt (_("Name of new snapshot"));
2722 prompter.set_initial_text (_session->snap_name());
2726 struct tm local_time;
2729 localtime_r (&n, &local_time);
2730 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2731 prompter.set_initial_text (timebuf);
2734 bool finished = false;
2736 switch (prompter.run()) {
2737 case RESPONSE_ACCEPT:
2739 finished = process_snapshot_session_prompter (prompter, switch_to_it);
2750 /** Ask the user for a new session name and then rename the session to it.
2754 ARDOUR_UI::rename_session ()
2760 ArdourPrompter prompter (true);
2763 prompter.set_name ("Prompter");
2764 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2765 prompter.set_title (_("Rename Session"));
2766 prompter.set_prompt (_("New session name"));
2769 switch (prompter.run()) {
2770 case RESPONSE_ACCEPT:
2772 prompter.get_result (name);
2774 bool do_rename = (name.length() != 0);
2777 char illegal = Session::session_name_is_legal (name);
2780 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2781 "session names may not contain a '%1' character"), illegal));
2786 switch (_session->rename (name)) {
2788 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
2789 msg.set_position (WIN_POS_MOUSE);
2797 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
2798 msg.set_position (WIN_POS_MOUSE);
2814 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2816 if (!_session || _session->deletion_in_progress()) {
2820 XMLNode* node = new XMLNode (X_("UI"));
2822 WM::Manager::instance().add_state (*node);
2824 node->add_child_nocopy (gui_object_state->get_state());
2826 _session->add_extra_xml (*node);
2828 if (export_video_dialog) {
2829 _session->add_extra_xml (export_video_dialog->get_state());
2832 save_state_canfail (name, switch_to_it);
2836 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2841 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2846 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2851 ARDOUR_UI::primary_clock_value_changed ()
2854 _session->request_locate (primary_clock->current_time ());
2859 ARDOUR_UI::big_clock_value_changed ()
2862 _session->request_locate (big_clock->current_time ());
2867 ARDOUR_UI::secondary_clock_value_changed ()
2870 _session->request_locate (secondary_clock->current_time ());
2875 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2877 if (_session == 0) {
2881 if (_session->step_editing()) {
2885 Session::RecordState const r = _session->record_status ();
2886 bool const h = _session->have_rec_enabled_track ();
2888 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2890 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2892 rec_button.set_active_state (Gtkmm2ext::Off);
2894 } else if (r == Session::Recording && h) {
2895 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2897 rec_button.unset_active_state ();
2902 ARDOUR_UI::process_save_template_prompter (ArdourPrompter& prompter)
2906 prompter.get_result (name);
2908 if (name.length()) {
2909 int failed = _session->save_template (name);
2911 if (failed == -2) { /* file already exists. */
2912 bool overwrite = overwrite_file_dialog (prompter,
2913 _("Confirm Template Overwrite"),
2914 _("A template already exists with that name. Do you want to overwrite it?"));
2917 _session->save_template (name, true);
2929 ARDOUR_UI::save_template ()
2931 ArdourPrompter prompter (true);
2933 if (!check_audioengine (_main_window)) {
2937 prompter.set_name (X_("Prompter"));
2938 prompter.set_title (_("Save Template"));
2939 prompter.set_prompt (_("Name for template:"));
2940 prompter.set_initial_text(_session->name() + _("-template"));
2941 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2943 bool finished = false;
2945 switch (prompter.run()) {
2946 case RESPONSE_ACCEPT:
2947 finished = process_save_template_prompter (prompter);
2958 ARDOUR_UI::edit_metadata ()
2960 SessionMetadataEditor dialog;
2961 dialog.set_session (_session);
2962 dialog.grab_focus ();
2967 ARDOUR_UI::import_metadata ()
2969 SessionMetadataImporter dialog;
2970 dialog.set_session (_session);
2975 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
2977 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2979 MessageDialog msg (str,
2981 Gtk::MESSAGE_WARNING,
2982 Gtk::BUTTONS_YES_NO,
2986 msg.set_name (X_("OpenExistingDialog"));
2987 msg.set_title (_("Open Existing Session"));
2988 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
2989 msg.set_position (Gtk::WIN_POS_CENTER);
2990 pop_back_splash (msg);
2992 switch (msg.run()) {
3001 ARDOUR_UI::build_session_from_dialog (SessionDialog& sd, const std::string& session_path, const std::string& session_name)
3003 BusProfile bus_profile;
3007 bus_profile.master_out_channels = 2;
3008 bus_profile.input_ac = AutoConnectPhysical;
3009 bus_profile.output_ac = AutoConnectMaster;
3010 bus_profile.requested_physical_in = 0; // use all available
3011 bus_profile.requested_physical_out = 0; // use all available
3015 /* get settings from advanced section of NSD */
3017 if (sd.create_master_bus()) {
3018 bus_profile.master_out_channels = (uint32_t) sd.master_channel_count();
3020 bus_profile.master_out_channels = 0;
3023 if (sd.connect_inputs()) {
3024 bus_profile.input_ac = AutoConnectPhysical;
3026 bus_profile.input_ac = AutoConnectOption (0);
3029 bus_profile.output_ac = AutoConnectOption (0);
3031 if (sd.connect_outputs ()) {
3032 if (sd.connect_outs_to_master()) {
3033 bus_profile.output_ac = AutoConnectMaster;
3034 } else if (sd.connect_outs_to_physical()) {
3035 bus_profile.output_ac = AutoConnectPhysical;
3039 bus_profile.requested_physical_in = (uint32_t) sd.input_limit_count();
3040 bus_profile.requested_physical_out = (uint32_t) sd.output_limit_count();
3043 if (build_session (session_path, session_name, bus_profile)) {
3051 ARDOUR_UI::load_from_application_api (const std::string& path)
3053 ARDOUR_COMMAND_LINE::session_name = path;
3054 /* Cancel SessionDialog if it's visible to make OSX delegates work.
3056 * ARDOUR_UI::starting connects app->ShouldLoad signal and then shows a SessionDialog
3058 * - ShouldLoad does not arrive in time, ARDOUR_COMMAND_LINE::session_name is empty:
3059 * -> ARDOUR_UI::get_session_parameters starts a SessionDialog.
3060 * - ShouldLoad signal arrives, this function is called and sets ARDOUR_COMMAND_LINE::session_name
3061 * -> SessionDialog is not displayed
3064 if (_session_dialog) {
3065 std::string session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3066 std::string session_path = path;
3067 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_REGULAR)) {
3068 session_path = Glib::path_get_dirname (session_path);
3070 // signal the existing dialog in ARDOUR_UI::get_session_parameters()
3071 _session_dialog->set_provided_session (session_name, session_path);
3072 _session_dialog->response (RESPONSE_NONE);
3073 _session_dialog->hide();
3078 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
3079 /* /path/to/foo => /path/to/foo, foo */
3080 rv = load_session (path, basename_nosuffix (path));
3082 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
3083 rv =load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
3086 // if load_session fails -> pop up SessionDialog.
3088 ARDOUR_COMMAND_LINE::session_name = "";
3090 if (get_session_parameters (true, false)) {
3096 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
3098 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
3100 string session_name;
3101 string session_path;
3102 string template_name;
3104 bool likely_new = false;
3105 bool cancel_not_quit;
3107 /* deal with any existing DIRTY session now, rather than later. don't
3108 * treat a non-dirty session this way, so that it stays visible
3109 * as we bring up the new session dialog.
3112 if (_session && ARDOUR_UI::instance()->video_timeline) {
3113 ARDOUR_UI::instance()->video_timeline->sync_session_state();
3116 /* if there is already a session, relabel the button
3117 on the SessionDialog so that we don't Quit directly
3119 cancel_not_quit = (_session != 0);
3121 if (_session && _session->dirty()) {
3122 if (unload_session (false)) {
3123 /* unload cancelled by user */
3126 ARDOUR_COMMAND_LINE::session_name = "";
3129 if (!load_template.empty()) {
3130 should_be_new = true;
3131 template_name = load_template;
3134 session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3135 session_path = ARDOUR_COMMAND_LINE::session_name;
3137 if (!session_path.empty()) {
3138 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_EXISTS)) {
3139 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_IS_REGULAR)) {
3140 /* session/snapshot file, change path to be dir */
3141 session_path = Glib::path_get_dirname (session_path);
3146 SessionDialog session_dialog (should_be_new, session_name, session_path, load_template, cancel_not_quit);
3148 _session_dialog = &session_dialog;
3151 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
3153 /* if they named a specific statefile, use it, otherwise they are
3154 just giving a session folder, and we want to use it as is
3155 to find the session.
3158 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
3160 if (suffix != string::npos) {
3161 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
3162 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
3163 session_name = Glib::path_get_basename (session_name);
3165 session_path = ARDOUR_COMMAND_LINE::session_name;
3166 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
3171 session_dialog.clear_given ();
3174 if (should_be_new || session_name.empty()) {
3175 /* need the dialog to get info from user */
3177 cerr << "run dialog\n";
3179 switch (session_dialog.run()) {
3180 case RESPONSE_ACCEPT:
3183 /* this is used for async * app->ShouldLoad(). */
3184 continue; // while loop
3187 if (quit_on_cancel) {
3188 // JE - Currently (July 2014) this section can only get reached if the
3189 // user quits from the main 'Session Setup' dialog (i.e. reaching this
3190 // point does NOT indicate an abnormal termination). Therefore, let's
3191 // behave gracefully (i.e. let's do some cleanup) before we call exit()
3193 pthread_cancel_all ();
3201 session_dialog.hide ();
3204 /* if we run the startup dialog again, offer more than just "new session" */
3206 should_be_new = false;
3208 session_name = session_dialog.session_name (likely_new);
3209 session_path = session_dialog.session_folder ();
3215 string::size_type suffix = session_name.find (statefile_suffix);
3217 if (suffix != string::npos) {
3218 session_name = session_name.substr (0, suffix);
3221 /* this shouldn't happen, but we catch it just in case it does */
3223 if (session_name.empty()) {
3227 if (session_dialog.use_session_template()) {
3228 template_name = session_dialog.session_template_name();
3229 _session_is_new = true;
3232 if (session_name[0] == G_DIR_SEPARATOR ||
3233 #ifdef PLATFORM_WINDOWS
3234 (session_name.length() > 3 && session_name[1] == ':' && session_name[2] == G_DIR_SEPARATOR)
3236 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
3237 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)
3242 /* absolute path or cwd-relative path specified for session name: infer session folder
3243 from what was given.
3246 session_path = Glib::path_get_dirname (session_name);
3247 session_name = Glib::path_get_basename (session_name);
3251 session_path = session_dialog.session_folder();
3253 char illegal = Session::session_name_is_legal (session_name);
3256 MessageDialog msg (session_dialog,
3257 string_compose (_("To ensure compatibility with various systems\n"
3258 "session names may not contain a '%1' character"),
3261 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3266 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
3269 if (likely_new && !nsm) {
3271 std::string existing = Glib::build_filename (session_path, session_name);
3273 if (!ask_about_loading_existing_session (existing)) {
3274 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3279 _session_is_new = false;
3284 pop_back_splash (session_dialog);
3285 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
3287 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3291 char illegal = Session::session_name_is_legal(session_name);
3294 pop_back_splash (session_dialog);
3295 MessageDialog msg (session_dialog, string_compose(_("To ensure compatibility with various systems\n"
3296 "session names may not contain a '%1' character"), illegal));
3298 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3302 _session_is_new = true;
3305 if (likely_new && template_name.empty()) {
3307 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3311 ret = load_session (session_path, session_name, template_name);
3314 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
3318 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
3319 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
3323 /* clear this to avoid endless attempts to load the
3327 ARDOUR_COMMAND_LINE::session_name = "";
3331 _session_dialog = NULL;
3337 ARDOUR_UI::close_session()
3339 if (!check_audioengine (_main_window)) {
3343 if (unload_session (true)) {
3347 ARDOUR_COMMAND_LINE::session_name = "";
3349 if (get_session_parameters (true, false)) {
3352 if (splash && splash->is_visible()) {
3353 // in 1 second, hide the splash screen
3354 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
3358 /** @param snap_name Snapshot name (without .ardour suffix).
3359 * @return -2 if the load failed because we are not connected to the AudioEngine.
3362 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
3364 Session *new_session;
3369 unload_status = unload_session ();
3371 if (unload_status < 0) {
3373 } else if (unload_status > 0) {
3379 session_loaded = false;
3381 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
3384 new_session = new Session (*AudioEngine::instance(), path, snap_name, 0, mix_template);
3387 /* this one is special */
3389 catch (AudioEngine::PortRegistrationFailure& err) {
3391 MessageDialog msg (err.what(),
3394 Gtk::BUTTONS_CLOSE);
3396 msg.set_title (_("Port Registration Error"));
3397 msg.set_secondary_text (_("Click the Close button to try again."));
3398 msg.set_position (Gtk::WIN_POS_CENTER);
3399 pop_back_splash (msg);
3402 int response = msg.run ();
3407 case RESPONSE_CANCEL:
3414 catch (SessionException e) {
3415 MessageDialog msg (string_compose(
3416 _("Session \"%1 (snapshot %2)\" did not load successfully: %3"),
3417 path, snap_name, e.what()),
3422 msg.set_title (_("Loading Error"));
3423 msg.set_position (Gtk::WIN_POS_CENTER);
3424 pop_back_splash (msg);
3436 MessageDialog msg (string_compose(
3437 _("Session \"%1 (snapshot %2)\" did not load successfully"),
3443 msg.set_title (_("Loading Error"));
3444 msg.set_position (Gtk::WIN_POS_CENTER);
3445 pop_back_splash (msg);
3457 list<string> const u = new_session->unknown_processors ();
3459 MissingPluginDialog d (_session, u);
3464 if (!new_session->writable()) {
3465 MessageDialog msg (_("This session has been opened in read-only mode.\n\nYou will not be able to record or save."),
3470 msg.set_title (_("Read-only Session"));
3471 msg.set_position (Gtk::WIN_POS_CENTER);
3472 pop_back_splash (msg);
3479 /* Now the session been created, add the transport controls */
3480 new_session->add_controllable(roll_controllable);
3481 new_session->add_controllable(stop_controllable);
3482 new_session->add_controllable(goto_start_controllable);
3483 new_session->add_controllable(goto_end_controllable);
3484 new_session->add_controllable(auto_loop_controllable);
3485 new_session->add_controllable(play_selection_controllable);
3486 new_session->add_controllable(rec_controllable);
3488 set_session (new_session);
3490 session_loaded = true;
3493 _session->set_clean ();
3496 #ifdef WINDOWS_VST_SUPPORT
3497 fst_stop_threading();
3501 Timers::TimerSuspender t;
3505 #ifdef WINDOWS_VST_SUPPORT
3506 fst_start_threading();
3515 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
3517 Session *new_session;
3520 session_loaded = false;
3521 x = unload_session ();
3529 _session_is_new = true;
3532 new_session = new Session (*AudioEngine::instance(), path, snap_name, &bus_profile);
3535 catch (SessionException e) {
3537 MessageDialog msg (string_compose(_("Could not create session in \"%1\": %2"), path, e.what()));
3538 msg.set_title (_("Loading Error"));
3539 msg.set_position (Gtk::WIN_POS_CENTER);
3540 pop_back_splash (msg);
3546 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
3547 msg.set_title (_("Loading Error"));
3548 msg.set_position (Gtk::WIN_POS_CENTER);
3549 pop_back_splash (msg);
3554 /* Give the new session the default GUI state, if such things exist */
3557 n = Config->instant_xml (X_("Editor"));
3559 n->remove_nodes_and_delete ("Selection"); // no not apply selection to new sessions.
3560 new_session->add_instant_xml (*n, false);
3562 n = Config->instant_xml (X_("Mixer"));
3564 new_session->add_instant_xml (*n, false);
3567 /* Put the playhead at 0 and scroll fully left */
3568 n = new_session->instant_xml (X_("Editor"));
3570 n->add_property (X_("playhead"), X_("0"));
3571 n->add_property (X_("left-frame"), X_("0"));
3574 set_session (new_session);
3576 session_loaded = true;
3578 new_session->save_state(new_session->name());
3584 ARDOUR_UI::launch_chat ()
3586 MessageDialog dialog(_("<b>Just ask and wait for an answer.\nIt may take from minutes to hours.</b>"), true);
3588 dialog.set_title (_("About the Chat"));
3589 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."));
3591 switch (dialog.run()) {
3594 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
3595 #elif defined PLATFORM_WINDOWS
3596 open_uri("http://webchat.freenode.net/?channels=ardour-windows");
3598 open_uri("http://webchat.freenode.net/?channels=ardour");
3607 ARDOUR_UI::launch_manual ()
3609 PBD::open_uri (Config->get_tutorial_manual_url());
3613 ARDOUR_UI::launch_reference ()
3615 PBD::open_uri (Config->get_reference_manual_url());
3619 ARDOUR_UI::launch_tracker ()
3621 PBD::open_uri ("http://tracker.ardour.org");
3625 ARDOUR_UI::launch_subscribe ()
3627 PBD::open_uri ("https://community.ardour.org/s/subscribe");
3631 ARDOUR_UI::launch_cheat_sheet ()
3634 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheat_sheet_osx.pdf");
3636 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheatsheet.pdf");
3641 ARDOUR_UI::launch_website ()
3643 PBD::open_uri ("http://ardour.org");
3647 ARDOUR_UI::launch_website_dev ()
3649 PBD::open_uri ("http://ardour.org/development.html");
3653 ARDOUR_UI::launch_forums ()
3655 PBD::open_uri ("https://community.ardour.org/forums");
3659 ARDOUR_UI::launch_howto_report ()
3661 PBD::open_uri ("http://ardour.org/reporting_bugs");
3665 ARDOUR_UI::loading_message (const std::string& msg)
3667 if (ARDOUR_COMMAND_LINE::no_splash) {
3675 splash->message (msg);
3679 ARDOUR_UI::show_splash ()
3683 splash = new Splash;
3693 ARDOUR_UI::hide_splash ()
3700 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title, const bool msg_delete)
3704 removed = rep.paths.size();
3707 MessageDialog msgd (_main_window,
3708 _("No files were ready for clean-up"),
3712 msgd.set_title (_("Clean-up"));
3713 msgd.set_secondary_text (_("If this seems suprising, \n\
3714 check for any existing snapshots.\n\
3715 These may still include regions that\n\
3716 require some unused files to continue to exist."));
3722 ArdourDialog results (_("Clean-up"), true, false);
3724 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
3725 CleanupResultsModelColumns() {
3729 Gtk::TreeModelColumn<std::string> visible_name;
3730 Gtk::TreeModelColumn<std::string> fullpath;
3734 CleanupResultsModelColumns results_columns;
3735 Glib::RefPtr<Gtk::ListStore> results_model;
3736 Gtk::TreeView results_display;
3738 results_model = ListStore::create (results_columns);
3739 results_display.set_model (results_model);
3740 results_display.append_column (list_title, results_columns.visible_name);
3742 results_display.set_name ("CleanupResultsList");
3743 results_display.set_headers_visible (true);
3744 results_display.set_headers_clickable (false);
3745 results_display.set_reorderable (false);
3747 Gtk::ScrolledWindow list_scroller;
3750 Gtk::HBox dhbox; // the hbox for the image and text
3751 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
3752 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
3754 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
3756 const string dead_directory = _session->session_directory().dead_path();
3759 %1 - number of files removed
3760 %2 - location of "dead"
3761 %3 - size of files affected
3762 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
3765 const char* bprefix;
3766 double space_adjusted = 0;
3768 if (rep.space < 1000) {
3770 space_adjusted = rep.space;
3771 } else if (rep.space < 1000000) {
3772 bprefix = _("kilo");
3773 space_adjusted = floorf((float)rep.space / 1000.0);
3774 } else if (rep.space < 1000000 * 1000) {
3775 bprefix = _("mega");
3776 space_adjusted = floorf((float)rep.space / (1000.0 * 1000.0));
3778 bprefix = _("giga");
3779 space_adjusted = floorf((float)rep.space / (1000.0 * 1000 * 1000.0));
3783 txt.set_markup (string_compose (P_("\
3784 The following file was deleted from %2,\n\
3785 releasing %3 %4bytes of disk space", "\
3786 The following %1 files were deleted from %2,\n\
3787 releasing %3 %4bytes of disk space", removed),
3788 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3790 txt.set_markup (string_compose (P_("\
3791 The following file was not in use and \n\
3792 has been moved to: %2\n\n\
3793 After a restart of %5\n\n\
3794 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3795 will release an additional %3 %4bytes of disk space.\n", "\
3796 The following %1 files were not in use and \n\
3797 have been moved to: %2\n\n\
3798 After a restart of %5\n\n\
3799 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3800 will release an additional %3 %4bytes of disk space.\n", removed),
3801 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3804 dhbox.pack_start (*dimage, true, false, 5);
3805 dhbox.pack_start (txt, true, false, 5);
3807 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
3808 TreeModel::Row row = *(results_model->append());
3809 row[results_columns.visible_name] = *i;
3810 row[results_columns.fullpath] = *i;
3813 list_scroller.add (results_display);
3814 list_scroller.set_size_request (-1, 150);
3815 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
3817 dvbox.pack_start (dhbox, true, false, 5);
3818 dvbox.pack_start (list_scroller, true, false, 5);
3819 ddhbox.pack_start (dvbox, true, false, 5);
3821 results.get_vbox()->pack_start (ddhbox, true, false, 5);
3822 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
3823 results.set_default_response (RESPONSE_CLOSE);
3824 results.set_position (Gtk::WIN_POS_MOUSE);
3826 results_display.show();
3827 list_scroller.show();
3834 //results.get_vbox()->show();
3835 results.set_resizable (false);
3842 ARDOUR_UI::cleanup ()
3844 if (_session == 0) {
3845 /* shouldn't happen: menu item is insensitive */
3850 MessageDialog checker (_("Are you sure you want to clean-up?"),
3852 Gtk::MESSAGE_QUESTION,
3855 checker.set_title (_("Clean-up"));
3857 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
3858 ALL undo/redo information will be lost if you clean-up.\n\
3859 Clean-up will move all unused files to a \"dead\" location."));
3861 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3862 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
3863 checker.set_default_response (RESPONSE_CANCEL);
3865 checker.set_name (_("CleanupDialog"));
3866 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3867 checker.set_position (Gtk::WIN_POS_MOUSE);
3869 switch (checker.run()) {
3870 case RESPONSE_ACCEPT:
3876 ARDOUR::CleanupReport rep;
3878 editor->prepare_for_cleanup ();
3880 /* do not allow flush until a session is reloaded */
3882 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3884 act->set_sensitive (false);
3887 if (_session->cleanup_sources (rep)) {
3888 editor->finish_cleanup ();
3892 editor->finish_cleanup ();
3895 display_cleanup_results (rep, _("Cleaned Files"), false);
3899 ARDOUR_UI::flush_trash ()
3901 if (_session == 0) {
3902 /* shouldn't happen: menu item is insensitive */
3906 ARDOUR::CleanupReport rep;
3908 if (_session->cleanup_trash_sources (rep)) {
3912 display_cleanup_results (rep, _("deleted file"), true);
3916 ARDOUR_UI::cleanup_peakfiles ()
3918 if (_session == 0) {
3919 /* shouldn't happen: menu item is insensitive */
3923 if (! _session->can_cleanup_peakfiles ()) {
3927 // get all region-views in this session
3929 TrackViewList empty;
3931 editor->get_regions_after(rs, (framepos_t) 0, empty);
3932 std::list<RegionView*> views = rs.by_layer();
3934 // remove displayed audio-region-views waveforms
3935 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
3936 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
3937 if (!arv) { continue ; }
3938 arv->delete_waves();
3941 // cleanup peak files:
3942 // - stop pending peakfile threads
3943 // - close peakfiles if any
3944 // - remove peak dir in session
3945 // - setup peakfiles (background thread)
3946 _session->cleanup_peakfiles ();
3948 // re-add waves to ARV
3949 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
3950 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
3951 if (!arv) { continue ; }
3952 arv->create_waves();
3956 PresentationInfo::order_t
3957 ARDOUR_UI::translate_order (AddRouteDialog::InsertAt place)
3959 if (editor->get_selection().tracks.empty()) {
3960 return PresentationInfo::max_order;
3963 PresentationInfo::order_t order_hint = PresentationInfo::max_order;
3966 we want the new routes to have their order keys set starting from
3967 the highest order key in the selection + 1 (if available).
3970 if (place == AddRouteDialog::AfterSelection) {
3971 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.back());
3973 order_hint = rtav->route()->presentation_info().order();
3976 } else if (place == AddRouteDialog::BeforeSelection) {
3977 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.front());
3979 order_hint = rtav->route()->presentation_info().order();
3981 } else if (place == AddRouteDialog::First) {
3984 /* leave order_hint at max_order */
3991 ARDOUR_UI::start_duplicate_routes ()
3993 if (!duplicate_routes_dialog) {
3994 duplicate_routes_dialog = new DuplicateRouteDialog;
3997 if (duplicate_routes_dialog->restart (_session)) {
4001 duplicate_routes_dialog->present ();
4005 ARDOUR_UI::add_route ()
4007 if (!add_route_dialog.get (false)) {
4008 add_route_dialog->signal_response().connect (sigc::mem_fun (*this, &ARDOUR_UI::add_route_dialog_finished));
4015 if (add_route_dialog->is_visible()) {
4016 /* we're already doing this */
4020 add_route_dialog->set_position (WIN_POS_MOUSE);
4021 add_route_dialog->present();
4025 ARDOUR_UI::add_route_dialog_finished (int r)
4029 add_route_dialog->hide();
4032 case RESPONSE_ACCEPT:
4039 if ((count = add_route_dialog->count()) <= 0) {
4043 PresentationInfo::order_t order = translate_order (add_route_dialog->insert_at());
4044 string template_path = add_route_dialog->track_template();
4045 DisplaySuspender ds;
4047 if (!template_path.empty()) {
4048 if (add_route_dialog->name_template_is_default()) {
4049 _session->new_route_from_template (count, template_path, string());
4051 _session->new_route_from_template (count, template_path, add_route_dialog->name_template());
4056 ChanCount input_chan= add_route_dialog->channels ();
4057 ChanCount output_chan;
4058 string name_template = add_route_dialog->name_template ();
4059 PluginInfoPtr instrument = add_route_dialog->requested_instrument ();
4060 RouteGroup* route_group = add_route_dialog->route_group ();
4061 AutoConnectOption oac = Config->get_output_auto_connect();
4062 bool strict_io = add_route_dialog->use_strict_io ();
4064 if (oac & AutoConnectMaster) {
4065 output_chan.set (DataType::AUDIO, (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan.n_audio()));
4066 output_chan.set (DataType::MIDI, 0);
4068 output_chan = input_chan;
4071 /* XXX do something with name template */
4073 switch (add_route_dialog->type_wanted()) {
4074 case AddRouteDialog::AudioTrack:
4075 session_add_audio_track (input_chan.n_audio(), output_chan.n_audio(), add_route_dialog->mode(), route_group, count, name_template, strict_io, order);
4077 case AddRouteDialog::MidiTrack:
4078 session_add_midi_track (route_group, count, name_template, strict_io, instrument, 0, order);
4080 case AddRouteDialog::MixedTrack:
4081 session_add_mixed_track (input_chan, output_chan, route_group, count, name_template, strict_io, instrument, 0, order);
4083 case AddRouteDialog::AudioBus:
4084 session_add_audio_bus (input_chan.n_audio(), output_chan.n_audio(), route_group, count, name_template, strict_io, order);
4086 case AddRouteDialog::MidiBus:
4087 session_add_midi_bus (route_group, count, name_template, strict_io, instrument, 0, order);
4089 case AddRouteDialog::VCAMaster:
4090 session_add_vca (name_template, count);
4096 ARDOUR_UI::add_lua_script ()
4102 LuaScriptInfoPtr spi;
4103 ScriptSelector ss ("Add Lua Session Script", LuaScriptInfo::Session);
4104 switch (ss.run ()) {
4105 case Gtk::RESPONSE_ACCEPT:
4113 std::string script = "";
4116 script = Glib::file_get_contents (spi->path);
4117 } catch (Glib::FileError e) {
4118 string msg = string_compose (_("Cannot read session script '%1': %2"), spi->path, e.what());
4119 MessageDialog am (msg);
4124 LuaScriptParamList lsp = LuaScriptParams::script_params (spi, "sess_params");
4125 std::vector<std::string> reg = _session->registered_lua_functions ();
4127 ScriptParameterDialog spd (_("Set Script Parameters"), spi, reg, lsp);
4128 switch (spd.run ()) {
4129 case Gtk::RESPONSE_ACCEPT:
4136 _session->register_lua_function (spd.name(), script, lsp);
4137 } catch (luabridge::LuaException const& e) {
4138 string msg = string_compose (_("Session script '%1' instantiation failed: %2"), spd.name(), e.what ());
4139 MessageDialog am (msg);
4141 } catch (SessionException e) {
4142 string msg = string_compose (_("Loading Session script '%1' failed: %2"), spd.name(), e.what ());
4143 MessageDialog am (msg);
4149 ARDOUR_UI::remove_lua_script ()
4154 if (_session->registered_lua_function_count () == 0) {
4155 string msg = _("There are no active Lua session scripts present in this session.");
4156 MessageDialog am (msg);
4161 std::vector<std::string> reg = _session->registered_lua_functions ();
4162 SessionScriptManager sm ("Remove Lua Session Script", reg);
4163 switch (sm.run ()) {
4164 case Gtk::RESPONSE_ACCEPT:
4170 _session->unregister_lua_function (sm.name());
4171 } catch (luabridge::LuaException const& e) {
4172 string msg = string_compose (_("Session script '%1' removal failed: %2"), sm.name(), e.what ());
4173 MessageDialog am (msg);
4179 ARDOUR_UI::stop_video_server (bool ask_confirm)
4181 if (!video_server_process && ask_confirm) {
4182 warning << string_compose (_("Video-Server was not launched by %1. The request to stop it is ignored."), PROGRAM_NAME) << endmsg;
4184 if (video_server_process) {
4186 ArdourDialog confirm (_("Stop Video-Server"), true);
4187 Label m (_("Do you really want to stop the Video Server?"));
4188 confirm.get_vbox()->pack_start (m, true, true);
4189 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
4190 confirm.add_button (_("Yes, Stop It"), Gtk::RESPONSE_ACCEPT);
4191 confirm.show_all ();
4192 if (confirm.run() == RESPONSE_CANCEL) {
4196 delete video_server_process;
4197 video_server_process =0;
4202 ARDOUR_UI::start_video_server_menu (Gtk::Window* float_window)
4204 ARDOUR_UI::start_video_server( float_window, true);
4208 ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg)
4214 if (ARDOUR_UI::instance()->video_timeline->check_server()) {
4215 if (video_server_process) {
4216 popup_error(_("The Video Server is already started."));
4218 popup_error(_("An external Video Server is configured and can be reached. Not starting a new instance."));
4224 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4226 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4228 VideoServerDialog *video_server_dialog = new VideoServerDialog (_session);
4230 video_server_dialog->set_transient_for (*float_window);
4233 if (!Config->get_show_video_server_dialog() && firsttime < 2) {
4234 video_server_dialog->hide();
4236 ResponseType r = (ResponseType) video_server_dialog->run ();
4237 video_server_dialog->hide();
4238 if (r != RESPONSE_ACCEPT) { return false; }
4239 if (video_server_dialog->show_again()) {
4240 Config->set_show_video_server_dialog(false);
4244 std::string icsd_exec = video_server_dialog->get_exec_path();
4245 std::string icsd_docroot = video_server_dialog->get_docroot();
4246 if (icsd_docroot.empty()) {
4247 #ifndef PLATFORM_WINDOWS
4248 icsd_docroot = X_("/");
4250 icsd_docroot = X_("C:\\");
4255 if (g_lstat (icsd_docroot.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode)) {
4256 warning << _("Specified docroot is not an existing directory.") << endmsg;
4259 #ifndef PLATFORM_WINDOWS
4260 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4261 || (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0 ) {
4262 warning << _("Given Video Server is not an executable file.") << endmsg;
4266 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4267 || (sb.st_mode & (S_IXUSR)) == 0 ) {
4268 warning << _("Given Video Server is not an executable file.") << endmsg;
4274 argp=(char**) calloc(9,sizeof(char*));
4275 argp[0] = strdup(icsd_exec.c_str());
4276 argp[1] = strdup("-P");
4277 argp[2] = (char*) calloc(16,sizeof(char)); snprintf(argp[2], 16, "%s", video_server_dialog->get_listenaddr().c_str());
4278 argp[3] = strdup("-p");
4279 argp[4] = (char*) calloc(6,sizeof(char)); snprintf(argp[4], 6, "%i", video_server_dialog->get_listenport());
4280 argp[5] = strdup("-C");
4281 argp[6] = (char*) calloc(6,sizeof(char)); snprintf(argp[6], 6, "%i", video_server_dialog->get_cachesize());
4282 argp[7] = strdup(icsd_docroot.c_str());
4284 stop_video_server();
4286 if (icsd_docroot == X_("/") || icsd_docroot == X_("C:\\")) {
4287 Config->set_video_advanced_setup(false);
4289 std::ostringstream osstream;
4290 osstream << "http://127.0.0.1:" << video_server_dialog->get_listenport() << "/";
4291 Config->set_video_server_url(osstream.str());
4292 Config->set_video_server_docroot(icsd_docroot);
4293 Config->set_video_advanced_setup(true);
4296 if (video_server_process) {
4297 delete video_server_process;
4300 video_server_process = new ARDOUR::SystemExec(icsd_exec, argp);
4301 if (video_server_process->start()) {
4302 warning << _("Cannot launch the video-server") << endmsg;
4305 int timeout = 120; // 6 sec
4306 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4307 Glib::usleep (50000);
4309 if (--timeout <= 0 || !video_server_process->is_running()) break;
4312 warning << _("Video-server was started but does not respond to requests...") << endmsg;
4314 if (!ARDOUR_UI::instance()->video_timeline->check_server_docroot()) {
4315 delete video_server_process;
4316 video_server_process = 0;
4324 ARDOUR_UI::add_video (Gtk::Window* float_window)
4330 if (!start_video_server(float_window, false)) {
4331 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4336 add_video_dialog->set_transient_for (*float_window);
4339 if (add_video_dialog->is_visible()) {
4340 /* we're already doing this */
4344 ResponseType r = (ResponseType) add_video_dialog->run ();
4345 add_video_dialog->hide();
4346 if (r != RESPONSE_ACCEPT) { return; }
4348 bool local_file, orig_local_file;
4349 std::string path = add_video_dialog->file_name(local_file);
4351 std::string orig_path = path;
4352 orig_local_file = local_file;
4354 bool auto_set_session_fps = add_video_dialog->auto_set_session_fps();
4356 if (local_file && !Glib::file_test(path, Glib::FILE_TEST_EXISTS)) {
4357 warning << string_compose(_("could not open %1"), path) << endmsg;
4360 if (!local_file && path.length() == 0) {
4361 warning << _("no video-file selected") << endmsg;
4365 std::string audio_from_video;
4366 bool detect_ltc = false;
4368 switch (add_video_dialog->import_option()) {
4369 case VTL_IMPORT_TRANSCODE:
4371 TranscodeVideoDialog *transcode_video_dialog;
4372 transcode_video_dialog = new TranscodeVideoDialog (_session, path);
4373 ResponseType r = (ResponseType) transcode_video_dialog->run ();
4374 transcode_video_dialog->hide();
4375 if (r != RESPONSE_ACCEPT) {
4376 delete transcode_video_dialog;
4380 audio_from_video = transcode_video_dialog->get_audiofile();
4382 if (!audio_from_video.empty() && transcode_video_dialog->detect_ltc()) {
4385 else if (!audio_from_video.empty()) {
4386 editor->embed_audio_from_video(
4388 video_timeline->get_offset(),
4389 (transcode_video_dialog->import_option() != VTL_IMPORT_NO_VIDEO)
4392 switch (transcode_video_dialog->import_option()) {
4393 case VTL_IMPORT_TRANSCODED:
4394 path = transcode_video_dialog->get_filename();
4397 case VTL_IMPORT_REFERENCE:
4400 delete transcode_video_dialog;
4403 delete transcode_video_dialog;
4407 case VTL_IMPORT_NONE:
4411 /* strip _session->session_directory().video_path() from video file if possible */
4412 if (local_file && !path.compare(0, _session->session_directory().video_path().size(), _session->session_directory().video_path())) {
4413 path=path.substr(_session->session_directory().video_path().size());
4414 if (path.at(0) == G_DIR_SEPARATOR) {
4415 path=path.substr(1);
4419 video_timeline->set_update_session_fps(auto_set_session_fps);
4421 if (video_timeline->video_file_info(path, local_file)) {
4422 XMLNode* node = new XMLNode(X_("Videotimeline"));
4423 node->add_property (X_("Filename"), path);
4424 node->add_property (X_("AutoFPS"), auto_set_session_fps?X_("1"):X_("0"));
4425 node->add_property (X_("LocalFile"), local_file?X_("1"):X_("0"));
4426 if (orig_local_file) {
4427 node->add_property (X_("OriginalVideoFile"), orig_path);
4429 node->remove_property (X_("OriginalVideoFile"));
4431 _session->add_extra_xml (*node);
4432 _session->set_dirty ();
4434 if (!audio_from_video.empty() && detect_ltc) {
4435 std::vector<LTCFileReader::LTCMap> ltc_seq;
4438 /* TODO ask user about TV standard (LTC alignment if any) */
4439 LTCFileReader ltcr (audio_from_video, video_timeline->get_video_file_fps());
4440 /* TODO ASK user which channel: 0 .. ltcr->channels() - 1 */
4442 ltc_seq = ltcr.read_ltc (/*channel*/ 0, /*max LTC frames to decode*/ 15);
4444 /* TODO seek near end of file, and read LTC until end.
4445 * if it fails to find any LTC frames, scan complete file
4447 * calculate drift of LTC compared to video-duration,
4448 * ask user for reference (timecode from start/mid/end)
4451 // LTCFileReader will have written error messages
4454 ::g_unlink(audio_from_video.c_str());
4456 if (ltc_seq.size() == 0) {
4457 PBD::error << _("No LTC detected, video will not be aligned.") << endmsg;
4459 /* the very first TC in the file is somteimes not aligned properly */
4460 int i = ltc_seq.size() -1;
4461 ARDOUR::frameoffset_t video_start_offset =
4462 _session->nominal_frame_rate() * (ltc_seq[i].timecode_sec - ltc_seq[i].framepos_sec);
4463 PBD::info << string_compose (_("Align video-start to %1 [samples]"), video_start_offset) << endmsg;
4464 video_timeline->set_offset(video_start_offset);
4468 _session->maybe_update_session_range(
4469 std::max(video_timeline->get_offset(), (ARDOUR::frameoffset_t) 0),
4470 std::max(video_timeline->get_offset() + video_timeline->get_duration(), (ARDOUR::frameoffset_t) 0));
4473 if (add_video_dialog->launch_xjadeo() && local_file) {
4474 editor->set_xjadeo_sensitive(true);
4475 editor->toggle_xjadeo_proc(1);
4477 editor->toggle_xjadeo_proc(0);
4479 editor->toggle_ruler_video(true);
4484 ARDOUR_UI::remove_video ()
4486 video_timeline->close_session();
4487 editor->toggle_ruler_video(false);
4490 video_timeline->set_offset_locked(false);
4491 video_timeline->set_offset(0);
4493 /* delete session state */
4494 XMLNode* node = new XMLNode(X_("Videotimeline"));
4495 _session->add_extra_xml(*node);
4496 node = new XMLNode(X_("Videomonitor"));
4497 _session->add_extra_xml(*node);
4498 node = new XMLNode(X_("Videoexport"));
4499 _session->add_extra_xml(*node);
4500 stop_video_server();
4504 ARDOUR_UI::flush_videotimeline_cache (bool localcacheonly)
4506 if (localcacheonly) {
4507 video_timeline->vmon_update();
4509 video_timeline->flush_cache();
4511 editor->queue_visual_videotimeline_update();
4515 ARDOUR_UI::export_video (bool range)
4517 if (ARDOUR::Config->get_show_video_export_info()) {
4518 ExportVideoInfobox infobox (_session);
4519 Gtk::ResponseType rv = (Gtk::ResponseType) infobox.run();
4520 if (infobox.show_again()) {
4521 ARDOUR::Config->set_show_video_export_info(false);
4524 case GTK_RESPONSE_YES:
4525 PBD::open_uri (ARDOUR::Config->get_reference_manual_url() + "/video-timeline/operations/#export");
4531 export_video_dialog->set_session (_session);
4532 export_video_dialog->apply_state(editor->get_selection().time, range);
4533 export_video_dialog->run ();
4534 export_video_dialog->hide ();
4538 ARDOUR_UI::mixer_settings () const
4543 node = _session->instant_xml(X_("Mixer"));
4545 node = Config->instant_xml(X_("Mixer"));
4549 node = new XMLNode (X_("Mixer"));
4556 ARDOUR_UI::main_window_settings () const
4561 node = _session->instant_xml(X_("Main"));
4563 node = Config->instant_xml(X_("Main"));
4567 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4568 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4573 node = new XMLNode (X_("Main"));
4580 ARDOUR_UI::editor_settings () const
4585 node = _session->instant_xml(X_("Editor"));
4587 node = Config->instant_xml(X_("Editor"));
4591 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4592 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4597 node = new XMLNode (X_("Editor"));
4604 ARDOUR_UI::keyboard_settings () const
4608 node = Config->extra_xml(X_("Keyboard"));
4611 node = new XMLNode (X_("Keyboard"));
4618 ARDOUR_UI::create_xrun_marker (framepos_t where)
4621 Location *location = new Location (*_session, where, where, _("xrun"), Location::IsMark);
4622 _session->locations()->add (location);
4627 ARDOUR_UI::halt_on_xrun_message ()
4629 cerr << "HALT on xrun\n";
4630 MessageDialog msg (_main_window, _("Recording was stopped because your system could not keep up."));
4635 ARDOUR_UI::xrun_handler (framepos_t where)
4641 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
4643 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
4644 create_xrun_marker(where);
4647 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
4648 halt_on_xrun_message ();
4653 ARDOUR_UI::disk_overrun_handler ()
4655 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
4657 if (!have_disk_speed_dialog_displayed) {
4658 have_disk_speed_dialog_displayed = true;
4659 MessageDialog* msg = new MessageDialog (_main_window, string_compose (_("\
4660 The disk system on your computer\n\
4661 was not able to keep up with %1.\n\
4663 Specifically, it failed to write data to disk\n\
4664 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
4665 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4671 /* TODO: this is getting elaborate enough to warrant being split into a dedicated class */
4672 static MessageDialog *scan_dlg = NULL;
4673 static ProgressBar *scan_pbar = NULL;
4674 static HBox *scan_tbox = NULL;
4675 static Gtk::Button *scan_timeout_button;
4678 ARDOUR_UI::cancel_plugin_scan ()
4680 PluginManager::instance().cancel_plugin_scan();
4684 ARDOUR_UI::cancel_plugin_timeout ()
4686 PluginManager::instance().cancel_plugin_timeout();
4687 scan_timeout_button->set_sensitive (false);
4691 ARDOUR_UI::plugin_scan_timeout (int timeout)
4693 if (!scan_dlg || !scan_dlg->is_mapped() || !scan_pbar) {
4697 scan_pbar->set_sensitive (false);
4698 scan_timeout_button->set_sensitive (true);
4699 scan_pbar->set_fraction ((float) timeout / (float) Config->get_vst_scan_timeout());
4702 scan_pbar->set_sensitive (false);
4703 scan_timeout_button->set_sensitive (false);
4709 ARDOUR_UI::plugin_scan_dialog (std::string type, std::string plugin, bool can_cancel)
4711 if (type == X_("closeme") && !(scan_dlg && scan_dlg->is_mapped())) {
4715 const bool cancelled = PluginManager::instance().cancelled();
4716 if (type != X_("closeme") && (!UIConfiguration::instance().get_show_plugin_scan_window()) && !_initial_verbose_plugin_scan) {
4717 if (cancelled && scan_dlg->is_mapped()) {
4722 if (cancelled || !can_cancel) {
4727 static Gtk::Button *cancel_button;
4729 scan_dlg = new MessageDialog("", false, MESSAGE_INFO, BUTTONS_NONE); // TODO manage
4730 VBox* vbox = scan_dlg->get_vbox();
4731 vbox->set_size_request(400,-1);
4732 scan_dlg->set_title (_("Scanning for plugins"));
4734 cancel_button = manage(new Gtk::Button(_("Cancel plugin scan")));
4735 cancel_button->set_name ("EditorGTKButton");
4736 cancel_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_scan) );
4737 cancel_button->show();
4739 scan_dlg->get_vbox()->pack_start ( *cancel_button, PACK_SHRINK);
4741 scan_tbox = manage( new HBox() );
4743 scan_timeout_button = manage(new Gtk::Button(_("Stop Timeout")));
4744 scan_timeout_button->set_name ("EditorGTKButton");
4745 scan_timeout_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_timeout) );
4746 scan_timeout_button->show();
4748 scan_pbar = manage(new ProgressBar());
4749 scan_pbar->set_orientation(Gtk::PROGRESS_RIGHT_TO_LEFT);
4750 scan_pbar->set_text(_("Scan Timeout"));
4753 scan_tbox->pack_start (*scan_pbar, PACK_EXPAND_WIDGET, 4);
4754 scan_tbox->pack_start (*scan_timeout_button, PACK_SHRINK, 4);
4756 scan_dlg->get_vbox()->pack_start (*scan_tbox, PACK_SHRINK, 4);
4759 assert(scan_dlg && scan_tbox && cancel_button);
4761 if (type == X_("closeme")) {
4765 scan_dlg->set_message(type + ": " + Glib::path_get_basename(plugin));
4768 if (!can_cancel || !cancelled) {
4769 scan_timeout_button->set_sensitive(false);
4771 cancel_button->set_sensitive(can_cancel && !cancelled);
4777 ARDOUR_UI::gui_idle_handler ()
4780 /* due to idle calls, gtk_events_pending() may always return true */
4781 while (gtk_events_pending() && --timeout) {
4782 gtk_main_iteration ();
4787 ARDOUR_UI::disk_underrun_handler ()
4789 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
4791 if (!have_disk_speed_dialog_displayed) {
4792 have_disk_speed_dialog_displayed = true;
4793 MessageDialog* msg = new MessageDialog (
4794 _main_window, string_compose (_("The disk system on your computer\n\
4795 was not able to keep up with %1.\n\
4797 Specifically, it failed to read data from disk\n\
4798 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
4799 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4805 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
4807 have_disk_speed_dialog_displayed = false;
4812 ARDOUR_UI::session_dialog (std::string msg)
4814 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
4818 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
4825 ARDOUR_UI::pending_state_dialog ()
4827 HBox* hbox = manage (new HBox());
4828 Image* image = manage (new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG));
4829 ArdourDialog dialog (_("Crash Recovery"), true);
4830 Label message (string_compose (_("\
4831 This session appears to have been in the\n\
4832 middle of recording when %1 or\n\
4833 the computer was shutdown.\n\
4835 %1 can recover any captured audio for\n\
4836 you, or it can ignore it. Please decide\n\
4837 what you would like to do.\n"), PROGRAM_NAME));
4838 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4839 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4840 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4841 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4842 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
4843 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
4844 dialog.set_default_response (RESPONSE_ACCEPT);
4845 dialog.set_position (WIN_POS_CENTER);
4850 switch (dialog.run ()) {
4851 case RESPONSE_ACCEPT:
4859 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
4861 HBox* hbox = new HBox();
4862 Image* image = new Image (Stock::DIALOG_WARNING, ICON_SIZE_DIALOG);
4863 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
4864 Label message (string_compose (_("\
4865 This session was created with a sample rate of %1 Hz, but\n\
4866 %2 is currently running at %3 Hz. If you load this session,\n\
4867 audio may be played at the wrong sample rate.\n"), desired, PROGRAM_NAME, actual));
4869 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4870 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4871 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4872 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4873 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
4874 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
4875 dialog.set_default_response (RESPONSE_ACCEPT);
4876 dialog.set_position (WIN_POS_CENTER);
4881 switch (dialog.run()) {
4882 case RESPONSE_ACCEPT:
4892 ARDOUR_UI::sr_mismatch_message (framecnt_t desired, framecnt_t actual)
4894 MessageDialog msg (string_compose (_("\
4895 This session was created with a sample rate of %1 Hz, but\n\
4896 %2 is currently running at %3 Hz.\n\
4897 Audio will be recorded and played at the wrong sample rate.\n\
4898 Re-Configure the Audio Engine in\n\
4899 Menu > Window > Audio/Midi Setup"),
4900 desired, PROGRAM_NAME, actual),
4902 Gtk::MESSAGE_WARNING);
4907 ARDOUR_UI::use_config ()
4909 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
4911 set_transport_controllable_state (*node);
4916 ARDOUR_UI::update_transport_clocks (framepos_t pos)
4918 if (UIConfiguration::instance().get_primary_clock_delta_edit_cursor()) {
4919 primary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
4921 primary_clock->set (pos);
4924 if (UIConfiguration::instance().get_secondary_clock_delta_edit_cursor()) {
4925 secondary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
4927 secondary_clock->set (pos);
4930 if (big_clock_window) {
4931 big_clock->set (pos);
4933 ARDOUR_UI::instance()->video_timeline->manual_seek_video_monitor(pos);
4937 ARDOUR_UI::step_edit_status_change (bool yn)
4939 // XXX should really store pre-step edit status of things
4940 // we make insensitive
4943 rec_button.set_active_state (Gtkmm2ext::ImplicitActive);
4944 rec_button.set_sensitive (false);
4946 rec_button.unset_active_state ();;
4947 rec_button.set_sensitive (true);
4952 ARDOUR_UI::record_state_changed ()
4954 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
4956 if (!_session || !big_clock_window) {
4957 /* why bother - the clock isn't visible */
4961 if (_session->record_status () == Session::Recording && _session->have_rec_enabled_track ()) {
4962 big_clock->set_active (true);
4964 big_clock->set_active (false);
4969 ARDOUR_UI::first_idle ()
4972 _session->allow_auto_play (true);
4976 editor->first_idle();
4979 Keyboard::set_can_save_keybindings (true);
4984 ARDOUR_UI::store_clock_modes ()
4986 XMLNode* node = new XMLNode(X_("ClockModes"));
4988 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
4989 XMLNode* child = new XMLNode (X_("Clock"));
4991 child->add_property (X_("name"), (*x)->name());
4992 child->add_property (X_("mode"), enum_2_string ((*x)->mode()));
4993 child->add_property (X_("on"), ((*x)->off() ? X_("no") : X_("yes")));
4995 node->add_child_nocopy (*child);
4998 _session->add_extra_xml (*node);
4999 _session->set_dirty ();
5002 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
5003 : Controllable (name), ui (u), type(tp)
5009 ARDOUR_UI::TransportControllable::set_value (double val, PBD::Controllable::GroupControlDisposition /*group_override*/)
5012 /* do nothing: these are radio-style actions */
5016 const char *action = 0;
5020 action = X_("Roll");
5023 action = X_("Stop");
5026 action = X_("GotoStart");
5029 action = X_("GotoEnd");
5032 action = X_("Loop");
5035 action = X_("PlaySelection");
5038 action = X_("Record");
5048 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
5056 ARDOUR_UI::TransportControllable::get_value (void) const
5083 ARDOUR_UI::setup_profile ()
5085 if (gdk_screen_width() < 1200 || getenv ("ARDOUR_NARROW_SCREEN")) {
5086 Profile->set_small_screen ();
5089 if (g_getenv ("TRX")) {
5090 Profile->set_trx ();
5093 if (g_getenv ("MIXBUS")) {
5094 Profile->set_mixbus ();
5099 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
5101 MissingFileDialog dialog (s, str, type);
5106 int result = dialog.run ();
5113 return 1; // quit entire session load
5116 result = dialog.get_action ();
5122 ARDOUR_UI::ambiguous_file (std::string file, std::vector<std::string> hits)
5124 AmbiguousFileDialog dialog (file, hits);
5131 return dialog.get_which ();
5134 /** Allocate our thread-local buffers */
5136 ARDOUR_UI::get_process_buffers ()
5138 _process_thread->get_buffers ();
5141 /** Drop our thread-local buffers */
5143 ARDOUR_UI::drop_process_buffers ()
5145 _process_thread->drop_buffers ();
5149 ARDOUR_UI::feedback_detected ()
5151 _feedback_exists = true;
5155 ARDOUR_UI::successful_graph_sort ()
5157 _feedback_exists = false;
5161 ARDOUR_UI::midi_panic ()
5164 _session->midi_panic();
5169 ARDOUR_UI::session_format_mismatch (std::string xml_path, std::string backup_path)
5171 const char* start_big = "<span size=\"x-large\" weight=\"bold\">";
5172 const char* end_big = "</span>";
5173 const char* start_mono = "<tt>";
5174 const char* end_mono = "</tt>";
5176 MessageDialog msg (string_compose (_("%4This is a session from an older version of %3%5\n\n"
5177 "%3 has copied the old session file\n\n%6%1%7\n\nto\n\n%6%2%7\n\n"
5178 "From now on, use the backup copy with older versions of %3"),
5179 xml_path, backup_path, PROGRAM_NAME,
5181 start_mono, end_mono), true);
5188 ARDOUR_UI::reset_peak_display ()
5190 if (!_session || !_session->master_out() || !editor_meter) return;
5191 editor_meter->clear_meters();
5192 editor_meter_max_peak = -INFINITY;
5193 editor_meter_peak_display.set_active_state ( Gtkmm2ext::Off );
5197 ARDOUR_UI::reset_group_peak_display (RouteGroup* group)
5199 if (!_session || !_session->master_out()) return;
5200 if (group == _session->master_out()->route_group()) {
5201 reset_peak_display ();
5206 ARDOUR_UI::reset_route_peak_display (Route* route)
5208 if (!_session || !_session->master_out()) return;
5209 if (_session->master_out().get() == route) {
5210 reset_peak_display ();
5215 ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate)
5217 audio_midi_setup->set_desired_sample_rate (desired_sample_rate);
5218 audio_midi_setup->set_position (WIN_POS_CENTER);
5220 if (Config->get_try_autostart_engine () || getenv ("TRY_AUTOSTART_ENGINE")) {
5221 audio_midi_setup->try_autostart ();
5222 if (ARDOUR::AudioEngine::instance()->running()) {
5228 int response = audio_midi_setup->run();
5230 case Gtk::RESPONSE_OK:
5231 if (!AudioEngine::instance()->running()) {
5245 ARDOUR_UI::transport_numpad_timeout ()
5247 _numpad_locate_happening = false;
5248 if (_numpad_timeout_connection.connected() )
5249 _numpad_timeout_connection.disconnect();
5254 ARDOUR_UI::transport_numpad_decimal ()
5256 _numpad_timeout_connection.disconnect();
5258 if (_numpad_locate_happening) {
5259 if (editor) editor->goto_nth_marker(_pending_locate_num - 1);
5260 _numpad_locate_happening = false;
5262 _pending_locate_num = 0;
5263 _numpad_locate_happening = true;
5264 _numpad_timeout_connection = Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::transport_numpad_timeout), 2*1000);
5269 ARDOUR_UI::transport_numpad_event (int num)
5271 if ( _numpad_locate_happening ) {
5272 _pending_locate_num = _pending_locate_num*10 + num;
5275 case 0: toggle_roll(false, false); break;
5276 case 1: transport_rewind(1); break;
5277 case 2: transport_forward(1); break;
5278 case 3: transport_record(true); break;
5279 case 4: toggle_session_auto_loop(); break;
5280 case 5: transport_record(false); toggle_session_auto_loop(); break;
5281 case 6: toggle_punch(); break;
5282 case 7: toggle_click(); break;
5283 case 8: toggle_auto_return(); break;
5284 case 9: toggle_follow_edits(); break;
5290 ARDOUR_UI::set_flat_buttons ()
5292 CairoWidget::set_flat_buttons( UIConfiguration::instance().get_flat_buttons() );
5296 ARDOUR_UI::audioengine_became_silent ()
5298 MessageDialog msg (string_compose (_("This is a free/demo copy of %1. It has just switched to silent mode."), PROGRAM_NAME),
5300 Gtk::MESSAGE_WARNING,
5304 msg.set_title (string_compose (_("%1 is now silent"), PROGRAM_NAME));
5306 Gtk::Label pay_label (string_compose (_("Please consider paying for a copy of %1 - you can pay whatever you want."), PROGRAM_NAME));
5307 Gtk::Label subscribe_label (_("Better yet become a subscriber - subscriptions start at US$1 per month."));
5308 Gtk::Button pay_button (_("Pay for a copy (via the web)"));
5309 Gtk::Button subscribe_button (_("Become a subscriber (via the web)"));
5310 Gtk::HBox pay_button_box;
5311 Gtk::HBox subscribe_button_box;
5313 pay_button_box.pack_start (pay_button, true, false);
5314 subscribe_button_box.pack_start (subscribe_button, true, false);
5316 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 */
5318 pay_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://ardour.org/download")));
5319 subscribe_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://community.ardour.org/s/subscribe")));
5321 msg.get_vbox()->pack_start (pay_label);
5322 msg.get_vbox()->pack_start (pay_button_box);
5323 msg.get_vbox()->pack_start (subscribe_label);
5324 msg.get_vbox()->pack_start (subscribe_button_box);
5326 msg.get_vbox()->show_all ();
5328 msg.add_button (_("Remain silent"), Gtk::RESPONSE_CANCEL);
5329 msg.add_button (_("Save and quit"), Gtk::RESPONSE_NO);
5330 msg.add_button (_("Give me more time"), Gtk::RESPONSE_YES);
5335 case Gtk::RESPONSE_YES:
5336 AudioEngine::instance()->reset_silence_countdown ();
5339 case Gtk::RESPONSE_NO:
5341 save_state_canfail ("");
5345 case Gtk::RESPONSE_CANCEL:
5347 /* don't reset, save session and exit */
5353 ARDOUR_UI::hide_application ()
5355 Application::instance ()-> hide ();
5359 ARDOUR_UI::setup_toplevel_window (Gtk::Window& window, const string& name, void* owner)
5361 /* icons, titles, WM stuff */
5363 static list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
5365 if (window_icons.empty()) {
5366 Glib::RefPtr<Gdk::Pixbuf> icon;
5367 if ((icon = ::get_icon (PROGRAM_NAME "-icon_16px")) != 0) {
5368 window_icons.push_back (icon);
5370 if ((icon = ::get_icon (PROGRAM_NAME "-icon_22px")) != 0) {
5371 window_icons.push_back (icon);
5373 if ((icon = ::get_icon (PROGRAM_NAME "-icon_32px")) != 0) {
5374 window_icons.push_back (icon);
5376 if ((icon = ::get_icon (PROGRAM_NAME "-icon_48px")) != 0) {
5377 window_icons.push_back (icon);
5381 if (!window_icons.empty()) {
5382 window.set_default_icon_list (window_icons);
5385 Gtkmm2ext::WindowTitle title (Glib::get_application_name());
5387 if (!name.empty()) {
5391 window.set_title (title.get_string());
5392 window.set_wmclass (string_compose (X_("%1_%1"), downcase (PROGRAM_NAME), downcase (name)), PROGRAM_NAME);
5394 window.set_flags (CAN_FOCUS);
5395 window.add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
5397 /* This is a hack to ensure that GTK-accelerators continue to
5398 * work. Once we switch over to entirely native bindings, this will be
5399 * unnecessary and should be removed
5401 window.add_accel_group (ActionManager::ui_manager->get_accel_group());
5403 window.signal_configure_event().connect (sigc::mem_fun (*this, &ARDOUR_UI::configure_handler));
5404 window.signal_window_state_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::tabbed_window_state_event_handler), owner));
5405 window.signal_key_press_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5406 window.signal_key_release_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5410 ARDOUR_UI::key_event_handler (GdkEventKey* ev, Gtk::Window* event_window)
5412 Gtkmm2ext::Bindings* bindings = 0;
5413 Gtk::Window* window = 0;
5415 /* until we get ardour bindings working, we are not handling key
5419 if (ev->type != GDK_KEY_PRESS) {
5423 if (event_window == &_main_window) {
5425 window = event_window;
5427 /* find current tab contents */
5429 Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page());
5431 /* see if it uses the ardour binding system */
5434 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(w->get_data ("ardour-bindings"));
5437 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("main window key event, bindings = %1, global = %2\n", bindings, &global_bindings));
5441 window = event_window;
5443 /* see if window uses ardour binding system */
5445 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(window->get_data ("ardour-bindings"));
5448 /* An empty binding set is treated as if it doesn't exist */
5450 if (bindings && bindings->empty()) {
5454 return key_press_focus_accelerator_handler (*window, ev, bindings);
5457 static Gtkmm2ext::Bindings*
5458 get_bindings_from_widget_heirarchy (GtkWidget* w)
5463 if ((p = g_object_get_data (G_OBJECT(w), "ardour-bindings")) != 0) {
5466 w = gtk_widget_get_parent (w);
5469 return reinterpret_cast<Gtkmm2ext::Bindings*> (p);
5473 ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev, Gtkmm2ext::Bindings* bindings)
5475 GtkWindow* win = window.gobj();
5476 GtkWidget* focus = gtk_window_get_focus (win);
5477 bool special_handling_of_unmodified_accelerators = false;
5478 const guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK));
5482 /* some widget has keyboard focus */
5484 if (GTK_IS_ENTRY(focus) || Keyboard::some_magic_widget_has_focus()) {
5486 /* A particular kind of focusable widget currently has keyboard
5487 * focus. All unmodified key events should go to that widget
5488 * first and not be used as an accelerator by default
5491 special_handling_of_unmodified_accelerators = true;
5495 Gtkmm2ext::Bindings* focus_bindings = get_bindings_from_widget_heirarchy (focus);
5496 if (focus_bindings) {
5497 bindings = focus_bindings;
5498 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Switch bindings based on focus widget, now using %1\n", bindings->name()));
5503 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",
5506 show_gdk_event_state (ev->state),
5507 special_handling_of_unmodified_accelerators,
5508 Keyboard::some_magic_widget_has_focus(),
5510 (focus ? gtk_widget_get_name (focus) : "no focus widget"),
5511 ((ev->state & mask) ? "yes" : "no"),
5512 window.get_title()));
5514 /* This exists to allow us to override the way GTK handles
5515 key events. The normal sequence is:
5517 a) event is delivered to a GtkWindow
5518 b) accelerators/mnemonics are activated
5519 c) if (b) didn't handle the event, propagate to
5520 the focus widget and/or focus chain
5522 The problem with this is that if the accelerators include
5523 keys without modifiers, such as the space bar or the
5524 letter "e", then pressing the key while typing into
5525 a text entry widget results in the accelerator being
5526 activated, instead of the desired letter appearing
5529 There is no good way of fixing this, but this
5530 represents a compromise. The idea is that
5531 key events involving modifiers (not Shift)
5532 get routed into the activation pathway first, then
5533 get propagated to the focus widget if necessary.
5535 If the key event doesn't involve modifiers,
5536 we deliver to the focus widget first, thus allowing
5537 it to get "normal text" without interference
5540 Of course, this can also be problematic: if there
5541 is a widget with focus, then it will swallow
5542 all "normal text" accelerators.
5546 if (!special_handling_of_unmodified_accelerators || (ev->state & mask)) {
5548 /* no special handling or there are modifiers in effect: accelerate first */
5550 DEBUG_TRACE (DEBUG::Accelerators, "\tactivate, then propagate\n");
5551 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tevent send-event:%1 time:%2 length:%3 name %7 string:%4 hardware_keycode:%5 group:%6\n",
5552 ev->send_event, ev->time, ev->length, ev->string, ev->hardware_keycode, ev->group, gdk_keyval_name (ev->keyval)));
5554 DEBUG_TRACE (DEBUG::Accelerators, "\tsending to window\n");
5555 KeyboardKey k (ev->state, ev->keyval);
5559 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tusing Ardour bindings %1 @ %2 for this event\n", bindings->name(), bindings));
5561 if (bindings->activate (k, Bindings::Press)) {
5562 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5567 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5569 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5570 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5574 DEBUG_TRACE (DEBUG::Accelerators, "\tnot accelerated, now propagate\n");
5576 if (gtk_window_propagate_key_event (win, ev)) {
5577 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate handled\n");
5583 /* no modifiers, propagate first */
5585 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate, then activate\n");
5587 if (gtk_window_propagate_key_event (win, ev)) {
5588 DEBUG_TRACE (DEBUG::Accelerators, "\thandled by propagate\n");
5592 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagation didn't handle, so activate\n");
5593 KeyboardKey k (ev->state, ev->keyval);
5597 DEBUG_TRACE (DEBUG::Accelerators, "\tusing Ardour bindings for this window\n");
5600 if (bindings->activate (k, Bindings::Press)) {
5601 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5607 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5609 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5610 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5615 DEBUG_TRACE (DEBUG::Accelerators, "\tnot handled\n");
5620 ARDOUR_UI::load_bindings ()
5622 if ((global_bindings = Bindings::get_bindings (X_("Global"), global_actions)) == 0) {
5623 error << _("Global keybindings are missing") << endmsg;
5628 ARDOUR_UI::cancel_solo ()
5632 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_control), 0.0, Controllable::NoGroup);
5634 _session->clear_all_solo_state (_session->get_routes()); // safeguard, ideally this won't do anything, check the log-window