2 Copyright (C) 1999-2013 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include "gtk2ardour-config.h"
22 #include "gtk2ardour-version.h"
32 #ifndef PLATFORM_WINDOWS
33 #include <sys/resource.h>
37 #include <sys/types.h>
38 #include <sys/sysctl.h>
48 #include "pbd/gstdio_compat.h"
50 #include <gtkmm/messagedialog.h>
51 #include <gtkmm/accelmap.h>
52 #include <gtkmm/stock.h>
54 #include "pbd/error.h"
55 #include "pbd/basename.h"
56 #include "pbd/compose.h"
57 #include "pbd/convert.h"
58 #include "pbd/failed_constructor.h"
59 #include "pbd/file_archive.h"
60 #include "pbd/enumwriter.h"
61 #include "pbd/memento_command.h"
62 #include "pbd/openuri.h"
63 #include "pbd/stl_delete.h"
64 #include "pbd/file_utils.h"
65 #include "pbd/localtime_r.h"
66 #include "pbd/pthread_utils.h"
67 #include "pbd/replace_all.h"
68 #include "pbd/xml++.h"
70 #include "gtkmm2ext/application.h"
71 #include "gtkmm2ext/bindings.h"
72 #include "gtkmm2ext/gtk_ui.h"
73 #include "gtkmm2ext/utils.h"
74 #include "gtkmm2ext/click_box.h"
75 #include "gtkmm2ext/fastmeter.h"
76 #include "gtkmm2ext/popup.h"
77 #include "gtkmm2ext/window_title.h"
79 #include "ardour/ardour.h"
80 #include "ardour/audio_backend.h"
81 #include "ardour/audio_track.h"
82 #include "ardour/audioengine.h"
83 #include "ardour/audiofilesource.h"
84 #include "ardour/automation_watch.h"
85 #include "ardour/diskstream.h"
86 #include "ardour/filename_extensions.h"
87 #include "ardour/filesystem_paths.h"
88 #include "ardour/ltc_file_reader.h"
89 #include "ardour/midi_track.h"
90 #include "ardour/port.h"
91 #include "ardour/plugin_manager.h"
92 #include "ardour/process_thread.h"
93 #include "ardour/profile.h"
94 #include "ardour/recent_sessions.h"
95 #include "ardour/record_enable_control.h"
96 #include "ardour/session_directory.h"
97 #include "ardour/session_route.h"
98 #include "ardour/session_state_utils.h"
99 #include "ardour/session_utils.h"
100 #include "ardour/source_factory.h"
101 #include "ardour/slave.h"
102 #include "ardour/system_exec.h"
103 #include "ardour/track.h"
104 #include "ardour/vca_manager.h"
105 #include "ardour/utils.h"
107 #include "LuaBridge/LuaBridge.h"
109 #ifdef WINDOWS_VST_SUPPORT
112 #ifdef AUDIOUNIT_SUPPORT
113 #include "ardour/audio_unit.h"
116 // fix for OSX (nsm.h has a check function, AU/Apple defines check)
121 #include "timecode/time.h"
123 typedef uint64_t microseconds_t;
128 #include "add_route_dialog.h"
129 #include "ambiguous_file_dialog.h"
130 #include "ardour_ui.h"
131 #include "audio_clock.h"
132 #include "audio_region_view.h"
133 #include "big_clock_window.h"
134 #include "bundle_manager.h"
135 #include "duplicate_routes_dialog.h"
137 #include "engine_dialog.h"
138 #include "export_video_dialog.h"
139 #include "export_video_infobox.h"
140 #include "gain_meter.h"
141 #include "global_port_matrix.h"
142 #include "gui_object.h"
143 #include "gui_thread.h"
144 #include "keyboard.h"
145 #include "keyeditor.h"
146 #include "location_ui.h"
147 #include "lua_script_manager.h"
148 #include "luawindow.h"
149 #include "main_clock.h"
150 #include "missing_file_dialog.h"
151 #include "missing_plugin_dialog.h"
152 #include "mixer_ui.h"
153 #include "meterbridge.h"
154 #include "mouse_cursors.h"
157 #include "pingback.h"
158 #include "processor_box.h"
159 #include "prompter.h"
160 #include "public_editor.h"
161 #include "rc_option_editor.h"
162 #include "route_time_axis.h"
163 #include "route_params_ui.h"
164 #include "save_as_dialog.h"
165 #include "script_selector.h"
166 #include "session_archive_dialog.h"
167 #include "session_dialog.h"
168 #include "session_metadata_dialog.h"
169 #include "session_option_editor.h"
170 #include "shuttle_control.h"
171 #include "speaker_dialog.h"
174 #include "theme_manager.h"
175 #include "time_axis_view_item.h"
178 #include "video_server_dialog.h"
179 #include "add_video_dialog.h"
180 #include "transcode_video_dialog.h"
182 #include "pbd/i18n.h"
184 using namespace ARDOUR;
185 using namespace ARDOUR_UI_UTILS;
187 using namespace Gtkmm2ext;
190 using namespace Editing;
192 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
194 sigc::signal<void, framepos_t, bool, framepos_t> ARDOUR_UI::Clock;
195 sigc::signal<void> ARDOUR_UI::CloseAllDialogs;
198 ask_about_configuration_copy (string const & old_dir, string const & new_dir, int version)
200 MessageDialog msg (string_compose (_("%1 %2.x has discovered configuration files from %1 %3.x.\n\n"
201 "Would you like these files to be copied and used for %1 %2.x?\n\n"
202 "(This will require you to restart %1.)"),
203 PROGRAM_NAME, PROGRAM_VERSION, version),
204 false, /* no markup */
207 true /* modal, though it hardly matters since it is the only window */
210 msg.set_default_response (Gtk::RESPONSE_YES);
213 return (msg.run() == Gtk::RESPONSE_YES);
217 libxml_generic_error_func (void* /* parsing_context*/,
225 vsnprintf (buf, sizeof (buf), msg, ap);
226 error << buf << endmsg;
231 libxml_structured_error_func (void* /* parsing_context*/,
239 replace_all (msg, "\n", "");
242 if (err->file && err->line) {
243 error << X_("XML error: ") << msg << " in " << err->file << " at line " << err->line;
246 error << ':' << err->int2;
251 error << X_("XML error: ") << msg << endmsg;
257 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
258 : Gtkmm2ext::UI (PROGRAM_NAME, X_("gui"), argcp, argvp)
259 , session_loaded (false)
260 , gui_object_state (new GUIObjectState)
261 , primary_clock (new MainClock (X_("primary"), X_("transport"), true ))
262 , secondary_clock (new MainClock (X_("secondary"), X_("secondary"), false))
263 , big_clock (new AudioClock (X_("bigclock"), false, "big", true, true, false, false))
265 , global_actions (X_("global"))
266 , ignore_dual_punch (false)
267 , main_window_visibility (0)
272 , _mixer_on_top (false)
273 , _initial_verbose_plugin_scan (false)
274 , first_time_engine_run (true)
275 , roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll))
276 , stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop))
277 , goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart))
278 , goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd))
279 , auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop))
280 , play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection))
281 , rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable))
282 , auto_return_button (ArdourButton::led_default_elements)
283 , follow_edits_button (ArdourButton::led_default_elements)
284 , auto_input_button (ArdourButton::led_default_elements)
285 , auditioning_alert_button (_("Audition"))
286 , solo_alert_button (_("Solo"))
287 , feedback_alert_button (_("Feedback"))
288 , error_alert_button ( ArdourButton::just_led_default_elements )
290 , editor_meter_peak_display()
291 , _numpad_locate_happening (false)
292 , _session_is_new (false)
293 , last_key_press_time (0)
297 , rc_option_editor (0)
298 , speaker_config_window (X_("speaker-config"), _("Speaker Configuration"))
299 , add_route_dialog (X_("add-routes"), _("Add Tracks/Busses"))
300 , about (X_("about"), _("About"))
301 , location_ui (X_("locations"), S_("Ranges|Locations"))
302 , route_params (X_("inspector"), _("Tracks and Busses"))
303 , audio_midi_setup (X_("audio-midi-setup"), _("Audio/MIDI Setup"))
304 , export_video_dialog (X_("video-export"), _("Video Export Dialog"))
305 , lua_script_window (X_("script-manager"), _("Script Manager"))
306 , session_option_editor (X_("session-options-editor"), _("Properties"), boost::bind (&ARDOUR_UI::create_session_option_editor, this))
307 , add_video_dialog (X_("add-video"), _("Add Video"), boost::bind (&ARDOUR_UI::create_add_video_dialog, this))
308 , bundle_manager (X_("bundle-manager"), _("Bundle Manager"), boost::bind (&ARDOUR_UI::create_bundle_manager, this))
309 , big_clock_window (X_("big-clock"), _("Big Clock"), boost::bind (&ARDOUR_UI::create_big_clock_window, this))
310 , audio_port_matrix (X_("audio-connection-manager"), _("Audio Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::AUDIO))
311 , midi_port_matrix (X_("midi-connection-manager"), _("MIDI Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::MIDI))
312 , key_editor (X_("key-editor"), _("Bindings Editor"), boost::bind (&ARDOUR_UI::create_key_editor, this))
313 , video_server_process (0)
315 , have_configure_timeout (false)
316 , last_configure_time (0)
318 , have_disk_speed_dialog_displayed (false)
319 , _status_bar_visibility (X_("status-bar"))
320 , _feedback_exists (false)
321 , _log_not_acknowledged (LogLevelNone)
322 , duplicate_routes_dialog (0)
323 , editor_visibility_button (S_("Window|Editor"))
324 , mixer_visibility_button (S_("Window|Mixer"))
325 , prefs_visibility_button (S_("Window|Preferences"))
327 Gtkmm2ext::init (localedir);
329 UIConfiguration::instance().post_gui_init ();
331 if (ARDOUR::handle_old_configuration_files (boost::bind (ask_about_configuration_copy, _1, _2, _3))) {
332 MessageDialog msg (string_compose (_("Your configuration files were copied. You can now restart %1."), PROGRAM_NAME), true);
334 /* configuration was modified, exit immediately */
339 if (string (VERSIONSTRING).find (".pre") != string::npos) {
340 /* check this is not being run from ./ardev etc. */
341 if (!running_from_source_tree ()) {
342 pre_release_dialog ();
346 if (theArdourUI == 0) {
350 /* track main window visibility */
352 main_window_visibility = new VisibilityTracker (_main_window);
354 /* stop libxml from spewing to stdout/stderr */
356 xmlSetGenericErrorFunc (this, libxml_generic_error_func);
357 xmlSetStructuredErrorFunc (this, libxml_structured_error_func);
359 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::parameter_changed));
360 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
361 UIConfiguration::instance().map_parameters (pc);
363 roll_button.set_controllable (roll_controllable);
364 stop_button.set_controllable (stop_controllable);
365 goto_start_button.set_controllable (goto_start_controllable);
366 goto_end_button.set_controllable (goto_end_controllable);
367 auto_loop_button.set_controllable (auto_loop_controllable);
368 play_selection_button.set_controllable (play_selection_controllable);
369 rec_button.set_controllable (rec_controllable);
371 roll_button.set_name ("transport button");
372 stop_button.set_name ("transport button");
373 goto_start_button.set_name ("transport button");
374 goto_end_button.set_name ("transport button");
375 auto_loop_button.set_name ("transport button");
376 play_selection_button.set_name ("transport button");
377 rec_button.set_name ("transport recenable button");
378 midi_panic_button.set_name ("transport button");
380 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
381 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
383 ARDOUR::Session::VersionMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_format_mismatch, this, _1, _2), gui_context());
385 /* handle dialog requests */
387 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
389 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
391 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
393 /* handle Audio/MIDI setup when session requires it */
395 ARDOUR::Session::AudioEngineSetupRequired.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::do_audio_midi_setup, this, _1));
397 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
399 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
401 /* handle sr mismatch with a dialog - cross-thread from engine */
402 ARDOUR::Session::NotifyAboutSampleRateMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::sr_mismatch_message, this, _1, _2), gui_context ());
404 /* handle requests to quit (coming from JACK session) */
406 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::finish, this), gui_context ());
408 /* tell the user about feedback */
410 ARDOUR::Session::FeedbackDetected.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::feedback_detected, this), gui_context ());
411 ARDOUR::Session::SuccessfulGraphSort.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::successful_graph_sort, this), gui_context ());
413 /* handle requests to deal with missing files */
415 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
417 /* and ambiguous files */
419 ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2));
421 /* also plugin scan messages */
422 ARDOUR::PluginScanMessage.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_dialog, this, _1, _2, _3), gui_context());
423 ARDOUR::PluginScanTimeout.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_timeout, this, _1), gui_context());
425 ARDOUR::GUIIdle.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::gui_idle_handler, this), gui_context());
427 Config->ParameterChanged.connect ( forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::set_flat_buttons, this), gui_context() );
430 /* lets get this party started */
432 setup_gtk_ardour_enums ();
435 SessionEvent::create_per_thread_pool ("GUI", 4096);
437 /* we like keyboards */
439 keyboard = new ArdourKeyboard(*this);
441 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
443 keyboard->set_state (*node, Stateful::loading_state_version);
446 UIConfiguration::instance().reset_dpi ();
448 TimeAxisViewItem::set_constant_heights ();
450 /* Set this up so that our window proxies can register actions */
452 ActionManager::init ();
454 /* The following must happen after ARDOUR::init() so that Config is set up */
456 const XMLNode* ui_xml = Config->extra_xml (X_("UI"));
459 key_editor.set_state (*ui_xml, 0);
460 session_option_editor.set_state (*ui_xml, 0);
461 speaker_config_window.set_state (*ui_xml, 0);
462 about.set_state (*ui_xml, 0);
463 add_route_dialog.set_state (*ui_xml, 0);
464 add_video_dialog.set_state (*ui_xml, 0);
465 route_params.set_state (*ui_xml, 0);
466 bundle_manager.set_state (*ui_xml, 0);
467 location_ui.set_state (*ui_xml, 0);
468 big_clock_window.set_state (*ui_xml, 0);
469 audio_port_matrix.set_state (*ui_xml, 0);
470 midi_port_matrix.set_state (*ui_xml, 0);
471 export_video_dialog.set_state (*ui_xml, 0);
472 lua_script_window.set_state (*ui_xml, 0);
475 /* Separate windows */
477 WM::Manager::instance().register_window (&key_editor);
478 WM::Manager::instance().register_window (&session_option_editor);
479 WM::Manager::instance().register_window (&speaker_config_window);
480 WM::Manager::instance().register_window (&about);
481 WM::Manager::instance().register_window (&add_route_dialog);
482 WM::Manager::instance().register_window (&add_video_dialog);
483 WM::Manager::instance().register_window (&route_params);
484 WM::Manager::instance().register_window (&audio_midi_setup);
485 WM::Manager::instance().register_window (&export_video_dialog);
486 WM::Manager::instance().register_window (&lua_script_window);
487 WM::Manager::instance().register_window (&bundle_manager);
488 WM::Manager::instance().register_window (&location_ui);
489 WM::Manager::instance().register_window (&big_clock_window);
490 WM::Manager::instance().register_window (&audio_port_matrix);
491 WM::Manager::instance().register_window (&midi_port_matrix);
493 /* do not retain position for add route dialog */
494 add_route_dialog.set_state_mask (WindowProxy::Size);
496 /* Trigger setting up the color scheme and loading the GTK RC file */
498 UIConfiguration::instance().load_rc_file (false);
500 _process_thread = new ProcessThread ();
501 _process_thread->init ();
503 UIConfiguration::instance().DPIReset.connect (sigc::mem_fun (*this, &ARDOUR_UI::resize_text_widgets));
509 ARDOUR_UI::pre_release_dialog ()
511 ArdourDialog d (_("Pre-Release Warning"), true, false);
512 d.add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
514 Label* label = manage (new Label);
515 label->set_markup (string_compose (_("<b>Welcome to this pre-release build of %1 %2</b>\n\n\
516 There are still several issues and bugs to be worked on,\n\
517 as well as general workflow improvements, before this can be considered\n\
518 release software. So, a few guidelines:\n\
520 1) Please do <b>NOT</b> use this software with the expectation that it is stable or reliable\n\
521 though it may be so, depending on your workflow.\n\
522 2) Please wait for a helpful writeup of new features.\n\
523 3) <b>Please do NOT use the forums at ardour.org to report issues</b>.\n\
524 4) Please <b>DO</b> use the bugtracker at http://tracker.ardour.org/ to report issues\n\
525 making sure to note the product version number as 5.0-pre.\n\
526 5) Please <b>DO</b> use the ardour-users mailing list to discuss ideas and pass on comments.\n\
527 6) Please <b>DO</b> join us on IRC for real time discussions about %1 %2. You\n\
528 can get there directly from within the program via the Help->Chat menu option.\n\
530 Full information on all the above can be found on the support page at\n\
532 http://ardour.org/support\n\
533 "), PROGRAM_NAME, VERSIONSTRING));
535 d.get_vbox()->set_border_width (12);
536 d.get_vbox()->pack_start (*label, false, false, 12);
537 d.get_vbox()->show_all ();
542 GlobalPortMatrixWindow*
543 ARDOUR_UI::create_global_port_matrix (ARDOUR::DataType type)
548 return new GlobalPortMatrixWindow (_session, type);
552 ARDOUR_UI::attach_to_engine ()
554 AudioEngine::instance()->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
555 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
559 ARDOUR_UI::engine_stopped ()
561 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
562 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
563 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
564 update_sample_rate (0);
569 ARDOUR_UI::engine_running ()
571 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
572 if (first_time_engine_run) {
574 first_time_engine_run = false;
578 _session->reset_xrun_count ();
580 update_disk_space ();
582 update_xrun_count ();
583 update_sample_rate (AudioEngine::instance()->sample_rate());
584 update_timecode_format ();
585 update_peak_thread_work ();
586 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, true);
587 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, false);
591 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
593 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
594 /* we can't rely on the original string continuing to exist when we are called
595 again in the GUI thread, so make a copy and note that we need to
598 char *copy = strdup (reason);
599 Gtkmm2ext::UI::instance()->call_slot (MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
603 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
604 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
606 update_sample_rate (0);
610 /* if the reason is a non-empty string, it means that the backend was shutdown
611 rather than just Ardour.
614 if (strlen (reason)) {
615 msgstr = string_compose (_("The audio backend was shutdown because:\n\n%1"), reason);
617 msgstr = string_compose (_("\
618 The audio backend has either been shutdown or it\n\
619 disconnected %1 because %1\n\
620 was not fast enough. Try to restart\n\
621 the audio backend and save the session."), PROGRAM_NAME);
624 MessageDialog msg (_main_window, msgstr);
625 pop_back_splash (msg);
629 free (const_cast<char*> (reason));
634 ARDOUR_UI::post_engine ()
636 /* Things to be done once (and once ONLY) after we have a backend running in the AudioEngine
638 #ifdef AUDIOUNIT_SUPPORT
640 if (AUPluginInfo::au_get_crashlog(au_msg)) {
641 popup_error(_("Audio Unit Plugin Scan Failed. Automatic AU scanning has been disabled. Please see the log window for further details."));
642 error << _("Audio Unit Plugin Scan Failed:") << endmsg;
643 info << au_msg << endmsg;
647 ARDOUR::init_post_engine ();
649 /* connect to important signals */
651 AudioEngine::instance()->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
652 AudioEngine::instance()->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
653 AudioEngine::instance()->BufferSizeChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
654 AudioEngine::instance()->Halted.connect_same_thread (halt_connection, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
655 AudioEngine::instance()->BecameSilent.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::audioengine_became_silent, this), gui_context());
657 if (setup_windows ()) {
658 throw failed_constructor ();
661 /* Do this after setup_windows (), as that's when the _status_bar_visibility is created */
662 XMLNode* n = Config->extra_xml (X_("UI"));
664 _status_bar_visibility.set_state (*n);
667 check_memory_locking();
669 /* this is the first point at which all the possible actions are
670 * available, because some of the available actions are dependent on
671 * aspects of the engine/backend.
674 if (ARDOUR_COMMAND_LINE::show_key_actions) {
677 vector<string> paths;
678 vector<string> labels;
679 vector<string> tooltips;
681 vector<Glib::RefPtr<Gtk::Action> > actions;
683 Gtkmm2ext::ActionMap::get_all_actions (paths, labels, tooltips, keys, actions);
685 vector<string>::iterator k;
686 vector<string>::iterator p;
688 for (p = paths.begin(), k = keys.begin(); p != paths.end(); ++k, ++p) {
693 cout << *p << " => " << *k << endl;
697 halt_connection.disconnect ();
698 AudioEngine::instance()->stop ();
702 /* this being a GUI and all, we want peakfiles */
704 AudioFileSource::set_build_peakfiles (true);
705 AudioFileSource::set_build_missing_peakfiles (true);
707 /* set default clock modes */
709 primary_clock->set_mode (AudioClock::Timecode);
710 secondary_clock->set_mode (AudioClock::BBT);
712 /* start the time-of-day-clock */
715 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
716 update_wall_clock ();
717 Glib::signal_timeout().connect_seconds (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 1);
722 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
723 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
724 Config->map_parameters (pc);
726 UIConfiguration::instance().map_parameters (pc);
730 ARDOUR_UI::~ARDOUR_UI ()
732 UIConfiguration::instance().save_state();
736 if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
737 // don't bother at 'real' exit. the OS cleans up for us.
738 delete big_clock; big_clock = 0;
739 delete primary_clock; primary_clock = 0;
740 delete secondary_clock; secondary_clock = 0;
741 delete _process_thread; _process_thread = 0;
742 delete meterbridge; meterbridge = 0;
743 delete luawindow; luawindow = 0;
744 delete editor; editor = 0;
745 delete mixer; mixer = 0;
747 delete gui_object_state; gui_object_state = 0;
748 delete main_window_visibility;
749 FastMeter::flush_pattern_cache ();
750 PixFader::flush_pattern_cache ();
754 /* Small trick to flush main-thread event pool.
755 * Other thread-pools are destroyed at pthread_exit(),
756 * but tmain thread termination is too late to trigger Pool::~Pool()
758 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.
759 delete ev->event_pool();
764 ARDOUR_UI::pop_back_splash (Gtk::Window& win)
766 if (Splash::instance()) {
767 Splash::instance()->pop_back_for (win);
772 ARDOUR_UI::configure_timeout ()
774 if (last_configure_time == 0) {
775 /* no configure events yet */
779 /* force a gap of 0.5 seconds since the last configure event
782 if (get_microseconds() - last_configure_time < 500000) {
785 have_configure_timeout = false;
786 save_ardour_state ();
792 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
794 if (have_configure_timeout) {
795 last_configure_time = get_microseconds();
797 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
798 have_configure_timeout = true;
805 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
807 XMLProperty const * prop;
809 if ((prop = node.property ("roll")) != 0) {
810 roll_controllable->set_id (prop->value());
812 if ((prop = node.property ("stop")) != 0) {
813 stop_controllable->set_id (prop->value());
815 if ((prop = node.property ("goto-start")) != 0) {
816 goto_start_controllable->set_id (prop->value());
818 if ((prop = node.property ("goto-end")) != 0) {
819 goto_end_controllable->set_id (prop->value());
821 if ((prop = node.property ("auto-loop")) != 0) {
822 auto_loop_controllable->set_id (prop->value());
824 if ((prop = node.property ("play-selection")) != 0) {
825 play_selection_controllable->set_id (prop->value());
827 if ((prop = node.property ("rec")) != 0) {
828 rec_controllable->set_id (prop->value());
830 if ((prop = node.property ("shuttle")) != 0) {
831 shuttle_box->controllable()->set_id (prop->value());
836 ARDOUR_UI::get_transport_controllable_state ()
838 XMLNode* node = new XMLNode(X_("TransportControllables"));
841 roll_controllable->id().print (buf, sizeof (buf));
842 node->add_property (X_("roll"), buf);
843 stop_controllable->id().print (buf, sizeof (buf));
844 node->add_property (X_("stop"), buf);
845 goto_start_controllable->id().print (buf, sizeof (buf));
846 node->add_property (X_("goto_start"), buf);
847 goto_end_controllable->id().print (buf, sizeof (buf));
848 node->add_property (X_("goto_end"), buf);
849 auto_loop_controllable->id().print (buf, sizeof (buf));
850 node->add_property (X_("auto_loop"), buf);
851 play_selection_controllable->id().print (buf, sizeof (buf));
852 node->add_property (X_("play_selection"), buf);
853 rec_controllable->id().print (buf, sizeof (buf));
854 node->add_property (X_("rec"), buf);
855 shuttle_box->controllable()->id().print (buf, sizeof (buf));
856 node->add_property (X_("shuttle"), buf);
862 ARDOUR_UI::save_session_at_its_request (std::string snapshot_name)
865 _session->save_state (snapshot_name);
870 ARDOUR_UI::autosave_session ()
872 if (g_main_depth() > 1) {
873 /* inside a recursive main loop,
874 give up because we may not be able to
880 if (!Config->get_periodic_safety_backups()) {
885 _session->maybe_write_autosave();
892 ARDOUR_UI::session_dirty_changed ()
899 ARDOUR_UI::update_autosave ()
901 if (_session && _session->dirty()) {
902 if (_autosave_connection.connected()) {
903 _autosave_connection.disconnect();
906 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
907 Config->get_periodic_safety_backup_interval() * 1000);
910 if (_autosave_connection.connected()) {
911 _autosave_connection.disconnect();
917 ARDOUR_UI::check_announcements ()
920 string _annc_filename;
923 _annc_filename = PROGRAM_NAME "_announcements_osx_";
924 #elif defined PLATFORM_WINDOWS
925 _annc_filename = PROGRAM_NAME "_announcements_windows_";
927 _annc_filename = PROGRAM_NAME "_announcements_linux_";
929 _annc_filename.append (VERSIONSTRING);
931 _announce_string = "";
933 std::string path = Glib::build_filename (user_config_directory(), _annc_filename);
934 FILE* fin = g_fopen (path.c_str(), "rb");
936 while (!feof (fin)) {
939 if ((len = fread (tmp, sizeof(char), 1024, fin)) == 0 || ferror (fin)) {
942 _announce_string.append (tmp, len);
947 pingback (VERSIONSTRING, path);
952 _hide_splash (gpointer arg)
954 ((ARDOUR_UI*)arg)->hide_splash();
959 ARDOUR_UI::starting ()
961 Application* app = Application::instance ();
963 bool brand_new_user = ArdourStartup::required ();
965 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
966 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::load_from_application_api));
968 if (ARDOUR_COMMAND_LINE::check_announcements) {
969 check_announcements ();
974 /* we need to create this early because it may need to set the
975 * audio backend end up.
979 audio_midi_setup.get (true);
981 std::cerr << "audio-midi engine setup failed."<< std::endl;
985 if ((nsm_url = g_getenv ("NSM_URL")) != 0) {
986 nsm = new NSM_Client;
987 if (!nsm->init (nsm_url)) {
988 /* the ardour executable may have different names:
990 * waf's obj.target for distro versions: eg ardour4, ardourvst4
991 * Ardour4, Mixbus3 for bundled versions + full path on OSX & windows
992 * argv[0] does not apply since we need the wrapper-script (not the binary itself)
994 * The wrapper startup script should set the environment variable 'ARDOUR_SELF'
996 const char *process_name = g_getenv ("ARDOUR_SELF");
997 nsm->announce (PROGRAM_NAME, ":dirty:", process_name ? process_name : "ardour4");
1000 // wait for announce reply from nsm server
1001 for ( i = 0; i < 5000; ++i) {
1005 if (nsm->is_active()) {
1010 error << _("NSM server did not announce itself") << endmsg;
1013 // wait for open command from nsm server
1014 for ( i = 0; i < 5000; ++i) {
1016 Glib::usleep (1000);
1017 if (nsm->client_id ()) {
1023 error << _("NSM: no client ID provided") << endmsg;
1027 if (_session && nsm) {
1028 _session->set_nsm_state( nsm->is_active() );
1030 error << _("NSM: no session created") << endmsg;
1034 // nsm requires these actions disabled
1035 vector<string> action_names;
1036 action_names.push_back("SaveAs");
1037 action_names.push_back("Rename");
1038 action_names.push_back("New");
1039 action_names.push_back("Open");
1040 action_names.push_back("Recent");
1041 action_names.push_back("Close");
1043 for (vector<string>::const_iterator n = action_names.begin(); n != action_names.end(); ++n) {
1044 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), (*n).c_str());
1046 act->set_sensitive (false);
1053 error << _("NSM: initialization failed") << endmsg;
1059 if (brand_new_user) {
1060 _initial_verbose_plugin_scan = true;
1065 _initial_verbose_plugin_scan = false;
1066 switch (s.response ()) {
1067 case Gtk::RESPONSE_OK:
1074 // TODO: maybe IFF brand_new_user
1075 if (ARDOUR::Profile->get_mixbus () && Config->get_copy_demo_sessions ()) {
1076 std::string dspd (Config->get_default_session_parent_dir());
1077 Searchpath ds (ARDOUR::ardour_data_search_path());
1078 ds.add_subdirectory_to_paths ("sessions");
1079 vector<string> demos;
1080 find_files_matching_pattern (demos, ds, "*.tar.xz");
1082 ARDOUR::RecentSessions rs;
1083 ARDOUR::read_recent_sessions (rs);
1085 for (vector<string>::iterator i = demos.begin(); i != demos.end (); ++i) {
1086 /* "demo-session" must be inside "demo-session.tar.xz"
1089 std::string name = basename_nosuffix (basename_nosuffix (*i));
1090 std::string path = Glib::build_filename (dspd, name);
1091 /* skip if session-dir already exists */
1092 if (Glib::file_test(path.c_str(), Glib::FILE_TEST_IS_DIR)) {
1095 /* skip sessions that are already in 'recent'.
1096 * eg. a new user changed <session-default-dir> shorly after installation
1098 for (ARDOUR::RecentSessions::iterator r = rs.begin(); r != rs.end(); ++r) {
1099 if ((*r).first == name) {
1104 PBD::FileArchive ar (*i);
1105 if (0 == ar.inflate (dspd)) {
1106 store_recent_sessions (name, path);
1107 info << string_compose (_("Copied Demo Session %1."), name) << endmsg;
1113 #ifdef NO_PLUGIN_STATE
1115 ARDOUR::RecentSessions rs;
1116 ARDOUR::read_recent_sessions (rs);
1118 string path = Glib::build_filename (user_config_directory(), ".iknowaboutfreeversion");
1120 if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS) && !rs.empty()) {
1122 /* already used Ardour, have sessions ... warn about plugin state */
1124 ArdourDialog d (_("Free/Demo Version Warning"), true);
1126 Button b (string_compose (_("Subscribe and support development of %1"), PROGRAM_NAME));
1127 CheckButton c (_("Don't warn me about this again"));
1129 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"),
1130 string_compose (_("This is a free/demo version of %1"), PROGRAM_NAME),
1131 _("It will not restore OR save any plugin settings"),
1132 _("If you load an existing session with plugin settings\n"
1133 "they will not be used and will be lost."),
1134 _("To get full access to updates without this limitation\n"
1135 "consider becoming a subscriber for a low cost every month.")));
1136 l.set_justify (JUSTIFY_CENTER);
1138 b.signal_clicked().connect (mem_fun(*this, &ARDOUR_UI::launch_subscribe));
1140 d.get_vbox()->pack_start (l, true, true);
1141 d.get_vbox()->pack_start (b, false, false, 12);
1142 d.get_vbox()->pack_start (c, false, false, 12);
1144 d.add_button (_("Quit now"), RESPONSE_CANCEL);
1145 d.add_button (string_compose (_("Continue using %1"), PROGRAM_NAME), RESPONSE_OK);
1149 c.signal_toggled().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (toggle_file_existence), path)));
1151 if (d.run () != RESPONSE_OK) {
1157 /* go get a session */
1159 const bool new_session_required = (ARDOUR_COMMAND_LINE::new_session || brand_new_user);
1161 if (get_session_parameters (false, new_session_required, ARDOUR_COMMAND_LINE::load_template)) {
1162 std::cerr << "Cannot get session parameters."<< std::endl;
1169 WM::Manager::instance().show_visible ();
1171 /* We have to do this here since goto_editor_window() ends up calling show_all() on the
1172 * editor window, and we may want stuff to be hidden.
1174 _status_bar_visibility.update ();
1176 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
1178 if (splash && splash->is_visible()) {
1179 // in 1 second, hide the splash screen
1180 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
1183 /* all other dialogs are created conditionally */
1189 ARDOUR_UI::check_memory_locking ()
1191 #if defined(__APPLE__) || defined(PLATFORM_WINDOWS)
1192 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
1196 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
1198 if (AudioEngine::instance()->is_realtime() && memory_warning_node == 0) {
1200 struct rlimit limits;
1202 long pages, page_size;
1204 size_t pages_len=sizeof(pages);
1205 if ((page_size = getpagesize()) < 0 ||
1206 sysctlbyname("hw.availpages", &pages, &pages_len, NULL, 0))
1208 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0)
1213 ram = (int64_t) pages * (int64_t) page_size;
1216 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
1220 if (limits.rlim_cur != RLIM_INFINITY) {
1222 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
1226 _("WARNING: Your system has a limit for maximum amount of locked memory. "
1227 "This might cause %1 to run out of memory before your system "
1228 "runs out of memory. \n\n"
1229 "You can view the memory limit with 'ulimit -l', "
1230 "and it is normally controlled by %2"),
1233 X_("/etc/login.conf")
1235 X_(" /etc/security/limits.conf")
1239 msg.set_default_response (RESPONSE_OK);
1241 VBox* vbox = msg.get_vbox();
1243 CheckButton cb (_("Do not show this window again"));
1244 hbox.pack_start (cb, true, false);
1245 vbox->pack_start (hbox);
1250 pop_back_splash (msg);
1254 if (cb.get_active()) {
1255 XMLNode node (X_("no-memory-warning"));
1256 Config->add_instant_xml (node);
1261 #endif // !__APPLE__
1266 ARDOUR_UI::queue_finish ()
1268 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
1272 ARDOUR_UI::idle_finish ()
1275 return false; /* do not call again */
1282 ARDOUR_UI::instance()->video_timeline->sync_session_state();
1284 if (_session->dirty()) {
1285 vector<string> actions;
1286 actions.push_back (_("Don't quit"));
1287 actions.push_back (_("Just quit"));
1288 actions.push_back (_("Save and quit"));
1289 switch (ask_about_saving_session(actions)) {
1294 /* use the default name */
1295 if (save_state_canfail ("")) {
1296 /* failed - don't quit */
1297 MessageDialog msg (_main_window,
1298 string_compose (_("\
1299 %1 was unable to save your session.\n\n\
1300 If you still wish to quit, please use the\n\n\
1301 \"Just quit\" option."), PROGRAM_NAME));
1302 pop_back_splash(msg);
1312 second_connection.disconnect ();
1313 point_one_second_connection.disconnect ();
1314 point_zero_something_second_connection.disconnect();
1315 fps_connection.disconnect();
1318 delete ARDOUR_UI::instance()->video_timeline;
1319 ARDOUR_UI::instance()->video_timeline = NULL;
1320 stop_video_server();
1322 /* Save state before deleting the session, as that causes some
1323 windows to be destroyed before their visible state can be
1326 save_ardour_state ();
1328 if (key_editor.get (false)) {
1329 key_editor->disconnect ();
1332 close_all_dialogs ();
1335 _session->set_clean ();
1336 _session->remove_pending_capture_state ();
1341 halt_connection.disconnect ();
1342 AudioEngine::instance()->stop ();
1343 #ifdef WINDOWS_VST_SUPPORT
1344 fst_stop_threading();
1350 ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
1352 ArdourDialog window (_("Unsaved Session"));
1353 Gtk::HBox dhbox; // the hbox for the image and text
1354 Gtk::Label prompt_label;
1355 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
1359 assert (actions.size() >= 3);
1361 window.add_button (actions[0], RESPONSE_REJECT);
1362 window.add_button (actions[1], RESPONSE_APPLY);
1363 window.add_button (actions[2], RESPONSE_ACCEPT);
1365 window.set_default_response (RESPONSE_ACCEPT);
1367 Gtk::Button noquit_button (msg);
1368 noquit_button.set_name ("EditorGTKButton");
1372 if (_session->snap_name() == _session->name()) {
1373 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?"),
1374 _session->snap_name());
1376 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?"),
1377 _session->snap_name());
1380 prompt_label.set_text (prompt);
1381 prompt_label.set_name (X_("PrompterLabel"));
1382 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
1384 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
1385 dhbox.set_homogeneous (false);
1386 dhbox.pack_start (*dimage, false, false, 5);
1387 dhbox.pack_start (prompt_label, true, false, 5);
1388 window.get_vbox()->pack_start (dhbox);
1390 window.set_name (_("Prompter"));
1391 window.set_modal (true);
1392 window.set_resizable (false);
1395 prompt_label.show();
1400 ResponseType r = (ResponseType) window.run();
1405 case RESPONSE_ACCEPT: // save and get out of here
1407 case RESPONSE_APPLY: // get out of here
1418 ARDOUR_UI::every_second ()
1421 update_xrun_count ();
1422 update_buffer_load ();
1423 update_disk_space ();
1424 update_timecode_format ();
1425 update_peak_thread_work ();
1427 if (nsm && nsm->is_active ()) {
1430 if (!_was_dirty && _session->dirty ()) {
1434 else if (_was_dirty && !_session->dirty ()){
1442 ARDOUR_UI::every_point_one_seconds ()
1444 // TODO get rid of this..
1445 // ShuttleControl is updated directly via TransportStateChange signal
1449 ARDOUR_UI::every_point_zero_something_seconds ()
1451 // august 2007: actual update frequency: 25Hz (40ms), not 100Hz
1453 if (editor_meter && UIConfiguration::instance().get_show_editor_meter()) {
1454 float mpeak = editor_meter->update_meters();
1455 if (mpeak > editor_meter_max_peak) {
1456 if (mpeak >= UIConfiguration::instance().get_meter_peak()) {
1457 editor_meter_peak_display.set_active_state ( Gtkmm2ext::ExplicitActive );
1464 ARDOUR_UI::set_fps_timeout_connection ()
1466 unsigned int interval = 40;
1467 if (!_session) return;
1468 if (_session->timecode_frames_per_second() != 0) {
1469 /* ideally we'll use a select() to sleep and not accumulate
1470 * idle time to provide a regular periodic signal.
1471 * See linux_vst_gui_support.cc 'elapsed_time_ms'.
1472 * However, that'll require a dedicated thread and cross-thread
1473 * signals to the GUI Thread..
1475 interval = floor(500. /* update twice per FPS, since Glib::signal_timeout is very irregular */
1476 * _session->frame_rate() / _session->nominal_frame_rate()
1477 / _session->timecode_frames_per_second()
1479 #ifdef PLATFORM_WINDOWS
1480 // the smallest windows scheduler time-slice is ~15ms.
1481 // periodic GUI timeouts shorter than that will cause
1482 // WaitForSingleObject to spinlock (100% of one CPU Core)
1483 // and gtk never enters idle mode.
1484 // also changing timeBeginPeriod(1) does not affect that in
1485 // any beneficial way, so we just limit the max rate for now.
1486 interval = std::max(30u, interval); // at most ~33Hz.
1488 interval = std::max(8u, interval); // at most 120Hz.
1491 fps_connection.disconnect();
1492 Timers::set_fps_interval (interval);
1496 ARDOUR_UI::update_sample_rate (framecnt_t)
1500 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
1502 if (!AudioEngine::instance()->connected()) {
1504 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1508 framecnt_t rate = AudioEngine::instance()->sample_rate();
1511 /* no sample rate available */
1512 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1515 if (fmod (rate, 1000.0) != 0.0) {
1516 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
1517 (float) rate / 1000.0f,
1518 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1520 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
1522 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1526 sample_rate_label.set_markup (buf);
1530 ARDOUR_UI::update_format ()
1533 format_label.set_text ("");
1538 s << _("File:") << X_(" <span foreground=\"green\">");
1540 switch (_session->config.get_native_file_header_format ()) {
1572 switch (_session->config.get_native_file_data_format ()) {
1586 format_label.set_markup (s.str ());
1590 ARDOUR_UI::update_xrun_count ()
1594 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1595 should also be changed.
1599 const unsigned int x = _session->get_xrun_count ();
1601 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">>10K</span>"), X_("red"));
1603 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">%u</span>"), x > 0 ? X_("red") : X_("green"), x);
1606 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">?</span>"), X_("yellow"));
1608 xrun_label.set_markup (buf);
1609 set_tip (xrun_label, _("Audio dropouts. Shift+click to reset"));
1613 ARDOUR_UI::update_cpu_load ()
1617 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1618 should also be changed.
1621 double const c = AudioEngine::instance()->get_dsp_load ();
1622 snprintf (buf, sizeof (buf), _("DSP: <span foreground=\"%s\">%5.1f%%</span>"), c >= 90 ? X_("red") : X_("green"), c);
1623 cpu_load_label.set_markup (buf);
1627 ARDOUR_UI::update_peak_thread_work ()
1630 const int c = SourceFactory::peak_work_queue_length ();
1632 snprintf (buf, sizeof (buf), _("PkBld: <span foreground=\"%s\">%d</span>"), c >= 2 ? X_("red") : X_("green"), c);
1633 peak_thread_work_label.set_markup (buf);
1635 peak_thread_work_label.set_markup (X_(""));
1640 ARDOUR_UI::update_buffer_load ()
1644 uint32_t const playback = _session ? _session->playback_load () : 100;
1645 uint32_t const capture = _session ? _session->capture_load () : 100;
1647 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1648 should also be changed.
1654 _("Buffers: <span foreground=\"green\">p:</span><span foreground=\"%s\">%" PRIu32 "%%</span> "
1655 "<span foreground=\"green\">c:</span><span foreground=\"%s\">%" PRIu32 "%%</span>"),
1656 playback <= 5 ? X_("red") : X_("green"),
1658 capture <= 5 ? X_("red") : X_("green"),
1662 buffer_load_label.set_markup (buf);
1664 buffer_load_label.set_text ("");
1669 ARDOUR_UI::count_recenabled_streams (Route& route)
1671 Track* track = dynamic_cast<Track*>(&route);
1672 if (track && track->rec_enable_control()->get_value()) {
1673 rec_enabled_streams += track->n_inputs().n_total();
1678 ARDOUR_UI::update_disk_space()
1680 if (_session == 0) {
1684 boost::optional<framecnt_t> opt_frames = _session->available_capture_duration();
1686 framecnt_t fr = _session->frame_rate();
1689 /* skip update - no SR available */
1694 /* Available space is unknown */
1695 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">Unknown</span>"));
1696 } else if (opt_frames.get_value_or (0) == max_framecnt) {
1697 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">24hrs+</span>"));
1699 rec_enabled_streams = 0;
1700 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams, false);
1702 framecnt_t frames = opt_frames.get_value_or (0);
1704 if (rec_enabled_streams) {
1705 frames /= rec_enabled_streams;
1712 hrs = frames / (fr * 3600);
1715 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">>24 hrs</span>"));
1717 frames -= hrs * fr * 3600;
1718 mins = frames / (fr * 60);
1719 frames -= mins * fr * 60;
1722 bool const low = (hrs == 0 && mins <= 30);
1726 _("Disk: <span foreground=\"%s\">%02dh:%02dm:%02ds</span>"),
1727 low ? X_("red") : X_("green"),
1733 disk_space_label.set_markup (buf);
1737 ARDOUR_UI::update_timecode_format ()
1743 TimecodeSlave* tcslave;
1744 SyncSource sync_src = Config->get_sync_source();
1746 if ((sync_src == LTC || sync_src == MTC) && (tcslave = dynamic_cast<TimecodeSlave*>(_session->slave())) != 0) {
1747 matching = (tcslave->apparent_timecode_format() == _session->config.get_timecode_format());
1752 snprintf (buf, sizeof (buf), S_("Timecode|TC: <span foreground=\"%s\">%s</span>"),
1753 matching ? X_("green") : X_("red"),
1754 Timecode::timecode_format_name (_session->config.get_timecode_format()).c_str());
1756 snprintf (buf, sizeof (buf), "TC: n/a");
1759 timecode_format_label.set_markup (buf);
1763 ARDOUR_UI::update_wall_clock ()
1767 static int last_min = -1;
1770 tm_now = localtime (&now);
1771 if (last_min != tm_now->tm_min) {
1773 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1774 wall_clock_label.set_text (buf);
1775 last_min = tm_now->tm_min;
1782 ARDOUR_UI::open_recent_session ()
1784 bool can_return = (_session != 0);
1786 SessionDialog recent_session_dialog;
1790 ResponseType r = (ResponseType) recent_session_dialog.run ();
1793 case RESPONSE_ACCEPT:
1797 recent_session_dialog.hide();
1804 recent_session_dialog.hide();
1808 std::string path = recent_session_dialog.session_folder();
1809 std::string state = recent_session_dialog.session_name (should_be_new);
1811 if (should_be_new == true) {
1815 _session_is_new = false;
1817 if (load_session (path, state) == 0) {
1823 if (splash && splash->is_visible()) {
1824 // in 1 second, hide the splash screen
1825 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
1830 ARDOUR_UI::check_audioengine (Gtk::Window& parent)
1832 if (!AudioEngine::instance()->connected()) {
1833 MessageDialog msg (parent, string_compose (
1834 _("%1 is not connected to any audio backend.\n"
1835 "You cannot open or close sessions in this condition"),
1837 pop_back_splash (msg);
1845 ARDOUR_UI::open_session ()
1847 if (!check_audioengine (_main_window)) {
1851 /* ardour sessions are folders */
1852 Gtk::FileChooserDialog open_session_selector(_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1853 open_session_selector.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1854 open_session_selector.add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1855 open_session_selector.set_default_response(Gtk::RESPONSE_ACCEPT);
1858 string session_parent_dir = Glib::path_get_dirname(_session->path());
1859 open_session_selector.set_current_folder(session_parent_dir);
1861 open_session_selector.set_current_folder(Config->get_default_session_parent_dir());
1864 Gtkmm2ext::add_volume_shortcuts (open_session_selector);
1866 /* add_shortcut_folder throws an exception if the folder being added already has a shortcut */
1867 string default_session_folder = Config->get_default_session_parent_dir();
1868 open_session_selector.add_shortcut_folder (default_session_folder);
1870 catch (Glib::Error & e) {
1871 std::cerr << "open_session_selector.add_shortcut_folder() threw Glib::Error " << e.what() << std::endl;
1874 FileFilter session_filter;
1875 session_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::statefile_suffix));
1876 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1877 open_session_selector.add_filter (session_filter);
1878 open_session_selector.set_filter (session_filter);
1880 int response = open_session_selector.run();
1881 open_session_selector.hide ();
1883 if (response == Gtk::RESPONSE_CANCEL) {
1887 string session_path = open_session_selector.get_filename();
1891 if (session_path.length() > 0) {
1892 if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1893 _session_is_new = isnew;
1894 load_session (path, name);
1900 ARDOUR_UI::session_add_vca (const string& name_template, uint32_t n)
1906 _session->vca_manager().create_vca (n, name_template);
1910 ARDOUR_UI::session_add_mixed_track (
1911 const ChanCount& input,
1912 const ChanCount& output,
1913 RouteGroup* route_group,
1915 const string& name_template,
1917 PluginInfoPtr instrument,
1918 Plugin::PresetRecord* pset,
1919 ARDOUR::PresentationInfo::order_t order)
1921 list<boost::shared_ptr<MidiTrack> > tracks;
1923 if (_session == 0) {
1924 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1929 tracks = _session->new_midi_track (input, output, instrument, pset, route_group, how_many, name_template, order, ARDOUR::Normal);
1931 if (tracks.size() != how_many) {
1932 error << string_compose(P_("could not create %1 new mixed track", "could not create %1 new mixed tracks", how_many), how_many) << endmsg;
1937 display_insufficient_ports_message ();
1942 for (list<boost::shared_ptr<MidiTrack> >::iterator i = tracks.begin(); i != tracks.end(); ++i) {
1943 (*i)->set_strict_io (true);
1949 ARDOUR_UI::session_add_midi_bus (
1950 RouteGroup* route_group,
1952 const string& name_template,
1954 PluginInfoPtr instrument,
1955 Plugin::PresetRecord* pset,
1956 ARDOUR::PresentationInfo::order_t order)
1960 if (_session == 0) {
1961 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1967 routes = _session->new_midi_route (route_group, how_many, name_template, instrument, pset, PresentationInfo::MidiBus, order);
1968 if (routes.size() != how_many) {
1969 error << string_compose(P_("could not create %1 new Midi Bus", "could not create %1 new Midi Busses", how_many), how_many) << endmsg;
1974 display_insufficient_ports_message ();
1979 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
1980 (*i)->set_strict_io (true);
1986 ARDOUR_UI::session_add_midi_route (
1988 RouteGroup* route_group,
1990 const string& name_template,
1992 PluginInfoPtr instrument,
1993 Plugin::PresetRecord* pset,
1994 ARDOUR::PresentationInfo::order_t order)
1996 ChanCount one_midi_channel;
1997 one_midi_channel.set (DataType::MIDI, 1);
2000 session_add_mixed_track (one_midi_channel, one_midi_channel, route_group, how_many, name_template, strict_io, instrument, pset, order);
2002 session_add_midi_bus (route_group, how_many, name_template, strict_io, instrument, pset, order);
2007 ARDOUR_UI::session_add_audio_route (
2009 int32_t input_channels,
2010 int32_t output_channels,
2011 ARDOUR::TrackMode mode,
2012 RouteGroup* route_group,
2014 string const & name_template,
2016 ARDOUR::PresentationInfo::order_t order)
2018 list<boost::shared_ptr<AudioTrack> > tracks;
2021 if (_session == 0) {
2022 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
2028 tracks = _session->new_audio_track (input_channels, output_channels, route_group, how_many, name_template, order, mode);
2030 if (tracks.size() != how_many) {
2031 error << string_compose (P_("could not create %1 new audio track", "could not create %1 new audio tracks", how_many), how_many)
2037 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template, PresentationInfo::AudioBus, order);
2039 if (routes.size() != how_many) {
2040 error << string_compose (P_("could not create %1 new audio bus", "could not create %1 new audio busses", how_many), how_many)
2047 display_insufficient_ports_message ();
2052 for (list<boost::shared_ptr<AudioTrack> >::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2053 (*i)->set_strict_io (true);
2055 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
2056 (*i)->set_strict_io (true);
2062 ARDOUR_UI::display_insufficient_ports_message ()
2064 MessageDialog msg (_main_window,
2065 string_compose (_("There are insufficient ports available\n\
2066 to create a new track or bus.\n\
2067 You should save %1, exit and\n\
2068 restart with more ports."), PROGRAM_NAME));
2069 pop_back_splash (msg);
2074 ARDOUR_UI::transport_goto_start ()
2077 _session->goto_start();
2079 /* force displayed area in editor to start no matter
2080 what "follow playhead" setting is.
2084 editor->center_screen (_session->current_start_frame ());
2090 ARDOUR_UI::transport_goto_zero ()
2093 _session->request_locate (0);
2095 /* force displayed area in editor to start no matter
2096 what "follow playhead" setting is.
2100 editor->reset_x_origin (0);
2106 ARDOUR_UI::transport_goto_wallclock ()
2108 if (_session && editor) {
2115 localtime_r (&now, &tmnow);
2117 framecnt_t frame_rate = _session->frame_rate();
2119 if (frame_rate == 0) {
2120 /* no frame rate available */
2124 frames = tmnow.tm_hour * (60 * 60 * frame_rate);
2125 frames += tmnow.tm_min * (60 * frame_rate);
2126 frames += tmnow.tm_sec * frame_rate;
2128 _session->request_locate (frames, _session->transport_rolling ());
2130 /* force displayed area in editor to start no matter
2131 what "follow playhead" setting is.
2135 editor->center_screen (frames);
2141 ARDOUR_UI::transport_goto_end ()
2144 framepos_t const frame = _session->current_end_frame();
2145 _session->request_locate (frame);
2147 /* force displayed area in editor to start no matter
2148 what "follow playhead" setting is.
2152 editor->center_screen (frame);
2158 ARDOUR_UI::transport_stop ()
2164 if (_session->is_auditioning()) {
2165 _session->cancel_audition ();
2169 _session->request_stop (false, true);
2172 /** Check if any tracks are record enabled. If none are, record enable all of them.
2173 * @return true if track record-enabled status was changed, false otherwise.
2176 ARDOUR_UI::trx_record_enable_all_tracks ()
2182 boost::shared_ptr<RouteList> rl = _session->get_tracks ();
2183 bool none_record_enabled = true;
2185 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
2186 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*r);
2189 if (t->rec_enable_control()->get_value()) {
2190 none_record_enabled = false;
2195 if (none_record_enabled) {
2196 _session->set_controls (route_list_to_control_list (rl, &Stripable::rec_enable_control), 1.0, Controllable::NoGroup);
2199 return none_record_enabled;
2203 ARDOUR_UI::transport_record (bool roll)
2206 switch (_session->record_status()) {
2207 case Session::Disabled:
2208 if (_session->ntracks() == 0) {
2209 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."));
2213 if (Profile->get_trx()) {
2214 roll = trx_record_enable_all_tracks ();
2216 _session->maybe_enable_record ();
2221 case Session::Recording:
2223 _session->request_stop();
2225 _session->disable_record (false, true);
2229 case Session::Enabled:
2230 _session->disable_record (false, true);
2236 ARDOUR_UI::transport_roll ()
2242 if (_session->is_auditioning()) {
2247 if (_session->config.get_external_sync()) {
2248 switch (Config->get_sync_source()) {
2252 /* transport controlled by the master */
2258 bool rolling = _session->transport_rolling();
2260 if (_session->get_play_loop()) {
2262 /* If loop playback is not a mode, then we should cancel
2263 it when this action is requested. If it is a mode
2264 we just leave it in place.
2267 if (!Config->get_loop_is_mode()) {
2268 /* XXX it is not possible to just leave seamless loop and keep
2269 playing at present (nov 4th 2009)
2271 if (!Config->get_seamless_loop()) {
2272 /* stop loop playback and stop rolling */
2273 _session->request_play_loop (false, true);
2274 } else if (rolling) {
2275 /* stop loop playback but keep rolling */
2276 _session->request_play_loop (false, false);
2280 } else if (_session->get_play_range () ) {
2281 /* stop playing a range if we currently are */
2282 _session->request_play_range (0, true);
2286 _session->request_transport_speed (1.0f);
2291 ARDOUR_UI::get_smart_mode() const
2293 return ( editor->get_smart_mode() );
2298 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
2304 if (_session->is_auditioning()) {
2305 _session->cancel_audition ();
2309 if (_session->config.get_external_sync()) {
2310 switch (Config->get_sync_source()) {
2314 /* transport controlled by the master */
2319 bool rolling = _session->transport_rolling();
2320 bool affect_transport = true;
2322 if (rolling && roll_out_of_bounded_mode) {
2323 /* drop out of loop/range playback but leave transport rolling */
2324 if (_session->get_play_loop()) {
2325 if (_session->actively_recording()) {
2327 /* just stop using the loop, then actually stop
2330 _session->request_play_loop (false, affect_transport);
2333 if (Config->get_seamless_loop()) {
2334 /* the disk buffers contain copies of the loop - we can't
2335 just keep playing, so stop the transport. the user
2336 can restart as they wish.
2338 affect_transport = true;
2340 /* disk buffers are normal, so we can keep playing */
2341 affect_transport = false;
2343 _session->request_play_loop (false, affect_transport);
2345 } else if (_session->get_play_range ()) {
2346 affect_transport = false;
2347 _session->request_play_range (0, true);
2351 if (affect_transport) {
2353 _session->request_stop (with_abort, true);
2355 } else if (!with_abort) { /* with_abort == true means the
2356 * command was intended to stop
2357 * transport, not start.
2360 /* the only external sync condition we can be in here
2361 * would be Engine (JACK) sync, in which case we still
2365 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
2366 _session->request_play_range (&editor->get_selection().time, true);
2367 _session->set_requested_return_frame( editor->get_selection().time.front().start ); //force an auto-return here
2369 _session->request_transport_speed (1.0f);
2375 ARDOUR_UI::toggle_session_auto_loop ()
2381 Location * looploc = _session->locations()->auto_loop_location();
2387 if (_session->get_play_loop()) {
2389 /* looping enabled, our job is to disable it */
2391 _session->request_play_loop (false);
2395 /* looping not enabled, our job is to enable it.
2397 loop-is-NOT-mode: this action always starts the transport rolling.
2398 loop-IS-mode: this action simply sets the loop play mechanism, but
2399 does not start transport.
2401 if (Config->get_loop_is_mode()) {
2402 _session->request_play_loop (true, false);
2404 _session->request_play_loop (true, true);
2408 //show the loop markers
2409 looploc->set_hidden (false, this);
2413 ARDOUR_UI::transport_play_selection ()
2419 editor->play_selection ();
2423 ARDOUR_UI::transport_play_preroll ()
2428 editor->play_with_preroll ();
2432 ARDOUR_UI::transport_rewind (int option)
2434 float current_transport_speed;
2437 current_transport_speed = _session->transport_speed();
2439 if (current_transport_speed >= 0.0f) {
2442 _session->request_transport_speed (-1.0f);
2445 _session->request_transport_speed (-4.0f);
2448 _session->request_transport_speed (-0.5f);
2453 _session->request_transport_speed (current_transport_speed * 1.5f);
2459 ARDOUR_UI::transport_forward (int option)
2465 float current_transport_speed = _session->transport_speed();
2467 if (current_transport_speed <= 0.0f) {
2470 _session->request_transport_speed (1.0f);
2473 _session->request_transport_speed (4.0f);
2476 _session->request_transport_speed (0.5f);
2481 _session->request_transport_speed (current_transport_speed * 1.5f);
2486 ARDOUR_UI::toggle_record_enable (uint16_t rid)
2492 boost::shared_ptr<Route> r;
2494 if ((r = _session->get_remote_nth_route (rid)) != 0) {
2496 boost::shared_ptr<Track> t;
2498 if ((t = boost::dynamic_pointer_cast<Track>(r)) != 0) {
2499 t->rec_enable_control()->set_value (!t->rec_enable_control()->get_value(), Controllable::UseGroup);
2505 ARDOUR_UI::map_transport_state ()
2508 auto_loop_button.unset_active_state ();
2509 play_selection_button.unset_active_state ();
2510 roll_button.unset_active_state ();
2511 stop_button.set_active_state (Gtkmm2ext::ExplicitActive);
2515 shuttle_box->map_transport_state ();
2517 float sp = _session->transport_speed();
2523 if (_session->get_play_range()) {
2525 play_selection_button.set_active_state (Gtkmm2ext::ExplicitActive);
2526 roll_button.unset_active_state ();
2527 auto_loop_button.unset_active_state ();
2529 } else if (_session->get_play_loop ()) {
2531 auto_loop_button.set_active (true);
2532 play_selection_button.set_active (false);
2533 if (Config->get_loop_is_mode()) {
2534 roll_button.set_active (true);
2536 roll_button.set_active (false);
2541 roll_button.set_active (true);
2542 play_selection_button.set_active (false);
2543 auto_loop_button.set_active (false);
2546 if (UIConfiguration::instance().get_follow_edits() && !_session->config.get_external_sync()) {
2547 /* light up both roll and play-selection if they are joined */
2548 roll_button.set_active (true);
2549 play_selection_button.set_active (true);
2552 stop_button.set_active (false);
2556 stop_button.set_active (true);
2557 roll_button.set_active (false);
2558 play_selection_button.set_active (false);
2559 if (Config->get_loop_is_mode ()) {
2560 auto_loop_button.set_active (_session->get_play_loop());
2562 auto_loop_button.set_active (false);
2564 update_disk_space ();
2569 ARDOUR_UI::blink_handler (bool blink_on)
2571 transport_rec_enable_blink (blink_on);
2572 solo_blink (blink_on);
2573 sync_blink (blink_on);
2574 audition_blink (blink_on);
2575 feedback_blink (blink_on);
2576 error_blink (blink_on);
2580 ARDOUR_UI::update_clocks ()
2582 if (!_session) return;
2584 if (editor && !editor->dragging_playhead()) {
2585 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD)); /* EMIT_SIGNAL */
2590 ARDOUR_UI::start_clocking ()
2592 if (UIConfiguration::instance().get_super_rapid_clock_update()) {
2593 clock_signal_connection = Timers::fps_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2595 clock_signal_connection = Timers::rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2600 ARDOUR_UI::stop_clocking ()
2602 clock_signal_connection.disconnect ();
2606 ARDOUR_UI::save_as_progress_update (float fraction, int64_t cnt, int64_t total, Gtk::Label* label, Gtk::ProgressBar* bar)
2610 snprintf (buf, sizeof (buf), _("Copied %" PRId64 " of %" PRId64), cnt, total);
2612 label->set_text (buf);
2613 bar->set_fraction (fraction);
2615 /* process events, redraws, etc. */
2617 while (gtk_events_pending()) {
2618 gtk_main_iteration ();
2621 return true; /* continue with save-as */
2625 ARDOUR_UI::save_session_as ()
2631 if (!save_as_dialog) {
2632 save_as_dialog = new SaveAsDialog;
2635 save_as_dialog->set_name (_session->name());
2637 int response = save_as_dialog->run ();
2639 save_as_dialog->hide ();
2642 case Gtk::RESPONSE_OK:
2651 sa.new_parent_folder = save_as_dialog->new_parent_folder ();
2652 sa.new_name = save_as_dialog->new_name ();
2653 sa.switch_to = save_as_dialog->switch_to();
2654 sa.copy_media = save_as_dialog->copy_media();
2655 sa.copy_external = save_as_dialog->copy_external();
2656 sa.include_media = save_as_dialog->include_media ();
2658 /* Only bother with a progress dialog if we're going to copy
2659 media into the save-as target. Without that choice, this
2660 will be very fast because we're only talking about a few kB's to
2661 perhaps a couple of MB's of data.
2664 ArdourDialog progress_dialog (_("Save As"), true);
2666 if (sa.include_media && sa.copy_media) {
2669 Gtk::ProgressBar progress_bar;
2671 progress_dialog.get_vbox()->pack_start (label);
2672 progress_dialog.get_vbox()->pack_start (progress_bar);
2674 progress_bar.show ();
2676 /* this signal will be emitted from within this, the calling thread,
2677 * after every file is copied. It provides information on percentage
2678 * complete (in terms of total data to copy), the number of files
2679 * copied so far, and the total number to copy.
2684 sa.Progress.connect_same_thread (c, boost::bind (&ARDOUR_UI::save_as_progress_update, this, _1, _2, _3, &label, &progress_bar));
2686 progress_dialog.show_all ();
2687 progress_dialog.present ();
2690 if (_session->save_as (sa)) {
2692 MessageDialog msg (string_compose (_("Save As failed: %1"), sa.failure_message));
2696 if (!sa.include_media) {
2697 unload_session (false);
2698 load_session (sa.final_session_folder_name, sa.new_name);
2703 ARDOUR_UI::archive_session ()
2711 Glib::DateTime gdt (Glib::DateTime::create_now_local (n));
2713 SessionArchiveDialog sad;
2714 sad.set_name (_session->name() + gdt.format ("_%F_%H%M%S"));
2715 int response = sad.run ();
2717 if (response != Gtk::RESPONSE_OK) {
2722 if (_session->archive_session (sad.target_folder(), sad.name(), &sad)) {
2723 MessageDialog msg (_("Session Archiving failed."));
2729 ARDOUR_UI::quick_snapshot_session (bool switch_to_it)
2733 struct tm local_time;
2736 localtime_r (&n, &local_time);
2737 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2739 save_state (timebuf, switch_to_it);
2744 ARDOUR_UI::process_snapshot_session_prompter (ArdourPrompter& prompter, bool switch_to_it)
2748 prompter.get_result (snapname);
2750 bool do_save = (snapname.length() != 0);
2753 char illegal = Session::session_name_is_legal(snapname);
2755 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2756 "snapshot names may not contain a '%1' character"), illegal));
2762 vector<std::string> p;
2763 get_state_files_in_directory (_session->session_directory().root_path(), p);
2764 vector<string> n = get_file_names_no_extension (p);
2766 if (find (n.begin(), n.end(), snapname) != n.end()) {
2768 do_save = overwrite_file_dialog (prompter,
2769 _("Confirm Snapshot Overwrite"),
2770 _("A snapshot already exists with that name. Do you want to overwrite it?"));
2774 save_state (snapname, switch_to_it);
2784 /** Ask the user for the name of a new snapshot and then take it.
2788 ARDOUR_UI::snapshot_session (bool switch_to_it)
2790 ArdourPrompter prompter (true);
2792 prompter.set_name ("Prompter");
2793 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2795 prompter.set_title (_("Snapshot and switch"));
2796 prompter.set_prompt (_("New session name"));
2798 prompter.set_title (_("Take Snapshot"));
2799 prompter.set_prompt (_("Name of new snapshot"));
2803 prompter.set_initial_text (_session->snap_name());
2805 Glib::DateTime tm (g_date_time_new_now_local ());
2806 prompter.set_initial_text (tm.format ("%FT%H.%M.%S"));
2809 bool finished = false;
2811 switch (prompter.run()) {
2812 case RESPONSE_ACCEPT:
2814 finished = process_snapshot_session_prompter (prompter, switch_to_it);
2825 /** Ask the user for a new session name and then rename the session to it.
2829 ARDOUR_UI::rename_session ()
2835 ArdourPrompter prompter (true);
2838 prompter.set_name ("Prompter");
2839 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2840 prompter.set_title (_("Rename Session"));
2841 prompter.set_prompt (_("New session name"));
2844 switch (prompter.run()) {
2845 case RESPONSE_ACCEPT:
2847 prompter.get_result (name);
2849 bool do_rename = (name.length() != 0);
2852 char illegal = Session::session_name_is_legal (name);
2855 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2856 "session names may not contain a '%1' character"), illegal));
2861 switch (_session->rename (name)) {
2863 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
2864 msg.set_position (WIN_POS_MOUSE);
2872 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
2873 msg.set_position (WIN_POS_MOUSE);
2889 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2891 if (!_session || _session->deletion_in_progress()) {
2895 XMLNode* node = new XMLNode (X_("UI"));
2897 WM::Manager::instance().add_state (*node);
2899 node->add_child_nocopy (gui_object_state->get_state());
2901 _session->add_extra_xml (*node);
2903 if (export_video_dialog) {
2904 _session->add_extra_xml (export_video_dialog->get_state());
2907 save_state_canfail (name, switch_to_it);
2911 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2916 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2921 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2926 ARDOUR_UI::primary_clock_value_changed ()
2929 _session->request_locate (primary_clock->current_time ());
2934 ARDOUR_UI::big_clock_value_changed ()
2937 _session->request_locate (big_clock->current_time ());
2942 ARDOUR_UI::secondary_clock_value_changed ()
2945 _session->request_locate (secondary_clock->current_time ());
2950 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2952 if (_session == 0) {
2956 if (_session->step_editing()) {
2960 Session::RecordState const r = _session->record_status ();
2961 bool const h = _session->have_rec_enabled_track ();
2963 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2965 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2967 rec_button.set_active_state (Gtkmm2ext::Off);
2969 } else if (r == Session::Recording && h) {
2970 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2972 rec_button.unset_active_state ();
2977 ARDOUR_UI::process_save_template_prompter (ArdourPrompter& prompter)
2981 prompter.get_result (name);
2983 if (name.length()) {
2984 int failed = _session->save_template (name);
2986 if (failed == -2) { /* file already exists. */
2987 bool overwrite = overwrite_file_dialog (prompter,
2988 _("Confirm Template Overwrite"),
2989 _("A template already exists with that name. Do you want to overwrite it?"));
2992 _session->save_template (name, true);
3004 ARDOUR_UI::save_template ()
3006 ArdourPrompter prompter (true);
3008 if (!check_audioengine (_main_window)) {
3012 prompter.set_name (X_("Prompter"));
3013 prompter.set_title (_("Save Template"));
3014 prompter.set_prompt (_("Name for template:"));
3015 prompter.set_initial_text(_session->name() + _("-template"));
3016 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
3018 bool finished = false;
3020 switch (prompter.run()) {
3021 case RESPONSE_ACCEPT:
3022 finished = process_save_template_prompter (prompter);
3033 ARDOUR_UI::edit_metadata ()
3035 SessionMetadataEditor dialog;
3036 dialog.set_session (_session);
3037 dialog.grab_focus ();
3042 ARDOUR_UI::import_metadata ()
3044 SessionMetadataImporter dialog;
3045 dialog.set_session (_session);
3050 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
3052 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
3054 MessageDialog msg (str,
3056 Gtk::MESSAGE_WARNING,
3057 Gtk::BUTTONS_YES_NO,
3061 msg.set_name (X_("OpenExistingDialog"));
3062 msg.set_title (_("Open Existing Session"));
3063 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
3064 msg.set_position (Gtk::WIN_POS_CENTER);
3065 pop_back_splash (msg);
3067 switch (msg.run()) {
3076 ARDOUR_UI::build_session_from_dialog (SessionDialog& sd, const std::string& session_path, const std::string& session_name)
3078 BusProfile bus_profile;
3082 bus_profile.master_out_channels = 2;
3083 bus_profile.input_ac = AutoConnectPhysical;
3084 bus_profile.output_ac = AutoConnectMaster;
3085 bus_profile.requested_physical_in = 0; // use all available
3086 bus_profile.requested_physical_out = 0; // use all available
3090 /* get settings from advanced section of NSD */
3092 if (sd.create_master_bus()) {
3093 bus_profile.master_out_channels = (uint32_t) sd.master_channel_count();
3095 bus_profile.master_out_channels = 0;
3098 if (sd.connect_inputs()) {
3099 bus_profile.input_ac = AutoConnectPhysical;
3101 bus_profile.input_ac = AutoConnectOption (0);
3104 bus_profile.output_ac = AutoConnectOption (0);
3106 if (sd.connect_outputs ()) {
3107 if (sd.connect_outs_to_master()) {
3108 bus_profile.output_ac = AutoConnectMaster;
3109 } else if (sd.connect_outs_to_physical()) {
3110 bus_profile.output_ac = AutoConnectPhysical;
3114 bus_profile.requested_physical_in = (uint32_t) sd.input_limit_count();
3115 bus_profile.requested_physical_out = (uint32_t) sd.output_limit_count();
3118 if (build_session (session_path, session_name, bus_profile)) {
3126 ARDOUR_UI::load_from_application_api (const std::string& path)
3128 ARDOUR_COMMAND_LINE::session_name = path;
3129 /* Cancel SessionDialog if it's visible to make OSX delegates work.
3131 * ARDOUR_UI::starting connects app->ShouldLoad signal and then shows a SessionDialog
3133 * - ShouldLoad does not arrive in time, ARDOUR_COMMAND_LINE::session_name is empty:
3134 * -> ARDOUR_UI::get_session_parameters starts a SessionDialog.
3135 * - ShouldLoad signal arrives, this function is called and sets ARDOUR_COMMAND_LINE::session_name
3136 * -> SessionDialog is not displayed
3139 if (_session_dialog) {
3140 std::string session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3141 std::string session_path = path;
3142 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_REGULAR)) {
3143 session_path = Glib::path_get_dirname (session_path);
3145 // signal the existing dialog in ARDOUR_UI::get_session_parameters()
3146 _session_dialog->set_provided_session (session_name, session_path);
3147 _session_dialog->response (RESPONSE_NONE);
3148 _session_dialog->hide();
3153 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
3154 /* /path/to/foo => /path/to/foo, foo */
3155 rv = load_session (path, basename_nosuffix (path));
3157 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
3158 rv =load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
3161 // if load_session fails -> pop up SessionDialog.
3163 ARDOUR_COMMAND_LINE::session_name = "";
3165 if (get_session_parameters (true, false)) {
3171 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
3173 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
3175 string session_name;
3176 string session_path;
3177 string template_name;
3179 bool likely_new = false;
3180 bool cancel_not_quit;
3182 /* deal with any existing DIRTY session now, rather than later. don't
3183 * treat a non-dirty session this way, so that it stays visible
3184 * as we bring up the new session dialog.
3187 if (_session && ARDOUR_UI::instance()->video_timeline) {
3188 ARDOUR_UI::instance()->video_timeline->sync_session_state();
3191 /* if there is already a session, relabel the button
3192 on the SessionDialog so that we don't Quit directly
3194 cancel_not_quit = (_session != 0);
3196 if (_session && _session->dirty()) {
3197 if (unload_session (false)) {
3198 /* unload cancelled by user */
3201 ARDOUR_COMMAND_LINE::session_name = "";
3204 if (!load_template.empty()) {
3205 should_be_new = true;
3206 template_name = load_template;
3209 session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3210 session_path = ARDOUR_COMMAND_LINE::session_name;
3212 if (!session_path.empty()) {
3213 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_EXISTS)) {
3214 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_IS_REGULAR)) {
3215 /* session/snapshot file, change path to be dir */
3216 session_path = Glib::path_get_dirname (session_path);
3221 SessionDialog session_dialog (should_be_new, session_name, session_path, load_template, cancel_not_quit);
3223 _session_dialog = &session_dialog;
3226 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
3228 /* if they named a specific statefile, use it, otherwise they are
3229 just giving a session folder, and we want to use it as is
3230 to find the session.
3233 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
3235 if (suffix != string::npos) {
3236 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
3237 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
3238 session_name = Glib::path_get_basename (session_name);
3240 session_path = ARDOUR_COMMAND_LINE::session_name;
3241 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
3246 session_dialog.clear_given ();
3249 if (should_be_new || session_name.empty()) {
3250 /* need the dialog to get info from user */
3252 cerr << "run dialog\n";
3254 switch (session_dialog.run()) {
3255 case RESPONSE_ACCEPT:
3258 /* this is used for async * app->ShouldLoad(). */
3259 continue; // while loop
3262 if (quit_on_cancel) {
3263 // JE - Currently (July 2014) this section can only get reached if the
3264 // user quits from the main 'Session Setup' dialog (i.e. reaching this
3265 // point does NOT indicate an abnormal termination). Therefore, let's
3266 // behave gracefully (i.e. let's do some cleanup) before we call exit()
3268 pthread_cancel_all ();
3276 session_dialog.hide ();
3279 /* if we run the startup dialog again, offer more than just "new session" */
3281 should_be_new = false;
3283 session_name = session_dialog.session_name (likely_new);
3284 session_path = session_dialog.session_folder ();
3290 string::size_type suffix = session_name.find (statefile_suffix);
3292 if (suffix != string::npos) {
3293 session_name = session_name.substr (0, suffix);
3296 /* this shouldn't happen, but we catch it just in case it does */
3298 if (session_name.empty()) {
3302 if (session_dialog.use_session_template()) {
3303 template_name = session_dialog.session_template_name();
3304 _session_is_new = true;
3307 if (session_name[0] == G_DIR_SEPARATOR ||
3308 #ifdef PLATFORM_WINDOWS
3309 (session_name.length() > 3 && session_name[1] == ':' && session_name[2] == G_DIR_SEPARATOR)
3311 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
3312 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)
3317 /* absolute path or cwd-relative path specified for session name: infer session folder
3318 from what was given.
3321 session_path = Glib::path_get_dirname (session_name);
3322 session_name = Glib::path_get_basename (session_name);
3326 session_path = session_dialog.session_folder();
3328 char illegal = Session::session_name_is_legal (session_name);
3331 MessageDialog msg (session_dialog,
3332 string_compose (_("To ensure compatibility with various systems\n"
3333 "session names may not contain a '%1' character"),
3336 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3341 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
3344 if (likely_new && !nsm) {
3346 std::string existing = Glib::build_filename (session_path, session_name);
3348 if (!ask_about_loading_existing_session (existing)) {
3349 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3354 _session_is_new = false;
3359 pop_back_splash (session_dialog);
3360 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
3362 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3366 char illegal = Session::session_name_is_legal(session_name);
3369 pop_back_splash (session_dialog);
3370 MessageDialog msg (session_dialog, string_compose(_("To ensure compatibility with various systems\n"
3371 "session names may not contain a '%1' character"), illegal));
3373 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3377 _session_is_new = true;
3380 if (likely_new && template_name.empty()) {
3382 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3386 ret = load_session (session_path, session_name, template_name);
3389 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
3393 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
3394 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
3398 /* clear this to avoid endless attempts to load the
3402 ARDOUR_COMMAND_LINE::session_name = "";
3406 _session_dialog = NULL;
3412 ARDOUR_UI::close_session()
3414 if (!check_audioengine (_main_window)) {
3418 if (unload_session (true)) {
3422 ARDOUR_COMMAND_LINE::session_name = "";
3424 if (get_session_parameters (true, false)) {
3427 if (splash && splash->is_visible()) {
3428 // in 1 second, hide the splash screen
3429 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
3433 /** @param snap_name Snapshot name (without .ardour suffix).
3434 * @return -2 if the load failed because we are not connected to the AudioEngine.
3437 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
3439 Session *new_session;
3444 unload_status = unload_session ();
3446 if (unload_status < 0) {
3448 } else if (unload_status > 0) {
3454 session_loaded = false;
3456 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
3459 new_session = new Session (*AudioEngine::instance(), path, snap_name, 0, mix_template);
3462 /* this one is special */
3464 catch (AudioEngine::PortRegistrationFailure& err) {
3466 MessageDialog msg (err.what(),
3469 Gtk::BUTTONS_CLOSE);
3471 msg.set_title (_("Port Registration Error"));
3472 msg.set_secondary_text (_("Click the Close button to try again."));
3473 msg.set_position (Gtk::WIN_POS_CENTER);
3474 pop_back_splash (msg);
3477 int response = msg.run ();
3482 case RESPONSE_CANCEL:
3489 catch (SessionException e) {
3490 MessageDialog msg (string_compose(
3491 _("Session \"%1 (snapshot %2)\" did not load successfully: %3"),
3492 path, snap_name, e.what()),
3497 msg.set_title (_("Loading Error"));
3498 msg.set_position (Gtk::WIN_POS_CENTER);
3499 pop_back_splash (msg);
3511 MessageDialog msg (string_compose(
3512 _("Session \"%1 (snapshot %2)\" did not load successfully"),
3518 msg.set_title (_("Loading Error"));
3519 msg.set_position (Gtk::WIN_POS_CENTER);
3520 pop_back_splash (msg);
3532 list<string> const u = new_session->unknown_processors ();
3534 MissingPluginDialog d (_session, u);
3539 if (!new_session->writable()) {
3540 MessageDialog msg (_("This session has been opened in read-only mode.\n\nYou will not be able to record or save."),
3545 msg.set_title (_("Read-only Session"));
3546 msg.set_position (Gtk::WIN_POS_CENTER);
3547 pop_back_splash (msg);
3554 /* Now the session been created, add the transport controls */
3555 new_session->add_controllable(roll_controllable);
3556 new_session->add_controllable(stop_controllable);
3557 new_session->add_controllable(goto_start_controllable);
3558 new_session->add_controllable(goto_end_controllable);
3559 new_session->add_controllable(auto_loop_controllable);
3560 new_session->add_controllable(play_selection_controllable);
3561 new_session->add_controllable(rec_controllable);
3563 set_session (new_session);
3565 session_loaded = true;
3568 _session->set_clean ();
3571 #ifdef WINDOWS_VST_SUPPORT
3572 fst_stop_threading();
3576 Timers::TimerSuspender t;
3580 #ifdef WINDOWS_VST_SUPPORT
3581 fst_start_threading();
3590 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
3592 Session *new_session;
3595 session_loaded = false;
3596 x = unload_session ();
3604 _session_is_new = true;
3607 new_session = new Session (*AudioEngine::instance(), path, snap_name, &bus_profile);
3610 catch (SessionException e) {
3612 MessageDialog msg (string_compose(_("Could not create session in \"%1\": %2"), path, e.what()));
3613 msg.set_title (_("Loading Error"));
3614 msg.set_position (Gtk::WIN_POS_CENTER);
3615 pop_back_splash (msg);
3621 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
3622 msg.set_title (_("Loading Error"));
3623 msg.set_position (Gtk::WIN_POS_CENTER);
3624 pop_back_splash (msg);
3629 /* Give the new session the default GUI state, if such things exist */
3632 n = Config->instant_xml (X_("Editor"));
3634 n->remove_nodes_and_delete ("Selection"); // no not apply selection to new sessions.
3635 new_session->add_instant_xml (*n, false);
3637 n = Config->instant_xml (X_("Mixer"));
3639 new_session->add_instant_xml (*n, false);
3642 n = Config->instant_xml (X_("Preferences"));
3644 new_session->add_instant_xml (*n, false);
3647 /* Put the playhead at 0 and scroll fully left */
3648 n = new_session->instant_xml (X_("Editor"));
3650 n->add_property (X_("playhead"), X_("0"));
3651 n->add_property (X_("left-frame"), X_("0"));
3654 set_session (new_session);
3656 session_loaded = true;
3658 new_session->save_state(new_session->name());
3664 ARDOUR_UI::launch_chat ()
3666 MessageDialog dialog(_("<b>Just ask and wait for an answer.\nIt may take from minutes to hours.</b>"), true);
3668 dialog.set_title (_("About the Chat"));
3669 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."));
3671 switch (dialog.run()) {
3674 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
3675 #elif defined PLATFORM_WINDOWS
3676 open_uri("http://webchat.freenode.net/?channels=ardour-windows");
3678 open_uri("http://webchat.freenode.net/?channels=ardour");
3687 ARDOUR_UI::launch_manual ()
3689 PBD::open_uri (Config->get_tutorial_manual_url());
3693 ARDOUR_UI::launch_reference ()
3695 PBD::open_uri (Config->get_reference_manual_url());
3699 ARDOUR_UI::launch_tracker ()
3701 PBD::open_uri ("http://tracker.ardour.org");
3705 ARDOUR_UI::launch_subscribe ()
3707 PBD::open_uri ("https://community.ardour.org/s/subscribe");
3711 ARDOUR_UI::launch_cheat_sheet ()
3714 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheat_sheet_osx.pdf");
3716 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheatsheet.pdf");
3721 ARDOUR_UI::launch_website ()
3723 PBD::open_uri ("http://ardour.org");
3727 ARDOUR_UI::launch_website_dev ()
3729 PBD::open_uri ("http://ardour.org/development.html");
3733 ARDOUR_UI::launch_forums ()
3735 PBD::open_uri ("https://community.ardour.org/forums");
3739 ARDOUR_UI::launch_howto_report ()
3741 PBD::open_uri ("http://ardour.org/reporting_bugs");
3745 ARDOUR_UI::loading_message (const std::string& msg)
3747 if (ARDOUR_COMMAND_LINE::no_splash) {
3755 splash->message (msg);
3759 ARDOUR_UI::show_splash ()
3763 splash = new Splash;
3773 ARDOUR_UI::hide_splash ()
3780 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title, const bool msg_delete)
3784 removed = rep.paths.size();
3787 MessageDialog msgd (_main_window,
3788 _("No files were ready for clean-up"),
3792 msgd.set_title (_("Clean-up"));
3793 msgd.set_secondary_text (_("If this seems suprising, \n\
3794 check for any existing snapshots.\n\
3795 These may still include regions that\n\
3796 require some unused files to continue to exist."));
3802 ArdourDialog results (_("Clean-up"), true, false);
3804 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
3805 CleanupResultsModelColumns() {
3809 Gtk::TreeModelColumn<std::string> visible_name;
3810 Gtk::TreeModelColumn<std::string> fullpath;
3814 CleanupResultsModelColumns results_columns;
3815 Glib::RefPtr<Gtk::ListStore> results_model;
3816 Gtk::TreeView results_display;
3818 results_model = ListStore::create (results_columns);
3819 results_display.set_model (results_model);
3820 results_display.append_column (list_title, results_columns.visible_name);
3822 results_display.set_name ("CleanupResultsList");
3823 results_display.set_headers_visible (true);
3824 results_display.set_headers_clickable (false);
3825 results_display.set_reorderable (false);
3827 Gtk::ScrolledWindow list_scroller;
3830 Gtk::HBox dhbox; // the hbox for the image and text
3831 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
3832 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
3834 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
3836 const string dead_directory = _session->session_directory().dead_path();
3839 %1 - number of files removed
3840 %2 - location of "dead"
3841 %3 - size of files affected
3842 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
3845 const char* bprefix;
3846 double space_adjusted = 0;
3848 if (rep.space < 1000) {
3850 space_adjusted = rep.space;
3851 } else if (rep.space < 1000000) {
3852 bprefix = _("kilo");
3853 space_adjusted = floorf((float)rep.space / 1000.0);
3854 } else if (rep.space < 1000000 * 1000) {
3855 bprefix = _("mega");
3856 space_adjusted = floorf((float)rep.space / (1000.0 * 1000.0));
3858 bprefix = _("giga");
3859 space_adjusted = floorf((float)rep.space / (1000.0 * 1000 * 1000.0));
3863 txt.set_markup (string_compose (P_("\
3864 The following file was deleted from %2,\n\
3865 releasing %3 %4bytes of disk space", "\
3866 The following %1 files were deleted from %2,\n\
3867 releasing %3 %4bytes of disk space", removed),
3868 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3870 txt.set_markup (string_compose (P_("\
3871 The following file was not in use and \n\
3872 has been moved to: %2\n\n\
3873 After a restart of %5\n\n\
3874 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3875 will release an additional %3 %4bytes of disk space.\n", "\
3876 The following %1 files were not in use and \n\
3877 have been moved to: %2\n\n\
3878 After a restart of %5\n\n\
3879 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3880 will release an additional %3 %4bytes of disk space.\n", removed),
3881 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3884 dhbox.pack_start (*dimage, true, false, 5);
3885 dhbox.pack_start (txt, true, false, 5);
3887 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
3888 TreeModel::Row row = *(results_model->append());
3889 row[results_columns.visible_name] = *i;
3890 row[results_columns.fullpath] = *i;
3893 list_scroller.add (results_display);
3894 list_scroller.set_size_request (-1, 150);
3895 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
3897 dvbox.pack_start (dhbox, true, false, 5);
3898 dvbox.pack_start (list_scroller, true, false, 5);
3899 ddhbox.pack_start (dvbox, true, false, 5);
3901 results.get_vbox()->pack_start (ddhbox, true, false, 5);
3902 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
3903 results.set_default_response (RESPONSE_CLOSE);
3904 results.set_position (Gtk::WIN_POS_MOUSE);
3906 results_display.show();
3907 list_scroller.show();
3914 //results.get_vbox()->show();
3915 results.set_resizable (false);
3922 ARDOUR_UI::cleanup ()
3924 if (_session == 0) {
3925 /* shouldn't happen: menu item is insensitive */
3930 MessageDialog checker (_("Are you sure you want to clean-up?"),
3932 Gtk::MESSAGE_QUESTION,
3935 checker.set_title (_("Clean-up"));
3937 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
3938 ALL undo/redo information will be lost if you clean-up.\n\
3939 Clean-up will move all unused files to a \"dead\" location."));
3941 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3942 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
3943 checker.set_default_response (RESPONSE_CANCEL);
3945 checker.set_name (_("CleanupDialog"));
3946 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3947 checker.set_position (Gtk::WIN_POS_MOUSE);
3949 switch (checker.run()) {
3950 case RESPONSE_ACCEPT:
3956 ARDOUR::CleanupReport rep;
3958 editor->prepare_for_cleanup ();
3960 /* do not allow flush until a session is reloaded */
3962 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3964 act->set_sensitive (false);
3967 if (_session->cleanup_sources (rep)) {
3968 editor->finish_cleanup ();
3972 editor->finish_cleanup ();
3975 display_cleanup_results (rep, _("Cleaned Files"), false);
3979 ARDOUR_UI::flush_trash ()
3981 if (_session == 0) {
3982 /* shouldn't happen: menu item is insensitive */
3986 ARDOUR::CleanupReport rep;
3988 if (_session->cleanup_trash_sources (rep)) {
3992 display_cleanup_results (rep, _("deleted file"), true);
3996 ARDOUR_UI::cleanup_peakfiles ()
3998 if (_session == 0) {
3999 /* shouldn't happen: menu item is insensitive */
4003 if (! _session->can_cleanup_peakfiles ()) {
4007 // get all region-views in this session
4009 TrackViewList empty;
4011 editor->get_regions_after(rs, (framepos_t) 0, empty);
4012 std::list<RegionView*> views = rs.by_layer();
4014 // remove displayed audio-region-views waveforms
4015 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
4016 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
4017 if (!arv) { continue ; }
4018 arv->delete_waves();
4021 // cleanup peak files:
4022 // - stop pending peakfile threads
4023 // - close peakfiles if any
4024 // - remove peak dir in session
4025 // - setup peakfiles (background thread)
4026 _session->cleanup_peakfiles ();
4028 // re-add waves to ARV
4029 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
4030 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
4031 if (!arv) { continue ; }
4032 arv->create_waves();
4036 PresentationInfo::order_t
4037 ARDOUR_UI::translate_order (RouteDialogs::InsertAt place)
4039 if (editor->get_selection().tracks.empty()) {
4040 return PresentationInfo::max_order;
4043 PresentationInfo::order_t order_hint = PresentationInfo::max_order;
4046 we want the new routes to have their order keys set starting from
4047 the highest order key in the selection + 1 (if available).
4050 if (place == RouteDialogs::AfterSelection) {
4051 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.back());
4053 order_hint = rtav->route()->presentation_info().order();
4056 } else if (place == RouteDialogs::BeforeSelection) {
4057 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.front());
4059 order_hint = rtav->route()->presentation_info().order();
4061 } else if (place == RouteDialogs::First) {
4064 /* leave order_hint at max_order */
4071 ARDOUR_UI::start_duplicate_routes ()
4073 if (!duplicate_routes_dialog) {
4074 duplicate_routes_dialog = new DuplicateRouteDialog;
4077 if (duplicate_routes_dialog->restart (_session)) {
4081 duplicate_routes_dialog->present ();
4085 ARDOUR_UI::add_route ()
4087 if (!add_route_dialog.get (false)) {
4088 add_route_dialog->signal_response().connect (sigc::mem_fun (*this, &ARDOUR_UI::add_route_dialog_finished));
4095 if (add_route_dialog->is_visible()) {
4096 /* we're already doing this */
4100 add_route_dialog->set_position (WIN_POS_MOUSE);
4101 add_route_dialog->present();
4105 ARDOUR_UI::add_route_dialog_finished (int r)
4109 add_route_dialog->hide();
4112 case RESPONSE_ACCEPT:
4119 if ((count = add_route_dialog->count()) <= 0) {
4123 PresentationInfo::order_t order = translate_order (add_route_dialog->insert_at());
4124 string template_path = add_route_dialog->track_template();
4125 DisplaySuspender ds;
4127 if (!template_path.empty()) {
4128 if (add_route_dialog->name_template_is_default()) {
4129 _session->new_route_from_template (count, order, template_path, string());
4131 _session->new_route_from_template (count, order, template_path, add_route_dialog->name_template());
4136 ChanCount input_chan= add_route_dialog->channels ();
4137 ChanCount output_chan;
4138 string name_template = add_route_dialog->name_template ();
4139 PluginInfoPtr instrument = add_route_dialog->requested_instrument ();
4140 RouteGroup* route_group = add_route_dialog->route_group ();
4141 AutoConnectOption oac = Config->get_output_auto_connect();
4142 bool strict_io = add_route_dialog->use_strict_io ();
4144 if (oac & AutoConnectMaster) {
4145 output_chan.set (DataType::AUDIO, (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan.n_audio()));
4146 output_chan.set (DataType::MIDI, 0);
4148 output_chan = input_chan;
4151 /* XXX do something with name template */
4153 switch (add_route_dialog->type_wanted()) {
4154 case AddRouteDialog::AudioTrack:
4155 session_add_audio_track (input_chan.n_audio(), output_chan.n_audio(), add_route_dialog->mode(), route_group, count, name_template, strict_io, order);
4157 case AddRouteDialog::MidiTrack:
4158 session_add_midi_track (route_group, count, name_template, strict_io, instrument, 0, order);
4160 case AddRouteDialog::MixedTrack:
4161 session_add_mixed_track (input_chan, output_chan, route_group, count, name_template, strict_io, instrument, 0, order);
4163 case AddRouteDialog::AudioBus:
4164 session_add_audio_bus (input_chan.n_audio(), output_chan.n_audio(), route_group, count, name_template, strict_io, order);
4166 case AddRouteDialog::MidiBus:
4167 session_add_midi_bus (route_group, count, name_template, strict_io, instrument, 0, order);
4169 case AddRouteDialog::VCAMaster:
4170 session_add_vca (name_template, count);
4176 ARDOUR_UI::add_lua_script ()
4182 LuaScriptInfoPtr spi;
4183 ScriptSelector ss ("Add Lua Session Script", LuaScriptInfo::Session);
4184 switch (ss.run ()) {
4185 case Gtk::RESPONSE_ACCEPT:
4193 std::string script = "";
4196 script = Glib::file_get_contents (spi->path);
4197 } catch (Glib::FileError e) {
4198 string msg = string_compose (_("Cannot read session script '%1': %2"), spi->path, e.what());
4199 MessageDialog am (msg);
4204 LuaScriptParamList lsp = LuaScriptParams::script_params (spi, "sess_params");
4205 std::vector<std::string> reg = _session->registered_lua_functions ();
4207 ScriptParameterDialog spd (_("Set Script Parameters"), spi, reg, lsp);
4208 switch (spd.run ()) {
4209 case Gtk::RESPONSE_ACCEPT:
4216 _session->register_lua_function (spd.name(), script, lsp);
4217 } catch (luabridge::LuaException const& e) {
4218 string msg = string_compose (_("Session script '%1' instantiation failed: %2"), spd.name(), e.what ());
4219 MessageDialog am (msg);
4221 } catch (SessionException e) {
4222 string msg = string_compose (_("Loading Session script '%1' failed: %2"), spd.name(), e.what ());
4223 MessageDialog am (msg);
4229 ARDOUR_UI::remove_lua_script ()
4234 if (_session->registered_lua_function_count () == 0) {
4235 string msg = _("There are no active Lua session scripts present in this session.");
4236 MessageDialog am (msg);
4241 std::vector<std::string> reg = _session->registered_lua_functions ();
4242 SessionScriptManager sm ("Remove Lua Session Script", reg);
4243 switch (sm.run ()) {
4244 case Gtk::RESPONSE_ACCEPT:
4250 _session->unregister_lua_function (sm.name());
4251 } catch (luabridge::LuaException const& e) {
4252 string msg = string_compose (_("Session script '%1' removal failed: %2"), sm.name(), e.what ());
4253 MessageDialog am (msg);
4259 ARDOUR_UI::stop_video_server (bool ask_confirm)
4261 if (!video_server_process && ask_confirm) {
4262 warning << string_compose (_("Video-Server was not launched by %1. The request to stop it is ignored."), PROGRAM_NAME) << endmsg;
4264 if (video_server_process) {
4266 ArdourDialog confirm (_("Stop Video-Server"), true);
4267 Label m (_("Do you really want to stop the Video Server?"));
4268 confirm.get_vbox()->pack_start (m, true, true);
4269 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
4270 confirm.add_button (_("Yes, Stop It"), Gtk::RESPONSE_ACCEPT);
4271 confirm.show_all ();
4272 if (confirm.run() == RESPONSE_CANCEL) {
4276 delete video_server_process;
4277 video_server_process =0;
4282 ARDOUR_UI::start_video_server_menu (Gtk::Window* float_window)
4284 ARDOUR_UI::start_video_server( float_window, true);
4288 ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg)
4294 if (ARDOUR_UI::instance()->video_timeline->check_server()) {
4295 if (video_server_process) {
4296 popup_error(_("The Video Server is already started."));
4298 popup_error(_("An external Video Server is configured and can be reached. Not starting a new instance."));
4304 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4306 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4308 VideoServerDialog *video_server_dialog = new VideoServerDialog (_session);
4310 video_server_dialog->set_transient_for (*float_window);
4313 if (!Config->get_show_video_server_dialog() && firsttime < 2) {
4314 video_server_dialog->hide();
4316 ResponseType r = (ResponseType) video_server_dialog->run ();
4317 video_server_dialog->hide();
4318 if (r != RESPONSE_ACCEPT) { return false; }
4319 if (video_server_dialog->show_again()) {
4320 Config->set_show_video_server_dialog(false);
4324 std::string icsd_exec = video_server_dialog->get_exec_path();
4325 std::string icsd_docroot = video_server_dialog->get_docroot();
4326 if (icsd_docroot.empty()) {
4327 #ifndef PLATFORM_WINDOWS
4328 icsd_docroot = X_("/");
4330 icsd_docroot = X_("C:\\");
4335 if (g_lstat (icsd_docroot.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode)) {
4336 warning << _("Specified docroot is not an existing directory.") << endmsg;
4339 #ifndef PLATFORM_WINDOWS
4340 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4341 || (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0 ) {
4342 warning << _("Given Video Server is not an executable file.") << endmsg;
4346 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4347 || (sb.st_mode & (S_IXUSR)) == 0 ) {
4348 warning << _("Given Video Server is not an executable file.") << endmsg;
4354 argp=(char**) calloc(9,sizeof(char*));
4355 argp[0] = strdup(icsd_exec.c_str());
4356 argp[1] = strdup("-P");
4357 argp[2] = (char*) calloc(16,sizeof(char)); snprintf(argp[2], 16, "%s", video_server_dialog->get_listenaddr().c_str());
4358 argp[3] = strdup("-p");
4359 argp[4] = (char*) calloc(6,sizeof(char)); snprintf(argp[4], 6, "%i", video_server_dialog->get_listenport());
4360 argp[5] = strdup("-C");
4361 argp[6] = (char*) calloc(6,sizeof(char)); snprintf(argp[6], 6, "%i", video_server_dialog->get_cachesize());
4362 argp[7] = strdup(icsd_docroot.c_str());
4364 stop_video_server();
4366 if (icsd_docroot == X_("/") || icsd_docroot == X_("C:\\")) {
4367 Config->set_video_advanced_setup(false);
4369 std::ostringstream osstream;
4370 osstream << "http://127.0.0.1:" << video_server_dialog->get_listenport() << "/";
4371 Config->set_video_server_url(osstream.str());
4372 Config->set_video_server_docroot(icsd_docroot);
4373 Config->set_video_advanced_setup(true);
4376 if (video_server_process) {
4377 delete video_server_process;
4380 video_server_process = new ARDOUR::SystemExec(icsd_exec, argp);
4381 if (video_server_process->start()) {
4382 warning << _("Cannot launch the video-server") << endmsg;
4385 int timeout = 120; // 6 sec
4386 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4387 Glib::usleep (50000);
4389 if (--timeout <= 0 || !video_server_process->is_running()) break;
4392 warning << _("Video-server was started but does not respond to requests...") << endmsg;
4394 if (!ARDOUR_UI::instance()->video_timeline->check_server_docroot()) {
4395 delete video_server_process;
4396 video_server_process = 0;
4404 ARDOUR_UI::add_video (Gtk::Window* float_window)
4410 if (!start_video_server(float_window, false)) {
4411 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4416 add_video_dialog->set_transient_for (*float_window);
4419 if (add_video_dialog->is_visible()) {
4420 /* we're already doing this */
4424 ResponseType r = (ResponseType) add_video_dialog->run ();
4425 add_video_dialog->hide();
4426 if (r != RESPONSE_ACCEPT) { return; }
4428 bool local_file, orig_local_file;
4429 std::string path = add_video_dialog->file_name(local_file);
4431 std::string orig_path = path;
4432 orig_local_file = local_file;
4434 bool auto_set_session_fps = add_video_dialog->auto_set_session_fps();
4436 if (local_file && !Glib::file_test(path, Glib::FILE_TEST_EXISTS)) {
4437 warning << string_compose(_("could not open %1"), path) << endmsg;
4440 if (!local_file && path.length() == 0) {
4441 warning << _("no video-file selected") << endmsg;
4445 std::string audio_from_video;
4446 bool detect_ltc = false;
4448 switch (add_video_dialog->import_option()) {
4449 case VTL_IMPORT_TRANSCODE:
4451 TranscodeVideoDialog *transcode_video_dialog;
4452 transcode_video_dialog = new TranscodeVideoDialog (_session, path);
4453 ResponseType r = (ResponseType) transcode_video_dialog->run ();
4454 transcode_video_dialog->hide();
4455 if (r != RESPONSE_ACCEPT) {
4456 delete transcode_video_dialog;
4460 audio_from_video = transcode_video_dialog->get_audiofile();
4462 if (!audio_from_video.empty() && transcode_video_dialog->detect_ltc()) {
4465 else if (!audio_from_video.empty()) {
4466 editor->embed_audio_from_video(
4468 video_timeline->get_offset(),
4469 (transcode_video_dialog->import_option() != VTL_IMPORT_NO_VIDEO)
4472 switch (transcode_video_dialog->import_option()) {
4473 case VTL_IMPORT_TRANSCODED:
4474 path = transcode_video_dialog->get_filename();
4477 case VTL_IMPORT_REFERENCE:
4480 delete transcode_video_dialog;
4483 delete transcode_video_dialog;
4487 case VTL_IMPORT_NONE:
4491 /* strip _session->session_directory().video_path() from video file if possible */
4492 if (local_file && !path.compare(0, _session->session_directory().video_path().size(), _session->session_directory().video_path())) {
4493 path=path.substr(_session->session_directory().video_path().size());
4494 if (path.at(0) == G_DIR_SEPARATOR) {
4495 path=path.substr(1);
4499 video_timeline->set_update_session_fps(auto_set_session_fps);
4501 if (video_timeline->video_file_info(path, local_file)) {
4502 XMLNode* node = new XMLNode(X_("Videotimeline"));
4503 node->add_property (X_("Filename"), path);
4504 node->add_property (X_("AutoFPS"), auto_set_session_fps?X_("1"):X_("0"));
4505 node->add_property (X_("LocalFile"), local_file?X_("1"):X_("0"));
4506 if (orig_local_file) {
4507 node->add_property (X_("OriginalVideoFile"), orig_path);
4509 node->remove_property (X_("OriginalVideoFile"));
4511 _session->add_extra_xml (*node);
4512 _session->set_dirty ();
4514 if (!audio_from_video.empty() && detect_ltc) {
4515 std::vector<LTCFileReader::LTCMap> ltc_seq;
4518 /* TODO ask user about TV standard (LTC alignment if any) */
4519 LTCFileReader ltcr (audio_from_video, video_timeline->get_video_file_fps());
4520 /* TODO ASK user which channel: 0 .. ltcr->channels() - 1 */
4522 ltc_seq = ltcr.read_ltc (/*channel*/ 0, /*max LTC frames to decode*/ 15);
4524 /* TODO seek near end of file, and read LTC until end.
4525 * if it fails to find any LTC frames, scan complete file
4527 * calculate drift of LTC compared to video-duration,
4528 * ask user for reference (timecode from start/mid/end)
4531 // LTCFileReader will have written error messages
4534 ::g_unlink(audio_from_video.c_str());
4536 if (ltc_seq.size() == 0) {
4537 PBD::error << _("No LTC detected, video will not be aligned.") << endmsg;
4539 /* the very first TC in the file is somteimes not aligned properly */
4540 int i = ltc_seq.size() -1;
4541 ARDOUR::frameoffset_t video_start_offset =
4542 _session->nominal_frame_rate() * (ltc_seq[i].timecode_sec - ltc_seq[i].framepos_sec);
4543 PBD::info << string_compose (_("Align video-start to %1 [samples]"), video_start_offset) << endmsg;
4544 video_timeline->set_offset(video_start_offset);
4548 _session->maybe_update_session_range(
4549 std::max(video_timeline->get_offset(), (ARDOUR::frameoffset_t) 0),
4550 std::max(video_timeline->get_offset() + video_timeline->get_duration(), (ARDOUR::frameoffset_t) 0));
4553 if (add_video_dialog->launch_xjadeo() && local_file) {
4554 editor->set_xjadeo_sensitive(true);
4555 editor->toggle_xjadeo_proc(1);
4557 editor->toggle_xjadeo_proc(0);
4559 editor->toggle_ruler_video(true);
4564 ARDOUR_UI::remove_video ()
4566 video_timeline->close_session();
4567 editor->toggle_ruler_video(false);
4570 video_timeline->set_offset_locked(false);
4571 video_timeline->set_offset(0);
4573 /* delete session state */
4574 XMLNode* node = new XMLNode(X_("Videotimeline"));
4575 _session->add_extra_xml(*node);
4576 node = new XMLNode(X_("Videomonitor"));
4577 _session->add_extra_xml(*node);
4578 node = new XMLNode(X_("Videoexport"));
4579 _session->add_extra_xml(*node);
4580 stop_video_server();
4584 ARDOUR_UI::flush_videotimeline_cache (bool localcacheonly)
4586 if (localcacheonly) {
4587 video_timeline->vmon_update();
4589 video_timeline->flush_cache();
4591 editor->queue_visual_videotimeline_update();
4595 ARDOUR_UI::export_video (bool range)
4597 if (ARDOUR::Config->get_show_video_export_info()) {
4598 ExportVideoInfobox infobox (_session);
4599 Gtk::ResponseType rv = (Gtk::ResponseType) infobox.run();
4600 if (infobox.show_again()) {
4601 ARDOUR::Config->set_show_video_export_info(false);
4604 case GTK_RESPONSE_YES:
4605 PBD::open_uri (ARDOUR::Config->get_reference_manual_url() + "/video-timeline/operations/#export");
4611 export_video_dialog->set_session (_session);
4612 export_video_dialog->apply_state(editor->get_selection().time, range);
4613 export_video_dialog->run ();
4614 export_video_dialog->hide ();
4618 ARDOUR_UI::preferences_settings () const
4623 node = _session->instant_xml(X_("Preferences"));
4625 node = Config->instant_xml(X_("Preferences"));
4629 node = new XMLNode (X_("Preferences"));
4636 ARDOUR_UI::mixer_settings () const
4641 node = _session->instant_xml(X_("Mixer"));
4643 node = Config->instant_xml(X_("Mixer"));
4647 node = new XMLNode (X_("Mixer"));
4654 ARDOUR_UI::main_window_settings () const
4659 node = _session->instant_xml(X_("Main"));
4661 node = Config->instant_xml(X_("Main"));
4665 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4666 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4671 node = new XMLNode (X_("Main"));
4678 ARDOUR_UI::editor_settings () const
4683 node = _session->instant_xml(X_("Editor"));
4685 node = Config->instant_xml(X_("Editor"));
4689 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4690 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4695 node = new XMLNode (X_("Editor"));
4702 ARDOUR_UI::keyboard_settings () const
4706 node = Config->extra_xml(X_("Keyboard"));
4709 node = new XMLNode (X_("Keyboard"));
4716 ARDOUR_UI::create_xrun_marker (framepos_t where)
4719 Location *location = new Location (*_session, where, where, _("xrun"), Location::IsMark);
4720 _session->locations()->add (location);
4725 ARDOUR_UI::halt_on_xrun_message ()
4727 cerr << "HALT on xrun\n";
4728 MessageDialog msg (_main_window, _("Recording was stopped because your system could not keep up."));
4733 ARDOUR_UI::xrun_handler (framepos_t where)
4739 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
4741 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
4742 create_xrun_marker(where);
4745 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
4746 halt_on_xrun_message ();
4751 ARDOUR_UI::disk_overrun_handler ()
4753 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
4755 if (!have_disk_speed_dialog_displayed) {
4756 have_disk_speed_dialog_displayed = true;
4757 MessageDialog* msg = new MessageDialog (_main_window, string_compose (_("\
4758 The disk system on your computer\n\
4759 was not able to keep up with %1.\n\
4761 Specifically, it failed to write data to disk\n\
4762 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
4763 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4769 /* TODO: this is getting elaborate enough to warrant being split into a dedicated class */
4770 static MessageDialog *scan_dlg = NULL;
4771 static ProgressBar *scan_pbar = NULL;
4772 static HBox *scan_tbox = NULL;
4773 static Gtk::Button *scan_timeout_button;
4776 ARDOUR_UI::cancel_plugin_scan ()
4778 PluginManager::instance().cancel_plugin_scan();
4782 ARDOUR_UI::cancel_plugin_timeout ()
4784 PluginManager::instance().cancel_plugin_timeout();
4785 scan_timeout_button->set_sensitive (false);
4789 ARDOUR_UI::plugin_scan_timeout (int timeout)
4791 if (!scan_dlg || !scan_dlg->is_mapped() || !scan_pbar) {
4795 scan_pbar->set_sensitive (false);
4796 scan_timeout_button->set_sensitive (true);
4797 scan_pbar->set_fraction ((float) timeout / (float) Config->get_vst_scan_timeout());
4800 scan_pbar->set_sensitive (false);
4801 scan_timeout_button->set_sensitive (false);
4807 ARDOUR_UI::plugin_scan_dialog (std::string type, std::string plugin, bool can_cancel)
4809 if (type == X_("closeme") && !(scan_dlg && scan_dlg->is_mapped())) {
4813 const bool cancelled = PluginManager::instance().cancelled();
4814 if (type != X_("closeme") && (!UIConfiguration::instance().get_show_plugin_scan_window()) && !_initial_verbose_plugin_scan) {
4815 if (cancelled && scan_dlg->is_mapped()) {
4820 if (cancelled || !can_cancel) {
4825 static Gtk::Button *cancel_button;
4827 scan_dlg = new MessageDialog("", false, MESSAGE_INFO, BUTTONS_NONE); // TODO manage
4828 VBox* vbox = scan_dlg->get_vbox();
4829 vbox->set_size_request(400,-1);
4830 scan_dlg->set_title (_("Scanning for plugins"));
4832 cancel_button = manage(new Gtk::Button(_("Cancel plugin scan")));
4833 cancel_button->set_name ("EditorGTKButton");
4834 cancel_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_scan) );
4835 cancel_button->show();
4837 scan_dlg->get_vbox()->pack_start ( *cancel_button, PACK_SHRINK);
4839 scan_tbox = manage( new HBox() );
4841 scan_timeout_button = manage(new Gtk::Button(_("Stop Timeout")));
4842 scan_timeout_button->set_name ("EditorGTKButton");
4843 scan_timeout_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_timeout) );
4844 scan_timeout_button->show();
4846 scan_pbar = manage(new ProgressBar());
4847 scan_pbar->set_orientation(Gtk::PROGRESS_RIGHT_TO_LEFT);
4848 scan_pbar->set_text(_("Scan Timeout"));
4851 scan_tbox->pack_start (*scan_pbar, PACK_EXPAND_WIDGET, 4);
4852 scan_tbox->pack_start (*scan_timeout_button, PACK_SHRINK, 4);
4854 scan_dlg->get_vbox()->pack_start (*scan_tbox, PACK_SHRINK, 4);
4857 assert(scan_dlg && scan_tbox && cancel_button);
4859 if (type == X_("closeme")) {
4863 scan_dlg->set_message(type + ": " + Glib::path_get_basename(plugin));
4866 if (!can_cancel || !cancelled) {
4867 scan_timeout_button->set_sensitive(false);
4869 cancel_button->set_sensitive(can_cancel && !cancelled);
4875 ARDOUR_UI::gui_idle_handler ()
4878 /* due to idle calls, gtk_events_pending() may always return true */
4879 while (gtk_events_pending() && --timeout) {
4880 gtk_main_iteration ();
4885 ARDOUR_UI::disk_underrun_handler ()
4887 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
4889 if (!have_disk_speed_dialog_displayed) {
4890 have_disk_speed_dialog_displayed = true;
4891 MessageDialog* msg = new MessageDialog (
4892 _main_window, string_compose (_("The disk system on your computer\n\
4893 was not able to keep up with %1.\n\
4895 Specifically, it failed to read data from disk\n\
4896 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
4897 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4903 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
4905 have_disk_speed_dialog_displayed = false;
4910 ARDOUR_UI::session_dialog (std::string msg)
4912 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
4916 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
4923 ARDOUR_UI::pending_state_dialog ()
4925 HBox* hbox = manage (new HBox());
4926 Image* image = manage (new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG));
4927 ArdourDialog dialog (_("Crash Recovery"), true);
4928 Label message (string_compose (_("\
4929 This session appears to have been in the\n\
4930 middle of recording when %1 or\n\
4931 the computer was shutdown.\n\
4933 %1 can recover any captured audio for\n\
4934 you, or it can ignore it. Please decide\n\
4935 what you would like to do.\n"), PROGRAM_NAME));
4936 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4937 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4938 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4939 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4940 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
4941 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
4942 dialog.set_default_response (RESPONSE_ACCEPT);
4943 dialog.set_position (WIN_POS_CENTER);
4948 switch (dialog.run ()) {
4949 case RESPONSE_ACCEPT:
4957 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
4959 HBox* hbox = new HBox();
4960 Image* image = new Image (Stock::DIALOG_WARNING, ICON_SIZE_DIALOG);
4961 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
4962 Label message (string_compose (_("\
4963 This session was created with a sample rate of %1 Hz, but\n\
4964 %2 is currently running at %3 Hz. If you load this session,\n\
4965 audio may be played at the wrong sample rate.\n"), desired, PROGRAM_NAME, actual));
4967 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4968 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4969 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4970 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4971 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
4972 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
4973 dialog.set_default_response (RESPONSE_ACCEPT);
4974 dialog.set_position (WIN_POS_CENTER);
4979 switch (dialog.run()) {
4980 case RESPONSE_ACCEPT:
4990 ARDOUR_UI::sr_mismatch_message (framecnt_t desired, framecnt_t actual)
4992 MessageDialog msg (string_compose (_("\
4993 This session was created with a sample rate of %1 Hz, but\n\
4994 %2 is currently running at %3 Hz.\n\
4995 Audio will be recorded and played at the wrong sample rate.\n\
4996 Re-Configure the Audio Engine in\n\
4997 Menu > Window > Audio/Midi Setup"),
4998 desired, PROGRAM_NAME, actual),
5000 Gtk::MESSAGE_WARNING);
5005 ARDOUR_UI::use_config ()
5007 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
5009 set_transport_controllable_state (*node);
5014 ARDOUR_UI::update_transport_clocks (framepos_t pos)
5016 if (UIConfiguration::instance().get_primary_clock_delta_edit_cursor()) {
5017 primary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
5019 primary_clock->set (pos);
5022 if (UIConfiguration::instance().get_secondary_clock_delta_edit_cursor()) {
5023 secondary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
5025 secondary_clock->set (pos);
5028 if (big_clock_window) {
5029 big_clock->set (pos);
5031 ARDOUR_UI::instance()->video_timeline->manual_seek_video_monitor(pos);
5035 ARDOUR_UI::step_edit_status_change (bool yn)
5037 // XXX should really store pre-step edit status of things
5038 // we make insensitive
5041 rec_button.set_active_state (Gtkmm2ext::ImplicitActive);
5042 rec_button.set_sensitive (false);
5044 rec_button.unset_active_state ();;
5045 rec_button.set_sensitive (true);
5050 ARDOUR_UI::record_state_changed ()
5052 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
5055 /* why bother - the clock isn't visible */
5059 ActionManager::set_sensitive (ActionManager::rec_sensitive_actions, !_session->actively_recording());
5061 if (big_clock_window) {
5062 if (_session->record_status () == Session::Recording && _session->have_rec_enabled_track ()) {
5063 big_clock->set_active (true);
5065 big_clock->set_active (false);
5072 ARDOUR_UI::first_idle ()
5075 _session->allow_auto_play (true);
5079 editor->first_idle();
5082 Keyboard::set_can_save_keybindings (true);
5087 ARDOUR_UI::store_clock_modes ()
5089 XMLNode* node = new XMLNode(X_("ClockModes"));
5091 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
5092 XMLNode* child = new XMLNode (X_("Clock"));
5094 child->add_property (X_("name"), (*x)->name());
5095 child->add_property (X_("mode"), enum_2_string ((*x)->mode()));
5096 child->add_property (X_("on"), ((*x)->off() ? X_("no") : X_("yes")));
5098 node->add_child_nocopy (*child);
5101 _session->add_extra_xml (*node);
5102 _session->set_dirty ();
5105 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
5106 : Controllable (name), ui (u), type(tp)
5112 ARDOUR_UI::TransportControllable::set_value (double val, PBD::Controllable::GroupControlDisposition /*group_override*/)
5115 /* do nothing: these are radio-style actions */
5119 const char *action = 0;
5123 action = X_("Roll");
5126 action = X_("Stop");
5129 action = X_("GotoStart");
5132 action = X_("GotoEnd");
5135 action = X_("Loop");
5138 action = X_("PlaySelection");
5141 action = X_("Record");
5151 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
5159 ARDOUR_UI::TransportControllable::get_value (void) const
5186 ARDOUR_UI::setup_profile ()
5188 if (gdk_screen_width() < 1200 || getenv ("ARDOUR_NARROW_SCREEN")) {
5189 Profile->set_small_screen ();
5192 if (g_getenv ("TRX")) {
5193 Profile->set_trx ();
5196 if (g_getenv ("MIXBUS")) {
5197 Profile->set_mixbus ();
5202 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
5204 MissingFileDialog dialog (s, str, type);
5209 int result = dialog.run ();
5216 return 1; // quit entire session load
5219 result = dialog.get_action ();
5225 ARDOUR_UI::ambiguous_file (std::string file, std::vector<std::string> hits)
5227 AmbiguousFileDialog dialog (file, hits);
5234 return dialog.get_which ();
5237 /** Allocate our thread-local buffers */
5239 ARDOUR_UI::get_process_buffers ()
5241 _process_thread->get_buffers ();
5244 /** Drop our thread-local buffers */
5246 ARDOUR_UI::drop_process_buffers ()
5248 _process_thread->drop_buffers ();
5252 ARDOUR_UI::feedback_detected ()
5254 _feedback_exists = true;
5258 ARDOUR_UI::successful_graph_sort ()
5260 _feedback_exists = false;
5264 ARDOUR_UI::midi_panic ()
5267 _session->midi_panic();
5272 ARDOUR_UI::session_format_mismatch (std::string xml_path, std::string backup_path)
5274 const char* start_big = "<span size=\"x-large\" weight=\"bold\">";
5275 const char* end_big = "</span>";
5276 const char* start_mono = "<tt>";
5277 const char* end_mono = "</tt>";
5279 MessageDialog msg (string_compose (_("%4This is a session from an older version of %3%5\n\n"
5280 "%3 has copied the old session file\n\n%6%1%7\n\nto\n\n%6%2%7\n\n"
5281 "From now on, use the backup copy with older versions of %3"),
5282 xml_path, backup_path, PROGRAM_NAME,
5284 start_mono, end_mono), true);
5291 ARDOUR_UI::reset_peak_display ()
5293 if (!_session || !_session->master_out() || !editor_meter) return;
5294 editor_meter->clear_meters();
5295 editor_meter_max_peak = -INFINITY;
5296 editor_meter_peak_display.set_active_state ( Gtkmm2ext::Off );
5300 ARDOUR_UI::reset_group_peak_display (RouteGroup* group)
5302 if (!_session || !_session->master_out()) return;
5303 if (group == _session->master_out()->route_group()) {
5304 reset_peak_display ();
5309 ARDOUR_UI::reset_route_peak_display (Route* route)
5311 if (!_session || !_session->master_out()) return;
5312 if (_session->master_out().get() == route) {
5313 reset_peak_display ();
5318 ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate)
5320 audio_midi_setup->set_desired_sample_rate (desired_sample_rate);
5321 audio_midi_setup->set_position (WIN_POS_CENTER);
5323 if (Config->get_try_autostart_engine () || getenv ("TRY_AUTOSTART_ENGINE")) {
5324 audio_midi_setup->try_autostart ();
5325 if (ARDOUR::AudioEngine::instance()->running()) {
5331 int response = audio_midi_setup->run();
5333 case Gtk::RESPONSE_OK:
5334 if (!AudioEngine::instance()->running()) {
5348 ARDOUR_UI::transport_numpad_timeout ()
5350 _numpad_locate_happening = false;
5351 if (_numpad_timeout_connection.connected() )
5352 _numpad_timeout_connection.disconnect();
5357 ARDOUR_UI::transport_numpad_decimal ()
5359 _numpad_timeout_connection.disconnect();
5361 if (_numpad_locate_happening) {
5362 if (editor) editor->goto_nth_marker(_pending_locate_num - 1);
5363 _numpad_locate_happening = false;
5365 _pending_locate_num = 0;
5366 _numpad_locate_happening = true;
5367 _numpad_timeout_connection = Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::transport_numpad_timeout), 2*1000);
5372 ARDOUR_UI::transport_numpad_event (int num)
5374 if ( _numpad_locate_happening ) {
5375 _pending_locate_num = _pending_locate_num*10 + num;
5378 case 0: toggle_roll(false, false); break;
5379 case 1: transport_rewind(1); break;
5380 case 2: transport_forward(1); break;
5381 case 3: transport_record(true); break;
5382 case 4: toggle_session_auto_loop(); break;
5383 case 5: transport_record(false); toggle_session_auto_loop(); break;
5384 case 6: toggle_punch(); break;
5385 case 7: toggle_click(); break;
5386 case 8: toggle_auto_return(); break;
5387 case 9: toggle_follow_edits(); break;
5393 ARDOUR_UI::set_flat_buttons ()
5395 CairoWidget::set_flat_buttons( UIConfiguration::instance().get_flat_buttons() );
5399 ARDOUR_UI::audioengine_became_silent ()
5401 MessageDialog msg (string_compose (_("This is a free/demo copy of %1. It has just switched to silent mode."), PROGRAM_NAME),
5403 Gtk::MESSAGE_WARNING,
5407 msg.set_title (string_compose (_("%1 is now silent"), PROGRAM_NAME));
5409 Gtk::Label pay_label (string_compose (_("Please consider paying for a copy of %1 - you can pay whatever you want."), PROGRAM_NAME));
5410 Gtk::Label subscribe_label (_("Better yet become a subscriber - subscriptions start at US$1 per month."));
5411 Gtk::Button pay_button (_("Pay for a copy (via the web)"));
5412 Gtk::Button subscribe_button (_("Become a subscriber (via the web)"));
5413 Gtk::HBox pay_button_box;
5414 Gtk::HBox subscribe_button_box;
5416 pay_button_box.pack_start (pay_button, true, false);
5417 subscribe_button_box.pack_start (subscribe_button, true, false);
5419 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 */
5421 pay_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://ardour.org/download")));
5422 subscribe_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://community.ardour.org/s/subscribe")));
5424 msg.get_vbox()->pack_start (pay_label);
5425 msg.get_vbox()->pack_start (pay_button_box);
5426 msg.get_vbox()->pack_start (subscribe_label);
5427 msg.get_vbox()->pack_start (subscribe_button_box);
5429 msg.get_vbox()->show_all ();
5431 msg.add_button (_("Remain silent"), Gtk::RESPONSE_CANCEL);
5432 msg.add_button (_("Save and quit"), Gtk::RESPONSE_NO);
5433 msg.add_button (_("Give me more time"), Gtk::RESPONSE_YES);
5438 case Gtk::RESPONSE_YES:
5439 AudioEngine::instance()->reset_silence_countdown ();
5442 case Gtk::RESPONSE_NO:
5444 save_state_canfail ("");
5448 case Gtk::RESPONSE_CANCEL:
5450 /* don't reset, save session and exit */
5456 ARDOUR_UI::hide_application ()
5458 Application::instance ()-> hide ();
5462 ARDOUR_UI::setup_toplevel_window (Gtk::Window& window, const string& name, void* owner)
5464 /* icons, titles, WM stuff */
5466 static list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
5468 if (window_icons.empty()) {
5469 Glib::RefPtr<Gdk::Pixbuf> icon;
5470 if ((icon = ::get_icon (PROGRAM_NAME "-icon_16px"))) {
5471 window_icons.push_back (icon);
5473 if ((icon = ::get_icon (PROGRAM_NAME "-icon_22px"))) {
5474 window_icons.push_back (icon);
5476 if ((icon = ::get_icon (PROGRAM_NAME "-icon_32px"))) {
5477 window_icons.push_back (icon);
5479 if ((icon = ::get_icon (PROGRAM_NAME "-icon_48px"))) {
5480 window_icons.push_back (icon);
5484 if (!window_icons.empty()) {
5485 window.set_default_icon_list (window_icons);
5488 Gtkmm2ext::WindowTitle title (Glib::get_application_name());
5490 if (!name.empty()) {
5494 window.set_title (title.get_string());
5495 window.set_wmclass (string_compose (X_("%1_%1"), downcase (PROGRAM_NAME), downcase (name)), PROGRAM_NAME);
5497 window.set_flags (CAN_FOCUS);
5498 window.add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
5500 /* This is a hack to ensure that GTK-accelerators continue to
5501 * work. Once we switch over to entirely native bindings, this will be
5502 * unnecessary and should be removed
5504 window.add_accel_group (ActionManager::ui_manager->get_accel_group());
5506 window.signal_configure_event().connect (sigc::mem_fun (*this, &ARDOUR_UI::configure_handler));
5507 window.signal_window_state_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::tabbed_window_state_event_handler), owner));
5508 window.signal_key_press_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5509 window.signal_key_release_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5513 ARDOUR_UI::key_event_handler (GdkEventKey* ev, Gtk::Window* event_window)
5515 Gtkmm2ext::Bindings* bindings = 0;
5516 Gtk::Window* window = 0;
5518 /* until we get ardour bindings working, we are not handling key
5522 if (ev->type != GDK_KEY_PRESS) {
5526 if (event_window == &_main_window) {
5528 window = event_window;
5530 /* find current tab contents */
5532 Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page());
5534 /* see if it uses the ardour binding system */
5537 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(w->get_data ("ardour-bindings"));
5540 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("main window key event, bindings = %1, global = %2\n", bindings, &global_bindings));
5544 window = event_window;
5546 /* see if window uses ardour binding system */
5548 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(window->get_data ("ardour-bindings"));
5551 /* An empty binding set is treated as if it doesn't exist */
5553 if (bindings && bindings->empty()) {
5557 return key_press_focus_accelerator_handler (*window, ev, bindings);
5560 static Gtkmm2ext::Bindings*
5561 get_bindings_from_widget_heirarchy (GtkWidget* w)
5566 if ((p = g_object_get_data (G_OBJECT(w), "ardour-bindings")) != 0) {
5569 w = gtk_widget_get_parent (w);
5572 return reinterpret_cast<Gtkmm2ext::Bindings*> (p);
5576 ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev, Gtkmm2ext::Bindings* bindings)
5578 GtkWindow* win = window.gobj();
5579 GtkWidget* focus = gtk_window_get_focus (win);
5580 bool special_handling_of_unmodified_accelerators = false;
5581 const guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK));
5585 /* some widget has keyboard focus */
5587 if (GTK_IS_ENTRY(focus) || Keyboard::some_magic_widget_has_focus()) {
5589 /* A particular kind of focusable widget currently has keyboard
5590 * focus. All unmodified key events should go to that widget
5591 * first and not be used as an accelerator by default
5594 special_handling_of_unmodified_accelerators = true;
5598 Gtkmm2ext::Bindings* focus_bindings = get_bindings_from_widget_heirarchy (focus);
5599 if (focus_bindings) {
5600 bindings = focus_bindings;
5601 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Switch bindings based on focus widget, now using %1\n", bindings->name()));
5606 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",
5609 Gtkmm2ext::show_gdk_event_state (ev->state),
5610 special_handling_of_unmodified_accelerators,
5611 Keyboard::some_magic_widget_has_focus(),
5613 (focus ? gtk_widget_get_name (focus) : "no focus widget"),
5614 ((ev->state & mask) ? "yes" : "no"),
5615 window.get_title()));
5617 /* This exists to allow us to override the way GTK handles
5618 key events. The normal sequence is:
5620 a) event is delivered to a GtkWindow
5621 b) accelerators/mnemonics are activated
5622 c) if (b) didn't handle the event, propagate to
5623 the focus widget and/or focus chain
5625 The problem with this is that if the accelerators include
5626 keys without modifiers, such as the space bar or the
5627 letter "e", then pressing the key while typing into
5628 a text entry widget results in the accelerator being
5629 activated, instead of the desired letter appearing
5632 There is no good way of fixing this, but this
5633 represents a compromise. The idea is that
5634 key events involving modifiers (not Shift)
5635 get routed into the activation pathway first, then
5636 get propagated to the focus widget if necessary.
5638 If the key event doesn't involve modifiers,
5639 we deliver to the focus widget first, thus allowing
5640 it to get "normal text" without interference
5643 Of course, this can also be problematic: if there
5644 is a widget with focus, then it will swallow
5645 all "normal text" accelerators.
5649 if (!special_handling_of_unmodified_accelerators || (ev->state & mask)) {
5651 /* no special handling or there are modifiers in effect: accelerate first */
5653 DEBUG_TRACE (DEBUG::Accelerators, "\tactivate, then propagate\n");
5654 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tevent send-event:%1 time:%2 length:%3 name %7 string:%4 hardware_keycode:%5 group:%6\n",
5655 ev->send_event, ev->time, ev->length, ev->string, ev->hardware_keycode, ev->group, gdk_keyval_name (ev->keyval)));
5657 DEBUG_TRACE (DEBUG::Accelerators, "\tsending to window\n");
5658 KeyboardKey k (ev->state, ev->keyval);
5662 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tusing Ardour bindings %1 @ %2 for this event\n", bindings->name(), bindings));
5664 if (bindings->activate (k, Bindings::Press)) {
5665 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5670 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5672 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5673 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5677 DEBUG_TRACE (DEBUG::Accelerators, "\tnot accelerated, now propagate\n");
5679 if (gtk_window_propagate_key_event (win, ev)) {
5680 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate handled\n");
5686 /* no modifiers, propagate first */
5688 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate, then activate\n");
5690 if (gtk_window_propagate_key_event (win, ev)) {
5691 DEBUG_TRACE (DEBUG::Accelerators, "\thandled by propagate\n");
5695 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagation didn't handle, so activate\n");
5696 KeyboardKey k (ev->state, ev->keyval);
5700 DEBUG_TRACE (DEBUG::Accelerators, "\tusing Ardour bindings for this window\n");
5703 if (bindings->activate (k, Bindings::Press)) {
5704 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5710 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5712 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5713 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5718 DEBUG_TRACE (DEBUG::Accelerators, "\tnot handled\n");
5723 ARDOUR_UI::load_bindings ()
5725 if ((global_bindings = Bindings::get_bindings (X_("Global"), global_actions)) == 0) {
5726 error << _("Global keybindings are missing") << endmsg;
5731 ARDOUR_UI::cancel_solo ()
5734 _session->cancel_all_solo ();
5739 ARDOUR_UI::reset_focus (Gtk::Widget* w)
5741 /* this resets focus to the first focusable parent of the given widget,
5742 * or, if there is no focusable parent, cancels focus in the toplevel
5743 * window that the given widget is packed into (if there is one).
5750 Gtk::Widget* top = w->get_toplevel();
5752 if (!top || !top->is_toplevel()) {
5756 w = w->get_parent ();
5760 if (w->is_toplevel()) {
5761 /* Setting the focus widget to a Gtk::Window causes all
5762 * subsequent calls to ::has_focus() on the nominal
5763 * focus widget in that window to return
5764 * false. Workaround: never set focus to the toplevel
5770 if (w->get_can_focus ()) {
5771 Gtk::Window* win = dynamic_cast<Gtk::Window*> (top);
5772 win->set_focus (*w);
5775 w = w->get_parent ();
5778 if (top == &_main_window) {
5782 /* no focusable parent found, cancel focus in top level window.
5783 C++ API cannot be used for this. Thanks, references.
5786 gtk_window_set_focus (GTK_WINDOW(top->gobj()), 0);