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 "speaker_dialog.h"
173 #include "time_axis_view_item.h"
174 #include "time_info_box.h"
177 #include "utils_videotl.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 , ignore_session_monitoring (false)
268 , main_window_visibility (0)
273 , _mixer_on_top (false)
274 , _initial_verbose_plugin_scan (false)
275 , first_time_engine_run (true)
276 , secondary_clock_spacer (0)
277 , roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll))
278 , stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop))
279 , goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart))
280 , goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd))
281 , auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop))
282 , play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection))
283 , rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable))
285 , auto_input_button (ArdourButton::led_default_elements)
286 , auto_return_button (ArdourButton::led_default_elements)
287 , follow_edits_button (ArdourButton::led_default_elements)
288 , auditioning_alert_button (_("Audition"))
289 , solo_alert_button (_("Solo"))
290 , feedback_alert_button (_("Feedback"))
291 , error_alert_button ( ArdourButton::just_led_default_elements )
293 , editor_meter_peak_display()
294 , _numpad_locate_happening (false)
295 , _session_is_new (false)
296 , last_key_press_time (0)
300 , rc_option_editor (0)
301 , speaker_config_window (X_("speaker-config"), _("Speaker Configuration"))
302 , add_route_dialog (X_("add-routes"), _("Add Tracks/Busses"))
303 , about (X_("about"), _("About"))
304 , location_ui (X_("locations"), S_("Ranges|Locations"))
305 , route_params (X_("inspector"), _("Tracks and Busses"))
306 , audio_midi_setup (X_("audio-midi-setup"), _("Audio/MIDI Setup"))
307 , export_video_dialog (X_("video-export"), _("Video Export Dialog"))
308 , lua_script_window (X_("script-manager"), _("Script Manager"))
309 , session_option_editor (X_("session-options-editor"), _("Properties"), boost::bind (&ARDOUR_UI::create_session_option_editor, this))
310 , add_video_dialog (X_("add-video"), _("Add Video"), boost::bind (&ARDOUR_UI::create_add_video_dialog, this))
311 , bundle_manager (X_("bundle-manager"), _("Bundle Manager"), boost::bind (&ARDOUR_UI::create_bundle_manager, this))
312 , big_clock_window (X_("big-clock"), _("Big Clock"), boost::bind (&ARDOUR_UI::create_big_clock_window, this))
313 , audio_port_matrix (X_("audio-connection-manager"), _("Audio Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::AUDIO))
314 , midi_port_matrix (X_("midi-connection-manager"), _("MIDI Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::MIDI))
315 , key_editor (X_("key-editor"), _("Keyboard Shortcuts"), boost::bind (&ARDOUR_UI::create_key_editor, this))
316 , video_server_process (0)
318 , have_configure_timeout (false)
319 , last_configure_time (0)
321 , have_disk_speed_dialog_displayed (false)
322 , _status_bar_visibility (X_("status-bar"))
323 , _feedback_exists (false)
324 , _log_not_acknowledged (LogLevelNone)
325 , duplicate_routes_dialog (0)
326 , editor_visibility_button (S_("Window|Editor"))
327 , mixer_visibility_button (S_("Window|Mixer"))
328 , prefs_visibility_button (S_("Window|Preferences"))
330 Gtkmm2ext::init (localedir);
332 UIConfiguration::instance().post_gui_init ();
334 if (ARDOUR::handle_old_configuration_files (boost::bind (ask_about_configuration_copy, _1, _2, _3))) {
335 MessageDialog msg (string_compose (_("Your configuration files were copied. You can now restart %1."), PROGRAM_NAME), true);
337 /* configuration was modified, exit immediately */
342 if (string (VERSIONSTRING).find (".pre") != string::npos) {
343 /* check this is not being run from ./ardev etc. */
344 if (!running_from_source_tree ()) {
345 pre_release_dialog ();
349 if (theArdourUI == 0) {
353 /* track main window visibility */
355 main_window_visibility = new VisibilityTracker (_main_window);
357 /* stop libxml from spewing to stdout/stderr */
359 xmlSetGenericErrorFunc (this, libxml_generic_error_func);
360 xmlSetStructuredErrorFunc (this, libxml_structured_error_func);
362 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::parameter_changed));
363 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
364 UIConfiguration::instance().map_parameters (pc);
366 roll_button.set_controllable (roll_controllable);
367 stop_button.set_controllable (stop_controllable);
368 goto_start_button.set_controllable (goto_start_controllable);
369 goto_end_button.set_controllable (goto_end_controllable);
370 auto_loop_button.set_controllable (auto_loop_controllable);
371 play_selection_button.set_controllable (play_selection_controllable);
372 rec_button.set_controllable (rec_controllable);
374 roll_button.set_name ("transport button");
375 stop_button.set_name ("transport button");
376 goto_start_button.set_name ("transport button");
377 goto_end_button.set_name ("transport button");
378 auto_loop_button.set_name ("transport button");
379 play_selection_button.set_name ("transport button");
380 rec_button.set_name ("transport recenable button");
381 midi_panic_button.set_name ("transport button");
383 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
384 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
386 ARDOUR::Session::VersionMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_format_mismatch, this, _1, _2), gui_context());
388 /* handle dialog requests */
390 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
392 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
394 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
396 /* handle Audio/MIDI setup when session requires it */
398 ARDOUR::Session::AudioEngineSetupRequired.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::do_audio_midi_setup, this, _1));
400 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
402 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
404 /* handle sr mismatch with a dialog - cross-thread from engine */
405 ARDOUR::Session::NotifyAboutSampleRateMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::sr_mismatch_message, this, _1, _2), gui_context ());
407 /* handle requests to quit (coming from JACK session) */
409 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::finish, this), gui_context ());
411 /* tell the user about feedback */
413 ARDOUR::Session::FeedbackDetected.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::feedback_detected, this), gui_context ());
414 ARDOUR::Session::SuccessfulGraphSort.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::successful_graph_sort, this), gui_context ());
416 /* handle requests to deal with missing files */
418 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
420 /* and ambiguous files */
422 ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2));
424 /* also plugin scan messages */
425 ARDOUR::PluginScanMessage.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_dialog, this, _1, _2, _3), gui_context());
426 ARDOUR::PluginScanTimeout.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_timeout, this, _1), gui_context());
428 ARDOUR::GUIIdle.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::gui_idle_handler, this), gui_context());
430 Config->ParameterChanged.connect ( forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::set_flat_buttons, this), gui_context() );
433 /* lets get this party started */
435 setup_gtk_ardour_enums ();
438 SessionEvent::create_per_thread_pool ("GUI", 4096);
440 /* we like keyboards */
442 keyboard = new ArdourKeyboard(*this);
444 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
446 keyboard->set_state (*node, Stateful::loading_state_version);
449 UIConfiguration::instance().reset_dpi ();
451 TimeAxisViewItem::set_constant_heights ();
453 /* Set this up so that our window proxies can register actions */
455 ActionManager::init ();
457 /* The following must happen after ARDOUR::init() so that Config is set up */
459 const XMLNode* ui_xml = Config->extra_xml (X_("UI"));
462 key_editor.set_state (*ui_xml, 0);
463 session_option_editor.set_state (*ui_xml, 0);
464 speaker_config_window.set_state (*ui_xml, 0);
465 about.set_state (*ui_xml, 0);
466 add_route_dialog.set_state (*ui_xml, 0);
467 add_video_dialog.set_state (*ui_xml, 0);
468 route_params.set_state (*ui_xml, 0);
469 bundle_manager.set_state (*ui_xml, 0);
470 location_ui.set_state (*ui_xml, 0);
471 big_clock_window.set_state (*ui_xml, 0);
472 audio_port_matrix.set_state (*ui_xml, 0);
473 midi_port_matrix.set_state (*ui_xml, 0);
474 export_video_dialog.set_state (*ui_xml, 0);
475 lua_script_window.set_state (*ui_xml, 0);
478 /* Separate windows */
480 WM::Manager::instance().register_window (&key_editor);
481 WM::Manager::instance().register_window (&session_option_editor);
482 WM::Manager::instance().register_window (&speaker_config_window);
483 WM::Manager::instance().register_window (&about);
484 WM::Manager::instance().register_window (&add_route_dialog);
485 WM::Manager::instance().register_window (&add_video_dialog);
486 WM::Manager::instance().register_window (&route_params);
487 WM::Manager::instance().register_window (&audio_midi_setup);
488 WM::Manager::instance().register_window (&export_video_dialog);
489 WM::Manager::instance().register_window (&lua_script_window);
490 WM::Manager::instance().register_window (&bundle_manager);
491 WM::Manager::instance().register_window (&location_ui);
492 WM::Manager::instance().register_window (&big_clock_window);
493 WM::Manager::instance().register_window (&audio_port_matrix);
494 WM::Manager::instance().register_window (&midi_port_matrix);
496 /* do not retain position for add route dialog */
497 add_route_dialog.set_state_mask (WindowProxy::Size);
499 /* Trigger setting up the color scheme and loading the GTK RC file */
501 UIConfiguration::instance().load_rc_file (false);
503 _process_thread = new ProcessThread ();
504 _process_thread->init ();
506 UIConfiguration::instance().DPIReset.connect (sigc::mem_fun (*this, &ARDOUR_UI::resize_text_widgets));
512 ARDOUR_UI::pre_release_dialog ()
514 ArdourDialog d (_("Pre-Release Warning"), true, false);
515 d.add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
517 Label* label = manage (new Label);
518 label->set_markup (string_compose (_("<b>Welcome to this pre-release build of %1 %2</b>\n\n\
519 There are still several issues and bugs to be worked on,\n\
520 as well as general workflow improvements, before this can be considered\n\
521 release software. So, a few guidelines:\n\
523 1) Please do <b>NOT</b> use this software with the expectation that it is stable or reliable\n\
524 though it may be so, depending on your workflow.\n\
525 2) Please wait for a helpful writeup of new features.\n\
526 3) <b>Please do NOT use the forums at ardour.org to report issues</b>.\n\
527 4) Please <b>DO</b> use the bugtracker at http://tracker.ardour.org/ to report issues\n\
528 making sure to note the product version number as 5.0-pre.\n\
529 5) Please <b>DO</b> use the ardour-users mailing list to discuss ideas and pass on comments.\n\
530 6) Please <b>DO</b> join us on IRC for real time discussions about %1 %2. You\n\
531 can get there directly from within the program via the Help->Chat menu option.\n\
533 Full information on all the above can be found on the support page at\n\
535 http://ardour.org/support\n\
536 "), PROGRAM_NAME, VERSIONSTRING));
538 d.get_vbox()->set_border_width (12);
539 d.get_vbox()->pack_start (*label, false, false, 12);
540 d.get_vbox()->show_all ();
545 GlobalPortMatrixWindow*
546 ARDOUR_UI::create_global_port_matrix (ARDOUR::DataType type)
551 return new GlobalPortMatrixWindow (_session, type);
555 ARDOUR_UI::attach_to_engine ()
557 AudioEngine::instance()->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
558 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
562 ARDOUR_UI::engine_stopped ()
564 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
565 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
566 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
567 update_sample_rate (0);
572 ARDOUR_UI::engine_running ()
574 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
575 if (first_time_engine_run) {
577 first_time_engine_run = false;
581 _session->reset_xrun_count ();
583 update_disk_space ();
585 update_xrun_count ();
586 update_sample_rate (AudioEngine::instance()->sample_rate());
587 update_timecode_format ();
588 update_peak_thread_work ();
589 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, true);
590 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, false);
594 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
596 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
597 /* we can't rely on the original string continuing to exist when we are called
598 again in the GUI thread, so make a copy and note that we need to
601 char *copy = strdup (reason);
602 Gtkmm2ext::UI::instance()->call_slot (MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
606 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
607 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
609 update_sample_rate (0);
613 /* if the reason is a non-empty string, it means that the backend was shutdown
614 rather than just Ardour.
617 if (strlen (reason)) {
618 msgstr = string_compose (_("The audio backend was shutdown because:\n\n%1"), reason);
620 msgstr = string_compose (_("\
621 The audio backend has either been shutdown or it\n\
622 disconnected %1 because %1\n\
623 was not fast enough. Try to restart\n\
624 the audio backend and save the session."), PROGRAM_NAME);
627 MessageDialog msg (_main_window, msgstr);
628 pop_back_splash (msg);
632 free (const_cast<char*> (reason));
637 ARDOUR_UI::post_engine ()
639 /* Things to be done once (and once ONLY) after we have a backend running in the AudioEngine
641 #ifdef AUDIOUNIT_SUPPORT
643 if (AUPluginInfo::au_get_crashlog(au_msg)) {
644 popup_error(_("Audio Unit Plugin Scan Failed. Automatic AU scanning has been disabled. Please see the log window for further details."));
645 error << _("Audio Unit Plugin Scan Failed:") << endmsg;
646 info << au_msg << endmsg;
650 ARDOUR::init_post_engine ();
652 /* connect to important signals */
654 AudioEngine::instance()->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
655 AudioEngine::instance()->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
656 AudioEngine::instance()->BufferSizeChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
657 AudioEngine::instance()->Halted.connect_same_thread (halt_connection, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
658 AudioEngine::instance()->BecameSilent.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::audioengine_became_silent, this), gui_context());
660 if (setup_windows ()) {
661 throw failed_constructor ();
664 /* Do this after setup_windows (), as that's when the _status_bar_visibility is created */
665 XMLNode* n = Config->extra_xml (X_("UI"));
667 _status_bar_visibility.set_state (*n);
670 check_memory_locking();
672 /* this is the first point at which all the possible actions are
673 * available, because some of the available actions are dependent on
674 * aspects of the engine/backend.
677 if (ARDOUR_COMMAND_LINE::show_key_actions) {
680 vector<string> paths;
681 vector<string> labels;
682 vector<string> tooltips;
684 vector<Glib::RefPtr<Gtk::Action> > actions;
686 Gtkmm2ext::ActionMap::get_all_actions (paths, labels, tooltips, keys, actions);
688 vector<string>::iterator k;
689 vector<string>::iterator p;
691 for (p = paths.begin(), k = keys.begin(); p != paths.end(); ++k, ++p) {
696 cout << *p << " => " << *k << endl;
700 halt_connection.disconnect ();
701 AudioEngine::instance()->stop ();
705 /* this being a GUI and all, we want peakfiles */
707 AudioFileSource::set_build_peakfiles (true);
708 AudioFileSource::set_build_missing_peakfiles (true);
710 /* set default clock modes */
712 primary_clock->set_mode (AudioClock::Timecode);
713 secondary_clock->set_mode (AudioClock::BBT);
715 /* start the time-of-day-clock */
718 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
719 update_wall_clock ();
720 Glib::signal_timeout().connect_seconds (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 1);
725 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
726 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
727 Config->map_parameters (pc);
729 UIConfiguration::instance().map_parameters (pc);
733 ARDOUR_UI::~ARDOUR_UI ()
735 UIConfiguration::instance().save_state();
739 if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
740 // don't bother at 'real' exit. the OS cleans up for us.
741 delete big_clock; big_clock = 0;
742 delete primary_clock; primary_clock = 0;
743 delete secondary_clock; secondary_clock = 0;
744 delete _process_thread; _process_thread = 0;
745 delete time_info_box; time_info_box = 0;
746 delete meterbridge; meterbridge = 0;
747 delete luawindow; luawindow = 0;
748 delete editor; editor = 0;
749 delete mixer; mixer = 0;
751 delete gui_object_state; gui_object_state = 0;
752 delete main_window_visibility;
753 FastMeter::flush_pattern_cache ();
754 PixFader::flush_pattern_cache ();
758 /* Small trick to flush main-thread event pool.
759 * Other thread-pools are destroyed at pthread_exit(),
760 * but tmain thread termination is too late to trigger Pool::~Pool()
762 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.
763 delete ev->event_pool();
768 ARDOUR_UI::pop_back_splash (Gtk::Window& win)
770 if (Splash::instance()) {
771 Splash::instance()->pop_back_for (win);
776 ARDOUR_UI::configure_timeout ()
778 if (last_configure_time == 0) {
779 /* no configure events yet */
783 /* force a gap of 0.5 seconds since the last configure event
786 if (get_microseconds() - last_configure_time < 500000) {
789 have_configure_timeout = false;
790 save_ardour_state ();
796 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
798 if (have_configure_timeout) {
799 last_configure_time = get_microseconds();
801 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
802 have_configure_timeout = true;
809 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
811 XMLProperty const * prop;
813 if ((prop = node.property ("roll")) != 0) {
814 roll_controllable->set_id (prop->value());
816 if ((prop = node.property ("stop")) != 0) {
817 stop_controllable->set_id (prop->value());
819 if ((prop = node.property ("goto-start")) != 0) {
820 goto_start_controllable->set_id (prop->value());
822 if ((prop = node.property ("goto-end")) != 0) {
823 goto_end_controllable->set_id (prop->value());
825 if ((prop = node.property ("auto-loop")) != 0) {
826 auto_loop_controllable->set_id (prop->value());
828 if ((prop = node.property ("play-selection")) != 0) {
829 play_selection_controllable->set_id (prop->value());
831 if ((prop = node.property ("rec")) != 0) {
832 rec_controllable->set_id (prop->value());
834 if ((prop = node.property ("shuttle")) != 0) {
835 shuttle_box.controllable()->set_id (prop->value());
840 ARDOUR_UI::get_transport_controllable_state ()
842 XMLNode* node = new XMLNode(X_("TransportControllables"));
845 roll_controllable->id().print (buf, sizeof (buf));
846 node->add_property (X_("roll"), buf);
847 stop_controllable->id().print (buf, sizeof (buf));
848 node->add_property (X_("stop"), buf);
849 goto_start_controllable->id().print (buf, sizeof (buf));
850 node->add_property (X_("goto_start"), buf);
851 goto_end_controllable->id().print (buf, sizeof (buf));
852 node->add_property (X_("goto_end"), buf);
853 auto_loop_controllable->id().print (buf, sizeof (buf));
854 node->add_property (X_("auto_loop"), buf);
855 play_selection_controllable->id().print (buf, sizeof (buf));
856 node->add_property (X_("play_selection"), buf);
857 rec_controllable->id().print (buf, sizeof (buf));
858 node->add_property (X_("rec"), buf);
859 shuttle_box.controllable()->id().print (buf, sizeof (buf));
860 node->add_property (X_("shuttle"), buf);
866 ARDOUR_UI::save_session_at_its_request (std::string snapshot_name)
869 _session->save_state (snapshot_name);
874 ARDOUR_UI::autosave_session ()
876 if (g_main_depth() > 1) {
877 /* inside a recursive main loop,
878 give up because we may not be able to
884 if (!Config->get_periodic_safety_backups()) {
889 _session->maybe_write_autosave();
896 ARDOUR_UI::session_dirty_changed ()
903 ARDOUR_UI::update_autosave ()
905 if (_session && _session->dirty()) {
906 if (_autosave_connection.connected()) {
907 _autosave_connection.disconnect();
910 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
911 Config->get_periodic_safety_backup_interval() * 1000);
914 if (_autosave_connection.connected()) {
915 _autosave_connection.disconnect();
921 ARDOUR_UI::check_announcements ()
924 string _annc_filename;
927 _annc_filename = PROGRAM_NAME "_announcements_osx_";
928 #elif defined PLATFORM_WINDOWS
929 _annc_filename = PROGRAM_NAME "_announcements_windows_";
931 _annc_filename = PROGRAM_NAME "_announcements_linux_";
933 _annc_filename.append (VERSIONSTRING);
935 _announce_string = "";
937 std::string path = Glib::build_filename (user_config_directory(), _annc_filename);
938 FILE* fin = g_fopen (path.c_str(), "rb");
940 while (!feof (fin)) {
943 if ((len = fread (tmp, sizeof(char), 1024, fin)) == 0 || ferror (fin)) {
946 _announce_string.append (tmp, len);
951 pingback (VERSIONSTRING, path);
956 _hide_splash (gpointer arg)
958 ((ARDOUR_UI*)arg)->hide_splash();
963 ARDOUR_UI::starting ()
965 Application* app = Application::instance ();
967 bool brand_new_user = ArdourStartup::required ();
969 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
970 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::load_from_application_api));
972 if (ARDOUR_COMMAND_LINE::check_announcements) {
973 check_announcements ();
978 /* we need to create this early because it may need to set the
979 * audio backend end up.
983 audio_midi_setup.get (true);
985 std::cerr << "audio-midi engine setup failed."<< std::endl;
989 if ((nsm_url = g_getenv ("NSM_URL")) != 0) {
990 nsm = new NSM_Client;
991 if (!nsm->init (nsm_url)) {
992 /* the ardour executable may have different names:
994 * waf's obj.target for distro versions: eg ardour4, ardourvst4
995 * Ardour4, Mixbus3 for bundled versions + full path on OSX & windows
996 * argv[0] does not apply since we need the wrapper-script (not the binary itself)
998 * The wrapper startup script should set the environment variable 'ARDOUR_SELF'
1000 const char *process_name = g_getenv ("ARDOUR_SELF");
1001 nsm->announce (PROGRAM_NAME, ":dirty:", process_name ? process_name : "ardour4");
1004 // wait for announce reply from nsm server
1005 for ( i = 0; i < 5000; ++i) {
1009 if (nsm->is_active()) {
1014 error << _("NSM server did not announce itself") << endmsg;
1017 // wait for open command from nsm server
1018 for ( i = 0; i < 5000; ++i) {
1020 Glib::usleep (1000);
1021 if (nsm->client_id ()) {
1027 error << _("NSM: no client ID provided") << endmsg;
1031 if (_session && nsm) {
1032 _session->set_nsm_state( nsm->is_active() );
1034 error << _("NSM: no session created") << endmsg;
1038 // nsm requires these actions disabled
1039 vector<string> action_names;
1040 action_names.push_back("SaveAs");
1041 action_names.push_back("Rename");
1042 action_names.push_back("New");
1043 action_names.push_back("Open");
1044 action_names.push_back("Recent");
1045 action_names.push_back("Close");
1047 for (vector<string>::const_iterator n = action_names.begin(); n != action_names.end(); ++n) {
1048 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), (*n).c_str());
1050 act->set_sensitive (false);
1057 error << _("NSM: initialization failed") << endmsg;
1063 if (brand_new_user) {
1064 _initial_verbose_plugin_scan = true;
1069 _initial_verbose_plugin_scan = false;
1070 switch (s.response ()) {
1071 case Gtk::RESPONSE_OK:
1078 // TODO: maybe IFF brand_new_user
1079 if (ARDOUR::Profile->get_mixbus () && Config->get_copy_demo_sessions ()) {
1080 std::string dspd (Config->get_default_session_parent_dir());
1081 Searchpath ds (ARDOUR::ardour_data_search_path());
1082 ds.add_subdirectory_to_paths ("sessions");
1083 vector<string> demos;
1084 find_files_matching_pattern (demos, ds, "*.tar.xz");
1086 ARDOUR::RecentSessions rs;
1087 ARDOUR::read_recent_sessions (rs);
1089 for (vector<string>::iterator i = demos.begin(); i != demos.end (); ++i) {
1090 /* "demo-session" must be inside "demo-session.tar.xz"
1093 std::string name = basename_nosuffix (basename_nosuffix (*i));
1094 std::string path = Glib::build_filename (dspd, name);
1095 /* skip if session-dir already exists */
1096 if (Glib::file_test(path.c_str(), Glib::FILE_TEST_IS_DIR)) {
1099 /* skip sessions that are already in 'recent'.
1100 * eg. a new user changed <session-default-dir> shorly after installation
1102 for (ARDOUR::RecentSessions::iterator r = rs.begin(); r != rs.end(); ++r) {
1103 if ((*r).first == name) {
1108 PBD::FileArchive ar (*i);
1109 if (0 == ar.inflate (dspd)) {
1110 store_recent_sessions (name, path);
1111 info << string_compose (_("Copied Demo Session %1."), name) << endmsg;
1117 #ifdef NO_PLUGIN_STATE
1119 ARDOUR::RecentSessions rs;
1120 ARDOUR::read_recent_sessions (rs);
1122 string path = Glib::build_filename (user_config_directory(), ".iknowaboutfreeversion");
1124 if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS) && !rs.empty()) {
1126 /* already used Ardour, have sessions ... warn about plugin state */
1128 ArdourDialog d (_("Free/Demo Version Warning"), true);
1130 Button b (string_compose (_("Subscribe and support development of %1"), PROGRAM_NAME));
1131 CheckButton c (_("Don't warn me about this again"));
1133 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"),
1134 string_compose (_("This is a free/demo version of %1"), PROGRAM_NAME),
1135 _("It will not restore OR save any plugin settings"),
1136 _("If you load an existing session with plugin settings\n"
1137 "they will not be used and will be lost."),
1138 _("To get full access to updates without this limitation\n"
1139 "consider becoming a subscriber for a low cost every month.")));
1140 l.set_justify (JUSTIFY_CENTER);
1142 b.signal_clicked().connect (mem_fun(*this, &ARDOUR_UI::launch_subscribe));
1144 d.get_vbox()->pack_start (l, true, true);
1145 d.get_vbox()->pack_start (b, false, false, 12);
1146 d.get_vbox()->pack_start (c, false, false, 12);
1148 d.add_button (_("Quit now"), RESPONSE_CANCEL);
1149 d.add_button (string_compose (_("Continue using %1"), PROGRAM_NAME), RESPONSE_OK);
1153 c.signal_toggled().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (toggle_file_existence), path)));
1155 if (d.run () != RESPONSE_OK) {
1161 /* go get a session */
1163 const bool new_session_required = (ARDOUR_COMMAND_LINE::new_session || brand_new_user);
1165 if (get_session_parameters (false, new_session_required, ARDOUR_COMMAND_LINE::load_template)) {
1166 std::cerr << "Cannot get session parameters."<< std::endl;
1173 WM::Manager::instance().show_visible ();
1175 /* We have to do this here since goto_editor_window() ends up calling show_all() on the
1176 * editor window, and we may want stuff to be hidden.
1178 _status_bar_visibility.update ();
1180 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
1182 if (splash && splash->is_visible()) {
1183 // in 1 second, hide the splash screen
1184 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
1187 /* all other dialogs are created conditionally */
1193 ARDOUR_UI::check_memory_locking ()
1195 #if defined(__APPLE__) || defined(PLATFORM_WINDOWS)
1196 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
1200 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
1202 if (AudioEngine::instance()->is_realtime() && memory_warning_node == 0) {
1204 struct rlimit limits;
1206 long pages, page_size;
1208 size_t pages_len=sizeof(pages);
1209 if ((page_size = getpagesize()) < 0 ||
1210 sysctlbyname("hw.availpages", &pages, &pages_len, NULL, 0))
1212 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0)
1217 ram = (int64_t) pages * (int64_t) page_size;
1220 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
1224 if (limits.rlim_cur != RLIM_INFINITY) {
1226 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
1230 _("WARNING: Your system has a limit for maximum amount of locked memory. "
1231 "This might cause %1 to run out of memory before your system "
1232 "runs out of memory. \n\n"
1233 "You can view the memory limit with 'ulimit -l', "
1234 "and it is normally controlled by %2"),
1237 X_("/etc/login.conf")
1239 X_(" /etc/security/limits.conf")
1243 msg.set_default_response (RESPONSE_OK);
1245 VBox* vbox = msg.get_vbox();
1247 CheckButton cb (_("Do not show this window again"));
1248 hbox.pack_start (cb, true, false);
1249 vbox->pack_start (hbox);
1254 pop_back_splash (msg);
1258 if (cb.get_active()) {
1259 XMLNode node (X_("no-memory-warning"));
1260 Config->add_instant_xml (node);
1265 #endif // !__APPLE__
1270 ARDOUR_UI::queue_finish ()
1272 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
1276 ARDOUR_UI::idle_finish ()
1279 return false; /* do not call again */
1286 ARDOUR_UI::instance()->video_timeline->sync_session_state();
1288 if (_session->dirty()) {
1289 vector<string> actions;
1290 actions.push_back (_("Don't quit"));
1291 actions.push_back (_("Just quit"));
1292 actions.push_back (_("Save and quit"));
1293 switch (ask_about_saving_session(actions)) {
1298 /* use the default name */
1299 if (save_state_canfail ("")) {
1300 /* failed - don't quit */
1301 MessageDialog msg (_main_window,
1302 string_compose (_("\
1303 %1 was unable to save your session.\n\n\
1304 If you still wish to quit, please use the\n\n\
1305 \"Just quit\" option."), PROGRAM_NAME));
1306 pop_back_splash(msg);
1316 second_connection.disconnect ();
1317 point_one_second_connection.disconnect ();
1318 point_zero_something_second_connection.disconnect();
1319 fps_connection.disconnect();
1322 delete ARDOUR_UI::instance()->video_timeline;
1323 ARDOUR_UI::instance()->video_timeline = NULL;
1324 stop_video_server();
1326 /* Save state before deleting the session, as that causes some
1327 windows to be destroyed before their visible state can be
1330 save_ardour_state ();
1332 if (key_editor.get (false)) {
1333 key_editor->disconnect ();
1336 close_all_dialogs ();
1339 _session->set_clean ();
1340 _session->remove_pending_capture_state ();
1345 halt_connection.disconnect ();
1346 AudioEngine::instance()->stop ();
1347 #ifdef WINDOWS_VST_SUPPORT
1348 fst_stop_threading();
1354 ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
1356 ArdourDialog window (_("Unsaved Session"));
1357 Gtk::HBox dhbox; // the hbox for the image and text
1358 Gtk::Label prompt_label;
1359 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
1363 assert (actions.size() >= 3);
1365 window.add_button (actions[0], RESPONSE_REJECT);
1366 window.add_button (actions[1], RESPONSE_APPLY);
1367 window.add_button (actions[2], RESPONSE_ACCEPT);
1369 window.set_default_response (RESPONSE_ACCEPT);
1371 Gtk::Button noquit_button (msg);
1372 noquit_button.set_name ("EditorGTKButton");
1376 if (_session->snap_name() == _session->name()) {
1377 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?"),
1378 _session->snap_name());
1380 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?"),
1381 _session->snap_name());
1384 prompt_label.set_text (prompt);
1385 prompt_label.set_name (X_("PrompterLabel"));
1386 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
1388 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
1389 dhbox.set_homogeneous (false);
1390 dhbox.pack_start (*dimage, false, false, 5);
1391 dhbox.pack_start (prompt_label, true, false, 5);
1392 window.get_vbox()->pack_start (dhbox);
1394 window.set_name (_("Prompter"));
1395 window.set_modal (true);
1396 window.set_resizable (false);
1399 prompt_label.show();
1404 ResponseType r = (ResponseType) window.run();
1409 case RESPONSE_ACCEPT: // save and get out of here
1411 case RESPONSE_APPLY: // get out of here
1422 ARDOUR_UI::every_second ()
1425 update_xrun_count ();
1426 update_buffer_load ();
1427 update_disk_space ();
1428 update_timecode_format ();
1429 update_peak_thread_work ();
1431 if (nsm && nsm->is_active ()) {
1434 if (!_was_dirty && _session->dirty ()) {
1438 else if (_was_dirty && !_session->dirty ()){
1446 ARDOUR_UI::every_point_one_seconds ()
1448 // TODO get rid of this..
1449 // ShuttleControl is updated directly via TransportStateChange signal
1453 ARDOUR_UI::every_point_zero_something_seconds ()
1455 // august 2007: actual update frequency: 25Hz (40ms), not 100Hz
1457 if (editor_meter && UIConfiguration::instance().get_show_editor_meter() && editor_meter_peak_display.is_mapped ()) {
1458 float mpeak = editor_meter->update_meters();
1459 if (mpeak > editor_meter_max_peak) {
1460 if (mpeak >= UIConfiguration::instance().get_meter_peak()) {
1461 editor_meter_peak_display.set_active_state ( Gtkmm2ext::ExplicitActive );
1468 ARDOUR_UI::set_fps_timeout_connection ()
1470 unsigned int interval = 40;
1471 if (!_session) return;
1472 if (_session->timecode_frames_per_second() != 0) {
1473 /* ideally we'll use a select() to sleep and not accumulate
1474 * idle time to provide a regular periodic signal.
1475 * See linux_vst_gui_support.cc 'elapsed_time_ms'.
1476 * However, that'll require a dedicated thread and cross-thread
1477 * signals to the GUI Thread..
1479 interval = floor(500. /* update twice per FPS, since Glib::signal_timeout is very irregular */
1480 * _session->frame_rate() / _session->nominal_frame_rate()
1481 / _session->timecode_frames_per_second()
1483 #ifdef PLATFORM_WINDOWS
1484 // the smallest windows scheduler time-slice is ~15ms.
1485 // periodic GUI timeouts shorter than that will cause
1486 // WaitForSingleObject to spinlock (100% of one CPU Core)
1487 // and gtk never enters idle mode.
1488 // also changing timeBeginPeriod(1) does not affect that in
1489 // any beneficial way, so we just limit the max rate for now.
1490 interval = std::max(30u, interval); // at most ~33Hz.
1492 interval = std::max(8u, interval); // at most 120Hz.
1495 fps_connection.disconnect();
1496 Timers::set_fps_interval (interval);
1500 ARDOUR_UI::update_sample_rate (framecnt_t)
1504 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
1506 if (!AudioEngine::instance()->connected()) {
1508 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1512 framecnt_t rate = AudioEngine::instance()->sample_rate();
1515 /* no sample rate available */
1516 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1519 if (fmod (rate, 1000.0) != 0.0) {
1520 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
1521 (float) rate / 1000.0f,
1522 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1524 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
1526 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1530 sample_rate_label.set_markup (buf);
1534 ARDOUR_UI::update_format ()
1537 format_label.set_text ("");
1542 s << _("File:") << X_(" <span foreground=\"green\">");
1544 switch (_session->config.get_native_file_header_format ()) {
1576 switch (_session->config.get_native_file_data_format ()) {
1590 format_label.set_markup (s.str ());
1594 ARDOUR_UI::update_xrun_count ()
1598 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1599 should also be changed.
1603 const unsigned int x = _session->get_xrun_count ();
1605 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">>10K</span>"), X_("red"));
1607 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">%u</span>"), x > 0 ? X_("red") : X_("green"), x);
1610 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">?</span>"), X_("yellow"));
1612 xrun_label.set_markup (buf);
1613 set_tip (xrun_label, _("Audio dropouts. Shift+click to reset"));
1617 ARDOUR_UI::update_cpu_load ()
1621 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1622 should also be changed.
1625 double const c = AudioEngine::instance()->get_dsp_load ();
1626 snprintf (buf, sizeof (buf), _("DSP: <span foreground=\"%s\">%5.1f%%</span>"), c >= 90 ? X_("red") : X_("green"), c);
1627 cpu_load_label.set_markup (buf);
1631 ARDOUR_UI::update_peak_thread_work ()
1634 const int c = SourceFactory::peak_work_queue_length ();
1636 snprintf (buf, sizeof (buf), _("PkBld: <span foreground=\"%s\">%d</span>"), c >= 2 ? X_("red") : X_("green"), c);
1637 peak_thread_work_label.set_markup (buf);
1639 peak_thread_work_label.set_markup (X_(""));
1644 ARDOUR_UI::update_buffer_load ()
1648 uint32_t const playback = _session ? _session->playback_load () : 100;
1649 uint32_t const capture = _session ? _session->capture_load () : 100;
1651 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1652 should also be changed.
1658 _("Buffers: <span foreground=\"green\">p:</span><span foreground=\"%s\">%" PRIu32 "%%</span> "
1659 "<span foreground=\"green\">c:</span><span foreground=\"%s\">%" PRIu32 "%%</span>"),
1660 playback <= 5 ? X_("red") : X_("green"),
1662 capture <= 5 ? X_("red") : X_("green"),
1666 buffer_load_label.set_markup (buf);
1668 buffer_load_label.set_text ("");
1673 ARDOUR_UI::count_recenabled_streams (Route& route)
1675 Track* track = dynamic_cast<Track*>(&route);
1676 if (track && track->rec_enable_control()->get_value()) {
1677 rec_enabled_streams += track->n_inputs().n_total();
1682 ARDOUR_UI::update_disk_space()
1684 if (_session == 0) {
1688 boost::optional<framecnt_t> opt_frames = _session->available_capture_duration();
1690 framecnt_t fr = _session->frame_rate();
1693 /* skip update - no SR available */
1698 /* Available space is unknown */
1699 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">Unknown</span>"));
1700 } else if (opt_frames.get_value_or (0) == max_framecnt) {
1701 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">24hrs+</span>"));
1703 rec_enabled_streams = 0;
1704 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams, false);
1706 framecnt_t frames = opt_frames.get_value_or (0);
1708 if (rec_enabled_streams) {
1709 frames /= rec_enabled_streams;
1716 hrs = frames / (fr * 3600);
1719 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">>24 hrs</span>"));
1721 frames -= hrs * fr * 3600;
1722 mins = frames / (fr * 60);
1723 frames -= mins * fr * 60;
1726 bool const low = (hrs == 0 && mins <= 30);
1730 _("Disk: <span foreground=\"%s\">%02dh:%02dm:%02ds</span>"),
1731 low ? X_("red") : X_("green"),
1737 disk_space_label.set_markup (buf);
1741 ARDOUR_UI::update_timecode_format ()
1747 TimecodeSlave* tcslave;
1748 SyncSource sync_src = Config->get_sync_source();
1750 if ((sync_src == LTC || sync_src == MTC) && (tcslave = dynamic_cast<TimecodeSlave*>(_session->slave())) != 0) {
1751 matching = (tcslave->apparent_timecode_format() == _session->config.get_timecode_format());
1756 snprintf (buf, sizeof (buf), S_("Timecode|TC: <span foreground=\"%s\">%s</span>"),
1757 matching ? X_("green") : X_("red"),
1758 Timecode::timecode_format_name (_session->config.get_timecode_format()).c_str());
1760 snprintf (buf, sizeof (buf), "TC: n/a");
1763 timecode_format_label.set_markup (buf);
1767 ARDOUR_UI::update_wall_clock ()
1771 static int last_min = -1;
1774 tm_now = localtime (&now);
1775 if (last_min != tm_now->tm_min) {
1777 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1778 wall_clock_label.set_text (buf);
1779 last_min = tm_now->tm_min;
1786 ARDOUR_UI::open_recent_session ()
1788 bool can_return = (_session != 0);
1790 SessionDialog recent_session_dialog;
1794 ResponseType r = (ResponseType) recent_session_dialog.run ();
1797 case RESPONSE_ACCEPT:
1801 recent_session_dialog.hide();
1808 recent_session_dialog.hide();
1812 std::string path = recent_session_dialog.session_folder();
1813 std::string state = recent_session_dialog.session_name (should_be_new);
1815 if (should_be_new == true) {
1819 _session_is_new = false;
1821 if (load_session (path, state) == 0) {
1827 if (splash && splash->is_visible()) {
1828 // in 1 second, hide the splash screen
1829 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
1834 ARDOUR_UI::check_audioengine (Gtk::Window& parent)
1836 if (!AudioEngine::instance()->connected()) {
1837 MessageDialog msg (parent, string_compose (
1838 _("%1 is not connected to any audio backend.\n"
1839 "You cannot open or close sessions in this condition"),
1841 pop_back_splash (msg);
1849 ARDOUR_UI::open_session ()
1851 if (!check_audioengine (_main_window)) {
1855 /* ardour sessions are folders */
1856 Gtk::FileChooserDialog open_session_selector(_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1857 open_session_selector.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1858 open_session_selector.add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1859 open_session_selector.set_default_response(Gtk::RESPONSE_ACCEPT);
1862 string session_parent_dir = Glib::path_get_dirname(_session->path());
1863 open_session_selector.set_current_folder(session_parent_dir);
1865 open_session_selector.set_current_folder(Config->get_default_session_parent_dir());
1868 Gtkmm2ext::add_volume_shortcuts (open_session_selector);
1870 /* add_shortcut_folder throws an exception if the folder being added already has a shortcut */
1871 string default_session_folder = Config->get_default_session_parent_dir();
1872 open_session_selector.add_shortcut_folder (default_session_folder);
1874 catch (Glib::Error & e) {
1875 std::cerr << "open_session_selector.add_shortcut_folder() threw Glib::Error " << e.what() << std::endl;
1878 FileFilter session_filter;
1879 session_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::statefile_suffix));
1880 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1881 open_session_selector.add_filter (session_filter);
1883 FileFilter archive_filter;
1884 archive_filter.add_pattern (X_("*.tar.xz"));
1885 archive_filter.set_name (_("Session Archives"));
1887 open_session_selector.add_filter (archive_filter);
1889 open_session_selector.set_filter (session_filter);
1891 int response = open_session_selector.run();
1892 open_session_selector.hide ();
1894 if (response == Gtk::RESPONSE_CANCEL) {
1898 string session_path = open_session_selector.get_filename();
1902 if (session_path.length() > 0) {
1903 int rv = ARDOUR::inflate_session (session_path,
1904 Config->get_default_session_parent_dir(), path, name);
1906 _session_is_new = false;
1907 load_session (path, name);
1910 MessageDialog msg (_main_window,
1911 string_compose (_("Extracting session-archive failed: %1"), inflate_error (rv)));
1914 else if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1915 _session_is_new = isnew;
1916 load_session (path, name);
1922 ARDOUR_UI::session_add_vca (const string& name_template, uint32_t n)
1928 _session->vca_manager().create_vca (n, name_template);
1932 ARDOUR_UI::session_add_mixed_track (
1933 const ChanCount& input,
1934 const ChanCount& output,
1935 RouteGroup* route_group,
1937 const string& name_template,
1939 PluginInfoPtr instrument,
1940 Plugin::PresetRecord* pset,
1941 ARDOUR::PresentationInfo::order_t order)
1943 list<boost::shared_ptr<MidiTrack> > tracks;
1945 if (_session == 0) {
1946 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1951 tracks = _session->new_midi_track (input, output, instrument, pset, route_group, how_many, name_template, order, ARDOUR::Normal);
1953 if (tracks.size() != how_many) {
1954 error << string_compose(P_("could not create %1 new mixed track", "could not create %1 new mixed tracks", how_many), how_many) << endmsg;
1959 display_insufficient_ports_message ();
1964 for (list<boost::shared_ptr<MidiTrack> >::iterator i = tracks.begin(); i != tracks.end(); ++i) {
1965 (*i)->set_strict_io (true);
1971 ARDOUR_UI::session_add_midi_bus (
1972 RouteGroup* route_group,
1974 const string& name_template,
1976 PluginInfoPtr instrument,
1977 Plugin::PresetRecord* pset,
1978 ARDOUR::PresentationInfo::order_t order)
1982 if (_session == 0) {
1983 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1989 routes = _session->new_midi_route (route_group, how_many, name_template, instrument, pset, PresentationInfo::MidiBus, order);
1990 if (routes.size() != how_many) {
1991 error << string_compose(P_("could not create %1 new Midi Bus", "could not create %1 new Midi Busses", how_many), how_many) << endmsg;
1996 display_insufficient_ports_message ();
2001 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
2002 (*i)->set_strict_io (true);
2008 ARDOUR_UI::session_add_midi_route (
2010 RouteGroup* route_group,
2012 const string& name_template,
2014 PluginInfoPtr instrument,
2015 Plugin::PresetRecord* pset,
2016 ARDOUR::PresentationInfo::order_t order)
2018 ChanCount one_midi_channel;
2019 one_midi_channel.set (DataType::MIDI, 1);
2022 session_add_mixed_track (one_midi_channel, one_midi_channel, route_group, how_many, name_template, strict_io, instrument, pset, order);
2024 session_add_midi_bus (route_group, how_many, name_template, strict_io, instrument, pset, order);
2029 ARDOUR_UI::session_add_audio_route (
2031 int32_t input_channels,
2032 int32_t output_channels,
2033 ARDOUR::TrackMode mode,
2034 RouteGroup* route_group,
2036 string const & name_template,
2038 ARDOUR::PresentationInfo::order_t order)
2040 list<boost::shared_ptr<AudioTrack> > tracks;
2043 if (_session == 0) {
2044 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
2050 tracks = _session->new_audio_track (input_channels, output_channels, route_group, how_many, name_template, order, mode);
2052 if (tracks.size() != how_many) {
2053 error << string_compose (P_("could not create %1 new audio track", "could not create %1 new audio tracks", how_many), how_many)
2059 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template, PresentationInfo::AudioBus, order);
2061 if (routes.size() != how_many) {
2062 error << string_compose (P_("could not create %1 new audio bus", "could not create %1 new audio busses", how_many), how_many)
2069 display_insufficient_ports_message ();
2074 for (list<boost::shared_ptr<AudioTrack> >::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2075 (*i)->set_strict_io (true);
2077 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
2078 (*i)->set_strict_io (true);
2084 ARDOUR_UI::display_insufficient_ports_message ()
2086 MessageDialog msg (_main_window,
2087 string_compose (_("There are insufficient ports available\n\
2088 to create a new track or bus.\n\
2089 You should save %1, exit and\n\
2090 restart with more ports."), PROGRAM_NAME));
2091 pop_back_splash (msg);
2096 ARDOUR_UI::transport_goto_start ()
2099 _session->goto_start();
2101 /* force displayed area in editor to start no matter
2102 what "follow playhead" setting is.
2106 editor->center_screen (_session->current_start_frame ());
2112 ARDOUR_UI::transport_goto_zero ()
2115 _session->request_locate (0);
2117 /* force displayed area in editor to start no matter
2118 what "follow playhead" setting is.
2122 editor->reset_x_origin (0);
2128 ARDOUR_UI::transport_goto_wallclock ()
2130 if (_session && editor) {
2137 localtime_r (&now, &tmnow);
2139 framecnt_t frame_rate = _session->frame_rate();
2141 if (frame_rate == 0) {
2142 /* no frame rate available */
2146 frames = tmnow.tm_hour * (60 * 60 * frame_rate);
2147 frames += tmnow.tm_min * (60 * frame_rate);
2148 frames += tmnow.tm_sec * frame_rate;
2150 _session->request_locate (frames, _session->transport_rolling ());
2152 /* force displayed area in editor to start no matter
2153 what "follow playhead" setting is.
2157 editor->center_screen (frames);
2163 ARDOUR_UI::transport_goto_end ()
2166 framepos_t const frame = _session->current_end_frame();
2167 _session->request_locate (frame);
2169 /* force displayed area in editor to start no matter
2170 what "follow playhead" setting is.
2174 editor->center_screen (frame);
2180 ARDOUR_UI::transport_stop ()
2186 if (_session->is_auditioning()) {
2187 _session->cancel_audition ();
2191 _session->request_stop (false, true);
2194 /** Check if any tracks are record enabled. If none are, record enable all of them.
2195 * @return true if track record-enabled status was changed, false otherwise.
2198 ARDOUR_UI::trx_record_enable_all_tracks ()
2204 boost::shared_ptr<RouteList> rl = _session->get_tracks ();
2205 bool none_record_enabled = true;
2207 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
2208 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*r);
2211 if (t->rec_enable_control()->get_value()) {
2212 none_record_enabled = false;
2217 if (none_record_enabled) {
2218 _session->set_controls (route_list_to_control_list (rl, &Stripable::rec_enable_control), 1.0, Controllable::NoGroup);
2221 return none_record_enabled;
2225 ARDOUR_UI::transport_record (bool roll)
2228 switch (_session->record_status()) {
2229 case Session::Disabled:
2230 if (_session->ntracks() == 0) {
2231 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."));
2235 if (Profile->get_trx()) {
2236 roll = trx_record_enable_all_tracks ();
2238 _session->maybe_enable_record ();
2243 case Session::Recording:
2245 _session->request_stop();
2247 _session->disable_record (false, true);
2251 case Session::Enabled:
2252 _session->disable_record (false, true);
2258 ARDOUR_UI::transport_roll ()
2264 if (_session->is_auditioning()) {
2269 if (_session->config.get_external_sync()) {
2270 switch (Config->get_sync_source()) {
2274 /* transport controlled by the master */
2280 bool rolling = _session->transport_rolling();
2282 if (_session->get_play_loop()) {
2284 /* If loop playback is not a mode, then we should cancel
2285 it when this action is requested. If it is a mode
2286 we just leave it in place.
2289 if (!Config->get_loop_is_mode()) {
2290 /* XXX it is not possible to just leave seamless loop and keep
2291 playing at present (nov 4th 2009)
2293 if (!Config->get_seamless_loop()) {
2294 /* stop loop playback and stop rolling */
2295 _session->request_play_loop (false, true);
2296 } else if (rolling) {
2297 /* stop loop playback but keep rolling */
2298 _session->request_play_loop (false, false);
2302 } else if (_session->get_play_range () ) {
2303 /* stop playing a range if we currently are */
2304 _session->request_play_range (0, true);
2308 _session->request_transport_speed (1.0f);
2313 ARDOUR_UI::get_smart_mode() const
2315 return ( editor->get_smart_mode() );
2320 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
2326 if (_session->is_auditioning()) {
2327 _session->cancel_audition ();
2331 if (_session->config.get_external_sync()) {
2332 switch (Config->get_sync_source()) {
2336 /* transport controlled by the master */
2341 bool rolling = _session->transport_rolling();
2342 bool affect_transport = true;
2344 if (rolling && roll_out_of_bounded_mode) {
2345 /* drop out of loop/range playback but leave transport rolling */
2346 if (_session->get_play_loop()) {
2347 if (_session->actively_recording()) {
2349 /* just stop using the loop, then actually stop
2352 _session->request_play_loop (false, affect_transport);
2355 if (Config->get_seamless_loop()) {
2356 /* the disk buffers contain copies of the loop - we can't
2357 just keep playing, so stop the transport. the user
2358 can restart as they wish.
2360 affect_transport = true;
2362 /* disk buffers are normal, so we can keep playing */
2363 affect_transport = false;
2365 _session->request_play_loop (false, affect_transport);
2367 } else if (_session->get_play_range ()) {
2368 affect_transport = false;
2369 _session->request_play_range (0, true);
2373 if (affect_transport) {
2375 _session->request_stop (with_abort, true);
2377 } else if (!with_abort) { /* with_abort == true means the
2378 * command was intended to stop
2379 * transport, not start.
2382 /* the only external sync condition we can be in here
2383 * would be Engine (JACK) sync, in which case we still
2387 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
2388 _session->request_play_range (&editor->get_selection().time, true);
2389 _session->set_requested_return_frame( editor->get_selection().time.front().start ); //force an auto-return here
2391 _session->request_transport_speed (1.0f);
2397 ARDOUR_UI::toggle_session_auto_loop ()
2403 Location * looploc = _session->locations()->auto_loop_location();
2409 if (_session->get_play_loop()) {
2411 /* looping enabled, our job is to disable it */
2413 _session->request_play_loop (false);
2417 /* looping not enabled, our job is to enable it.
2419 loop-is-NOT-mode: this action always starts the transport rolling.
2420 loop-IS-mode: this action simply sets the loop play mechanism, but
2421 does not start transport.
2423 if (Config->get_loop_is_mode()) {
2424 _session->request_play_loop (true, false);
2426 _session->request_play_loop (true, true);
2430 //show the loop markers
2431 looploc->set_hidden (false, this);
2435 ARDOUR_UI::transport_play_selection ()
2441 editor->play_selection ();
2445 ARDOUR_UI::transport_play_preroll ()
2450 editor->play_with_preroll ();
2454 ARDOUR_UI::transport_rewind (int option)
2456 float current_transport_speed;
2459 current_transport_speed = _session->transport_speed();
2461 if (current_transport_speed >= 0.0f) {
2464 _session->request_transport_speed (-1.0f);
2467 _session->request_transport_speed (-4.0f);
2470 _session->request_transport_speed (-0.5f);
2475 _session->request_transport_speed (current_transport_speed * 1.5f);
2481 ARDOUR_UI::transport_forward (int option)
2487 float current_transport_speed = _session->transport_speed();
2489 if (current_transport_speed <= 0.0f) {
2492 _session->request_transport_speed (1.0f);
2495 _session->request_transport_speed (4.0f);
2498 _session->request_transport_speed (0.5f);
2503 _session->request_transport_speed (current_transport_speed * 1.5f);
2508 ARDOUR_UI::toggle_record_enable (uint16_t rid)
2514 boost::shared_ptr<Route> r;
2516 if ((r = _session->get_remote_nth_route (rid)) != 0) {
2518 boost::shared_ptr<Track> t;
2520 if ((t = boost::dynamic_pointer_cast<Track>(r)) != 0) {
2521 t->rec_enable_control()->set_value (!t->rec_enable_control()->get_value(), Controllable::UseGroup);
2527 ARDOUR_UI::map_transport_state ()
2530 auto_loop_button.unset_active_state ();
2531 play_selection_button.unset_active_state ();
2532 roll_button.unset_active_state ();
2533 stop_button.set_active_state (Gtkmm2ext::ExplicitActive);
2534 layered_button.set_sensitive (false);
2538 shuttle_box.map_transport_state ();
2540 float sp = _session->transport_speed();
2546 if (_session->get_play_range()) {
2548 play_selection_button.set_active_state (Gtkmm2ext::ExplicitActive);
2549 roll_button.unset_active_state ();
2550 auto_loop_button.unset_active_state ();
2552 } else if (_session->get_play_loop ()) {
2554 auto_loop_button.set_active (true);
2555 play_selection_button.set_active (false);
2556 if (Config->get_loop_is_mode()) {
2557 roll_button.set_active (true);
2559 roll_button.set_active (false);
2564 roll_button.set_active (true);
2565 play_selection_button.set_active (false);
2566 auto_loop_button.set_active (false);
2569 if (UIConfiguration::instance().get_follow_edits() && !_session->config.get_external_sync()) {
2570 /* light up both roll and play-selection if they are joined */
2571 roll_button.set_active (true);
2572 play_selection_button.set_active (true);
2574 layered_button.set_sensitive (!_session->actively_recording ());
2576 stop_button.set_active (false);
2580 layered_button.set_sensitive (true);
2581 stop_button.set_active (true);
2582 roll_button.set_active (false);
2583 play_selection_button.set_active (false);
2584 if (Config->get_loop_is_mode ()) {
2585 auto_loop_button.set_active (_session->get_play_loop());
2587 auto_loop_button.set_active (false);
2589 update_disk_space ();
2594 ARDOUR_UI::blink_handler (bool blink_on)
2596 transport_rec_enable_blink (blink_on);
2597 solo_blink (blink_on);
2598 sync_blink (blink_on);
2599 audition_blink (blink_on);
2600 feedback_blink (blink_on);
2601 error_blink (blink_on);
2605 ARDOUR_UI::update_clocks ()
2607 if (!_session) return;
2609 if (editor && !editor->dragging_playhead()) {
2610 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD)); /* EMIT_SIGNAL */
2615 ARDOUR_UI::start_clocking ()
2617 if (UIConfiguration::instance().get_super_rapid_clock_update()) {
2618 clock_signal_connection = Timers::fps_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2620 clock_signal_connection = Timers::rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2625 ARDOUR_UI::stop_clocking ()
2627 clock_signal_connection.disconnect ();
2631 ARDOUR_UI::save_as_progress_update (float fraction, int64_t cnt, int64_t total, Gtk::Label* label, Gtk::ProgressBar* bar)
2635 snprintf (buf, sizeof (buf), _("Copied %" PRId64 " of %" PRId64), cnt, total);
2637 label->set_text (buf);
2638 bar->set_fraction (fraction);
2640 /* process events, redraws, etc. */
2642 while (gtk_events_pending()) {
2643 gtk_main_iteration ();
2646 return true; /* continue with save-as */
2650 ARDOUR_UI::save_session_as ()
2656 if (!save_as_dialog) {
2657 save_as_dialog = new SaveAsDialog;
2660 save_as_dialog->set_name (_session->name());
2662 int response = save_as_dialog->run ();
2664 save_as_dialog->hide ();
2667 case Gtk::RESPONSE_OK:
2676 sa.new_parent_folder = save_as_dialog->new_parent_folder ();
2677 sa.new_name = save_as_dialog->new_name ();
2678 sa.switch_to = save_as_dialog->switch_to();
2679 sa.copy_media = save_as_dialog->copy_media();
2680 sa.copy_external = save_as_dialog->copy_external();
2681 sa.include_media = save_as_dialog->include_media ();
2683 /* Only bother with a progress dialog if we're going to copy
2684 media into the save-as target. Without that choice, this
2685 will be very fast because we're only talking about a few kB's to
2686 perhaps a couple of MB's of data.
2689 ArdourDialog progress_dialog (_("Save As"), true);
2691 if (sa.include_media && sa.copy_media) {
2694 Gtk::ProgressBar progress_bar;
2696 progress_dialog.get_vbox()->pack_start (label);
2697 progress_dialog.get_vbox()->pack_start (progress_bar);
2699 progress_bar.show ();
2701 /* this signal will be emitted from within this, the calling thread,
2702 * after every file is copied. It provides information on percentage
2703 * complete (in terms of total data to copy), the number of files
2704 * copied so far, and the total number to copy.
2709 sa.Progress.connect_same_thread (c, boost::bind (&ARDOUR_UI::save_as_progress_update, this, _1, _2, _3, &label, &progress_bar));
2711 progress_dialog.show_all ();
2712 progress_dialog.present ();
2715 if (_session->save_as (sa)) {
2717 MessageDialog msg (string_compose (_("Save As failed: %1"), sa.failure_message));
2721 if (!sa.include_media) {
2722 unload_session (false);
2723 load_session (sa.final_session_folder_name, sa.new_name);
2728 ARDOUR_UI::archive_session ()
2736 Glib::DateTime gdt (Glib::DateTime::create_now_local (n));
2738 SessionArchiveDialog sad;
2739 sad.set_name (_session->name() + gdt.format ("_%F_%H%M%S"));
2740 int response = sad.run ();
2742 if (response != Gtk::RESPONSE_OK) {
2747 if (_session->archive_session (sad.target_folder(), sad.name(), sad.encode_option (), sad.only_used_sources (), &sad)) {
2748 MessageDialog msg (_("Session Archiving failed."));
2754 ARDOUR_UI::quick_snapshot_session (bool switch_to_it)
2758 struct tm local_time;
2761 localtime_r (&n, &local_time);
2762 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2764 save_state (timebuf, switch_to_it);
2769 ARDOUR_UI::process_snapshot_session_prompter (ArdourPrompter& prompter, bool switch_to_it)
2773 prompter.get_result (snapname);
2775 bool do_save = (snapname.length() != 0);
2778 char illegal = Session::session_name_is_legal(snapname);
2780 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2781 "snapshot names may not contain a '%1' character"), illegal));
2787 vector<std::string> p;
2788 get_state_files_in_directory (_session->session_directory().root_path(), p);
2789 vector<string> n = get_file_names_no_extension (p);
2791 if (find (n.begin(), n.end(), snapname) != n.end()) {
2793 do_save = overwrite_file_dialog (prompter,
2794 _("Confirm Snapshot Overwrite"),
2795 _("A snapshot already exists with that name. Do you want to overwrite it?"));
2799 save_state (snapname, switch_to_it);
2809 /** Ask the user for the name of a new snapshot and then take it.
2813 ARDOUR_UI::snapshot_session (bool switch_to_it)
2815 ArdourPrompter prompter (true);
2817 prompter.set_name ("Prompter");
2818 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2820 prompter.set_title (_("Snapshot and switch"));
2821 prompter.set_prompt (_("New session name"));
2823 prompter.set_title (_("Take Snapshot"));
2824 prompter.set_prompt (_("Name of new snapshot"));
2828 prompter.set_initial_text (_session->snap_name());
2830 Glib::DateTime tm (g_date_time_new_now_local ());
2831 prompter.set_initial_text (tm.format ("%FT%H.%M.%S"));
2834 bool finished = false;
2836 switch (prompter.run()) {
2837 case RESPONSE_ACCEPT:
2839 finished = process_snapshot_session_prompter (prompter, switch_to_it);
2850 /** Ask the user for a new session name and then rename the session to it.
2854 ARDOUR_UI::rename_session ()
2860 ArdourPrompter prompter (true);
2863 prompter.set_name ("Prompter");
2864 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2865 prompter.set_title (_("Rename Session"));
2866 prompter.set_prompt (_("New session name"));
2869 switch (prompter.run()) {
2870 case RESPONSE_ACCEPT:
2872 prompter.get_result (name);
2874 bool do_rename = (name.length() != 0);
2877 char illegal = Session::session_name_is_legal (name);
2880 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2881 "session names may not contain a '%1' character"), illegal));
2886 switch (_session->rename (name)) {
2888 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
2889 msg.set_position (WIN_POS_MOUSE);
2897 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
2898 msg.set_position (WIN_POS_MOUSE);
2914 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2916 if (!_session || _session->deletion_in_progress()) {
2920 XMLNode* node = new XMLNode (X_("UI"));
2922 WM::Manager::instance().add_state (*node);
2924 node->add_child_nocopy (gui_object_state->get_state());
2926 _session->add_extra_xml (*node);
2928 if (export_video_dialog) {
2929 _session->add_extra_xml (export_video_dialog->get_state());
2932 save_state_canfail (name, switch_to_it);
2936 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2941 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2946 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2951 ARDOUR_UI::primary_clock_value_changed ()
2954 _session->request_locate (primary_clock->current_time ());
2959 ARDOUR_UI::big_clock_value_changed ()
2962 _session->request_locate (big_clock->current_time ());
2967 ARDOUR_UI::secondary_clock_value_changed ()
2970 _session->request_locate (secondary_clock->current_time ());
2975 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2977 if (_session == 0) {
2981 if (_session->step_editing()) {
2985 Session::RecordState const r = _session->record_status ();
2986 bool const h = _session->have_rec_enabled_track ();
2988 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2990 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2992 rec_button.set_active_state (Gtkmm2ext::Off);
2994 } else if (r == Session::Recording && h) {
2995 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2997 rec_button.unset_active_state ();
3002 ARDOUR_UI::process_save_template_prompter (ArdourPrompter& prompter)
3006 prompter.get_result (name);
3008 if (name.length()) {
3009 int failed = _session->save_template (name);
3011 if (failed == -2) { /* file already exists. */
3012 bool overwrite = overwrite_file_dialog (prompter,
3013 _("Confirm Template Overwrite"),
3014 _("A template already exists with that name. Do you want to overwrite it?"));
3017 _session->save_template (name, true);
3029 ARDOUR_UI::save_template ()
3031 ArdourPrompter prompter (true);
3033 if (!check_audioengine (_main_window)) {
3037 prompter.set_name (X_("Prompter"));
3038 prompter.set_title (_("Save Template"));
3039 prompter.set_prompt (_("Name for template:"));
3040 prompter.set_initial_text(_session->name() + _("-template"));
3041 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
3043 bool finished = false;
3045 switch (prompter.run()) {
3046 case RESPONSE_ACCEPT:
3047 finished = process_save_template_prompter (prompter);
3058 ARDOUR_UI::edit_metadata ()
3060 SessionMetadataEditor dialog;
3061 dialog.set_session (_session);
3062 dialog.grab_focus ();
3067 ARDOUR_UI::import_metadata ()
3069 SessionMetadataImporter dialog;
3070 dialog.set_session (_session);
3075 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
3077 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
3079 MessageDialog msg (str,
3081 Gtk::MESSAGE_WARNING,
3082 Gtk::BUTTONS_YES_NO,
3086 msg.set_name (X_("OpenExistingDialog"));
3087 msg.set_title (_("Open Existing Session"));
3088 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
3089 msg.set_position (Gtk::WIN_POS_CENTER);
3090 pop_back_splash (msg);
3092 switch (msg.run()) {
3101 ARDOUR_UI::build_session_from_dialog (SessionDialog& sd, const std::string& session_path, const std::string& session_name)
3103 BusProfile bus_profile;
3107 bus_profile.master_out_channels = 2;
3108 bus_profile.input_ac = AutoConnectPhysical;
3109 bus_profile.output_ac = AutoConnectMaster;
3110 bus_profile.requested_physical_in = 0; // use all available
3111 bus_profile.requested_physical_out = 0; // use all available
3115 /* get settings from advanced section of NSD */
3117 if (sd.create_master_bus()) {
3118 bus_profile.master_out_channels = (uint32_t) sd.master_channel_count();
3120 bus_profile.master_out_channels = 0;
3123 if (sd.connect_inputs()) {
3124 bus_profile.input_ac = AutoConnectPhysical;
3126 bus_profile.input_ac = AutoConnectOption (0);
3129 bus_profile.output_ac = AutoConnectOption (0);
3131 if (sd.connect_outputs ()) {
3132 if (sd.connect_outs_to_master()) {
3133 bus_profile.output_ac = AutoConnectMaster;
3134 } else if (sd.connect_outs_to_physical()) {
3135 bus_profile.output_ac = AutoConnectPhysical;
3139 bus_profile.requested_physical_in = (uint32_t) sd.input_limit_count();
3140 bus_profile.requested_physical_out = (uint32_t) sd.output_limit_count();
3143 if (build_session (session_path, session_name, bus_profile)) {
3151 ARDOUR_UI::load_from_application_api (const std::string& path)
3153 /* OS X El Capitan (and probably later) now somehow passes the command
3154 line arguments to an app via the openFile delegate protocol. Ardour
3155 already does its own command line processing, and having both
3156 pathways active causes crashes. So, if the command line was already
3157 set, do nothing here.
3160 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
3164 ARDOUR_COMMAND_LINE::session_name = path;
3166 /* Cancel SessionDialog if it's visible to make OSX delegates work.
3168 * ARDOUR_UI::starting connects app->ShouldLoad signal and then shows a SessionDialog
3170 * - ShouldLoad does not arrive in time, ARDOUR_COMMAND_LINE::session_name is empty:
3171 * -> ARDOUR_UI::get_session_parameters starts a SessionDialog.
3172 * - ShouldLoad signal arrives, this function is called and sets ARDOUR_COMMAND_LINE::session_name
3173 * -> SessionDialog is not displayed
3176 if (_session_dialog) {
3177 std::string session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3178 std::string session_path = path;
3179 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_REGULAR)) {
3180 session_path = Glib::path_get_dirname (session_path);
3182 // signal the existing dialog in ARDOUR_UI::get_session_parameters()
3183 _session_dialog->set_provided_session (session_name, session_path);
3184 _session_dialog->response (RESPONSE_NONE);
3185 _session_dialog->hide();
3190 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
3191 /* /path/to/foo => /path/to/foo, foo */
3192 rv = load_session (path, basename_nosuffix (path));
3194 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
3195 rv =load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
3198 // if load_session fails -> pop up SessionDialog.
3200 ARDOUR_COMMAND_LINE::session_name = "";
3202 if (get_session_parameters (true, false)) {
3208 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
3210 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
3212 string session_name;
3213 string session_path;
3214 string template_name;
3216 bool likely_new = false;
3217 bool cancel_not_quit;
3219 /* deal with any existing DIRTY session now, rather than later. don't
3220 * treat a non-dirty session this way, so that it stays visible
3221 * as we bring up the new session dialog.
3224 if (_session && ARDOUR_UI::instance()->video_timeline) {
3225 ARDOUR_UI::instance()->video_timeline->sync_session_state();
3228 /* if there is already a session, relabel the button
3229 on the SessionDialog so that we don't Quit directly
3231 cancel_not_quit = (_session != 0);
3233 if (_session && _session->dirty()) {
3234 if (unload_session (false)) {
3235 /* unload cancelled by user */
3238 ARDOUR_COMMAND_LINE::session_name = "";
3241 if (!load_template.empty()) {
3242 should_be_new = true;
3243 template_name = load_template;
3246 session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3247 session_path = ARDOUR_COMMAND_LINE::session_name;
3249 if (!session_path.empty()) {
3250 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_EXISTS)) {
3251 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_IS_REGULAR)) {
3252 /* session/snapshot file, change path to be dir */
3253 session_path = Glib::path_get_dirname (session_path);
3258 SessionDialog session_dialog (should_be_new, session_name, session_path, load_template, cancel_not_quit);
3260 _session_dialog = &session_dialog;
3263 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
3265 /* if they named a specific statefile, use it, otherwise they are
3266 just giving a session folder, and we want to use it as is
3267 to find the session.
3270 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
3272 if (suffix != string::npos) {
3273 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
3274 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
3275 session_name = Glib::path_get_basename (session_name);
3277 session_path = ARDOUR_COMMAND_LINE::session_name;
3278 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
3283 session_dialog.clear_given ();
3286 if (should_be_new || session_name.empty()) {
3287 /* need the dialog to get info from user */
3289 cerr << "run dialog\n";
3291 switch (session_dialog.run()) {
3292 case RESPONSE_ACCEPT:
3295 /* this is used for async * app->ShouldLoad(). */
3296 continue; // while loop
3299 if (quit_on_cancel) {
3300 // JE - Currently (July 2014) this section can only get reached if the
3301 // user quits from the main 'Session Setup' dialog (i.e. reaching this
3302 // point does NOT indicate an abnormal termination). Therefore, let's
3303 // behave gracefully (i.e. let's do some cleanup) before we call exit()
3305 pthread_cancel_all ();
3313 session_dialog.hide ();
3316 /* if we run the startup dialog again, offer more than just "new session" */
3318 should_be_new = false;
3320 session_name = session_dialog.session_name (likely_new);
3321 session_path = session_dialog.session_folder ();
3328 int rv = ARDOUR::inflate_session (session_name,
3329 Config->get_default_session_parent_dir(), session_path, session_name);
3331 MessageDialog msg (session_dialog,
3332 string_compose (_("Extracting session-archive failed: %1"), inflate_error (rv)));
3337 session_dialog.set_provided_session (session_name, session_path);
3341 // XXX check archive, inflate
3342 string::size_type suffix = session_name.find (statefile_suffix);
3344 if (suffix != string::npos) {
3345 session_name = session_name.substr (0, suffix);
3348 /* this shouldn't happen, but we catch it just in case it does */
3350 if (session_name.empty()) {
3354 if (session_dialog.use_session_template()) {
3355 template_name = session_dialog.session_template_name();
3356 _session_is_new = true;
3359 if (session_name[0] == G_DIR_SEPARATOR ||
3360 #ifdef PLATFORM_WINDOWS
3361 (session_name.length() > 3 && session_name[1] == ':' && session_name[2] == G_DIR_SEPARATOR)
3363 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
3364 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)
3369 /* absolute path or cwd-relative path specified for session name: infer session folder
3370 from what was given.
3373 session_path = Glib::path_get_dirname (session_name);
3374 session_name = Glib::path_get_basename (session_name);
3378 session_path = session_dialog.session_folder();
3380 char illegal = Session::session_name_is_legal (session_name);
3383 MessageDialog msg (session_dialog,
3384 string_compose (_("To ensure compatibility with various systems\n"
3385 "session names may not contain a '%1' character"),
3388 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3393 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
3396 if (likely_new && !nsm) {
3398 std::string existing = Glib::build_filename (session_path, session_name);
3400 if (!ask_about_loading_existing_session (existing)) {
3401 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3406 _session_is_new = false;
3411 pop_back_splash (session_dialog);
3412 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
3414 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3418 char illegal = Session::session_name_is_legal(session_name);
3421 pop_back_splash (session_dialog);
3422 MessageDialog msg (session_dialog, string_compose(_("To ensure compatibility with various systems\n"
3423 "session names may not contain a '%1' character"), illegal));
3425 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3429 _session_is_new = true;
3432 if (likely_new && template_name.empty()) {
3434 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3438 ret = load_session (session_path, session_name, template_name);
3441 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
3445 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
3446 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
3450 /* clear this to avoid endless attempts to load the
3454 ARDOUR_COMMAND_LINE::session_name = "";
3458 _session_dialog = NULL;
3464 ARDOUR_UI::close_session()
3466 if (!check_audioengine (_main_window)) {
3470 if (unload_session (true)) {
3474 ARDOUR_COMMAND_LINE::session_name = "";
3476 if (get_session_parameters (true, false)) {
3479 if (splash && splash->is_visible()) {
3480 // in 1 second, hide the splash screen
3481 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
3485 /** @param snap_name Snapshot name (without .ardour suffix).
3486 * @return -2 if the load failed because we are not connected to the AudioEngine.
3489 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
3491 Session *new_session;
3496 unload_status = unload_session ();
3498 if (unload_status < 0) {
3500 } else if (unload_status > 0) {
3506 session_loaded = false;
3508 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
3511 new_session = new Session (*AudioEngine::instance(), path, snap_name, 0, mix_template);
3514 /* this one is special */
3516 catch (AudioEngine::PortRegistrationFailure& err) {
3518 MessageDialog msg (err.what(),
3521 Gtk::BUTTONS_CLOSE);
3523 msg.set_title (_("Port Registration Error"));
3524 msg.set_secondary_text (_("Click the Close button to try again."));
3525 msg.set_position (Gtk::WIN_POS_CENTER);
3526 pop_back_splash (msg);
3529 int response = msg.run ();
3534 case RESPONSE_CANCEL:
3541 catch (SessionException e) {
3542 MessageDialog msg (string_compose(
3543 _("Session \"%1 (snapshot %2)\" did not load successfully: %3"),
3544 path, snap_name, e.what()),
3549 msg.set_title (_("Loading Error"));
3550 msg.set_position (Gtk::WIN_POS_CENTER);
3551 pop_back_splash (msg);
3563 MessageDialog msg (string_compose(
3564 _("Session \"%1 (snapshot %2)\" did not load successfully"),
3570 msg.set_title (_("Loading Error"));
3571 msg.set_position (Gtk::WIN_POS_CENTER);
3572 pop_back_splash (msg);
3584 list<string> const u = new_session->unknown_processors ();
3586 MissingPluginDialog d (_session, u);
3591 if (!new_session->writable()) {
3592 MessageDialog msg (_("This session has been opened in read-only mode.\n\nYou will not be able to record or save."),
3597 msg.set_title (_("Read-only Session"));
3598 msg.set_position (Gtk::WIN_POS_CENTER);
3599 pop_back_splash (msg);
3606 /* Now the session been created, add the transport controls */
3607 new_session->add_controllable(roll_controllable);
3608 new_session->add_controllable(stop_controllable);
3609 new_session->add_controllable(goto_start_controllable);
3610 new_session->add_controllable(goto_end_controllable);
3611 new_session->add_controllable(auto_loop_controllable);
3612 new_session->add_controllable(play_selection_controllable);
3613 new_session->add_controllable(rec_controllable);
3615 set_session (new_session);
3617 session_loaded = true;
3620 _session->set_clean ();
3623 #ifdef WINDOWS_VST_SUPPORT
3624 fst_stop_threading();
3628 Timers::TimerSuspender t;
3632 #ifdef WINDOWS_VST_SUPPORT
3633 fst_start_threading();
3642 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
3644 Session *new_session;
3647 session_loaded = false;
3648 x = unload_session ();
3656 _session_is_new = true;
3659 new_session = new Session (*AudioEngine::instance(), path, snap_name, &bus_profile);
3662 catch (SessionException e) {
3663 cerr << "Here are the errors associated with this failed session:\n";
3665 cerr << "---------\n";
3666 MessageDialog msg (string_compose(_("Could not create session in \"%1\": %2"), path, e.what()));
3667 msg.set_title (_("Loading Error"));
3668 msg.set_position (Gtk::WIN_POS_CENTER);
3669 pop_back_splash (msg);
3674 cerr << "Here are the errors associated with this failed session:\n";
3676 cerr << "---------\n";
3677 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
3678 msg.set_title (_("Loading Error"));
3679 msg.set_position (Gtk::WIN_POS_CENTER);
3680 pop_back_splash (msg);
3685 /* Give the new session the default GUI state, if such things exist */
3688 n = Config->instant_xml (X_("Editor"));
3690 n->remove_nodes_and_delete ("Selection"); // no not apply selection to new sessions.
3691 new_session->add_instant_xml (*n, false);
3693 n = Config->instant_xml (X_("Mixer"));
3695 new_session->add_instant_xml (*n, false);
3698 n = Config->instant_xml (X_("Preferences"));
3700 new_session->add_instant_xml (*n, false);
3703 /* Put the playhead at 0 and scroll fully left */
3704 n = new_session->instant_xml (X_("Editor"));
3706 n->add_property (X_("playhead"), X_("0"));
3707 n->add_property (X_("left-frame"), X_("0"));
3710 set_session (new_session);
3712 session_loaded = true;
3714 new_session->save_state(new_session->name());
3720 ARDOUR_UI::launch_chat ()
3722 MessageDialog dialog(_("<b>Just ask and wait for an answer.\nIt may take from minutes to hours.</b>"), true);
3724 dialog.set_title (_("About the Chat"));
3725 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."));
3727 switch (dialog.run()) {
3730 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
3731 #elif defined PLATFORM_WINDOWS
3732 open_uri("http://webchat.freenode.net/?channels=ardour-windows");
3734 open_uri("http://webchat.freenode.net/?channels=ardour");
3743 ARDOUR_UI::launch_manual ()
3745 PBD::open_uri (Config->get_tutorial_manual_url());
3749 ARDOUR_UI::launch_reference ()
3751 PBD::open_uri (Config->get_reference_manual_url());
3755 ARDOUR_UI::launch_tracker ()
3757 PBD::open_uri ("http://tracker.ardour.org");
3761 ARDOUR_UI::launch_subscribe ()
3763 PBD::open_uri ("https://community.ardour.org/s/subscribe");
3767 ARDOUR_UI::launch_cheat_sheet ()
3770 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheat_sheet_osx.pdf");
3772 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheatsheet.pdf");
3777 ARDOUR_UI::launch_website ()
3779 PBD::open_uri ("http://ardour.org");
3783 ARDOUR_UI::launch_website_dev ()
3785 PBD::open_uri ("http://ardour.org/development.html");
3789 ARDOUR_UI::launch_forums ()
3791 PBD::open_uri ("https://community.ardour.org/forums");
3795 ARDOUR_UI::launch_howto_report ()
3797 PBD::open_uri ("http://ardour.org/reporting_bugs");
3801 ARDOUR_UI::loading_message (const std::string& msg)
3803 if (ARDOUR_COMMAND_LINE::no_splash) {
3811 splash->message (msg);
3815 ARDOUR_UI::show_splash ()
3819 splash = new Splash;
3829 ARDOUR_UI::hide_splash ()
3836 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title, const bool msg_delete)
3840 removed = rep.paths.size();
3843 MessageDialog msgd (_main_window,
3844 _("No files were ready for clean-up"),
3848 msgd.set_title (_("Clean-up"));
3849 msgd.set_secondary_text (_("If this seems suprising, \n\
3850 check for any existing snapshots.\n\
3851 These may still include regions that\n\
3852 require some unused files to continue to exist."));
3858 ArdourDialog results (_("Clean-up"), true, false);
3860 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
3861 CleanupResultsModelColumns() {
3865 Gtk::TreeModelColumn<std::string> visible_name;
3866 Gtk::TreeModelColumn<std::string> fullpath;
3870 CleanupResultsModelColumns results_columns;
3871 Glib::RefPtr<Gtk::ListStore> results_model;
3872 Gtk::TreeView results_display;
3874 results_model = ListStore::create (results_columns);
3875 results_display.set_model (results_model);
3876 results_display.append_column (list_title, results_columns.visible_name);
3878 results_display.set_name ("CleanupResultsList");
3879 results_display.set_headers_visible (true);
3880 results_display.set_headers_clickable (false);
3881 results_display.set_reorderable (false);
3883 Gtk::ScrolledWindow list_scroller;
3886 Gtk::HBox dhbox; // the hbox for the image and text
3887 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
3888 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
3890 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
3892 const string dead_directory = _session->session_directory().dead_path();
3895 %1 - number of files removed
3896 %2 - location of "dead"
3897 %3 - size of files affected
3898 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
3901 const char* bprefix;
3902 double space_adjusted = 0;
3904 if (rep.space < 1000) {
3906 space_adjusted = rep.space;
3907 } else if (rep.space < 1000000) {
3908 bprefix = _("kilo");
3909 space_adjusted = floorf((float)rep.space / 1000.0);
3910 } else if (rep.space < 1000000 * 1000) {
3911 bprefix = _("mega");
3912 space_adjusted = floorf((float)rep.space / (1000.0 * 1000.0));
3914 bprefix = _("giga");
3915 space_adjusted = floorf((float)rep.space / (1000.0 * 1000 * 1000.0));
3919 txt.set_markup (string_compose (P_("\
3920 The following file was deleted from %2,\n\
3921 releasing %3 %4bytes of disk space", "\
3922 The following %1 files were deleted from %2,\n\
3923 releasing %3 %4bytes of disk space", removed),
3924 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3926 txt.set_markup (string_compose (P_("\
3927 The following file was not in use and \n\
3928 has been moved to: %2\n\n\
3929 After a restart of %5\n\n\
3930 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3931 will release an additional %3 %4bytes of disk space.\n", "\
3932 The following %1 files were not in use and \n\
3933 have been moved to: %2\n\n\
3934 After a restart of %5\n\n\
3935 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3936 will release an additional %3 %4bytes of disk space.\n", removed),
3937 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3940 dhbox.pack_start (*dimage, true, false, 5);
3941 dhbox.pack_start (txt, true, false, 5);
3943 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
3944 TreeModel::Row row = *(results_model->append());
3945 row[results_columns.visible_name] = *i;
3946 row[results_columns.fullpath] = *i;
3949 list_scroller.add (results_display);
3950 list_scroller.set_size_request (-1, 150);
3951 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
3953 dvbox.pack_start (dhbox, true, false, 5);
3954 dvbox.pack_start (list_scroller, true, false, 5);
3955 ddhbox.pack_start (dvbox, true, false, 5);
3957 results.get_vbox()->pack_start (ddhbox, true, false, 5);
3958 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
3959 results.set_default_response (RESPONSE_CLOSE);
3960 results.set_position (Gtk::WIN_POS_MOUSE);
3962 results_display.show();
3963 list_scroller.show();
3970 //results.get_vbox()->show();
3971 results.set_resizable (false);
3978 ARDOUR_UI::cleanup ()
3980 if (_session == 0) {
3981 /* shouldn't happen: menu item is insensitive */
3986 MessageDialog checker (_("Are you sure you want to clean-up?"),
3988 Gtk::MESSAGE_QUESTION,
3991 checker.set_title (_("Clean-up"));
3993 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
3994 ALL undo/redo information will be lost if you clean-up.\n\
3995 Clean-up will move all unused files to a \"dead\" location."));
3997 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3998 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
3999 checker.set_default_response (RESPONSE_CANCEL);
4001 checker.set_name (_("CleanupDialog"));
4002 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
4003 checker.set_position (Gtk::WIN_POS_MOUSE);
4005 switch (checker.run()) {
4006 case RESPONSE_ACCEPT:
4012 ARDOUR::CleanupReport rep;
4014 editor->prepare_for_cleanup ();
4016 /* do not allow flush until a session is reloaded */
4018 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
4020 act->set_sensitive (false);
4023 if (_session->cleanup_sources (rep)) {
4024 editor->finish_cleanup ();
4028 editor->finish_cleanup ();
4031 display_cleanup_results (rep, _("Cleaned Files"), false);
4035 ARDOUR_UI::flush_trash ()
4037 if (_session == 0) {
4038 /* shouldn't happen: menu item is insensitive */
4042 ARDOUR::CleanupReport rep;
4044 if (_session->cleanup_trash_sources (rep)) {
4048 display_cleanup_results (rep, _("deleted file"), true);
4052 ARDOUR_UI::cleanup_peakfiles ()
4054 if (_session == 0) {
4055 /* shouldn't happen: menu item is insensitive */
4059 if (! _session->can_cleanup_peakfiles ()) {
4063 // get all region-views in this session
4065 TrackViewList empty;
4067 editor->get_regions_after(rs, (framepos_t) 0, empty);
4068 std::list<RegionView*> views = rs.by_layer();
4070 // remove displayed audio-region-views waveforms
4071 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
4072 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
4073 if (!arv) { continue ; }
4074 arv->delete_waves();
4077 // cleanup peak files:
4078 // - stop pending peakfile threads
4079 // - close peakfiles if any
4080 // - remove peak dir in session
4081 // - setup peakfiles (background thread)
4082 _session->cleanup_peakfiles ();
4084 // re-add waves to ARV
4085 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
4086 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
4087 if (!arv) { continue ; }
4088 arv->create_waves();
4092 PresentationInfo::order_t
4093 ARDOUR_UI::translate_order (RouteDialogs::InsertAt place)
4095 if (editor->get_selection().tracks.empty()) {
4096 return PresentationInfo::max_order;
4099 PresentationInfo::order_t order_hint = PresentationInfo::max_order;
4102 we want the new routes to have their order keys set starting from
4103 the highest order key in the selection + 1 (if available).
4106 if (place == RouteDialogs::AfterSelection) {
4107 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.back());
4109 order_hint = rtav->route()->presentation_info().order();
4112 } else if (place == RouteDialogs::BeforeSelection) {
4113 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.front());
4115 order_hint = rtav->route()->presentation_info().order();
4117 } else if (place == RouteDialogs::First) {
4120 /* leave order_hint at max_order */
4127 ARDOUR_UI::start_duplicate_routes ()
4129 if (!duplicate_routes_dialog) {
4130 duplicate_routes_dialog = new DuplicateRouteDialog;
4133 if (duplicate_routes_dialog->restart (_session)) {
4137 duplicate_routes_dialog->present ();
4141 ARDOUR_UI::add_route ()
4143 if (!add_route_dialog.get (false)) {
4144 add_route_dialog->signal_response().connect (sigc::mem_fun (*this, &ARDOUR_UI::add_route_dialog_finished));
4151 if (add_route_dialog->is_visible()) {
4152 /* we're already doing this */
4156 add_route_dialog->set_position (WIN_POS_MOUSE);
4157 add_route_dialog->present();
4161 ARDOUR_UI::add_route_dialog_finished (int r)
4165 add_route_dialog->hide();
4168 case RESPONSE_ACCEPT:
4175 if ((count = add_route_dialog->count()) <= 0) {
4179 PresentationInfo::order_t order = translate_order (add_route_dialog->insert_at());
4180 string template_path = add_route_dialog->track_template();
4181 DisplaySuspender ds;
4183 if (!template_path.empty()) {
4184 if (add_route_dialog->name_template_is_default()) {
4185 _session->new_route_from_template (count, order, template_path, string());
4187 _session->new_route_from_template (count, order, template_path, add_route_dialog->name_template());
4192 ChanCount input_chan= add_route_dialog->channels ();
4193 ChanCount output_chan;
4194 string name_template = add_route_dialog->name_template ();
4195 PluginInfoPtr instrument = add_route_dialog->requested_instrument ();
4196 RouteGroup* route_group = add_route_dialog->route_group ();
4197 AutoConnectOption oac = Config->get_output_auto_connect();
4198 bool strict_io = add_route_dialog->use_strict_io ();
4200 if (oac & AutoConnectMaster) {
4201 output_chan.set (DataType::AUDIO, (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan.n_audio()));
4202 output_chan.set (DataType::MIDI, 0);
4204 output_chan = input_chan;
4207 /* XXX do something with name template */
4209 Session::ProcessorChangeBlocker pcb (_session);
4211 switch (add_route_dialog->type_wanted()) {
4212 case AddRouteDialog::AudioTrack:
4213 session_add_audio_track (input_chan.n_audio(), output_chan.n_audio(), add_route_dialog->mode(), route_group, count, name_template, strict_io, order);
4215 case AddRouteDialog::MidiTrack:
4216 session_add_midi_track (route_group, count, name_template, strict_io, instrument, 0, order);
4218 case AddRouteDialog::MixedTrack:
4219 session_add_mixed_track (input_chan, output_chan, route_group, count, name_template, strict_io, instrument, 0, order);
4221 case AddRouteDialog::AudioBus:
4222 session_add_audio_bus (input_chan.n_audio(), output_chan.n_audio(), route_group, count, name_template, strict_io, order);
4224 case AddRouteDialog::MidiBus:
4225 session_add_midi_bus (route_group, count, name_template, strict_io, instrument, 0, order);
4227 case AddRouteDialog::VCAMaster:
4228 session_add_vca (name_template, count);
4234 ARDOUR_UI::add_lua_script ()
4240 LuaScriptInfoPtr spi;
4241 ScriptSelector ss ("Add Lua Session Script", LuaScriptInfo::Session);
4242 switch (ss.run ()) {
4243 case Gtk::RESPONSE_ACCEPT:
4251 std::string script = "";
4254 script = Glib::file_get_contents (spi->path);
4255 } catch (Glib::FileError e) {
4256 string msg = string_compose (_("Cannot read session script '%1': %2"), spi->path, e.what());
4257 MessageDialog am (msg);
4262 LuaScriptParamList lsp = LuaScriptParams::script_params (spi, "sess_params");
4263 std::vector<std::string> reg = _session->registered_lua_functions ();
4265 ScriptParameterDialog spd (_("Set Script Parameters"), spi, reg, lsp);
4266 switch (spd.run ()) {
4267 case Gtk::RESPONSE_ACCEPT:
4274 _session->register_lua_function (spd.name(), script, lsp);
4275 } catch (luabridge::LuaException const& e) {
4276 string msg = string_compose (_("Session script '%1' instantiation failed: %2"), spd.name(), e.what ());
4277 MessageDialog am (msg);
4279 } catch (SessionException e) {
4280 string msg = string_compose (_("Loading Session script '%1' failed: %2"), spd.name(), e.what ());
4281 MessageDialog am (msg);
4287 ARDOUR_UI::remove_lua_script ()
4292 if (_session->registered_lua_function_count () == 0) {
4293 string msg = _("There are no active Lua session scripts present in this session.");
4294 MessageDialog am (msg);
4299 std::vector<std::string> reg = _session->registered_lua_functions ();
4300 SessionScriptManager sm ("Remove Lua Session Script", reg);
4301 switch (sm.run ()) {
4302 case Gtk::RESPONSE_ACCEPT:
4308 _session->unregister_lua_function (sm.name());
4309 } catch (luabridge::LuaException const& e) {
4310 string msg = string_compose (_("Session script '%1' removal failed: %2"), sm.name(), e.what ());
4311 MessageDialog am (msg);
4317 ARDOUR_UI::stop_video_server (bool ask_confirm)
4319 if (!video_server_process && ask_confirm) {
4320 warning << string_compose (_("Video-Server was not launched by %1. The request to stop it is ignored."), PROGRAM_NAME) << endmsg;
4322 if (video_server_process) {
4324 ArdourDialog confirm (_("Stop Video-Server"), true);
4325 Label m (_("Do you really want to stop the Video Server?"));
4326 confirm.get_vbox()->pack_start (m, true, true);
4327 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
4328 confirm.add_button (_("Yes, Stop It"), Gtk::RESPONSE_ACCEPT);
4329 confirm.show_all ();
4330 if (confirm.run() == RESPONSE_CANCEL) {
4334 delete video_server_process;
4335 video_server_process =0;
4340 ARDOUR_UI::start_video_server_menu (Gtk::Window* float_window)
4342 ARDOUR_UI::start_video_server( float_window, true);
4346 ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg)
4352 if (ARDOUR_UI::instance()->video_timeline->check_server()) {
4353 if (video_server_process) {
4354 popup_error(_("The Video Server is already started."));
4356 popup_error(_("An external Video Server is configured and can be reached. Not starting a new instance."));
4362 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4364 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4366 VideoServerDialog *video_server_dialog = new VideoServerDialog (_session);
4368 video_server_dialog->set_transient_for (*float_window);
4371 if (!Config->get_show_video_server_dialog() && firsttime < 2) {
4372 video_server_dialog->hide();
4374 ResponseType r = (ResponseType) video_server_dialog->run ();
4375 video_server_dialog->hide();
4376 if (r != RESPONSE_ACCEPT) { return false; }
4377 if (video_server_dialog->show_again()) {
4378 Config->set_show_video_server_dialog(false);
4382 std::string icsd_exec = video_server_dialog->get_exec_path();
4383 std::string icsd_docroot = video_server_dialog->get_docroot();
4384 #ifndef PLATFORM_WINDOWS
4385 if (icsd_docroot.empty()) {
4386 icsd_docroot = VideoUtils::video_get_docroot (Config);
4391 #ifdef PLATFORM_WINDOWS
4392 if (VideoUtils::harvid_version >= 0x000802 && icsd_docroot.empty()) {
4393 /* OK, allow all drive letters */
4396 if (g_lstat (icsd_docroot.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode)) {
4397 warning << _("Specified docroot is not an existing directory.") << endmsg;
4400 #ifndef PLATFORM_WINDOWS
4401 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4402 || (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0 ) {
4403 warning << _("Given Video Server is not an executable file.") << endmsg;
4407 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4408 || (sb.st_mode & (S_IXUSR)) == 0 ) {
4409 warning << _("Given Video Server is not an executable file.") << endmsg;
4415 argp=(char**) calloc(9,sizeof(char*));
4416 argp[0] = strdup(icsd_exec.c_str());
4417 argp[1] = strdup("-P");
4418 argp[2] = (char*) calloc(16,sizeof(char)); snprintf(argp[2], 16, "%s", video_server_dialog->get_listenaddr().c_str());
4419 argp[3] = strdup("-p");
4420 argp[4] = (char*) calloc(6,sizeof(char)); snprintf(argp[4], 6, "%i", video_server_dialog->get_listenport());
4421 argp[5] = strdup("-C");
4422 argp[6] = (char*) calloc(6,sizeof(char)); snprintf(argp[6], 6, "%i", video_server_dialog->get_cachesize());
4423 argp[7] = strdup(icsd_docroot.c_str());
4425 stop_video_server();
4427 #ifdef PLATFORM_WINDOWS
4428 if (VideoUtils::harvid_version >= 0x000802 && icsd_docroot.empty()) {
4429 /* OK, allow all drive letters */
4432 if (icsd_docroot == X_("/") || icsd_docroot == X_("C:\\")) {
4433 Config->set_video_advanced_setup(false);
4435 std::ostringstream osstream;
4436 osstream << "http://127.0.0.1:" << video_server_dialog->get_listenport() << "/";
4437 Config->set_video_server_url(osstream.str());
4438 Config->set_video_server_docroot(icsd_docroot);
4439 Config->set_video_advanced_setup(true);
4442 if (video_server_process) {
4443 delete video_server_process;
4446 video_server_process = new ARDOUR::SystemExec(icsd_exec, argp);
4447 if (video_server_process->start()) {
4448 warning << _("Cannot launch the video-server") << endmsg;
4451 int timeout = 120; // 6 sec
4452 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4453 Glib::usleep (50000);
4455 if (--timeout <= 0 || !video_server_process->is_running()) break;
4458 warning << _("Video-server was started but does not respond to requests...") << endmsg;
4460 if (!ARDOUR_UI::instance()->video_timeline->check_server_docroot()) {
4461 delete video_server_process;
4462 video_server_process = 0;
4470 ARDOUR_UI::add_video (Gtk::Window* float_window)
4476 if (!start_video_server(float_window, false)) {
4477 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4482 add_video_dialog->set_transient_for (*float_window);
4485 if (add_video_dialog->is_visible()) {
4486 /* we're already doing this */
4490 ResponseType r = (ResponseType) add_video_dialog->run ();
4491 add_video_dialog->hide();
4492 if (r != RESPONSE_ACCEPT) { return; }
4494 bool local_file, orig_local_file;
4495 std::string path = add_video_dialog->file_name(local_file);
4497 std::string orig_path = path;
4498 orig_local_file = local_file;
4500 bool auto_set_session_fps = add_video_dialog->auto_set_session_fps();
4502 if (local_file && !Glib::file_test(path, Glib::FILE_TEST_EXISTS)) {
4503 warning << string_compose(_("could not open %1"), path) << endmsg;
4506 if (!local_file && path.length() == 0) {
4507 warning << _("no video-file selected") << endmsg;
4511 std::string audio_from_video;
4512 bool detect_ltc = false;
4514 switch (add_video_dialog->import_option()) {
4515 case VTL_IMPORT_TRANSCODE:
4517 TranscodeVideoDialog *transcode_video_dialog;
4518 transcode_video_dialog = new TranscodeVideoDialog (_session, path);
4519 ResponseType r = (ResponseType) transcode_video_dialog->run ();
4520 transcode_video_dialog->hide();
4521 if (r != RESPONSE_ACCEPT) {
4522 delete transcode_video_dialog;
4526 audio_from_video = transcode_video_dialog->get_audiofile();
4528 if (!audio_from_video.empty() && transcode_video_dialog->detect_ltc()) {
4531 else if (!audio_from_video.empty()) {
4532 editor->embed_audio_from_video(
4534 video_timeline->get_offset(),
4535 (transcode_video_dialog->import_option() != VTL_IMPORT_NO_VIDEO)
4538 switch (transcode_video_dialog->import_option()) {
4539 case VTL_IMPORT_TRANSCODED:
4540 path = transcode_video_dialog->get_filename();
4543 case VTL_IMPORT_REFERENCE:
4546 delete transcode_video_dialog;
4549 delete transcode_video_dialog;
4553 case VTL_IMPORT_NONE:
4557 /* strip _session->session_directory().video_path() from video file if possible */
4558 if (local_file && !path.compare(0, _session->session_directory().video_path().size(), _session->session_directory().video_path())) {
4559 path=path.substr(_session->session_directory().video_path().size());
4560 if (path.at(0) == G_DIR_SEPARATOR) {
4561 path=path.substr(1);
4565 video_timeline->set_update_session_fps(auto_set_session_fps);
4567 if (video_timeline->video_file_info(path, local_file)) {
4568 XMLNode* node = new XMLNode(X_("Videotimeline"));
4569 node->add_property (X_("Filename"), path);
4570 node->add_property (X_("AutoFPS"), auto_set_session_fps?X_("1"):X_("0"));
4571 node->add_property (X_("LocalFile"), local_file?X_("1"):X_("0"));
4572 if (orig_local_file) {
4573 node->add_property (X_("OriginalVideoFile"), orig_path);
4575 node->remove_property (X_("OriginalVideoFile"));
4577 _session->add_extra_xml (*node);
4578 _session->set_dirty ();
4580 if (!audio_from_video.empty() && detect_ltc) {
4581 std::vector<LTCFileReader::LTCMap> ltc_seq;
4584 /* TODO ask user about TV standard (LTC alignment if any) */
4585 LTCFileReader ltcr (audio_from_video, video_timeline->get_video_file_fps());
4586 /* TODO ASK user which channel: 0 .. ltcr->channels() - 1 */
4588 ltc_seq = ltcr.read_ltc (/*channel*/ 0, /*max LTC frames to decode*/ 15);
4590 /* TODO seek near end of file, and read LTC until end.
4591 * if it fails to find any LTC frames, scan complete file
4593 * calculate drift of LTC compared to video-duration,
4594 * ask user for reference (timecode from start/mid/end)
4597 // LTCFileReader will have written error messages
4600 ::g_unlink(audio_from_video.c_str());
4602 if (ltc_seq.size() == 0) {
4603 PBD::error << _("No LTC detected, video will not be aligned.") << endmsg;
4605 /* the very first TC in the file is somteimes not aligned properly */
4606 int i = ltc_seq.size() -1;
4607 ARDOUR::frameoffset_t video_start_offset =
4608 _session->nominal_frame_rate() * (ltc_seq[i].timecode_sec - ltc_seq[i].framepos_sec);
4609 PBD::info << string_compose (_("Align video-start to %1 [samples]"), video_start_offset) << endmsg;
4610 video_timeline->set_offset(video_start_offset);
4614 _session->maybe_update_session_range(
4615 std::max(video_timeline->get_offset(), (ARDOUR::frameoffset_t) 0),
4616 std::max(video_timeline->get_offset() + video_timeline->get_duration(), (ARDOUR::frameoffset_t) 0));
4619 if (add_video_dialog->launch_xjadeo() && local_file) {
4620 editor->set_xjadeo_sensitive(true);
4621 editor->toggle_xjadeo_proc(1);
4623 editor->toggle_xjadeo_proc(0);
4625 editor->toggle_ruler_video(true);
4630 ARDOUR_UI::remove_video ()
4632 video_timeline->close_session();
4633 editor->toggle_ruler_video(false);
4636 video_timeline->set_offset_locked(false);
4637 video_timeline->set_offset(0);
4639 /* delete session state */
4640 XMLNode* node = new XMLNode(X_("Videotimeline"));
4641 _session->add_extra_xml(*node);
4642 node = new XMLNode(X_("Videomonitor"));
4643 _session->add_extra_xml(*node);
4644 node = new XMLNode(X_("Videoexport"));
4645 _session->add_extra_xml(*node);
4646 stop_video_server();
4650 ARDOUR_UI::flush_videotimeline_cache (bool localcacheonly)
4652 if (localcacheonly) {
4653 video_timeline->vmon_update();
4655 video_timeline->flush_cache();
4657 editor->queue_visual_videotimeline_update();
4661 ARDOUR_UI::export_video (bool range)
4663 if (ARDOUR::Config->get_show_video_export_info()) {
4664 ExportVideoInfobox infobox (_session);
4665 Gtk::ResponseType rv = (Gtk::ResponseType) infobox.run();
4666 if (infobox.show_again()) {
4667 ARDOUR::Config->set_show_video_export_info(false);
4670 case GTK_RESPONSE_YES:
4671 PBD::open_uri (ARDOUR::Config->get_reference_manual_url() + "/video-timeline/operations/#export");
4677 export_video_dialog->set_session (_session);
4678 export_video_dialog->apply_state(editor->get_selection().time, range);
4679 export_video_dialog->run ();
4680 export_video_dialog->hide ();
4684 ARDOUR_UI::preferences_settings () const
4689 node = _session->instant_xml(X_("Preferences"));
4691 node = Config->instant_xml(X_("Preferences"));
4695 node = new XMLNode (X_("Preferences"));
4702 ARDOUR_UI::mixer_settings () const
4707 node = _session->instant_xml(X_("Mixer"));
4709 node = Config->instant_xml(X_("Mixer"));
4713 node = new XMLNode (X_("Mixer"));
4720 ARDOUR_UI::main_window_settings () const
4725 node = _session->instant_xml(X_("Main"));
4727 node = Config->instant_xml(X_("Main"));
4731 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4732 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4737 node = new XMLNode (X_("Main"));
4744 ARDOUR_UI::editor_settings () const
4749 node = _session->instant_xml(X_("Editor"));
4751 node = Config->instant_xml(X_("Editor"));
4755 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4756 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4761 node = new XMLNode (X_("Editor"));
4768 ARDOUR_UI::keyboard_settings () const
4772 node = Config->extra_xml(X_("Keyboard"));
4775 node = new XMLNode (X_("Keyboard"));
4782 ARDOUR_UI::create_xrun_marker (framepos_t where)
4785 Location *location = new Location (*_session, where, where, _("xrun"), Location::IsMark, 0);
4786 _session->locations()->add (location);
4791 ARDOUR_UI::halt_on_xrun_message ()
4793 cerr << "HALT on xrun\n";
4794 MessageDialog msg (_main_window, _("Recording was stopped because your system could not keep up."));
4799 ARDOUR_UI::xrun_handler (framepos_t where)
4805 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
4807 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
4808 create_xrun_marker(where);
4811 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
4812 halt_on_xrun_message ();
4817 ARDOUR_UI::disk_overrun_handler ()
4819 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
4821 if (!have_disk_speed_dialog_displayed) {
4822 have_disk_speed_dialog_displayed = true;
4823 MessageDialog* msg = new MessageDialog (_main_window, string_compose (_("\
4824 The disk system on your computer\n\
4825 was not able to keep up with %1.\n\
4827 Specifically, it failed to write data to disk\n\
4828 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
4829 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4835 /* TODO: this is getting elaborate enough to warrant being split into a dedicated class */
4836 static MessageDialog *scan_dlg = NULL;
4837 static ProgressBar *scan_pbar = NULL;
4838 static HBox *scan_tbox = NULL;
4839 static Gtk::Button *scan_timeout_button;
4842 ARDOUR_UI::cancel_plugin_scan ()
4844 PluginManager::instance().cancel_plugin_scan();
4848 ARDOUR_UI::cancel_plugin_timeout ()
4850 PluginManager::instance().cancel_plugin_timeout();
4851 scan_timeout_button->set_sensitive (false);
4855 ARDOUR_UI::plugin_scan_timeout (int timeout)
4857 if (!scan_dlg || !scan_dlg->is_mapped() || !scan_pbar) {
4861 scan_pbar->set_sensitive (false);
4862 scan_timeout_button->set_sensitive (true);
4863 scan_pbar->set_fraction ((float) timeout / (float) Config->get_vst_scan_timeout());
4866 scan_pbar->set_sensitive (false);
4867 scan_timeout_button->set_sensitive (false);
4873 ARDOUR_UI::plugin_scan_dialog (std::string type, std::string plugin, bool can_cancel)
4875 if (type == X_("closeme") && !(scan_dlg && scan_dlg->is_mapped())) {
4879 const bool cancelled = PluginManager::instance().cancelled();
4880 if (type != X_("closeme") && (!UIConfiguration::instance().get_show_plugin_scan_window()) && !_initial_verbose_plugin_scan) {
4881 if (cancelled && scan_dlg->is_mapped()) {
4886 if (cancelled || !can_cancel) {
4891 static Gtk::Button *cancel_button;
4893 scan_dlg = new MessageDialog("", false, MESSAGE_INFO, BUTTONS_NONE); // TODO manage
4894 VBox* vbox = scan_dlg->get_vbox();
4895 vbox->set_size_request(400,-1);
4896 scan_dlg->set_title (_("Scanning for plugins"));
4898 cancel_button = manage(new Gtk::Button(_("Cancel plugin scan")));
4899 cancel_button->set_name ("EditorGTKButton");
4900 cancel_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_scan) );
4901 cancel_button->show();
4903 scan_dlg->get_vbox()->pack_start ( *cancel_button, PACK_SHRINK);
4905 scan_tbox = manage( new HBox() );
4907 scan_timeout_button = manage(new Gtk::Button(_("Stop Timeout")));
4908 scan_timeout_button->set_name ("EditorGTKButton");
4909 scan_timeout_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_timeout) );
4910 scan_timeout_button->show();
4912 scan_pbar = manage(new ProgressBar());
4913 scan_pbar->set_orientation(Gtk::PROGRESS_RIGHT_TO_LEFT);
4914 scan_pbar->set_text(_("Scan Timeout"));
4917 scan_tbox->pack_start (*scan_pbar, PACK_EXPAND_WIDGET, 4);
4918 scan_tbox->pack_start (*scan_timeout_button, PACK_SHRINK, 4);
4920 scan_dlg->get_vbox()->pack_start (*scan_tbox, PACK_SHRINK, 4);
4923 assert(scan_dlg && scan_tbox && cancel_button);
4925 if (type == X_("closeme")) {
4929 scan_dlg->set_message(type + ": " + Glib::path_get_basename(plugin));
4932 if (!can_cancel || !cancelled) {
4933 scan_timeout_button->set_sensitive(false);
4935 cancel_button->set_sensitive(can_cancel && !cancelled);
4941 ARDOUR_UI::gui_idle_handler ()
4944 /* due to idle calls, gtk_events_pending() may always return true */
4945 while (gtk_events_pending() && --timeout) {
4946 gtk_main_iteration ();
4951 ARDOUR_UI::disk_underrun_handler ()
4953 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
4955 if (!have_disk_speed_dialog_displayed) {
4956 have_disk_speed_dialog_displayed = true;
4957 MessageDialog* msg = new MessageDialog (
4958 _main_window, string_compose (_("The disk system on your computer\n\
4959 was not able to keep up with %1.\n\
4961 Specifically, it failed to read data from disk\n\
4962 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
4963 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4969 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
4971 have_disk_speed_dialog_displayed = false;
4976 ARDOUR_UI::session_dialog (std::string msg)
4978 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
4982 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
4989 ARDOUR_UI::pending_state_dialog ()
4991 HBox* hbox = manage (new HBox());
4992 Image* image = manage (new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG));
4993 ArdourDialog dialog (_("Crash Recovery"), true);
4994 Label message (string_compose (_("\
4995 This session appears to have been in the\n\
4996 middle of recording when %1 or\n\
4997 the computer was shutdown.\n\
4999 %1 can recover any captured audio for\n\
5000 you, or it can ignore it. Please decide\n\
5001 what you would like to do.\n"), PROGRAM_NAME));
5002 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
5003 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
5004 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
5005 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
5006 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
5007 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
5008 dialog.set_default_response (RESPONSE_ACCEPT);
5009 dialog.set_position (WIN_POS_CENTER);
5014 switch (dialog.run ()) {
5015 case RESPONSE_ACCEPT:
5023 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
5025 HBox* hbox = new HBox();
5026 Image* image = new Image (Stock::DIALOG_WARNING, ICON_SIZE_DIALOG);
5027 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
5028 Label message (string_compose (_("\
5029 This session was created with a sample rate of %1 Hz, but\n\
5030 %2 is currently running at %3 Hz. If you load this session,\n\
5031 audio may be played at the wrong sample rate.\n"), desired, PROGRAM_NAME, actual));
5033 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
5034 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
5035 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
5036 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
5037 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
5038 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
5039 dialog.set_default_response (RESPONSE_ACCEPT);
5040 dialog.set_position (WIN_POS_CENTER);
5045 switch (dialog.run()) {
5046 case RESPONSE_ACCEPT:
5056 ARDOUR_UI::sr_mismatch_message (framecnt_t desired, framecnt_t actual)
5058 MessageDialog msg (string_compose (_("\
5059 This session was created with a sample rate of %1 Hz, but\n\
5060 %2 is currently running at %3 Hz.\n\
5061 Audio will be recorded and played at the wrong sample rate.\n\
5062 Re-Configure the Audio Engine in\n\
5063 Menu > Window > Audio/Midi Setup"),
5064 desired, PROGRAM_NAME, actual),
5066 Gtk::MESSAGE_WARNING);
5071 ARDOUR_UI::use_config ()
5073 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
5075 set_transport_controllable_state (*node);
5080 ARDOUR_UI::update_transport_clocks (framepos_t pos)
5082 if (UIConfiguration::instance().get_primary_clock_delta_edit_cursor()) {
5083 primary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
5085 primary_clock->set (pos);
5088 if (UIConfiguration::instance().get_secondary_clock_delta_edit_cursor()) {
5089 secondary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
5091 secondary_clock->set (pos);
5094 if (big_clock_window) {
5095 big_clock->set (pos);
5097 ARDOUR_UI::instance()->video_timeline->manual_seek_video_monitor(pos);
5101 ARDOUR_UI::step_edit_status_change (bool yn)
5103 // XXX should really store pre-step edit status of things
5104 // we make insensitive
5107 rec_button.set_active_state (Gtkmm2ext::ImplicitActive);
5108 rec_button.set_sensitive (false);
5110 rec_button.unset_active_state ();;
5111 rec_button.set_sensitive (true);
5116 ARDOUR_UI::record_state_changed ()
5118 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
5121 /* why bother - the clock isn't visible */
5125 ActionManager::set_sensitive (ActionManager::rec_sensitive_actions, !_session->actively_recording());
5127 if (big_clock_window) {
5128 if (_session->record_status () == Session::Recording && _session->have_rec_enabled_track ()) {
5129 big_clock->set_active (true);
5131 big_clock->set_active (false);
5138 ARDOUR_UI::first_idle ()
5141 _session->allow_auto_play (true);
5145 editor->first_idle();
5148 Keyboard::set_can_save_keybindings (true);
5153 ARDOUR_UI::store_clock_modes ()
5155 XMLNode* node = new XMLNode(X_("ClockModes"));
5157 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
5158 XMLNode* child = new XMLNode (X_("Clock"));
5160 child->add_property (X_("name"), (*x)->name());
5161 child->add_property (X_("mode"), enum_2_string ((*x)->mode()));
5162 child->add_property (X_("on"), ((*x)->off() ? X_("no") : X_("yes")));
5164 node->add_child_nocopy (*child);
5167 _session->add_extra_xml (*node);
5168 _session->set_dirty ();
5171 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
5172 : Controllable (name), ui (u), type(tp)
5178 ARDOUR_UI::TransportControllable::set_value (double val, PBD::Controllable::GroupControlDisposition /*group_override*/)
5181 /* do nothing: these are radio-style actions */
5185 const char *action = 0;
5189 action = X_("Roll");
5192 action = X_("Stop");
5195 action = X_("GotoStart");
5198 action = X_("GotoEnd");
5201 action = X_("Loop");
5204 action = X_("PlaySelection");
5207 action = X_("Record");
5217 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
5225 ARDOUR_UI::TransportControllable::get_value (void) const
5252 ARDOUR_UI::setup_profile ()
5254 if (gdk_screen_width() < 1200 || getenv ("ARDOUR_NARROW_SCREEN")) {
5255 Profile->set_small_screen ();
5258 if (g_getenv ("TRX")) {
5259 Profile->set_trx ();
5262 if (g_getenv ("MIXBUS")) {
5263 Profile->set_mixbus ();
5268 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
5270 MissingFileDialog dialog (s, str, type);
5275 int result = dialog.run ();
5282 return 1; // quit entire session load
5285 result = dialog.get_action ();
5291 ARDOUR_UI::ambiguous_file (std::string file, std::vector<std::string> hits)
5293 AmbiguousFileDialog dialog (file, hits);
5300 return dialog.get_which ();
5303 /** Allocate our thread-local buffers */
5305 ARDOUR_UI::get_process_buffers ()
5307 _process_thread->get_buffers ();
5310 /** Drop our thread-local buffers */
5312 ARDOUR_UI::drop_process_buffers ()
5314 _process_thread->drop_buffers ();
5318 ARDOUR_UI::feedback_detected ()
5320 _feedback_exists = true;
5324 ARDOUR_UI::successful_graph_sort ()
5326 _feedback_exists = false;
5330 ARDOUR_UI::midi_panic ()
5333 _session->midi_panic();
5338 ARDOUR_UI::session_format_mismatch (std::string xml_path, std::string backup_path)
5340 const char* start_big = "<span size=\"x-large\" weight=\"bold\">";
5341 const char* end_big = "</span>";
5342 const char* start_mono = "<tt>";
5343 const char* end_mono = "</tt>";
5345 MessageDialog msg (string_compose (_("%4This is a session from an older version of %3%5\n\n"
5346 "%3 has copied the old session file\n\n%6%1%7\n\nto\n\n%6%2%7\n\n"
5347 "From now on, use the backup copy with older versions of %3"),
5348 xml_path, backup_path, PROGRAM_NAME,
5350 start_mono, end_mono), true);
5357 ARDOUR_UI::reset_peak_display ()
5359 if (!_session || !_session->master_out() || !editor_meter) return;
5360 editor_meter->clear_meters();
5361 editor_meter_max_peak = -INFINITY;
5362 editor_meter_peak_display.set_active_state ( Gtkmm2ext::Off );
5366 ARDOUR_UI::reset_group_peak_display (RouteGroup* group)
5368 if (!_session || !_session->master_out()) return;
5369 if (group == _session->master_out()->route_group()) {
5370 reset_peak_display ();
5375 ARDOUR_UI::reset_route_peak_display (Route* route)
5377 if (!_session || !_session->master_out()) return;
5378 if (_session->master_out().get() == route) {
5379 reset_peak_display ();
5384 ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate)
5386 audio_midi_setup->set_desired_sample_rate (desired_sample_rate);
5387 audio_midi_setup->set_position (WIN_POS_CENTER);
5389 if (Config->get_try_autostart_engine () || getenv ("TRY_AUTOSTART_ENGINE")) {
5390 audio_midi_setup->try_autostart ();
5391 if (ARDOUR::AudioEngine::instance()->running()) {
5397 int response = audio_midi_setup->run();
5398 printf("RESPONSE %d\n", response);
5400 case Gtk::RESPONSE_DELETE_EVENT:
5403 if (!AudioEngine::instance()->running()) {
5406 audio_midi_setup->hide ();
5414 ARDOUR_UI::transport_numpad_timeout ()
5416 _numpad_locate_happening = false;
5417 if (_numpad_timeout_connection.connected() )
5418 _numpad_timeout_connection.disconnect();
5423 ARDOUR_UI::transport_numpad_decimal ()
5425 _numpad_timeout_connection.disconnect();
5427 if (_numpad_locate_happening) {
5428 if (editor) editor->goto_nth_marker(_pending_locate_num - 1);
5429 _numpad_locate_happening = false;
5431 _pending_locate_num = 0;
5432 _numpad_locate_happening = true;
5433 _numpad_timeout_connection = Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::transport_numpad_timeout), 2*1000);
5438 ARDOUR_UI::transport_numpad_event (int num)
5440 if ( _numpad_locate_happening ) {
5441 _pending_locate_num = _pending_locate_num*10 + num;
5444 case 0: toggle_roll(false, false); break;
5445 case 1: transport_rewind(1); break;
5446 case 2: transport_forward(1); break;
5447 case 3: transport_record(true); break;
5448 case 4: toggle_session_auto_loop(); break;
5449 case 5: transport_record(false); toggle_session_auto_loop(); break;
5450 case 6: toggle_punch(); break;
5451 case 7: toggle_click(); break;
5452 case 8: toggle_auto_return(); break;
5453 case 9: toggle_follow_edits(); break;
5459 ARDOUR_UI::set_flat_buttons ()
5461 CairoWidget::set_flat_buttons( UIConfiguration::instance().get_flat_buttons() );
5465 ARDOUR_UI::audioengine_became_silent ()
5467 MessageDialog msg (string_compose (_("This is a free/demo copy of %1. It has just switched to silent mode."), PROGRAM_NAME),
5469 Gtk::MESSAGE_WARNING,
5473 msg.set_title (string_compose (_("%1 is now silent"), PROGRAM_NAME));
5475 Gtk::Label pay_label (string_compose (_("Please consider paying for a copy of %1 - you can pay whatever you want."), PROGRAM_NAME));
5476 Gtk::Label subscribe_label (_("Better yet become a subscriber - subscriptions start at US$1 per month."));
5477 Gtk::Button pay_button (_("Pay for a copy (via the web)"));
5478 Gtk::Button subscribe_button (_("Become a subscriber (via the web)"));
5479 Gtk::HBox pay_button_box;
5480 Gtk::HBox subscribe_button_box;
5482 pay_button_box.pack_start (pay_button, true, false);
5483 subscribe_button_box.pack_start (subscribe_button, true, false);
5485 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 */
5487 pay_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://ardour.org/download")));
5488 subscribe_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://community.ardour.org/s/subscribe")));
5490 msg.get_vbox()->pack_start (pay_label);
5491 msg.get_vbox()->pack_start (pay_button_box);
5492 msg.get_vbox()->pack_start (subscribe_label);
5493 msg.get_vbox()->pack_start (subscribe_button_box);
5495 msg.get_vbox()->show_all ();
5497 msg.add_button (_("Remain silent"), Gtk::RESPONSE_CANCEL);
5498 msg.add_button (_("Save and quit"), Gtk::RESPONSE_NO);
5499 msg.add_button (_("Give me more time"), Gtk::RESPONSE_YES);
5504 case Gtk::RESPONSE_YES:
5505 AudioEngine::instance()->reset_silence_countdown ();
5508 case Gtk::RESPONSE_NO:
5510 save_state_canfail ("");
5514 case Gtk::RESPONSE_CANCEL:
5516 /* don't reset, save session and exit */
5522 ARDOUR_UI::hide_application ()
5524 Application::instance ()-> hide ();
5528 ARDOUR_UI::setup_toplevel_window (Gtk::Window& window, const string& name, void* owner)
5530 /* icons, titles, WM stuff */
5532 static list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
5534 if (window_icons.empty()) {
5535 Glib::RefPtr<Gdk::Pixbuf> icon;
5536 if ((icon = ::get_icon (PROGRAM_NAME "-icon_16px"))) {
5537 window_icons.push_back (icon);
5539 if ((icon = ::get_icon (PROGRAM_NAME "-icon_22px"))) {
5540 window_icons.push_back (icon);
5542 if ((icon = ::get_icon (PROGRAM_NAME "-icon_32px"))) {
5543 window_icons.push_back (icon);
5545 if ((icon = ::get_icon (PROGRAM_NAME "-icon_48px"))) {
5546 window_icons.push_back (icon);
5550 if (!window_icons.empty()) {
5551 window.set_default_icon_list (window_icons);
5554 Gtkmm2ext::WindowTitle title (Glib::get_application_name());
5556 if (!name.empty()) {
5560 window.set_title (title.get_string());
5561 window.set_wmclass (string_compose (X_("%1_%1"), downcase (PROGRAM_NAME), downcase (name)), PROGRAM_NAME);
5563 window.set_flags (CAN_FOCUS);
5564 window.add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
5566 /* This is a hack to ensure that GTK-accelerators continue to
5567 * work. Once we switch over to entirely native bindings, this will be
5568 * unnecessary and should be removed
5570 window.add_accel_group (ActionManager::ui_manager->get_accel_group());
5572 window.signal_configure_event().connect (sigc::mem_fun (*this, &ARDOUR_UI::configure_handler));
5573 window.signal_window_state_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::tabbed_window_state_event_handler), owner));
5574 window.signal_key_press_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5575 window.signal_key_release_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5579 ARDOUR_UI::key_event_handler (GdkEventKey* ev, Gtk::Window* event_window)
5581 Gtkmm2ext::Bindings* bindings = 0;
5582 Gtk::Window* window = 0;
5584 /* until we get ardour bindings working, we are not handling key
5588 if (ev->type != GDK_KEY_PRESS) {
5592 if (event_window == &_main_window) {
5594 window = event_window;
5596 /* find current tab contents */
5598 Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page());
5600 /* see if it uses the ardour binding system */
5603 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(w->get_data ("ardour-bindings"));
5606 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("main window key event, bindings = %1, global = %2\n", bindings, &global_bindings));
5610 window = event_window;
5612 /* see if window uses ardour binding system */
5614 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(window->get_data ("ardour-bindings"));
5617 /* An empty binding set is treated as if it doesn't exist */
5619 if (bindings && bindings->empty()) {
5623 return key_press_focus_accelerator_handler (*window, ev, bindings);
5626 static Gtkmm2ext::Bindings*
5627 get_bindings_from_widget_heirarchy (GtkWidget** w)
5632 if ((p = g_object_get_data (G_OBJECT(*w), "ardour-bindings")) != 0) {
5635 *w = gtk_widget_get_parent (*w);
5638 return reinterpret_cast<Gtkmm2ext::Bindings*> (p);
5642 ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev, Gtkmm2ext::Bindings* bindings)
5644 GtkWindow* win = window.gobj();
5645 GtkWidget* focus = gtk_window_get_focus (win);
5646 GtkWidget* binding_widget = focus;
5647 bool special_handling_of_unmodified_accelerators = false;
5648 const guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK));
5652 /* some widget has keyboard focus */
5654 if (GTK_IS_ENTRY(focus) || Keyboard::some_magic_widget_has_focus()) {
5656 /* A particular kind of focusable widget currently has keyboard
5657 * focus. All unmodified key events should go to that widget
5658 * first and not be used as an accelerator by default
5661 special_handling_of_unmodified_accelerators = true;
5665 Gtkmm2ext::Bindings* focus_bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5666 if (focus_bindings) {
5667 bindings = focus_bindings;
5668 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Switch bindings based on focus widget, now using %1\n", bindings->name()));
5673 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",
5676 Gtkmm2ext::show_gdk_event_state (ev->state),
5677 special_handling_of_unmodified_accelerators,
5678 Keyboard::some_magic_widget_has_focus(),
5680 (focus ? gtk_widget_get_name (focus) : "no focus widget"),
5681 ((ev->state & mask) ? "yes" : "no"),
5682 window.get_title()));
5684 /* This exists to allow us to override the way GTK handles
5685 key events. The normal sequence is:
5687 a) event is delivered to a GtkWindow
5688 b) accelerators/mnemonics are activated
5689 c) if (b) didn't handle the event, propagate to
5690 the focus widget and/or focus chain
5692 The problem with this is that if the accelerators include
5693 keys without modifiers, such as the space bar or the
5694 letter "e", then pressing the key while typing into
5695 a text entry widget results in the accelerator being
5696 activated, instead of the desired letter appearing
5699 There is no good way of fixing this, but this
5700 represents a compromise. The idea is that
5701 key events involving modifiers (not Shift)
5702 get routed into the activation pathway first, then
5703 get propagated to the focus widget if necessary.
5705 If the key event doesn't involve modifiers,
5706 we deliver to the focus widget first, thus allowing
5707 it to get "normal text" without interference
5710 Of course, this can also be problematic: if there
5711 is a widget with focus, then it will swallow
5712 all "normal text" accelerators.
5716 if (!special_handling_of_unmodified_accelerators || (ev->state & mask)) {
5718 /* no special handling or there are modifiers in effect: accelerate first */
5720 DEBUG_TRACE (DEBUG::Accelerators, "\tactivate, then propagate\n");
5721 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tevent send-event:%1 time:%2 length:%3 name %7 string:%4 hardware_keycode:%5 group:%6\n",
5722 ev->send_event, ev->time, ev->length, ev->string, ev->hardware_keycode, ev->group, gdk_keyval_name (ev->keyval)));
5724 DEBUG_TRACE (DEBUG::Accelerators, "\tsending to window\n");
5725 KeyboardKey k (ev->state, ev->keyval);
5729 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tusing Ardour bindings %1 @ %2 for this event\n", bindings->name(), bindings));
5731 if (bindings->activate (k, Bindings::Press)) {
5732 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5736 if (binding_widget) {
5737 binding_widget = gtk_widget_get_parent (binding_widget);
5738 if (binding_widget) {
5739 bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5748 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5750 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5751 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5755 DEBUG_TRACE (DEBUG::Accelerators, "\tnot accelerated, now propagate\n");
5757 if (gtk_window_propagate_key_event (win, ev)) {
5758 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate handled\n");
5764 /* no modifiers, propagate first */
5766 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate, then activate\n");
5768 if (gtk_window_propagate_key_event (win, ev)) {
5769 DEBUG_TRACE (DEBUG::Accelerators, "\thandled by propagate\n");
5773 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagation didn't handle, so activate\n");
5774 KeyboardKey k (ev->state, ev->keyval);
5778 DEBUG_TRACE (DEBUG::Accelerators, "\tusing Ardour bindings for this window\n");
5781 if (bindings->activate (k, Bindings::Press)) {
5782 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5786 if (binding_widget) {
5787 binding_widget = gtk_widget_get_parent (binding_widget);
5788 if (binding_widget) {
5789 bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5798 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5800 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5801 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5806 DEBUG_TRACE (DEBUG::Accelerators, "\tnot handled\n");
5811 ARDOUR_UI::load_bindings ()
5813 if ((global_bindings = Bindings::get_bindings (X_("Global"), global_actions)) == 0) {
5814 error << _("Global keybindings are missing") << endmsg;
5819 ARDOUR_UI::cancel_solo ()
5822 _session->cancel_all_solo ();
5827 ARDOUR_UI::reset_focus (Gtk::Widget* w)
5829 /* this resets focus to the first focusable parent of the given widget,
5830 * or, if there is no focusable parent, cancels focus in the toplevel
5831 * window that the given widget is packed into (if there is one).
5838 Gtk::Widget* top = w->get_toplevel();
5840 if (!top || !top->is_toplevel()) {
5844 w = w->get_parent ();
5848 if (w->is_toplevel()) {
5849 /* Setting the focus widget to a Gtk::Window causes all
5850 * subsequent calls to ::has_focus() on the nominal
5851 * focus widget in that window to return
5852 * false. Workaround: never set focus to the toplevel
5858 if (w->get_can_focus ()) {
5859 Gtk::Window* win = dynamic_cast<Gtk::Window*> (top);
5860 win->set_focus (*w);
5863 w = w->get_parent ();
5866 if (top == &_main_window) {
5870 /* no focusable parent found, cancel focus in top level window.
5871 C++ API cannot be used for this. Thanks, references.
5874 gtk_window_set_focus (GTK_WINDOW(top->gobj()), 0);