2 Copyright (C) 1999-2013 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include "gtk2ardour-config.h"
22 #include "gtk2ardour-version.h"
32 #ifndef PLATFORM_WINDOWS
33 #include <sys/resource.h>
37 #include <sys/types.h>
38 #include <sys/sysctl.h>
48 #include "pbd/gstdio_compat.h"
50 #include <gtkmm/messagedialog.h>
51 #include <gtkmm/accelmap.h>
52 #include <gtkmm/stock.h>
54 #include "pbd/error.h"
55 #include "pbd/basename.h"
56 #include "pbd/compose.h"
57 #include "pbd/convert.h"
58 #include "pbd/failed_constructor.h"
59 #include "pbd/file_archive.h"
60 #include "pbd/enumwriter.h"
61 #include "pbd/memento_command.h"
62 #include "pbd/openuri.h"
63 #include "pbd/stl_delete.h"
64 #include "pbd/file_utils.h"
65 #include "pbd/localtime_r.h"
66 #include "pbd/pthread_utils.h"
67 #include "pbd/replace_all.h"
68 #include "pbd/xml++.h"
70 #include "gtkmm2ext/application.h"
71 #include "gtkmm2ext/bindings.h"
72 #include "gtkmm2ext/gtk_ui.h"
73 #include "gtkmm2ext/utils.h"
74 #include "gtkmm2ext/click_box.h"
75 #include "gtkmm2ext/fastmeter.h"
76 #include "gtkmm2ext/popup.h"
77 #include "gtkmm2ext/window_title.h"
79 #include "ardour/ardour.h"
80 #include "ardour/audio_backend.h"
81 #include "ardour/audio_track.h"
82 #include "ardour/audioengine.h"
83 #include "ardour/audiofilesource.h"
84 #include "ardour/automation_watch.h"
85 #include "ardour/diskstream.h"
86 #include "ardour/filename_extensions.h"
87 #include "ardour/filesystem_paths.h"
88 #include "ardour/ltc_file_reader.h"
89 #include "ardour/midi_track.h"
90 #include "ardour/port.h"
91 #include "ardour/plugin_manager.h"
92 #include "ardour/process_thread.h"
93 #include "ardour/profile.h"
94 #include "ardour/recent_sessions.h"
95 #include "ardour/record_enable_control.h"
96 #include "ardour/session_directory.h"
97 #include "ardour/session_route.h"
98 #include "ardour/session_state_utils.h"
99 #include "ardour/session_utils.h"
100 #include "ardour/source_factory.h"
101 #include "ardour/slave.h"
102 #include "ardour/system_exec.h"
103 #include "ardour/track.h"
104 #include "ardour/vca_manager.h"
105 #include "ardour/utils.h"
107 #include "LuaBridge/LuaBridge.h"
109 #ifdef WINDOWS_VST_SUPPORT
112 #ifdef AUDIOUNIT_SUPPORT
113 #include "ardour/audio_unit.h"
116 // fix for OSX (nsm.h has a check function, AU/Apple defines check)
121 #include "timecode/time.h"
123 typedef uint64_t microseconds_t;
128 #include "add_route_dialog.h"
129 #include "ambiguous_file_dialog.h"
130 #include "ardour_ui.h"
131 #include "audio_clock.h"
132 #include "audio_region_view.h"
133 #include "big_clock_window.h"
134 #include "bundle_manager.h"
135 #include "duplicate_routes_dialog.h"
137 #include "engine_dialog.h"
138 #include "export_video_dialog.h"
139 #include "export_video_infobox.h"
140 #include "gain_meter.h"
141 #include "global_port_matrix.h"
142 #include "gui_object.h"
143 #include "gui_thread.h"
144 #include "keyboard.h"
145 #include "keyeditor.h"
146 #include "location_ui.h"
147 #include "lua_script_manager.h"
148 #include "luawindow.h"
149 #include "main_clock.h"
150 #include "missing_file_dialog.h"
151 #include "missing_plugin_dialog.h"
152 #include "mixer_ui.h"
153 #include "meterbridge.h"
154 #include "mouse_cursors.h"
157 #include "pingback.h"
158 #include "processor_box.h"
159 #include "prompter.h"
160 #include "public_editor.h"
161 #include "rc_option_editor.h"
162 #include "route_time_axis.h"
163 #include "route_params_ui.h"
164 #include "save_as_dialog.h"
165 #include "script_selector.h"
166 #include "session_archive_dialog.h"
167 #include "session_dialog.h"
168 #include "session_metadata_dialog.h"
169 #include "session_option_editor.h"
170 #include "shuttle_control.h"
171 #include "speaker_dialog.h"
174 #include "theme_manager.h"
175 #include "time_axis_view_item.h"
178 #include "video_server_dialog.h"
179 #include "add_video_dialog.h"
180 #include "transcode_video_dialog.h"
182 #include "pbd/i18n.h"
184 using namespace ARDOUR;
185 using namespace ARDOUR_UI_UTILS;
187 using namespace Gtkmm2ext;
190 using namespace Editing;
192 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
194 sigc::signal<void, framepos_t, bool, framepos_t> ARDOUR_UI::Clock;
195 sigc::signal<void> ARDOUR_UI::CloseAllDialogs;
198 ask_about_configuration_copy (string const & old_dir, string const & new_dir, int version)
200 MessageDialog msg (string_compose (_("%1 %2.x has discovered configuration files from %1 %3.x.\n\n"
201 "Would you like these files to be copied and used for %1 %2.x?\n\n"
202 "(This will require you to restart %1.)"),
203 PROGRAM_NAME, PROGRAM_VERSION, version),
204 false, /* no markup */
207 true /* modal, though it hardly matters since it is the only window */
210 msg.set_default_response (Gtk::RESPONSE_YES);
213 return (msg.run() == Gtk::RESPONSE_YES);
217 libxml_generic_error_func (void* /* parsing_context*/,
225 vsnprintf (buf, sizeof (buf), msg, ap);
226 error << buf << endmsg;
231 libxml_structured_error_func (void* /* parsing_context*/,
239 replace_all (msg, "\n", "");
242 if (err->file && err->line) {
243 error << X_("XML error: ") << msg << " in " << err->file << " at line " << err->line;
246 error << ':' << err->int2;
251 error << X_("XML error: ") << msg << endmsg;
257 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
258 : Gtkmm2ext::UI (PROGRAM_NAME, X_("gui"), argcp, argvp)
259 , session_loaded (false)
260 , gui_object_state (new GUIObjectState)
261 , primary_clock (new MainClock (X_("primary"), X_("transport"), true ))
262 , secondary_clock (new MainClock (X_("secondary"), X_("secondary"), false))
263 , big_clock (new AudioClock (X_("bigclock"), false, "big", true, true, false, false))
265 , global_actions (X_("global"))
266 , ignore_dual_punch (false)
267 , main_window_visibility (0)
272 , _mixer_on_top (false)
273 , _initial_verbose_plugin_scan (false)
274 , first_time_engine_run (true)
275 , roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll))
276 , stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop))
277 , goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart))
278 , goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd))
279 , auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop))
280 , play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection))
281 , rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable))
282 , auto_return_button (ArdourButton::led_default_elements)
283 , follow_edits_button (ArdourButton::led_default_elements)
284 , auto_input_button (ArdourButton::led_default_elements)
285 , auditioning_alert_button (_("Audition"))
286 , solo_alert_button (_("Solo"))
287 , feedback_alert_button (_("Feedback"))
288 , error_alert_button ( ArdourButton::just_led_default_elements )
290 , editor_meter_peak_display()
291 , _numpad_locate_happening (false)
292 , _session_is_new (false)
293 , last_key_press_time (0)
297 , rc_option_editor (0)
298 , speaker_config_window (X_("speaker-config"), _("Speaker Configuration"))
299 , add_route_dialog (X_("add-routes"), _("Add Tracks/Busses"))
300 , about (X_("about"), _("About"))
301 , location_ui (X_("locations"), S_("Ranges|Locations"))
302 , route_params (X_("inspector"), _("Tracks and Busses"))
303 , audio_midi_setup (X_("audio-midi-setup"), _("Audio/MIDI Setup"))
304 , export_video_dialog (X_("video-export"), _("Video Export Dialog"))
305 , lua_script_window (X_("script-manager"), _("Script Manager"))
306 , session_option_editor (X_("session-options-editor"), _("Properties"), boost::bind (&ARDOUR_UI::create_session_option_editor, this))
307 , add_video_dialog (X_("add-video"), _("Add Video"), boost::bind (&ARDOUR_UI::create_add_video_dialog, this))
308 , bundle_manager (X_("bundle-manager"), _("Bundle Manager"), boost::bind (&ARDOUR_UI::create_bundle_manager, this))
309 , big_clock_window (X_("big-clock"), _("Big Clock"), boost::bind (&ARDOUR_UI::create_big_clock_window, this))
310 , audio_port_matrix (X_("audio-connection-manager"), _("Audio Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::AUDIO))
311 , midi_port_matrix (X_("midi-connection-manager"), _("MIDI Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::MIDI))
312 , key_editor (X_("key-editor"), _("Bindings Editor"), boost::bind (&ARDOUR_UI::create_key_editor, this))
313 , video_server_process (0)
315 , have_configure_timeout (false)
316 , last_configure_time (0)
318 , have_disk_speed_dialog_displayed (false)
319 , _status_bar_visibility (X_("status-bar"))
320 , _feedback_exists (false)
321 , _log_not_acknowledged (LogLevelNone)
322 , duplicate_routes_dialog (0)
323 , editor_visibility_button (S_("Window|Editor"))
324 , mixer_visibility_button (S_("Window|Mixer"))
325 , prefs_visibility_button (S_("Window|Preferences"))
327 Gtkmm2ext::init (localedir);
329 UIConfiguration::instance().post_gui_init ();
331 if (ARDOUR::handle_old_configuration_files (boost::bind (ask_about_configuration_copy, _1, _2, _3))) {
332 MessageDialog msg (string_compose (_("Your configuration files were copied. You can now restart %1."), PROGRAM_NAME), true);
334 /* configuration was modified, exit immediately */
339 if (string (VERSIONSTRING).find (".pre") != string::npos) {
340 /* check this is not being run from ./ardev etc. */
341 if (!running_from_source_tree ()) {
342 pre_release_dialog ();
346 if (theArdourUI == 0) {
350 /* track main window visibility */
352 main_window_visibility = new VisibilityTracker (_main_window);
354 /* stop libxml from spewing to stdout/stderr */
356 xmlSetGenericErrorFunc (this, libxml_generic_error_func);
357 xmlSetStructuredErrorFunc (this, libxml_structured_error_func);
359 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::parameter_changed));
360 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
361 UIConfiguration::instance().map_parameters (pc);
363 roll_button.set_controllable (roll_controllable);
364 stop_button.set_controllable (stop_controllable);
365 goto_start_button.set_controllable (goto_start_controllable);
366 goto_end_button.set_controllable (goto_end_controllable);
367 auto_loop_button.set_controllable (auto_loop_controllable);
368 play_selection_button.set_controllable (play_selection_controllable);
369 rec_button.set_controllable (rec_controllable);
371 roll_button.set_name ("transport button");
372 stop_button.set_name ("transport button");
373 goto_start_button.set_name ("transport button");
374 goto_end_button.set_name ("transport button");
375 auto_loop_button.set_name ("transport button");
376 play_selection_button.set_name ("transport button");
377 rec_button.set_name ("transport recenable button");
378 midi_panic_button.set_name ("transport button");
380 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
381 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
383 ARDOUR::Session::VersionMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_format_mismatch, this, _1, _2), gui_context());
385 /* handle dialog requests */
387 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
389 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
391 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
393 /* handle Audio/MIDI setup when session requires it */
395 ARDOUR::Session::AudioEngineSetupRequired.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::do_audio_midi_setup, this, _1));
397 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
399 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
401 /* handle sr mismatch with a dialog - cross-thread from engine */
402 ARDOUR::Session::NotifyAboutSampleRateMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::sr_mismatch_message, this, _1, _2), gui_context ());
404 /* handle requests to quit (coming from JACK session) */
406 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::finish, this), gui_context ());
408 /* tell the user about feedback */
410 ARDOUR::Session::FeedbackDetected.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::feedback_detected, this), gui_context ());
411 ARDOUR::Session::SuccessfulGraphSort.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::successful_graph_sort, this), gui_context ());
413 /* handle requests to deal with missing files */
415 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
417 /* and ambiguous files */
419 ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2));
421 /* also plugin scan messages */
422 ARDOUR::PluginScanMessage.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_dialog, this, _1, _2, _3), gui_context());
423 ARDOUR::PluginScanTimeout.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_timeout, this, _1), gui_context());
425 ARDOUR::GUIIdle.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::gui_idle_handler, this), gui_context());
427 Config->ParameterChanged.connect ( forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::set_flat_buttons, this), gui_context() );
430 /* lets get this party started */
432 setup_gtk_ardour_enums ();
435 SessionEvent::create_per_thread_pool ("GUI", 4096);
437 /* we like keyboards */
439 keyboard = new ArdourKeyboard(*this);
441 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
443 keyboard->set_state (*node, Stateful::loading_state_version);
446 UIConfiguration::instance().reset_dpi ();
448 TimeAxisViewItem::set_constant_heights ();
450 /* Set this up so that our window proxies can register actions */
452 ActionManager::init ();
454 /* The following must happen after ARDOUR::init() so that Config is set up */
456 const XMLNode* ui_xml = Config->extra_xml (X_("UI"));
459 key_editor.set_state (*ui_xml, 0);
460 session_option_editor.set_state (*ui_xml, 0);
461 speaker_config_window.set_state (*ui_xml, 0);
462 about.set_state (*ui_xml, 0);
463 add_route_dialog.set_state (*ui_xml, 0);
464 add_video_dialog.set_state (*ui_xml, 0);
465 route_params.set_state (*ui_xml, 0);
466 bundle_manager.set_state (*ui_xml, 0);
467 location_ui.set_state (*ui_xml, 0);
468 big_clock_window.set_state (*ui_xml, 0);
469 audio_port_matrix.set_state (*ui_xml, 0);
470 midi_port_matrix.set_state (*ui_xml, 0);
471 export_video_dialog.set_state (*ui_xml, 0);
472 lua_script_window.set_state (*ui_xml, 0);
475 /* Separate windows */
477 WM::Manager::instance().register_window (&key_editor);
478 WM::Manager::instance().register_window (&session_option_editor);
479 WM::Manager::instance().register_window (&speaker_config_window);
480 WM::Manager::instance().register_window (&about);
481 WM::Manager::instance().register_window (&add_route_dialog);
482 WM::Manager::instance().register_window (&add_video_dialog);
483 WM::Manager::instance().register_window (&route_params);
484 WM::Manager::instance().register_window (&audio_midi_setup);
485 WM::Manager::instance().register_window (&export_video_dialog);
486 WM::Manager::instance().register_window (&lua_script_window);
487 WM::Manager::instance().register_window (&bundle_manager);
488 WM::Manager::instance().register_window (&location_ui);
489 WM::Manager::instance().register_window (&big_clock_window);
490 WM::Manager::instance().register_window (&audio_port_matrix);
491 WM::Manager::instance().register_window (&midi_port_matrix);
493 /* do not retain position for add route dialog */
494 add_route_dialog.set_state_mask (WindowProxy::Size);
496 /* Trigger setting up the color scheme and loading the GTK RC file */
498 UIConfiguration::instance().load_rc_file (false);
500 _process_thread = new ProcessThread ();
501 _process_thread->init ();
503 UIConfiguration::instance().DPIReset.connect (sigc::mem_fun (*this, &ARDOUR_UI::resize_text_widgets));
509 ARDOUR_UI::pre_release_dialog ()
511 ArdourDialog d (_("Pre-Release Warning"), true, false);
512 d.add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
514 Label* label = manage (new Label);
515 label->set_markup (string_compose (_("<b>Welcome to this pre-release build of %1 %2</b>\n\n\
516 There are still several issues and bugs to be worked on,\n\
517 as well as general workflow improvements, before this can be considered\n\
518 release software. So, a few guidelines:\n\
520 1) Please do <b>NOT</b> use this software with the expectation that it is stable or reliable\n\
521 though it may be so, depending on your workflow.\n\
522 2) Please wait for a helpful writeup of new features.\n\
523 3) <b>Please do NOT use the forums at ardour.org to report issues</b>.\n\
524 4) Please <b>DO</b> use the bugtracker at http://tracker.ardour.org/ to report issues\n\
525 making sure to note the product version number as 5.0-pre.\n\
526 5) Please <b>DO</b> use the ardour-users mailing list to discuss ideas and pass on comments.\n\
527 6) Please <b>DO</b> join us on IRC for real time discussions about %1 %2. You\n\
528 can get there directly from within the program via the Help->Chat menu option.\n\
530 Full information on all the above can be found on the support page at\n\
532 http://ardour.org/support\n\
533 "), PROGRAM_NAME, VERSIONSTRING));
535 d.get_vbox()->set_border_width (12);
536 d.get_vbox()->pack_start (*label, false, false, 12);
537 d.get_vbox()->show_all ();
542 GlobalPortMatrixWindow*
543 ARDOUR_UI::create_global_port_matrix (ARDOUR::DataType type)
548 return new GlobalPortMatrixWindow (_session, type);
552 ARDOUR_UI::attach_to_engine ()
554 AudioEngine::instance()->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
555 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
559 ARDOUR_UI::engine_stopped ()
561 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
562 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
563 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
564 update_sample_rate (0);
569 ARDOUR_UI::engine_running ()
571 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
572 if (first_time_engine_run) {
574 first_time_engine_run = false;
578 _session->reset_xrun_count ();
580 update_disk_space ();
582 update_xrun_count ();
583 update_sample_rate (AudioEngine::instance()->sample_rate());
584 update_timecode_format ();
585 update_peak_thread_work ();
586 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, true);
587 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, false);
591 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
593 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
594 /* we can't rely on the original string continuing to exist when we are called
595 again in the GUI thread, so make a copy and note that we need to
598 char *copy = strdup (reason);
599 Gtkmm2ext::UI::instance()->call_slot (MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
603 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
604 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
606 update_sample_rate (0);
610 /* if the reason is a non-empty string, it means that the backend was shutdown
611 rather than just Ardour.
614 if (strlen (reason)) {
615 msgstr = string_compose (_("The audio backend was shutdown because:\n\n%1"), reason);
617 msgstr = string_compose (_("\
618 The audio backend has either been shutdown or it\n\
619 disconnected %1 because %1\n\
620 was not fast enough. Try to restart\n\
621 the audio backend and save the session."), PROGRAM_NAME);
624 MessageDialog msg (_main_window, msgstr);
625 pop_back_splash (msg);
629 free (const_cast<char*> (reason));
634 ARDOUR_UI::post_engine ()
636 /* Things to be done once (and once ONLY) after we have a backend running in the AudioEngine
638 #ifdef AUDIOUNIT_SUPPORT
640 if (AUPluginInfo::au_get_crashlog(au_msg)) {
641 popup_error(_("Audio Unit Plugin Scan Failed. Automatic AU scanning has been disabled. Please see the log window for further details."));
642 error << _("Audio Unit Plugin Scan Failed:") << endmsg;
643 info << au_msg << endmsg;
647 ARDOUR::init_post_engine ();
649 /* connect to important signals */
651 AudioEngine::instance()->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
652 AudioEngine::instance()->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
653 AudioEngine::instance()->BufferSizeChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
654 AudioEngine::instance()->Halted.connect_same_thread (halt_connection, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
655 AudioEngine::instance()->BecameSilent.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::audioengine_became_silent, this), gui_context());
657 if (setup_windows ()) {
658 throw failed_constructor ();
661 /* Do this after setup_windows (), as that's when the _status_bar_visibility is created */
662 XMLNode* n = Config->extra_xml (X_("UI"));
664 _status_bar_visibility.set_state (*n);
667 check_memory_locking();
669 /* this is the first point at which all the possible actions are
670 * available, because some of the available actions are dependent on
671 * aspects of the engine/backend.
674 if (ARDOUR_COMMAND_LINE::show_key_actions) {
677 vector<string> paths;
678 vector<string> labels;
679 vector<string> tooltips;
681 vector<Glib::RefPtr<Gtk::Action> > actions;
683 Gtkmm2ext::ActionMap::get_all_actions (paths, labels, tooltips, keys, actions);
685 vector<string>::iterator k;
686 vector<string>::iterator p;
688 for (p = paths.begin(), k = keys.begin(); p != paths.end(); ++k, ++p) {
693 cout << *p << " => " << *k << endl;
697 halt_connection.disconnect ();
698 AudioEngine::instance()->stop ();
702 /* this being a GUI and all, we want peakfiles */
704 AudioFileSource::set_build_peakfiles (true);
705 AudioFileSource::set_build_missing_peakfiles (true);
707 /* set default clock modes */
709 primary_clock->set_mode (AudioClock::Timecode);
710 secondary_clock->set_mode (AudioClock::BBT);
712 /* start the time-of-day-clock */
715 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
716 update_wall_clock ();
717 Glib::signal_timeout().connect_seconds (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 1);
722 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
723 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
724 Config->map_parameters (pc);
726 UIConfiguration::instance().map_parameters (pc);
730 ARDOUR_UI::~ARDOUR_UI ()
732 UIConfiguration::instance().save_state();
736 if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
737 // don't bother at 'real' exit. the OS cleans up for us.
738 delete big_clock; big_clock = 0;
739 delete primary_clock; primary_clock = 0;
740 delete secondary_clock; secondary_clock = 0;
741 delete _process_thread; _process_thread = 0;
742 delete meterbridge; meterbridge = 0;
743 delete luawindow; luawindow = 0;
744 delete editor; editor = 0;
745 delete mixer; mixer = 0;
747 delete gui_object_state; gui_object_state = 0;
748 delete main_window_visibility;
749 FastMeter::flush_pattern_cache ();
750 PixFader::flush_pattern_cache ();
754 /* Small trick to flush main-thread event pool.
755 * Other thread-pools are destroyed at pthread_exit(),
756 * but tmain thread termination is too late to trigger Pool::~Pool()
758 SessionEvent* ev = new SessionEvent (SessionEvent::SetTransportSpeed, SessionEvent::Clear, SessionEvent::Immediate, 0, 0); // get the pool reference, values don't matter since the event is never queued.
759 delete ev->event_pool();
764 ARDOUR_UI::pop_back_splash (Gtk::Window& win)
766 if (Splash::instance()) {
767 Splash::instance()->pop_back_for (win);
772 ARDOUR_UI::configure_timeout ()
774 if (last_configure_time == 0) {
775 /* no configure events yet */
779 /* force a gap of 0.5 seconds since the last configure event
782 if (get_microseconds() - last_configure_time < 500000) {
785 have_configure_timeout = false;
786 save_ardour_state ();
792 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
794 if (have_configure_timeout) {
795 last_configure_time = get_microseconds();
797 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
798 have_configure_timeout = true;
805 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
807 XMLProperty const * prop;
809 if ((prop = node.property ("roll")) != 0) {
810 roll_controllable->set_id (prop->value());
812 if ((prop = node.property ("stop")) != 0) {
813 stop_controllable->set_id (prop->value());
815 if ((prop = node.property ("goto-start")) != 0) {
816 goto_start_controllable->set_id (prop->value());
818 if ((prop = node.property ("goto-end")) != 0) {
819 goto_end_controllable->set_id (prop->value());
821 if ((prop = node.property ("auto-loop")) != 0) {
822 auto_loop_controllable->set_id (prop->value());
824 if ((prop = node.property ("play-selection")) != 0) {
825 play_selection_controllable->set_id (prop->value());
827 if ((prop = node.property ("rec")) != 0) {
828 rec_controllable->set_id (prop->value());
830 if ((prop = node.property ("shuttle")) != 0) {
831 shuttle_box->controllable()->set_id (prop->value());
836 ARDOUR_UI::get_transport_controllable_state ()
838 XMLNode* node = new XMLNode(X_("TransportControllables"));
841 roll_controllable->id().print (buf, sizeof (buf));
842 node->add_property (X_("roll"), buf);
843 stop_controllable->id().print (buf, sizeof (buf));
844 node->add_property (X_("stop"), buf);
845 goto_start_controllable->id().print (buf, sizeof (buf));
846 node->add_property (X_("goto_start"), buf);
847 goto_end_controllable->id().print (buf, sizeof (buf));
848 node->add_property (X_("goto_end"), buf);
849 auto_loop_controllable->id().print (buf, sizeof (buf));
850 node->add_property (X_("auto_loop"), buf);
851 play_selection_controllable->id().print (buf, sizeof (buf));
852 node->add_property (X_("play_selection"), buf);
853 rec_controllable->id().print (buf, sizeof (buf));
854 node->add_property (X_("rec"), buf);
855 shuttle_box->controllable()->id().print (buf, sizeof (buf));
856 node->add_property (X_("shuttle"), buf);
862 ARDOUR_UI::save_session_at_its_request (std::string snapshot_name)
865 _session->save_state (snapshot_name);
870 ARDOUR_UI::autosave_session ()
872 if (g_main_depth() > 1) {
873 /* inside a recursive main loop,
874 give up because we may not be able to
880 if (!Config->get_periodic_safety_backups()) {
885 _session->maybe_write_autosave();
892 ARDOUR_UI::session_dirty_changed ()
899 ARDOUR_UI::update_autosave ()
901 if (_session && _session->dirty()) {
902 if (_autosave_connection.connected()) {
903 _autosave_connection.disconnect();
906 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
907 Config->get_periodic_safety_backup_interval() * 1000);
910 if (_autosave_connection.connected()) {
911 _autosave_connection.disconnect();
917 ARDOUR_UI::check_announcements ()
920 string _annc_filename;
923 _annc_filename = PROGRAM_NAME "_announcements_osx_";
924 #elif defined PLATFORM_WINDOWS
925 _annc_filename = PROGRAM_NAME "_announcements_windows_";
927 _annc_filename = PROGRAM_NAME "_announcements_linux_";
929 _annc_filename.append (VERSIONSTRING);
931 _announce_string = "";
933 std::string path = Glib::build_filename (user_config_directory(), _annc_filename);
934 FILE* fin = g_fopen (path.c_str(), "rb");
936 while (!feof (fin)) {
939 if ((len = fread (tmp, sizeof(char), 1024, fin)) == 0 || ferror (fin)) {
942 _announce_string.append (tmp, len);
947 pingback (VERSIONSTRING, path);
952 _hide_splash (gpointer arg)
954 ((ARDOUR_UI*)arg)->hide_splash();
959 ARDOUR_UI::starting ()
961 Application* app = Application::instance ();
963 bool brand_new_user = ArdourStartup::required ();
965 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
966 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::load_from_application_api));
968 if (ARDOUR_COMMAND_LINE::check_announcements) {
969 check_announcements ();
974 /* we need to create this early because it may need to set the
975 * audio backend end up.
979 audio_midi_setup.get (true);
981 std::cerr << "audio-midi engine setup failed."<< std::endl;
985 if ((nsm_url = g_getenv ("NSM_URL")) != 0) {
986 nsm = new NSM_Client;
987 if (!nsm->init (nsm_url)) {
988 /* the ardour executable may have different names:
990 * waf's obj.target for distro versions: eg ardour4, ardourvst4
991 * Ardour4, Mixbus3 for bundled versions + full path on OSX & windows
992 * argv[0] does not apply since we need the wrapper-script (not the binary itself)
994 * The wrapper startup script should set the environment variable 'ARDOUR_SELF'
996 const char *process_name = g_getenv ("ARDOUR_SELF");
997 nsm->announce (PROGRAM_NAME, ":dirty:", process_name ? process_name : "ardour4");
1000 // wait for announce reply from nsm server
1001 for ( i = 0; i < 5000; ++i) {
1005 if (nsm->is_active()) {
1010 error << _("NSM server did not announce itself") << endmsg;
1013 // wait for open command from nsm server
1014 for ( i = 0; i < 5000; ++i) {
1016 Glib::usleep (1000);
1017 if (nsm->client_id ()) {
1023 error << _("NSM: no client ID provided") << endmsg;
1027 if (_session && nsm) {
1028 _session->set_nsm_state( nsm->is_active() );
1030 error << _("NSM: no session created") << endmsg;
1034 // nsm requires these actions disabled
1035 vector<string> action_names;
1036 action_names.push_back("SaveAs");
1037 action_names.push_back("Rename");
1038 action_names.push_back("New");
1039 action_names.push_back("Open");
1040 action_names.push_back("Recent");
1041 action_names.push_back("Close");
1043 for (vector<string>::const_iterator n = action_names.begin(); n != action_names.end(); ++n) {
1044 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), (*n).c_str());
1046 act->set_sensitive (false);
1053 error << _("NSM: initialization failed") << endmsg;
1059 if (brand_new_user) {
1060 _initial_verbose_plugin_scan = true;
1065 _initial_verbose_plugin_scan = false;
1066 switch (s.response ()) {
1067 case Gtk::RESPONSE_OK:
1074 // TODO: maybe IFF brand_new_user
1075 if (ARDOUR::Profile->get_mixbus () && Config->get_copy_demo_sessions ()) {
1076 std::string dspd (Config->get_default_session_parent_dir());
1077 Searchpath ds (ARDOUR::ardour_data_search_path());
1078 ds.add_subdirectory_to_paths ("sessions");
1079 vector<string> demos;
1080 find_files_matching_pattern (demos, ds, "*.tar.xz");
1082 ARDOUR::RecentSessions rs;
1083 ARDOUR::read_recent_sessions (rs);
1085 for (vector<string>::iterator i = demos.begin(); i != demos.end (); ++i) {
1086 /* "demo-session" must be inside "demo-session.tar.xz"
1089 std::string name = basename_nosuffix (basename_nosuffix (*i));
1090 std::string path = Glib::build_filename (dspd, name);
1091 /* skip if session-dir already exists */
1092 if (Glib::file_test(path.c_str(), Glib::FILE_TEST_IS_DIR)) {
1095 /* skip sessions that are already in 'recent'.
1096 * eg. a new user changed <session-default-dir> shorly after installation
1098 for (ARDOUR::RecentSessions::iterator r = rs.begin(); r != rs.end(); ++r) {
1099 if ((*r).first == name) {
1104 PBD::FileArchive ar (*i);
1105 if (0 == ar.inflate (dspd)) {
1106 store_recent_sessions (name, path);
1107 info << string_compose (_("Copied Demo Session %1."), name) << endmsg;
1113 #ifdef NO_PLUGIN_STATE
1115 ARDOUR::RecentSessions rs;
1116 ARDOUR::read_recent_sessions (rs);
1118 string path = Glib::build_filename (user_config_directory(), ".iknowaboutfreeversion");
1120 if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS) && !rs.empty()) {
1122 /* already used Ardour, have sessions ... warn about plugin state */
1124 ArdourDialog d (_("Free/Demo Version Warning"), true);
1126 Button b (string_compose (_("Subscribe and support development of %1"), PROGRAM_NAME));
1127 CheckButton c (_("Don't warn me about this again"));
1129 l.set_markup (string_compose (_("<span weight=\"bold\" size=\"large\">%1</span>\n\n<b>%2</b>\n\n<i>%3</i>\n\n%4"),
1130 string_compose (_("This is a free/demo version of %1"), PROGRAM_NAME),
1131 _("It will not restore OR save any plugin settings"),
1132 _("If you load an existing session with plugin settings\n"
1133 "they will not be used and will be lost."),
1134 _("To get full access to updates without this limitation\n"
1135 "consider becoming a subscriber for a low cost every month.")));
1136 l.set_justify (JUSTIFY_CENTER);
1138 b.signal_clicked().connect (mem_fun(*this, &ARDOUR_UI::launch_subscribe));
1140 d.get_vbox()->pack_start (l, true, true);
1141 d.get_vbox()->pack_start (b, false, false, 12);
1142 d.get_vbox()->pack_start (c, false, false, 12);
1144 d.add_button (_("Quit now"), RESPONSE_CANCEL);
1145 d.add_button (string_compose (_("Continue using %1"), PROGRAM_NAME), RESPONSE_OK);
1149 c.signal_toggled().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (toggle_file_existence), path)));
1151 if (d.run () != RESPONSE_OK) {
1157 /* go get a session */
1159 const bool new_session_required = (ARDOUR_COMMAND_LINE::new_session || brand_new_user);
1161 if (get_session_parameters (false, new_session_required, ARDOUR_COMMAND_LINE::load_template)) {
1162 std::cerr << "Cannot get session parameters."<< std::endl;
1169 WM::Manager::instance().show_visible ();
1171 /* We have to do this here since goto_editor_window() ends up calling show_all() on the
1172 * editor window, and we may want stuff to be hidden.
1174 _status_bar_visibility.update ();
1176 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
1178 if (splash && splash->is_visible()) {
1179 // in 1 second, hide the splash screen
1180 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
1183 /* all other dialogs are created conditionally */
1189 ARDOUR_UI::check_memory_locking ()
1191 #if defined(__APPLE__) || defined(PLATFORM_WINDOWS)
1192 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
1196 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
1198 if (AudioEngine::instance()->is_realtime() && memory_warning_node == 0) {
1200 struct rlimit limits;
1202 long pages, page_size;
1204 size_t pages_len=sizeof(pages);
1205 if ((page_size = getpagesize()) < 0 ||
1206 sysctlbyname("hw.availpages", &pages, &pages_len, NULL, 0))
1208 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0)
1213 ram = (int64_t) pages * (int64_t) page_size;
1216 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
1220 if (limits.rlim_cur != RLIM_INFINITY) {
1222 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
1226 _("WARNING: Your system has a limit for maximum amount of locked memory. "
1227 "This might cause %1 to run out of memory before your system "
1228 "runs out of memory. \n\n"
1229 "You can view the memory limit with 'ulimit -l', "
1230 "and it is normally controlled by %2"),
1233 X_("/etc/login.conf")
1235 X_(" /etc/security/limits.conf")
1239 msg.set_default_response (RESPONSE_OK);
1241 VBox* vbox = msg.get_vbox();
1243 CheckButton cb (_("Do not show this window again"));
1244 hbox.pack_start (cb, true, false);
1245 vbox->pack_start (hbox);
1250 pop_back_splash (msg);
1254 if (cb.get_active()) {
1255 XMLNode node (X_("no-memory-warning"));
1256 Config->add_instant_xml (node);
1261 #endif // !__APPLE__
1266 ARDOUR_UI::queue_finish ()
1268 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
1272 ARDOUR_UI::idle_finish ()
1275 return false; /* do not call again */
1282 ARDOUR_UI::instance()->video_timeline->sync_session_state();
1284 if (_session->dirty()) {
1285 vector<string> actions;
1286 actions.push_back (_("Don't quit"));
1287 actions.push_back (_("Just quit"));
1288 actions.push_back (_("Save and quit"));
1289 switch (ask_about_saving_session(actions)) {
1294 /* use the default name */
1295 if (save_state_canfail ("")) {
1296 /* failed - don't quit */
1297 MessageDialog msg (_main_window,
1298 string_compose (_("\
1299 %1 was unable to save your session.\n\n\
1300 If you still wish to quit, please use the\n\n\
1301 \"Just quit\" option."), PROGRAM_NAME));
1302 pop_back_splash(msg);
1312 second_connection.disconnect ();
1313 point_one_second_connection.disconnect ();
1314 point_zero_something_second_connection.disconnect();
1315 fps_connection.disconnect();
1318 delete ARDOUR_UI::instance()->video_timeline;
1319 ARDOUR_UI::instance()->video_timeline = NULL;
1320 stop_video_server();
1322 /* Save state before deleting the session, as that causes some
1323 windows to be destroyed before their visible state can be
1326 save_ardour_state ();
1328 if (key_editor.get (false)) {
1329 key_editor->disconnect ();
1332 close_all_dialogs ();
1335 _session->set_clean ();
1336 _session->remove_pending_capture_state ();
1341 halt_connection.disconnect ();
1342 AudioEngine::instance()->stop ();
1343 #ifdef WINDOWS_VST_SUPPORT
1344 fst_stop_threading();
1350 ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
1352 ArdourDialog window (_("Unsaved Session"));
1353 Gtk::HBox dhbox; // the hbox for the image and text
1354 Gtk::Label prompt_label;
1355 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
1359 assert (actions.size() >= 3);
1361 window.add_button (actions[0], RESPONSE_REJECT);
1362 window.add_button (actions[1], RESPONSE_APPLY);
1363 window.add_button (actions[2], RESPONSE_ACCEPT);
1365 window.set_default_response (RESPONSE_ACCEPT);
1367 Gtk::Button noquit_button (msg);
1368 noquit_button.set_name ("EditorGTKButton");
1372 if (_session->snap_name() == _session->name()) {
1373 prompt = string_compose(_("The session \"%1\"\nhas not been saved.\n\nAny changes made this time\nwill be lost unless you save it.\n\nWhat do you want to do?"),
1374 _session->snap_name());
1376 prompt = string_compose(_("The snapshot \"%1\"\nhas not been saved.\n\nAny changes made this time\nwill be lost unless you save it.\n\nWhat do you want to do?"),
1377 _session->snap_name());
1380 prompt_label.set_text (prompt);
1381 prompt_label.set_name (X_("PrompterLabel"));
1382 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
1384 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
1385 dhbox.set_homogeneous (false);
1386 dhbox.pack_start (*dimage, false, false, 5);
1387 dhbox.pack_start (prompt_label, true, false, 5);
1388 window.get_vbox()->pack_start (dhbox);
1390 window.set_name (_("Prompter"));
1391 window.set_modal (true);
1392 window.set_resizable (false);
1395 prompt_label.show();
1400 ResponseType r = (ResponseType) window.run();
1405 case RESPONSE_ACCEPT: // save and get out of here
1407 case RESPONSE_APPLY: // get out of here
1418 ARDOUR_UI::every_second ()
1421 update_xrun_count ();
1422 update_buffer_load ();
1423 update_disk_space ();
1424 update_timecode_format ();
1425 update_peak_thread_work ();
1427 if (nsm && nsm->is_active ()) {
1430 if (!_was_dirty && _session->dirty ()) {
1434 else if (_was_dirty && !_session->dirty ()){
1442 ARDOUR_UI::every_point_one_seconds ()
1444 // TODO get rid of this..
1445 // ShuttleControl is updated directly via TransportStateChange signal
1449 ARDOUR_UI::every_point_zero_something_seconds ()
1451 // august 2007: actual update frequency: 25Hz (40ms), not 100Hz
1453 if (editor_meter && UIConfiguration::instance().get_show_editor_meter()) {
1454 float mpeak = editor_meter->update_meters();
1455 if (mpeak > editor_meter_max_peak) {
1456 if (mpeak >= UIConfiguration::instance().get_meter_peak()) {
1457 editor_meter_peak_display.set_active_state ( Gtkmm2ext::ExplicitActive );
1464 ARDOUR_UI::set_fps_timeout_connection ()
1466 unsigned int interval = 40;
1467 if (!_session) return;
1468 if (_session->timecode_frames_per_second() != 0) {
1469 /* ideally we'll use a select() to sleep and not accumulate
1470 * idle time to provide a regular periodic signal.
1471 * See linux_vst_gui_support.cc 'elapsed_time_ms'.
1472 * However, that'll require a dedicated thread and cross-thread
1473 * signals to the GUI Thread..
1475 interval = floor(500. /* update twice per FPS, since Glib::signal_timeout is very irregular */
1476 * _session->frame_rate() / _session->nominal_frame_rate()
1477 / _session->timecode_frames_per_second()
1479 #ifdef PLATFORM_WINDOWS
1480 // the smallest windows scheduler time-slice is ~15ms.
1481 // periodic GUI timeouts shorter than that will cause
1482 // WaitForSingleObject to spinlock (100% of one CPU Core)
1483 // and gtk never enters idle mode.
1484 // also changing timeBeginPeriod(1) does not affect that in
1485 // any beneficial way, so we just limit the max rate for now.
1486 interval = std::max(30u, interval); // at most ~33Hz.
1488 interval = std::max(8u, interval); // at most 120Hz.
1491 fps_connection.disconnect();
1492 Timers::set_fps_interval (interval);
1496 ARDOUR_UI::update_sample_rate (framecnt_t)
1500 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
1502 if (!AudioEngine::instance()->connected()) {
1504 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1508 framecnt_t rate = AudioEngine::instance()->sample_rate();
1511 /* no sample rate available */
1512 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1515 if (fmod (rate, 1000.0) != 0.0) {
1516 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
1517 (float) rate / 1000.0f,
1518 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1520 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
1522 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1526 sample_rate_label.set_markup (buf);
1530 ARDOUR_UI::update_format ()
1533 format_label.set_text ("");
1538 s << _("File:") << X_(" <span foreground=\"green\">");
1540 switch (_session->config.get_native_file_header_format ()) {
1572 switch (_session->config.get_native_file_data_format ()) {
1586 format_label.set_markup (s.str ());
1590 ARDOUR_UI::update_xrun_count ()
1594 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1595 should also be changed.
1599 const unsigned int x = _session->get_xrun_count ();
1601 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">>10K</span>"), X_("red"));
1603 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">%u</span>"), x > 0 ? X_("red") : X_("green"), x);
1606 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">?</span>"), X_("yellow"));
1608 xrun_label.set_markup (buf);
1609 set_tip (xrun_label, _("Audio dropouts. Shift+click to reset"));
1613 ARDOUR_UI::update_cpu_load ()
1617 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1618 should also be changed.
1621 double const c = AudioEngine::instance()->get_dsp_load ();
1622 snprintf (buf, sizeof (buf), _("DSP: <span foreground=\"%s\">%5.1f%%</span>"), c >= 90 ? X_("red") : X_("green"), c);
1623 cpu_load_label.set_markup (buf);
1627 ARDOUR_UI::update_peak_thread_work ()
1630 const int c = SourceFactory::peak_work_queue_length ();
1632 snprintf (buf, sizeof (buf), _("PkBld: <span foreground=\"%s\">%d</span>"), c >= 2 ? X_("red") : X_("green"), c);
1633 peak_thread_work_label.set_markup (buf);
1635 peak_thread_work_label.set_markup (X_(""));
1640 ARDOUR_UI::update_buffer_load ()
1644 uint32_t const playback = _session ? _session->playback_load () : 100;
1645 uint32_t const capture = _session ? _session->capture_load () : 100;
1647 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1648 should also be changed.
1654 _("Buffers: <span foreground=\"green\">p:</span><span foreground=\"%s\">%" PRIu32 "%%</span> "
1655 "<span foreground=\"green\">c:</span><span foreground=\"%s\">%" PRIu32 "%%</span>"),
1656 playback <= 5 ? X_("red") : X_("green"),
1658 capture <= 5 ? X_("red") : X_("green"),
1662 buffer_load_label.set_markup (buf);
1664 buffer_load_label.set_text ("");
1669 ARDOUR_UI::count_recenabled_streams (Route& route)
1671 Track* track = dynamic_cast<Track*>(&route);
1672 if (track && track->rec_enable_control()->get_value()) {
1673 rec_enabled_streams += track->n_inputs().n_total();
1678 ARDOUR_UI::update_disk_space()
1680 if (_session == 0) {
1684 boost::optional<framecnt_t> opt_frames = _session->available_capture_duration();
1686 framecnt_t fr = _session->frame_rate();
1689 /* skip update - no SR available */
1694 /* Available space is unknown */
1695 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">Unknown</span>"));
1696 } else if (opt_frames.get_value_or (0) == max_framecnt) {
1697 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">24hrs+</span>"));
1699 rec_enabled_streams = 0;
1700 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams, false);
1702 framecnt_t frames = opt_frames.get_value_or (0);
1704 if (rec_enabled_streams) {
1705 frames /= rec_enabled_streams;
1712 hrs = frames / (fr * 3600);
1715 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">>24 hrs</span>"));
1717 frames -= hrs * fr * 3600;
1718 mins = frames / (fr * 60);
1719 frames -= mins * fr * 60;
1722 bool const low = (hrs == 0 && mins <= 30);
1726 _("Disk: <span foreground=\"%s\">%02dh:%02dm:%02ds</span>"),
1727 low ? X_("red") : X_("green"),
1733 disk_space_label.set_markup (buf);
1737 ARDOUR_UI::update_timecode_format ()
1743 TimecodeSlave* tcslave;
1744 SyncSource sync_src = Config->get_sync_source();
1746 if ((sync_src == LTC || sync_src == MTC) && (tcslave = dynamic_cast<TimecodeSlave*>(_session->slave())) != 0) {
1747 matching = (tcslave->apparent_timecode_format() == _session->config.get_timecode_format());
1752 snprintf (buf, sizeof (buf), S_("Timecode|TC: <span foreground=\"%s\">%s</span>"),
1753 matching ? X_("green") : X_("red"),
1754 Timecode::timecode_format_name (_session->config.get_timecode_format()).c_str());
1756 snprintf (buf, sizeof (buf), "TC: n/a");
1759 timecode_format_label.set_markup (buf);
1763 ARDOUR_UI::update_wall_clock ()
1767 static int last_min = -1;
1770 tm_now = localtime (&now);
1771 if (last_min != tm_now->tm_min) {
1773 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1774 wall_clock_label.set_text (buf);
1775 last_min = tm_now->tm_min;
1782 ARDOUR_UI::open_recent_session ()
1784 bool can_return = (_session != 0);
1786 SessionDialog recent_session_dialog;
1790 ResponseType r = (ResponseType) recent_session_dialog.run ();
1793 case RESPONSE_ACCEPT:
1797 recent_session_dialog.hide();
1804 recent_session_dialog.hide();
1808 std::string path = recent_session_dialog.session_folder();
1809 std::string state = recent_session_dialog.session_name (should_be_new);
1811 if (should_be_new == true) {
1815 _session_is_new = false;
1817 if (load_session (path, state) == 0) {
1823 if (splash && splash->is_visible()) {
1824 // in 1 second, hide the splash screen
1825 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
1830 ARDOUR_UI::check_audioengine (Gtk::Window& parent)
1832 if (!AudioEngine::instance()->connected()) {
1833 MessageDialog msg (parent, string_compose (
1834 _("%1 is not connected to any audio backend.\n"
1835 "You cannot open or close sessions in this condition"),
1837 pop_back_splash (msg);
1845 ARDOUR_UI::open_session ()
1847 if (!check_audioengine (_main_window)) {
1851 /* ardour sessions are folders */
1852 Gtk::FileChooserDialog open_session_selector(_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1853 open_session_selector.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1854 open_session_selector.add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1855 open_session_selector.set_default_response(Gtk::RESPONSE_ACCEPT);
1858 string session_parent_dir = Glib::path_get_dirname(_session->path());
1859 open_session_selector.set_current_folder(session_parent_dir);
1861 open_session_selector.set_current_folder(Config->get_default_session_parent_dir());
1864 Gtkmm2ext::add_volume_shortcuts (open_session_selector);
1866 /* add_shortcut_folder throws an exception if the folder being added already has a shortcut */
1867 string default_session_folder = Config->get_default_session_parent_dir();
1868 open_session_selector.add_shortcut_folder (default_session_folder);
1870 catch (Glib::Error & e) {
1871 std::cerr << "open_session_selector.add_shortcut_folder() threw Glib::Error " << e.what() << std::endl;
1874 FileFilter session_filter;
1875 session_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::statefile_suffix));
1876 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1877 open_session_selector.add_filter (session_filter);
1878 open_session_selector.set_filter (session_filter);
1880 int response = open_session_selector.run();
1881 open_session_selector.hide ();
1883 if (response == Gtk::RESPONSE_CANCEL) {
1887 string session_path = open_session_selector.get_filename();
1891 if (session_path.length() > 0) {
1892 if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1893 _session_is_new = isnew;
1894 load_session (path, name);
1900 ARDOUR_UI::session_add_vca (const string& name_template, uint32_t n)
1906 _session->vca_manager().create_vca (n, name_template);
1910 ARDOUR_UI::session_add_mixed_track (
1911 const ChanCount& input,
1912 const ChanCount& output,
1913 RouteGroup* route_group,
1915 const string& name_template,
1917 PluginInfoPtr instrument,
1918 Plugin::PresetRecord* pset,
1919 ARDOUR::PresentationInfo::order_t order)
1921 list<boost::shared_ptr<MidiTrack> > tracks;
1923 if (_session == 0) {
1924 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1929 tracks = _session->new_midi_track (input, output, instrument, pset, route_group, how_many, name_template, order, ARDOUR::Normal);
1931 if (tracks.size() != how_many) {
1932 error << string_compose(P_("could not create %1 new mixed track", "could not create %1 new mixed tracks", how_many), how_many) << endmsg;
1937 display_insufficient_ports_message ();
1942 for (list<boost::shared_ptr<MidiTrack> >::iterator i = tracks.begin(); i != tracks.end(); ++i) {
1943 (*i)->set_strict_io (true);
1949 ARDOUR_UI::session_add_midi_bus (
1950 RouteGroup* route_group,
1952 const string& name_template,
1954 PluginInfoPtr instrument,
1955 Plugin::PresetRecord* pset,
1956 ARDOUR::PresentationInfo::order_t order)
1960 if (_session == 0) {
1961 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1967 routes = _session->new_midi_route (route_group, how_many, name_template, instrument, pset, PresentationInfo::MidiBus, order);
1968 if (routes.size() != how_many) {
1969 error << string_compose(P_("could not create %1 new Midi Bus", "could not create %1 new Midi Busses", how_many), how_many) << endmsg;
1974 display_insufficient_ports_message ();
1979 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
1980 (*i)->set_strict_io (true);
1986 ARDOUR_UI::session_add_midi_route (
1988 RouteGroup* route_group,
1990 const string& name_template,
1992 PluginInfoPtr instrument,
1993 Plugin::PresetRecord* pset,
1994 ARDOUR::PresentationInfo::order_t order)
1996 ChanCount one_midi_channel;
1997 one_midi_channel.set (DataType::MIDI, 1);
2000 session_add_mixed_track (one_midi_channel, one_midi_channel, route_group, how_many, name_template, strict_io, instrument, pset, order);
2002 session_add_midi_bus (route_group, how_many, name_template, strict_io, instrument, pset, order);
2007 ARDOUR_UI::session_add_audio_route (
2009 int32_t input_channels,
2010 int32_t output_channels,
2011 ARDOUR::TrackMode mode,
2012 RouteGroup* route_group,
2014 string const & name_template,
2016 ARDOUR::PresentationInfo::order_t order)
2018 list<boost::shared_ptr<AudioTrack> > tracks;
2021 if (_session == 0) {
2022 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
2028 tracks = _session->new_audio_track (input_channels, output_channels, route_group, how_many, name_template, order, mode);
2030 if (tracks.size() != how_many) {
2031 error << string_compose (P_("could not create %1 new audio track", "could not create %1 new audio tracks", how_many), how_many)
2037 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template, PresentationInfo::AudioBus, order);
2039 if (routes.size() != how_many) {
2040 error << string_compose (P_("could not create %1 new audio bus", "could not create %1 new audio busses", how_many), how_many)
2047 display_insufficient_ports_message ();
2052 for (list<boost::shared_ptr<AudioTrack> >::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2053 (*i)->set_strict_io (true);
2055 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
2056 (*i)->set_strict_io (true);
2062 ARDOUR_UI::display_insufficient_ports_message ()
2064 MessageDialog msg (_main_window,
2065 string_compose (_("There are insufficient ports available\n\
2066 to create a new track or bus.\n\
2067 You should save %1, exit and\n\
2068 restart with more ports."), PROGRAM_NAME));
2069 pop_back_splash (msg);
2074 ARDOUR_UI::transport_goto_start ()
2077 _session->goto_start();
2079 /* force displayed area in editor to start no matter
2080 what "follow playhead" setting is.
2084 editor->center_screen (_session->current_start_frame ());
2090 ARDOUR_UI::transport_goto_zero ()
2093 _session->request_locate (0);
2095 /* force displayed area in editor to start no matter
2096 what "follow playhead" setting is.
2100 editor->reset_x_origin (0);
2106 ARDOUR_UI::transport_goto_wallclock ()
2108 if (_session && editor) {
2115 localtime_r (&now, &tmnow);
2117 framecnt_t frame_rate = _session->frame_rate();
2119 if (frame_rate == 0) {
2120 /* no frame rate available */
2124 frames = tmnow.tm_hour * (60 * 60 * frame_rate);
2125 frames += tmnow.tm_min * (60 * frame_rate);
2126 frames += tmnow.tm_sec * frame_rate;
2128 _session->request_locate (frames, _session->transport_rolling ());
2130 /* force displayed area in editor to start no matter
2131 what "follow playhead" setting is.
2135 editor->center_screen (frames);
2141 ARDOUR_UI::transport_goto_end ()
2144 framepos_t const frame = _session->current_end_frame();
2145 _session->request_locate (frame);
2147 /* force displayed area in editor to start no matter
2148 what "follow playhead" setting is.
2152 editor->center_screen (frame);
2158 ARDOUR_UI::transport_stop ()
2164 if (_session->is_auditioning()) {
2165 _session->cancel_audition ();
2169 _session->request_stop (false, true);
2172 /** Check if any tracks are record enabled. If none are, record enable all of them.
2173 * @return true if track record-enabled status was changed, false otherwise.
2176 ARDOUR_UI::trx_record_enable_all_tracks ()
2182 boost::shared_ptr<RouteList> rl = _session->get_tracks ();
2183 bool none_record_enabled = true;
2185 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
2186 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*r);
2189 if (t->rec_enable_control()->get_value()) {
2190 none_record_enabled = false;
2195 if (none_record_enabled) {
2196 _session->set_controls (route_list_to_control_list (rl, &Stripable::rec_enable_control), 1.0, Controllable::NoGroup);
2199 return none_record_enabled;
2203 ARDOUR_UI::transport_record (bool roll)
2206 switch (_session->record_status()) {
2207 case Session::Disabled:
2208 if (_session->ntracks() == 0) {
2209 MessageDialog msg (_main_window, _("Please create one or more tracks before trying to record.\nYou can do this with the \"Add Track or Bus\" option in the Session menu."));
2213 if (Profile->get_trx()) {
2214 roll = trx_record_enable_all_tracks ();
2216 _session->maybe_enable_record ();
2221 case Session::Recording:
2223 _session->request_stop();
2225 _session->disable_record (false, true);
2229 case Session::Enabled:
2230 _session->disable_record (false, true);
2236 ARDOUR_UI::transport_roll ()
2242 if (_session->is_auditioning()) {
2247 if (_session->config.get_external_sync()) {
2248 switch (Config->get_sync_source()) {
2252 /* transport controlled by the master */
2258 bool rolling = _session->transport_rolling();
2260 if (_session->get_play_loop()) {
2262 /* If loop playback is not a mode, then we should cancel
2263 it when this action is requested. If it is a mode
2264 we just leave it in place.
2267 if (!Config->get_loop_is_mode()) {
2268 /* XXX it is not possible to just leave seamless loop and keep
2269 playing at present (nov 4th 2009)
2271 if (!Config->get_seamless_loop()) {
2272 /* stop loop playback and stop rolling */
2273 _session->request_play_loop (false, true);
2274 } else if (rolling) {
2275 /* stop loop playback but keep rolling */
2276 _session->request_play_loop (false, false);
2280 } else if (_session->get_play_range () ) {
2281 /* stop playing a range if we currently are */
2282 _session->request_play_range (0, true);
2286 _session->request_transport_speed (1.0f);
2291 ARDOUR_UI::get_smart_mode() const
2293 return ( editor->get_smart_mode() );
2298 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
2304 if (_session->is_auditioning()) {
2305 _session->cancel_audition ();
2309 if (_session->config.get_external_sync()) {
2310 switch (Config->get_sync_source()) {
2314 /* transport controlled by the master */
2319 bool rolling = _session->transport_rolling();
2320 bool affect_transport = true;
2322 if (rolling && roll_out_of_bounded_mode) {
2323 /* drop out of loop/range playback but leave transport rolling */
2324 if (_session->get_play_loop()) {
2325 if (_session->actively_recording()) {
2327 /* just stop using the loop, then actually stop
2330 _session->request_play_loop (false, affect_transport);
2333 if (Config->get_seamless_loop()) {
2334 /* the disk buffers contain copies of the loop - we can't
2335 just keep playing, so stop the transport. the user
2336 can restart as they wish.
2338 affect_transport = true;
2340 /* disk buffers are normal, so we can keep playing */
2341 affect_transport = false;
2343 _session->request_play_loop (false, affect_transport);
2345 } else if (_session->get_play_range ()) {
2346 affect_transport = false;
2347 _session->request_play_range (0, true);
2351 if (affect_transport) {
2353 _session->request_stop (with_abort, true);
2355 } else if (!with_abort) { /* with_abort == true means the
2356 * command was intended to stop
2357 * transport, not start.
2360 /* the only external sync condition we can be in here
2361 * would be Engine (JACK) sync, in which case we still
2365 if (UIConfiguration::instance().get_follow_edits() && ( editor->get_selection().time.front().start == _session->transport_frame() ) ) { //if playhead is exactly at the start of a range, we can assume it was placed there by follow_edits
2366 _session->request_play_range (&editor->get_selection().time, true);
2367 _session->set_requested_return_frame( editor->get_selection().time.front().start ); //force an auto-return here
2369 _session->request_transport_speed (1.0f);
2375 ARDOUR_UI::toggle_session_auto_loop ()
2381 Location * looploc = _session->locations()->auto_loop_location();
2387 if (_session->get_play_loop()) {
2389 /* looping enabled, our job is to disable it */
2391 _session->request_play_loop (false);
2395 /* looping not enabled, our job is to enable it.
2397 loop-is-NOT-mode: this action always starts the transport rolling.
2398 loop-IS-mode: this action simply sets the loop play mechanism, but
2399 does not start transport.
2401 if (Config->get_loop_is_mode()) {
2402 _session->request_play_loop (true, false);
2404 _session->request_play_loop (true, true);
2408 //show the loop markers
2409 looploc->set_hidden (false, this);
2413 ARDOUR_UI::transport_play_selection ()
2419 editor->play_selection ();
2423 ARDOUR_UI::transport_play_preroll ()
2428 editor->play_with_preroll ();
2432 ARDOUR_UI::transport_rewind (int option)
2434 float current_transport_speed;
2437 current_transport_speed = _session->transport_speed();
2439 if (current_transport_speed >= 0.0f) {
2442 _session->request_transport_speed (-1.0f);
2445 _session->request_transport_speed (-4.0f);
2448 _session->request_transport_speed (-0.5f);
2453 _session->request_transport_speed (current_transport_speed * 1.5f);
2459 ARDOUR_UI::transport_forward (int option)
2465 float current_transport_speed = _session->transport_speed();
2467 if (current_transport_speed <= 0.0f) {
2470 _session->request_transport_speed (1.0f);
2473 _session->request_transport_speed (4.0f);
2476 _session->request_transport_speed (0.5f);
2481 _session->request_transport_speed (current_transport_speed * 1.5f);
2486 ARDOUR_UI::toggle_record_enable (uint16_t rid)
2492 boost::shared_ptr<Route> r;
2494 if ((r = _session->get_remote_nth_route (rid)) != 0) {
2496 boost::shared_ptr<Track> t;
2498 if ((t = boost::dynamic_pointer_cast<Track>(r)) != 0) {
2499 t->rec_enable_control()->set_value (!t->rec_enable_control()->get_value(), Controllable::UseGroup);
2505 ARDOUR_UI::map_transport_state ()
2508 auto_loop_button.unset_active_state ();
2509 play_selection_button.unset_active_state ();
2510 roll_button.unset_active_state ();
2511 stop_button.set_active_state (Gtkmm2ext::ExplicitActive);
2512 layered_button.set_sensitive (false);
2516 shuttle_box->map_transport_state ();
2518 float sp = _session->transport_speed();
2524 if (_session->get_play_range()) {
2526 play_selection_button.set_active_state (Gtkmm2ext::ExplicitActive);
2527 roll_button.unset_active_state ();
2528 auto_loop_button.unset_active_state ();
2530 } else if (_session->get_play_loop ()) {
2532 auto_loop_button.set_active (true);
2533 play_selection_button.set_active (false);
2534 if (Config->get_loop_is_mode()) {
2535 roll_button.set_active (true);
2537 roll_button.set_active (false);
2542 roll_button.set_active (true);
2543 play_selection_button.set_active (false);
2544 auto_loop_button.set_active (false);
2547 if (UIConfiguration::instance().get_follow_edits() && !_session->config.get_external_sync()) {
2548 /* light up both roll and play-selection if they are joined */
2549 roll_button.set_active (true);
2550 play_selection_button.set_active (true);
2552 layered_button.set_sensitive (!_session->actively_recording ());
2554 stop_button.set_active (false);
2558 layered_button.set_sensitive (true);
2559 stop_button.set_active (true);
2560 roll_button.set_active (false);
2561 play_selection_button.set_active (false);
2562 if (Config->get_loop_is_mode ()) {
2563 auto_loop_button.set_active (_session->get_play_loop());
2565 auto_loop_button.set_active (false);
2567 update_disk_space ();
2572 ARDOUR_UI::blink_handler (bool blink_on)
2574 transport_rec_enable_blink (blink_on);
2575 solo_blink (blink_on);
2576 sync_blink (blink_on);
2577 audition_blink (blink_on);
2578 feedback_blink (blink_on);
2579 error_blink (blink_on);
2583 ARDOUR_UI::update_clocks ()
2585 if (!_session) return;
2587 if (editor && !editor->dragging_playhead()) {
2588 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD)); /* EMIT_SIGNAL */
2593 ARDOUR_UI::start_clocking ()
2595 if (UIConfiguration::instance().get_super_rapid_clock_update()) {
2596 clock_signal_connection = Timers::fps_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2598 clock_signal_connection = Timers::rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2603 ARDOUR_UI::stop_clocking ()
2605 clock_signal_connection.disconnect ();
2609 ARDOUR_UI::save_as_progress_update (float fraction, int64_t cnt, int64_t total, Gtk::Label* label, Gtk::ProgressBar* bar)
2613 snprintf (buf, sizeof (buf), _("Copied %" PRId64 " of %" PRId64), cnt, total);
2615 label->set_text (buf);
2616 bar->set_fraction (fraction);
2618 /* process events, redraws, etc. */
2620 while (gtk_events_pending()) {
2621 gtk_main_iteration ();
2624 return true; /* continue with save-as */
2628 ARDOUR_UI::save_session_as ()
2634 if (!save_as_dialog) {
2635 save_as_dialog = new SaveAsDialog;
2638 save_as_dialog->set_name (_session->name());
2640 int response = save_as_dialog->run ();
2642 save_as_dialog->hide ();
2645 case Gtk::RESPONSE_OK:
2654 sa.new_parent_folder = save_as_dialog->new_parent_folder ();
2655 sa.new_name = save_as_dialog->new_name ();
2656 sa.switch_to = save_as_dialog->switch_to();
2657 sa.copy_media = save_as_dialog->copy_media();
2658 sa.copy_external = save_as_dialog->copy_external();
2659 sa.include_media = save_as_dialog->include_media ();
2661 /* Only bother with a progress dialog if we're going to copy
2662 media into the save-as target. Without that choice, this
2663 will be very fast because we're only talking about a few kB's to
2664 perhaps a couple of MB's of data.
2667 ArdourDialog progress_dialog (_("Save As"), true);
2669 if (sa.include_media && sa.copy_media) {
2672 Gtk::ProgressBar progress_bar;
2674 progress_dialog.get_vbox()->pack_start (label);
2675 progress_dialog.get_vbox()->pack_start (progress_bar);
2677 progress_bar.show ();
2679 /* this signal will be emitted from within this, the calling thread,
2680 * after every file is copied. It provides information on percentage
2681 * complete (in terms of total data to copy), the number of files
2682 * copied so far, and the total number to copy.
2687 sa.Progress.connect_same_thread (c, boost::bind (&ARDOUR_UI::save_as_progress_update, this, _1, _2, _3, &label, &progress_bar));
2689 progress_dialog.show_all ();
2690 progress_dialog.present ();
2693 if (_session->save_as (sa)) {
2695 MessageDialog msg (string_compose (_("Save As failed: %1"), sa.failure_message));
2699 if (!sa.include_media) {
2700 unload_session (false);
2701 load_session (sa.final_session_folder_name, sa.new_name);
2706 ARDOUR_UI::archive_session ()
2714 Glib::DateTime gdt (Glib::DateTime::create_now_local (n));
2716 SessionArchiveDialog sad;
2717 sad.set_name (_session->name() + gdt.format ("_%F_%H%M%S"));
2718 int response = sad.run ();
2720 if (response != Gtk::RESPONSE_OK) {
2725 if (_session->archive_session (sad.target_folder(), sad.name(), sad.encode_option (), sad.only_used_sources (), &sad)) {
2726 MessageDialog msg (_("Session Archiving failed."));
2732 ARDOUR_UI::quick_snapshot_session (bool switch_to_it)
2736 struct tm local_time;
2739 localtime_r (&n, &local_time);
2740 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2742 save_state (timebuf, switch_to_it);
2747 ARDOUR_UI::process_snapshot_session_prompter (ArdourPrompter& prompter, bool switch_to_it)
2751 prompter.get_result (snapname);
2753 bool do_save = (snapname.length() != 0);
2756 char illegal = Session::session_name_is_legal(snapname);
2758 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2759 "snapshot names may not contain a '%1' character"), illegal));
2765 vector<std::string> p;
2766 get_state_files_in_directory (_session->session_directory().root_path(), p);
2767 vector<string> n = get_file_names_no_extension (p);
2769 if (find (n.begin(), n.end(), snapname) != n.end()) {
2771 do_save = overwrite_file_dialog (prompter,
2772 _("Confirm Snapshot Overwrite"),
2773 _("A snapshot already exists with that name. Do you want to overwrite it?"));
2777 save_state (snapname, switch_to_it);
2787 /** Ask the user for the name of a new snapshot and then take it.
2791 ARDOUR_UI::snapshot_session (bool switch_to_it)
2793 ArdourPrompter prompter (true);
2795 prompter.set_name ("Prompter");
2796 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2798 prompter.set_title (_("Snapshot and switch"));
2799 prompter.set_prompt (_("New session name"));
2801 prompter.set_title (_("Take Snapshot"));
2802 prompter.set_prompt (_("Name of new snapshot"));
2806 prompter.set_initial_text (_session->snap_name());
2808 Glib::DateTime tm (g_date_time_new_now_local ());
2809 prompter.set_initial_text (tm.format ("%FT%H.%M.%S"));
2812 bool finished = false;
2814 switch (prompter.run()) {
2815 case RESPONSE_ACCEPT:
2817 finished = process_snapshot_session_prompter (prompter, switch_to_it);
2828 /** Ask the user for a new session name and then rename the session to it.
2832 ARDOUR_UI::rename_session ()
2838 ArdourPrompter prompter (true);
2841 prompter.set_name ("Prompter");
2842 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2843 prompter.set_title (_("Rename Session"));
2844 prompter.set_prompt (_("New session name"));
2847 switch (prompter.run()) {
2848 case RESPONSE_ACCEPT:
2850 prompter.get_result (name);
2852 bool do_rename = (name.length() != 0);
2855 char illegal = Session::session_name_is_legal (name);
2858 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2859 "session names may not contain a '%1' character"), illegal));
2864 switch (_session->rename (name)) {
2866 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
2867 msg.set_position (WIN_POS_MOUSE);
2875 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
2876 msg.set_position (WIN_POS_MOUSE);
2892 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2894 if (!_session || _session->deletion_in_progress()) {
2898 XMLNode* node = new XMLNode (X_("UI"));
2900 WM::Manager::instance().add_state (*node);
2902 node->add_child_nocopy (gui_object_state->get_state());
2904 _session->add_extra_xml (*node);
2906 if (export_video_dialog) {
2907 _session->add_extra_xml (export_video_dialog->get_state());
2910 save_state_canfail (name, switch_to_it);
2914 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2919 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2924 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2929 ARDOUR_UI::primary_clock_value_changed ()
2932 _session->request_locate (primary_clock->current_time ());
2937 ARDOUR_UI::big_clock_value_changed ()
2940 _session->request_locate (big_clock->current_time ());
2945 ARDOUR_UI::secondary_clock_value_changed ()
2948 _session->request_locate (secondary_clock->current_time ());
2953 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2955 if (_session == 0) {
2959 if (_session->step_editing()) {
2963 Session::RecordState const r = _session->record_status ();
2964 bool const h = _session->have_rec_enabled_track ();
2966 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2968 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2970 rec_button.set_active_state (Gtkmm2ext::Off);
2972 } else if (r == Session::Recording && h) {
2973 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2975 rec_button.unset_active_state ();
2980 ARDOUR_UI::process_save_template_prompter (ArdourPrompter& prompter)
2984 prompter.get_result (name);
2986 if (name.length()) {
2987 int failed = _session->save_template (name);
2989 if (failed == -2) { /* file already exists. */
2990 bool overwrite = overwrite_file_dialog (prompter,
2991 _("Confirm Template Overwrite"),
2992 _("A template already exists with that name. Do you want to overwrite it?"));
2995 _session->save_template (name, true);
3007 ARDOUR_UI::save_template ()
3009 ArdourPrompter prompter (true);
3011 if (!check_audioengine (_main_window)) {
3015 prompter.set_name (X_("Prompter"));
3016 prompter.set_title (_("Save Template"));
3017 prompter.set_prompt (_("Name for template:"));
3018 prompter.set_initial_text(_session->name() + _("-template"));
3019 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
3021 bool finished = false;
3023 switch (prompter.run()) {
3024 case RESPONSE_ACCEPT:
3025 finished = process_save_template_prompter (prompter);
3036 ARDOUR_UI::edit_metadata ()
3038 SessionMetadataEditor dialog;
3039 dialog.set_session (_session);
3040 dialog.grab_focus ();
3045 ARDOUR_UI::import_metadata ()
3047 SessionMetadataImporter dialog;
3048 dialog.set_session (_session);
3053 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
3055 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
3057 MessageDialog msg (str,
3059 Gtk::MESSAGE_WARNING,
3060 Gtk::BUTTONS_YES_NO,
3064 msg.set_name (X_("OpenExistingDialog"));
3065 msg.set_title (_("Open Existing Session"));
3066 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
3067 msg.set_position (Gtk::WIN_POS_CENTER);
3068 pop_back_splash (msg);
3070 switch (msg.run()) {
3079 ARDOUR_UI::build_session_from_dialog (SessionDialog& sd, const std::string& session_path, const std::string& session_name)
3081 BusProfile bus_profile;
3085 bus_profile.master_out_channels = 2;
3086 bus_profile.input_ac = AutoConnectPhysical;
3087 bus_profile.output_ac = AutoConnectMaster;
3088 bus_profile.requested_physical_in = 0; // use all available
3089 bus_profile.requested_physical_out = 0; // use all available
3093 /* get settings from advanced section of NSD */
3095 if (sd.create_master_bus()) {
3096 bus_profile.master_out_channels = (uint32_t) sd.master_channel_count();
3098 bus_profile.master_out_channels = 0;
3101 if (sd.connect_inputs()) {
3102 bus_profile.input_ac = AutoConnectPhysical;
3104 bus_profile.input_ac = AutoConnectOption (0);
3107 bus_profile.output_ac = AutoConnectOption (0);
3109 if (sd.connect_outputs ()) {
3110 if (sd.connect_outs_to_master()) {
3111 bus_profile.output_ac = AutoConnectMaster;
3112 } else if (sd.connect_outs_to_physical()) {
3113 bus_profile.output_ac = AutoConnectPhysical;
3117 bus_profile.requested_physical_in = (uint32_t) sd.input_limit_count();
3118 bus_profile.requested_physical_out = (uint32_t) sd.output_limit_count();
3121 if (build_session (session_path, session_name, bus_profile)) {
3129 ARDOUR_UI::load_from_application_api (const std::string& path)
3131 /* OS X El Capitan (and probably later) now somehow passes the command
3132 line arguments to an app via the openFile delegate protocol. Ardour
3133 already does its own command line processing, and having both
3134 pathways active causes crashes. So, if the command line was already
3135 set, do nothing here.
3138 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
3142 ARDOUR_COMMAND_LINE::session_name = path;
3144 /* Cancel SessionDialog if it's visible to make OSX delegates work.
3146 * ARDOUR_UI::starting connects app->ShouldLoad signal and then shows a SessionDialog
3148 * - ShouldLoad does not arrive in time, ARDOUR_COMMAND_LINE::session_name is empty:
3149 * -> ARDOUR_UI::get_session_parameters starts a SessionDialog.
3150 * - ShouldLoad signal arrives, this function is called and sets ARDOUR_COMMAND_LINE::session_name
3151 * -> SessionDialog is not displayed
3154 if (_session_dialog) {
3155 std::string session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3156 std::string session_path = path;
3157 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_REGULAR)) {
3158 session_path = Glib::path_get_dirname (session_path);
3160 // signal the existing dialog in ARDOUR_UI::get_session_parameters()
3161 _session_dialog->set_provided_session (session_name, session_path);
3162 _session_dialog->response (RESPONSE_NONE);
3163 _session_dialog->hide();
3168 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
3169 /* /path/to/foo => /path/to/foo, foo */
3170 rv = load_session (path, basename_nosuffix (path));
3172 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
3173 rv =load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
3176 // if load_session fails -> pop up SessionDialog.
3178 ARDOUR_COMMAND_LINE::session_name = "";
3180 if (get_session_parameters (true, false)) {
3186 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
3188 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
3190 string session_name;
3191 string session_path;
3192 string template_name;
3194 bool likely_new = false;
3195 bool cancel_not_quit;
3197 /* deal with any existing DIRTY session now, rather than later. don't
3198 * treat a non-dirty session this way, so that it stays visible
3199 * as we bring up the new session dialog.
3202 if (_session && ARDOUR_UI::instance()->video_timeline) {
3203 ARDOUR_UI::instance()->video_timeline->sync_session_state();
3206 /* if there is already a session, relabel the button
3207 on the SessionDialog so that we don't Quit directly
3209 cancel_not_quit = (_session != 0);
3211 if (_session && _session->dirty()) {
3212 if (unload_session (false)) {
3213 /* unload cancelled by user */
3216 ARDOUR_COMMAND_LINE::session_name = "";
3219 if (!load_template.empty()) {
3220 should_be_new = true;
3221 template_name = load_template;
3224 session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3225 session_path = ARDOUR_COMMAND_LINE::session_name;
3227 if (!session_path.empty()) {
3228 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_EXISTS)) {
3229 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_IS_REGULAR)) {
3230 /* session/snapshot file, change path to be dir */
3231 session_path = Glib::path_get_dirname (session_path);
3236 SessionDialog session_dialog (should_be_new, session_name, session_path, load_template, cancel_not_quit);
3238 _session_dialog = &session_dialog;
3241 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
3243 /* if they named a specific statefile, use it, otherwise they are
3244 just giving a session folder, and we want to use it as is
3245 to find the session.
3248 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
3250 if (suffix != string::npos) {
3251 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
3252 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
3253 session_name = Glib::path_get_basename (session_name);
3255 session_path = ARDOUR_COMMAND_LINE::session_name;
3256 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
3261 session_dialog.clear_given ();
3264 if (should_be_new || session_name.empty()) {
3265 /* need the dialog to get info from user */
3267 cerr << "run dialog\n";
3269 switch (session_dialog.run()) {
3270 case RESPONSE_ACCEPT:
3273 /* this is used for async * app->ShouldLoad(). */
3274 continue; // while loop
3277 if (quit_on_cancel) {
3278 // JE - Currently (July 2014) this section can only get reached if the
3279 // user quits from the main 'Session Setup' dialog (i.e. reaching this
3280 // point does NOT indicate an abnormal termination). Therefore, let's
3281 // behave gracefully (i.e. let's do some cleanup) before we call exit()
3283 pthread_cancel_all ();
3291 session_dialog.hide ();
3294 /* if we run the startup dialog again, offer more than just "new session" */
3296 should_be_new = false;
3298 session_name = session_dialog.session_name (likely_new);
3299 session_path = session_dialog.session_folder ();
3305 string::size_type suffix = session_name.find (statefile_suffix);
3307 if (suffix != string::npos) {
3308 session_name = session_name.substr (0, suffix);
3311 /* this shouldn't happen, but we catch it just in case it does */
3313 if (session_name.empty()) {
3317 if (session_dialog.use_session_template()) {
3318 template_name = session_dialog.session_template_name();
3319 _session_is_new = true;
3322 if (session_name[0] == G_DIR_SEPARATOR ||
3323 #ifdef PLATFORM_WINDOWS
3324 (session_name.length() > 3 && session_name[1] == ':' && session_name[2] == G_DIR_SEPARATOR)
3326 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
3327 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)
3332 /* absolute path or cwd-relative path specified for session name: infer session folder
3333 from what was given.
3336 session_path = Glib::path_get_dirname (session_name);
3337 session_name = Glib::path_get_basename (session_name);
3341 session_path = session_dialog.session_folder();
3343 char illegal = Session::session_name_is_legal (session_name);
3346 MessageDialog msg (session_dialog,
3347 string_compose (_("To ensure compatibility with various systems\n"
3348 "session names may not contain a '%1' character"),
3351 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3356 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
3359 if (likely_new && !nsm) {
3361 std::string existing = Glib::build_filename (session_path, session_name);
3363 if (!ask_about_loading_existing_session (existing)) {
3364 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3369 _session_is_new = false;
3374 pop_back_splash (session_dialog);
3375 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
3377 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3381 char illegal = Session::session_name_is_legal(session_name);
3384 pop_back_splash (session_dialog);
3385 MessageDialog msg (session_dialog, string_compose(_("To ensure compatibility with various systems\n"
3386 "session names may not contain a '%1' character"), illegal));
3388 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3392 _session_is_new = true;
3395 if (likely_new && template_name.empty()) {
3397 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3401 ret = load_session (session_path, session_name, template_name);
3404 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
3408 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
3409 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
3413 /* clear this to avoid endless attempts to load the
3417 ARDOUR_COMMAND_LINE::session_name = "";
3421 _session_dialog = NULL;
3427 ARDOUR_UI::close_session()
3429 if (!check_audioengine (_main_window)) {
3433 if (unload_session (true)) {
3437 ARDOUR_COMMAND_LINE::session_name = "";
3439 if (get_session_parameters (true, false)) {
3442 if (splash && splash->is_visible()) {
3443 // in 1 second, hide the splash screen
3444 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
3448 /** @param snap_name Snapshot name (without .ardour suffix).
3449 * @return -2 if the load failed because we are not connected to the AudioEngine.
3452 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
3454 Session *new_session;
3459 unload_status = unload_session ();
3461 if (unload_status < 0) {
3463 } else if (unload_status > 0) {
3469 session_loaded = false;
3471 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
3474 new_session = new Session (*AudioEngine::instance(), path, snap_name, 0, mix_template);
3477 /* this one is special */
3479 catch (AudioEngine::PortRegistrationFailure& err) {
3481 MessageDialog msg (err.what(),
3484 Gtk::BUTTONS_CLOSE);
3486 msg.set_title (_("Port Registration Error"));
3487 msg.set_secondary_text (_("Click the Close button to try again."));
3488 msg.set_position (Gtk::WIN_POS_CENTER);
3489 pop_back_splash (msg);
3492 int response = msg.run ();
3497 case RESPONSE_CANCEL:
3504 catch (SessionException e) {
3505 MessageDialog msg (string_compose(
3506 _("Session \"%1 (snapshot %2)\" did not load successfully: %3"),
3507 path, snap_name, e.what()),
3512 msg.set_title (_("Loading Error"));
3513 msg.set_position (Gtk::WIN_POS_CENTER);
3514 pop_back_splash (msg);
3526 MessageDialog msg (string_compose(
3527 _("Session \"%1 (snapshot %2)\" did not load successfully"),
3533 msg.set_title (_("Loading Error"));
3534 msg.set_position (Gtk::WIN_POS_CENTER);
3535 pop_back_splash (msg);
3547 list<string> const u = new_session->unknown_processors ();
3549 MissingPluginDialog d (_session, u);
3554 if (!new_session->writable()) {
3555 MessageDialog msg (_("This session has been opened in read-only mode.\n\nYou will not be able to record or save."),
3560 msg.set_title (_("Read-only Session"));
3561 msg.set_position (Gtk::WIN_POS_CENTER);
3562 pop_back_splash (msg);
3569 /* Now the session been created, add the transport controls */
3570 new_session->add_controllable(roll_controllable);
3571 new_session->add_controllable(stop_controllable);
3572 new_session->add_controllable(goto_start_controllable);
3573 new_session->add_controllable(goto_end_controllable);
3574 new_session->add_controllable(auto_loop_controllable);
3575 new_session->add_controllable(play_selection_controllable);
3576 new_session->add_controllable(rec_controllable);
3578 set_session (new_session);
3580 session_loaded = true;
3583 _session->set_clean ();
3586 #ifdef WINDOWS_VST_SUPPORT
3587 fst_stop_threading();
3591 Timers::TimerSuspender t;
3595 #ifdef WINDOWS_VST_SUPPORT
3596 fst_start_threading();
3605 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
3607 Session *new_session;
3610 session_loaded = false;
3611 x = unload_session ();
3619 _session_is_new = true;
3622 new_session = new Session (*AudioEngine::instance(), path, snap_name, &bus_profile);
3625 catch (SessionException e) {
3626 cerr << "Here are the errors associated with this failed session:\n";
3628 cerr << "---------\n";
3629 MessageDialog msg (string_compose(_("Could not create session in \"%1\": %2"), path, e.what()));
3630 msg.set_title (_("Loading Error"));
3631 msg.set_position (Gtk::WIN_POS_CENTER);
3632 pop_back_splash (msg);
3637 cerr << "Here are the errors associated with this failed session:\n";
3639 cerr << "---------\n";
3640 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
3641 msg.set_title (_("Loading Error"));
3642 msg.set_position (Gtk::WIN_POS_CENTER);
3643 pop_back_splash (msg);
3648 /* Give the new session the default GUI state, if such things exist */
3651 n = Config->instant_xml (X_("Editor"));
3653 n->remove_nodes_and_delete ("Selection"); // no not apply selection to new sessions.
3654 new_session->add_instant_xml (*n, false);
3656 n = Config->instant_xml (X_("Mixer"));
3658 new_session->add_instant_xml (*n, false);
3661 n = Config->instant_xml (X_("Preferences"));
3663 new_session->add_instant_xml (*n, false);
3666 /* Put the playhead at 0 and scroll fully left */
3667 n = new_session->instant_xml (X_("Editor"));
3669 n->add_property (X_("playhead"), X_("0"));
3670 n->add_property (X_("left-frame"), X_("0"));
3673 set_session (new_session);
3675 session_loaded = true;
3677 new_session->save_state(new_session->name());
3683 ARDOUR_UI::launch_chat ()
3685 MessageDialog dialog(_("<b>Just ask and wait for an answer.\nIt may take from minutes to hours.</b>"), true);
3687 dialog.set_title (_("About the Chat"));
3688 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."));
3690 switch (dialog.run()) {
3693 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
3694 #elif defined PLATFORM_WINDOWS
3695 open_uri("http://webchat.freenode.net/?channels=ardour-windows");
3697 open_uri("http://webchat.freenode.net/?channels=ardour");
3706 ARDOUR_UI::launch_manual ()
3708 PBD::open_uri (Config->get_tutorial_manual_url());
3712 ARDOUR_UI::launch_reference ()
3714 PBD::open_uri (Config->get_reference_manual_url());
3718 ARDOUR_UI::launch_tracker ()
3720 PBD::open_uri ("http://tracker.ardour.org");
3724 ARDOUR_UI::launch_subscribe ()
3726 PBD::open_uri ("https://community.ardour.org/s/subscribe");
3730 ARDOUR_UI::launch_cheat_sheet ()
3733 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheat_sheet_osx.pdf");
3735 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheatsheet.pdf");
3740 ARDOUR_UI::launch_website ()
3742 PBD::open_uri ("http://ardour.org");
3746 ARDOUR_UI::launch_website_dev ()
3748 PBD::open_uri ("http://ardour.org/development.html");
3752 ARDOUR_UI::launch_forums ()
3754 PBD::open_uri ("https://community.ardour.org/forums");
3758 ARDOUR_UI::launch_howto_report ()
3760 PBD::open_uri ("http://ardour.org/reporting_bugs");
3764 ARDOUR_UI::loading_message (const std::string& msg)
3766 if (ARDOUR_COMMAND_LINE::no_splash) {
3774 splash->message (msg);
3778 ARDOUR_UI::show_splash ()
3782 splash = new Splash;
3792 ARDOUR_UI::hide_splash ()
3799 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title, const bool msg_delete)
3803 removed = rep.paths.size();
3806 MessageDialog msgd (_main_window,
3807 _("No files were ready for clean-up"),
3811 msgd.set_title (_("Clean-up"));
3812 msgd.set_secondary_text (_("If this seems suprising, \n\
3813 check for any existing snapshots.\n\
3814 These may still include regions that\n\
3815 require some unused files to continue to exist."));
3821 ArdourDialog results (_("Clean-up"), true, false);
3823 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
3824 CleanupResultsModelColumns() {
3828 Gtk::TreeModelColumn<std::string> visible_name;
3829 Gtk::TreeModelColumn<std::string> fullpath;
3833 CleanupResultsModelColumns results_columns;
3834 Glib::RefPtr<Gtk::ListStore> results_model;
3835 Gtk::TreeView results_display;
3837 results_model = ListStore::create (results_columns);
3838 results_display.set_model (results_model);
3839 results_display.append_column (list_title, results_columns.visible_name);
3841 results_display.set_name ("CleanupResultsList");
3842 results_display.set_headers_visible (true);
3843 results_display.set_headers_clickable (false);
3844 results_display.set_reorderable (false);
3846 Gtk::ScrolledWindow list_scroller;
3849 Gtk::HBox dhbox; // the hbox for the image and text
3850 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
3851 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
3853 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
3855 const string dead_directory = _session->session_directory().dead_path();
3858 %1 - number of files removed
3859 %2 - location of "dead"
3860 %3 - size of files affected
3861 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
3864 const char* bprefix;
3865 double space_adjusted = 0;
3867 if (rep.space < 1000) {
3869 space_adjusted = rep.space;
3870 } else if (rep.space < 1000000) {
3871 bprefix = _("kilo");
3872 space_adjusted = floorf((float)rep.space / 1000.0);
3873 } else if (rep.space < 1000000 * 1000) {
3874 bprefix = _("mega");
3875 space_adjusted = floorf((float)rep.space / (1000.0 * 1000.0));
3877 bprefix = _("giga");
3878 space_adjusted = floorf((float)rep.space / (1000.0 * 1000 * 1000.0));
3882 txt.set_markup (string_compose (P_("\
3883 The following file was deleted from %2,\n\
3884 releasing %3 %4bytes of disk space", "\
3885 The following %1 files were deleted from %2,\n\
3886 releasing %3 %4bytes of disk space", removed),
3887 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3889 txt.set_markup (string_compose (P_("\
3890 The following file was not in use and \n\
3891 has been moved to: %2\n\n\
3892 After a restart of %5\n\n\
3893 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3894 will release an additional %3 %4bytes of disk space.\n", "\
3895 The following %1 files were not in use and \n\
3896 have been moved to: %2\n\n\
3897 After a restart of %5\n\n\
3898 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3899 will release an additional %3 %4bytes of disk space.\n", removed),
3900 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3903 dhbox.pack_start (*dimage, true, false, 5);
3904 dhbox.pack_start (txt, true, false, 5);
3906 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
3907 TreeModel::Row row = *(results_model->append());
3908 row[results_columns.visible_name] = *i;
3909 row[results_columns.fullpath] = *i;
3912 list_scroller.add (results_display);
3913 list_scroller.set_size_request (-1, 150);
3914 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
3916 dvbox.pack_start (dhbox, true, false, 5);
3917 dvbox.pack_start (list_scroller, true, false, 5);
3918 ddhbox.pack_start (dvbox, true, false, 5);
3920 results.get_vbox()->pack_start (ddhbox, true, false, 5);
3921 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
3922 results.set_default_response (RESPONSE_CLOSE);
3923 results.set_position (Gtk::WIN_POS_MOUSE);
3925 results_display.show();
3926 list_scroller.show();
3933 //results.get_vbox()->show();
3934 results.set_resizable (false);
3941 ARDOUR_UI::cleanup ()
3943 if (_session == 0) {
3944 /* shouldn't happen: menu item is insensitive */
3949 MessageDialog checker (_("Are you sure you want to clean-up?"),
3951 Gtk::MESSAGE_QUESTION,
3954 checker.set_title (_("Clean-up"));
3956 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
3957 ALL undo/redo information will be lost if you clean-up.\n\
3958 Clean-up will move all unused files to a \"dead\" location."));
3960 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3961 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
3962 checker.set_default_response (RESPONSE_CANCEL);
3964 checker.set_name (_("CleanupDialog"));
3965 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3966 checker.set_position (Gtk::WIN_POS_MOUSE);
3968 switch (checker.run()) {
3969 case RESPONSE_ACCEPT:
3975 ARDOUR::CleanupReport rep;
3977 editor->prepare_for_cleanup ();
3979 /* do not allow flush until a session is reloaded */
3981 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3983 act->set_sensitive (false);
3986 if (_session->cleanup_sources (rep)) {
3987 editor->finish_cleanup ();
3991 editor->finish_cleanup ();
3994 display_cleanup_results (rep, _("Cleaned Files"), false);
3998 ARDOUR_UI::flush_trash ()
4000 if (_session == 0) {
4001 /* shouldn't happen: menu item is insensitive */
4005 ARDOUR::CleanupReport rep;
4007 if (_session->cleanup_trash_sources (rep)) {
4011 display_cleanup_results (rep, _("deleted file"), true);
4015 ARDOUR_UI::cleanup_peakfiles ()
4017 if (_session == 0) {
4018 /* shouldn't happen: menu item is insensitive */
4022 if (! _session->can_cleanup_peakfiles ()) {
4026 // get all region-views in this session
4028 TrackViewList empty;
4030 editor->get_regions_after(rs, (framepos_t) 0, empty);
4031 std::list<RegionView*> views = rs.by_layer();
4033 // remove displayed audio-region-views waveforms
4034 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
4035 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
4036 if (!arv) { continue ; }
4037 arv->delete_waves();
4040 // cleanup peak files:
4041 // - stop pending peakfile threads
4042 // - close peakfiles if any
4043 // - remove peak dir in session
4044 // - setup peakfiles (background thread)
4045 _session->cleanup_peakfiles ();
4047 // re-add waves to ARV
4048 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
4049 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
4050 if (!arv) { continue ; }
4051 arv->create_waves();
4055 PresentationInfo::order_t
4056 ARDOUR_UI::translate_order (RouteDialogs::InsertAt place)
4058 if (editor->get_selection().tracks.empty()) {
4059 return PresentationInfo::max_order;
4062 PresentationInfo::order_t order_hint = PresentationInfo::max_order;
4065 we want the new routes to have their order keys set starting from
4066 the highest order key in the selection + 1 (if available).
4069 if (place == RouteDialogs::AfterSelection) {
4070 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.back());
4072 order_hint = rtav->route()->presentation_info().order();
4075 } else if (place == RouteDialogs::BeforeSelection) {
4076 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.front());
4078 order_hint = rtav->route()->presentation_info().order();
4080 } else if (place == RouteDialogs::First) {
4083 /* leave order_hint at max_order */
4090 ARDOUR_UI::start_duplicate_routes ()
4092 if (!duplicate_routes_dialog) {
4093 duplicate_routes_dialog = new DuplicateRouteDialog;
4096 if (duplicate_routes_dialog->restart (_session)) {
4100 duplicate_routes_dialog->present ();
4104 ARDOUR_UI::add_route ()
4106 if (!add_route_dialog.get (false)) {
4107 add_route_dialog->signal_response().connect (sigc::mem_fun (*this, &ARDOUR_UI::add_route_dialog_finished));
4114 if (add_route_dialog->is_visible()) {
4115 /* we're already doing this */
4119 add_route_dialog->set_position (WIN_POS_MOUSE);
4120 add_route_dialog->present();
4124 ARDOUR_UI::add_route_dialog_finished (int r)
4128 add_route_dialog->hide();
4131 case RESPONSE_ACCEPT:
4138 if ((count = add_route_dialog->count()) <= 0) {
4142 PresentationInfo::order_t order = translate_order (add_route_dialog->insert_at());
4143 string template_path = add_route_dialog->track_template();
4144 DisplaySuspender ds;
4146 if (!template_path.empty()) {
4147 if (add_route_dialog->name_template_is_default()) {
4148 _session->new_route_from_template (count, order, template_path, string());
4150 _session->new_route_from_template (count, order, template_path, add_route_dialog->name_template());
4155 ChanCount input_chan= add_route_dialog->channels ();
4156 ChanCount output_chan;
4157 string name_template = add_route_dialog->name_template ();
4158 PluginInfoPtr instrument = add_route_dialog->requested_instrument ();
4159 RouteGroup* route_group = add_route_dialog->route_group ();
4160 AutoConnectOption oac = Config->get_output_auto_connect();
4161 bool strict_io = add_route_dialog->use_strict_io ();
4163 if (oac & AutoConnectMaster) {
4164 output_chan.set (DataType::AUDIO, (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan.n_audio()));
4165 output_chan.set (DataType::MIDI, 0);
4167 output_chan = input_chan;
4170 /* XXX do something with name template */
4172 Session::ProcessorChangeBlocker pcb (_session);
4174 switch (add_route_dialog->type_wanted()) {
4175 case AddRouteDialog::AudioTrack:
4176 session_add_audio_track (input_chan.n_audio(), output_chan.n_audio(), add_route_dialog->mode(), route_group, count, name_template, strict_io, order);
4178 case AddRouteDialog::MidiTrack:
4179 session_add_midi_track (route_group, count, name_template, strict_io, instrument, 0, order);
4181 case AddRouteDialog::MixedTrack:
4182 session_add_mixed_track (input_chan, output_chan, route_group, count, name_template, strict_io, instrument, 0, order);
4184 case AddRouteDialog::AudioBus:
4185 session_add_audio_bus (input_chan.n_audio(), output_chan.n_audio(), route_group, count, name_template, strict_io, order);
4187 case AddRouteDialog::MidiBus:
4188 session_add_midi_bus (route_group, count, name_template, strict_io, instrument, 0, order);
4190 case AddRouteDialog::VCAMaster:
4191 session_add_vca (name_template, count);
4197 ARDOUR_UI::add_lua_script ()
4203 LuaScriptInfoPtr spi;
4204 ScriptSelector ss ("Add Lua Session Script", LuaScriptInfo::Session);
4205 switch (ss.run ()) {
4206 case Gtk::RESPONSE_ACCEPT:
4214 std::string script = "";
4217 script = Glib::file_get_contents (spi->path);
4218 } catch (Glib::FileError e) {
4219 string msg = string_compose (_("Cannot read session script '%1': %2"), spi->path, e.what());
4220 MessageDialog am (msg);
4225 LuaScriptParamList lsp = LuaScriptParams::script_params (spi, "sess_params");
4226 std::vector<std::string> reg = _session->registered_lua_functions ();
4228 ScriptParameterDialog spd (_("Set Script Parameters"), spi, reg, lsp);
4229 switch (spd.run ()) {
4230 case Gtk::RESPONSE_ACCEPT:
4237 _session->register_lua_function (spd.name(), script, lsp);
4238 } catch (luabridge::LuaException const& e) {
4239 string msg = string_compose (_("Session script '%1' instantiation failed: %2"), spd.name(), e.what ());
4240 MessageDialog am (msg);
4242 } catch (SessionException e) {
4243 string msg = string_compose (_("Loading Session script '%1' failed: %2"), spd.name(), e.what ());
4244 MessageDialog am (msg);
4250 ARDOUR_UI::remove_lua_script ()
4255 if (_session->registered_lua_function_count () == 0) {
4256 string msg = _("There are no active Lua session scripts present in this session.");
4257 MessageDialog am (msg);
4262 std::vector<std::string> reg = _session->registered_lua_functions ();
4263 SessionScriptManager sm ("Remove Lua Session Script", reg);
4264 switch (sm.run ()) {
4265 case Gtk::RESPONSE_ACCEPT:
4271 _session->unregister_lua_function (sm.name());
4272 } catch (luabridge::LuaException const& e) {
4273 string msg = string_compose (_("Session script '%1' removal failed: %2"), sm.name(), e.what ());
4274 MessageDialog am (msg);
4280 ARDOUR_UI::stop_video_server (bool ask_confirm)
4282 if (!video_server_process && ask_confirm) {
4283 warning << string_compose (_("Video-Server was not launched by %1. The request to stop it is ignored."), PROGRAM_NAME) << endmsg;
4285 if (video_server_process) {
4287 ArdourDialog confirm (_("Stop Video-Server"), true);
4288 Label m (_("Do you really want to stop the Video Server?"));
4289 confirm.get_vbox()->pack_start (m, true, true);
4290 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
4291 confirm.add_button (_("Yes, Stop It"), Gtk::RESPONSE_ACCEPT);
4292 confirm.show_all ();
4293 if (confirm.run() == RESPONSE_CANCEL) {
4297 delete video_server_process;
4298 video_server_process =0;
4303 ARDOUR_UI::start_video_server_menu (Gtk::Window* float_window)
4305 ARDOUR_UI::start_video_server( float_window, true);
4309 ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg)
4315 if (ARDOUR_UI::instance()->video_timeline->check_server()) {
4316 if (video_server_process) {
4317 popup_error(_("The Video Server is already started."));
4319 popup_error(_("An external Video Server is configured and can be reached. Not starting a new instance."));
4325 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4327 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4329 VideoServerDialog *video_server_dialog = new VideoServerDialog (_session);
4331 video_server_dialog->set_transient_for (*float_window);
4334 if (!Config->get_show_video_server_dialog() && firsttime < 2) {
4335 video_server_dialog->hide();
4337 ResponseType r = (ResponseType) video_server_dialog->run ();
4338 video_server_dialog->hide();
4339 if (r != RESPONSE_ACCEPT) { return false; }
4340 if (video_server_dialog->show_again()) {
4341 Config->set_show_video_server_dialog(false);
4345 std::string icsd_exec = video_server_dialog->get_exec_path();
4346 std::string icsd_docroot = video_server_dialog->get_docroot();
4347 if (icsd_docroot.empty()) {
4348 #ifndef PLATFORM_WINDOWS
4349 icsd_docroot = X_("/");
4351 icsd_docroot = X_("C:\\");
4356 if (g_lstat (icsd_docroot.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode)) {
4357 warning << _("Specified docroot is not an existing directory.") << endmsg;
4360 #ifndef PLATFORM_WINDOWS
4361 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4362 || (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0 ) {
4363 warning << _("Given Video Server is not an executable file.") << endmsg;
4367 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4368 || (sb.st_mode & (S_IXUSR)) == 0 ) {
4369 warning << _("Given Video Server is not an executable file.") << endmsg;
4375 argp=(char**) calloc(9,sizeof(char*));
4376 argp[0] = strdup(icsd_exec.c_str());
4377 argp[1] = strdup("-P");
4378 argp[2] = (char*) calloc(16,sizeof(char)); snprintf(argp[2], 16, "%s", video_server_dialog->get_listenaddr().c_str());
4379 argp[3] = strdup("-p");
4380 argp[4] = (char*) calloc(6,sizeof(char)); snprintf(argp[4], 6, "%i", video_server_dialog->get_listenport());
4381 argp[5] = strdup("-C");
4382 argp[6] = (char*) calloc(6,sizeof(char)); snprintf(argp[6], 6, "%i", video_server_dialog->get_cachesize());
4383 argp[7] = strdup(icsd_docroot.c_str());
4385 stop_video_server();
4387 if (icsd_docroot == X_("/") || icsd_docroot == X_("C:\\")) {
4388 Config->set_video_advanced_setup(false);
4390 std::ostringstream osstream;
4391 osstream << "http://127.0.0.1:" << video_server_dialog->get_listenport() << "/";
4392 Config->set_video_server_url(osstream.str());
4393 Config->set_video_server_docroot(icsd_docroot);
4394 Config->set_video_advanced_setup(true);
4397 if (video_server_process) {
4398 delete video_server_process;
4401 video_server_process = new ARDOUR::SystemExec(icsd_exec, argp);
4402 if (video_server_process->start()) {
4403 warning << _("Cannot launch the video-server") << endmsg;
4406 int timeout = 120; // 6 sec
4407 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4408 Glib::usleep (50000);
4410 if (--timeout <= 0 || !video_server_process->is_running()) break;
4413 warning << _("Video-server was started but does not respond to requests...") << endmsg;
4415 if (!ARDOUR_UI::instance()->video_timeline->check_server_docroot()) {
4416 delete video_server_process;
4417 video_server_process = 0;
4425 ARDOUR_UI::add_video (Gtk::Window* float_window)
4431 if (!start_video_server(float_window, false)) {
4432 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4437 add_video_dialog->set_transient_for (*float_window);
4440 if (add_video_dialog->is_visible()) {
4441 /* we're already doing this */
4445 ResponseType r = (ResponseType) add_video_dialog->run ();
4446 add_video_dialog->hide();
4447 if (r != RESPONSE_ACCEPT) { return; }
4449 bool local_file, orig_local_file;
4450 std::string path = add_video_dialog->file_name(local_file);
4452 std::string orig_path = path;
4453 orig_local_file = local_file;
4455 bool auto_set_session_fps = add_video_dialog->auto_set_session_fps();
4457 if (local_file && !Glib::file_test(path, Glib::FILE_TEST_EXISTS)) {
4458 warning << string_compose(_("could not open %1"), path) << endmsg;
4461 if (!local_file && path.length() == 0) {
4462 warning << _("no video-file selected") << endmsg;
4466 std::string audio_from_video;
4467 bool detect_ltc = false;
4469 switch (add_video_dialog->import_option()) {
4470 case VTL_IMPORT_TRANSCODE:
4472 TranscodeVideoDialog *transcode_video_dialog;
4473 transcode_video_dialog = new TranscodeVideoDialog (_session, path);
4474 ResponseType r = (ResponseType) transcode_video_dialog->run ();
4475 transcode_video_dialog->hide();
4476 if (r != RESPONSE_ACCEPT) {
4477 delete transcode_video_dialog;
4481 audio_from_video = transcode_video_dialog->get_audiofile();
4483 if (!audio_from_video.empty() && transcode_video_dialog->detect_ltc()) {
4486 else if (!audio_from_video.empty()) {
4487 editor->embed_audio_from_video(
4489 video_timeline->get_offset(),
4490 (transcode_video_dialog->import_option() != VTL_IMPORT_NO_VIDEO)
4493 switch (transcode_video_dialog->import_option()) {
4494 case VTL_IMPORT_TRANSCODED:
4495 path = transcode_video_dialog->get_filename();
4498 case VTL_IMPORT_REFERENCE:
4501 delete transcode_video_dialog;
4504 delete transcode_video_dialog;
4508 case VTL_IMPORT_NONE:
4512 /* strip _session->session_directory().video_path() from video file if possible */
4513 if (local_file && !path.compare(0, _session->session_directory().video_path().size(), _session->session_directory().video_path())) {
4514 path=path.substr(_session->session_directory().video_path().size());
4515 if (path.at(0) == G_DIR_SEPARATOR) {
4516 path=path.substr(1);
4520 video_timeline->set_update_session_fps(auto_set_session_fps);
4522 if (video_timeline->video_file_info(path, local_file)) {
4523 XMLNode* node = new XMLNode(X_("Videotimeline"));
4524 node->add_property (X_("Filename"), path);
4525 node->add_property (X_("AutoFPS"), auto_set_session_fps?X_("1"):X_("0"));
4526 node->add_property (X_("LocalFile"), local_file?X_("1"):X_("0"));
4527 if (orig_local_file) {
4528 node->add_property (X_("OriginalVideoFile"), orig_path);
4530 node->remove_property (X_("OriginalVideoFile"));
4532 _session->add_extra_xml (*node);
4533 _session->set_dirty ();
4535 if (!audio_from_video.empty() && detect_ltc) {
4536 std::vector<LTCFileReader::LTCMap> ltc_seq;
4539 /* TODO ask user about TV standard (LTC alignment if any) */
4540 LTCFileReader ltcr (audio_from_video, video_timeline->get_video_file_fps());
4541 /* TODO ASK user which channel: 0 .. ltcr->channels() - 1 */
4543 ltc_seq = ltcr.read_ltc (/*channel*/ 0, /*max LTC frames to decode*/ 15);
4545 /* TODO seek near end of file, and read LTC until end.
4546 * if it fails to find any LTC frames, scan complete file
4548 * calculate drift of LTC compared to video-duration,
4549 * ask user for reference (timecode from start/mid/end)
4552 // LTCFileReader will have written error messages
4555 ::g_unlink(audio_from_video.c_str());
4557 if (ltc_seq.size() == 0) {
4558 PBD::error << _("No LTC detected, video will not be aligned.") << endmsg;
4560 /* the very first TC in the file is somteimes not aligned properly */
4561 int i = ltc_seq.size() -1;
4562 ARDOUR::frameoffset_t video_start_offset =
4563 _session->nominal_frame_rate() * (ltc_seq[i].timecode_sec - ltc_seq[i].framepos_sec);
4564 PBD::info << string_compose (_("Align video-start to %1 [samples]"), video_start_offset) << endmsg;
4565 video_timeline->set_offset(video_start_offset);
4569 _session->maybe_update_session_range(
4570 std::max(video_timeline->get_offset(), (ARDOUR::frameoffset_t) 0),
4571 std::max(video_timeline->get_offset() + video_timeline->get_duration(), (ARDOUR::frameoffset_t) 0));
4574 if (add_video_dialog->launch_xjadeo() && local_file) {
4575 editor->set_xjadeo_sensitive(true);
4576 editor->toggle_xjadeo_proc(1);
4578 editor->toggle_xjadeo_proc(0);
4580 editor->toggle_ruler_video(true);
4585 ARDOUR_UI::remove_video ()
4587 video_timeline->close_session();
4588 editor->toggle_ruler_video(false);
4591 video_timeline->set_offset_locked(false);
4592 video_timeline->set_offset(0);
4594 /* delete session state */
4595 XMLNode* node = new XMLNode(X_("Videotimeline"));
4596 _session->add_extra_xml(*node);
4597 node = new XMLNode(X_("Videomonitor"));
4598 _session->add_extra_xml(*node);
4599 node = new XMLNode(X_("Videoexport"));
4600 _session->add_extra_xml(*node);
4601 stop_video_server();
4605 ARDOUR_UI::flush_videotimeline_cache (bool localcacheonly)
4607 if (localcacheonly) {
4608 video_timeline->vmon_update();
4610 video_timeline->flush_cache();
4612 editor->queue_visual_videotimeline_update();
4616 ARDOUR_UI::export_video (bool range)
4618 if (ARDOUR::Config->get_show_video_export_info()) {
4619 ExportVideoInfobox infobox (_session);
4620 Gtk::ResponseType rv = (Gtk::ResponseType) infobox.run();
4621 if (infobox.show_again()) {
4622 ARDOUR::Config->set_show_video_export_info(false);
4625 case GTK_RESPONSE_YES:
4626 PBD::open_uri (ARDOUR::Config->get_reference_manual_url() + "/video-timeline/operations/#export");
4632 export_video_dialog->set_session (_session);
4633 export_video_dialog->apply_state(editor->get_selection().time, range);
4634 export_video_dialog->run ();
4635 export_video_dialog->hide ();
4639 ARDOUR_UI::preferences_settings () const
4644 node = _session->instant_xml(X_("Preferences"));
4646 node = Config->instant_xml(X_("Preferences"));
4650 node = new XMLNode (X_("Preferences"));
4657 ARDOUR_UI::mixer_settings () const
4662 node = _session->instant_xml(X_("Mixer"));
4664 node = Config->instant_xml(X_("Mixer"));
4668 node = new XMLNode (X_("Mixer"));
4675 ARDOUR_UI::main_window_settings () const
4680 node = _session->instant_xml(X_("Main"));
4682 node = Config->instant_xml(X_("Main"));
4686 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4687 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4692 node = new XMLNode (X_("Main"));
4699 ARDOUR_UI::editor_settings () const
4704 node = _session->instant_xml(X_("Editor"));
4706 node = Config->instant_xml(X_("Editor"));
4710 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4711 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4716 node = new XMLNode (X_("Editor"));
4723 ARDOUR_UI::keyboard_settings () const
4727 node = Config->extra_xml(X_("Keyboard"));
4730 node = new XMLNode (X_("Keyboard"));
4737 ARDOUR_UI::create_xrun_marker (framepos_t where)
4740 Location *location = new Location (*_session, where, where, _("xrun"), Location::IsMark);
4741 _session->locations()->add (location);
4746 ARDOUR_UI::halt_on_xrun_message ()
4748 cerr << "HALT on xrun\n";
4749 MessageDialog msg (_main_window, _("Recording was stopped because your system could not keep up."));
4754 ARDOUR_UI::xrun_handler (framepos_t where)
4760 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
4762 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
4763 create_xrun_marker(where);
4766 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
4767 halt_on_xrun_message ();
4772 ARDOUR_UI::disk_overrun_handler ()
4774 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
4776 if (!have_disk_speed_dialog_displayed) {
4777 have_disk_speed_dialog_displayed = true;
4778 MessageDialog* msg = new MessageDialog (_main_window, string_compose (_("\
4779 The disk system on your computer\n\
4780 was not able to keep up with %1.\n\
4782 Specifically, it failed to write data to disk\n\
4783 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
4784 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4790 /* TODO: this is getting elaborate enough to warrant being split into a dedicated class */
4791 static MessageDialog *scan_dlg = NULL;
4792 static ProgressBar *scan_pbar = NULL;
4793 static HBox *scan_tbox = NULL;
4794 static Gtk::Button *scan_timeout_button;
4797 ARDOUR_UI::cancel_plugin_scan ()
4799 PluginManager::instance().cancel_plugin_scan();
4803 ARDOUR_UI::cancel_plugin_timeout ()
4805 PluginManager::instance().cancel_plugin_timeout();
4806 scan_timeout_button->set_sensitive (false);
4810 ARDOUR_UI::plugin_scan_timeout (int timeout)
4812 if (!scan_dlg || !scan_dlg->is_mapped() || !scan_pbar) {
4816 scan_pbar->set_sensitive (false);
4817 scan_timeout_button->set_sensitive (true);
4818 scan_pbar->set_fraction ((float) timeout / (float) Config->get_vst_scan_timeout());
4821 scan_pbar->set_sensitive (false);
4822 scan_timeout_button->set_sensitive (false);
4828 ARDOUR_UI::plugin_scan_dialog (std::string type, std::string plugin, bool can_cancel)
4830 if (type == X_("closeme") && !(scan_dlg && scan_dlg->is_mapped())) {
4834 const bool cancelled = PluginManager::instance().cancelled();
4835 if (type != X_("closeme") && (!UIConfiguration::instance().get_show_plugin_scan_window()) && !_initial_verbose_plugin_scan) {
4836 if (cancelled && scan_dlg->is_mapped()) {
4841 if (cancelled || !can_cancel) {
4846 static Gtk::Button *cancel_button;
4848 scan_dlg = new MessageDialog("", false, MESSAGE_INFO, BUTTONS_NONE); // TODO manage
4849 VBox* vbox = scan_dlg->get_vbox();
4850 vbox->set_size_request(400,-1);
4851 scan_dlg->set_title (_("Scanning for plugins"));
4853 cancel_button = manage(new Gtk::Button(_("Cancel plugin scan")));
4854 cancel_button->set_name ("EditorGTKButton");
4855 cancel_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_scan) );
4856 cancel_button->show();
4858 scan_dlg->get_vbox()->pack_start ( *cancel_button, PACK_SHRINK);
4860 scan_tbox = manage( new HBox() );
4862 scan_timeout_button = manage(new Gtk::Button(_("Stop Timeout")));
4863 scan_timeout_button->set_name ("EditorGTKButton");
4864 scan_timeout_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_timeout) );
4865 scan_timeout_button->show();
4867 scan_pbar = manage(new ProgressBar());
4868 scan_pbar->set_orientation(Gtk::PROGRESS_RIGHT_TO_LEFT);
4869 scan_pbar->set_text(_("Scan Timeout"));
4872 scan_tbox->pack_start (*scan_pbar, PACK_EXPAND_WIDGET, 4);
4873 scan_tbox->pack_start (*scan_timeout_button, PACK_SHRINK, 4);
4875 scan_dlg->get_vbox()->pack_start (*scan_tbox, PACK_SHRINK, 4);
4878 assert(scan_dlg && scan_tbox && cancel_button);
4880 if (type == X_("closeme")) {
4884 scan_dlg->set_message(type + ": " + Glib::path_get_basename(plugin));
4887 if (!can_cancel || !cancelled) {
4888 scan_timeout_button->set_sensitive(false);
4890 cancel_button->set_sensitive(can_cancel && !cancelled);
4896 ARDOUR_UI::gui_idle_handler ()
4899 /* due to idle calls, gtk_events_pending() may always return true */
4900 while (gtk_events_pending() && --timeout) {
4901 gtk_main_iteration ();
4906 ARDOUR_UI::disk_underrun_handler ()
4908 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
4910 if (!have_disk_speed_dialog_displayed) {
4911 have_disk_speed_dialog_displayed = true;
4912 MessageDialog* msg = new MessageDialog (
4913 _main_window, string_compose (_("The disk system on your computer\n\
4914 was not able to keep up with %1.\n\
4916 Specifically, it failed to read data from disk\n\
4917 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
4918 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4924 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
4926 have_disk_speed_dialog_displayed = false;
4931 ARDOUR_UI::session_dialog (std::string msg)
4933 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
4937 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
4944 ARDOUR_UI::pending_state_dialog ()
4946 HBox* hbox = manage (new HBox());
4947 Image* image = manage (new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG));
4948 ArdourDialog dialog (_("Crash Recovery"), true);
4949 Label message (string_compose (_("\
4950 This session appears to have been in the\n\
4951 middle of recording when %1 or\n\
4952 the computer was shutdown.\n\
4954 %1 can recover any captured audio for\n\
4955 you, or it can ignore it. Please decide\n\
4956 what you would like to do.\n"), PROGRAM_NAME));
4957 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4958 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4959 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4960 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4961 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
4962 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
4963 dialog.set_default_response (RESPONSE_ACCEPT);
4964 dialog.set_position (WIN_POS_CENTER);
4969 switch (dialog.run ()) {
4970 case RESPONSE_ACCEPT:
4978 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
4980 HBox* hbox = new HBox();
4981 Image* image = new Image (Stock::DIALOG_WARNING, ICON_SIZE_DIALOG);
4982 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
4983 Label message (string_compose (_("\
4984 This session was created with a sample rate of %1 Hz, but\n\
4985 %2 is currently running at %3 Hz. If you load this session,\n\
4986 audio may be played at the wrong sample rate.\n"), desired, PROGRAM_NAME, actual));
4988 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4989 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4990 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4991 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4992 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
4993 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
4994 dialog.set_default_response (RESPONSE_ACCEPT);
4995 dialog.set_position (WIN_POS_CENTER);
5000 switch (dialog.run()) {
5001 case RESPONSE_ACCEPT:
5011 ARDOUR_UI::sr_mismatch_message (framecnt_t desired, framecnt_t actual)
5013 MessageDialog msg (string_compose (_("\
5014 This session was created with a sample rate of %1 Hz, but\n\
5015 %2 is currently running at %3 Hz.\n\
5016 Audio will be recorded and played at the wrong sample rate.\n\
5017 Re-Configure the Audio Engine in\n\
5018 Menu > Window > Audio/Midi Setup"),
5019 desired, PROGRAM_NAME, actual),
5021 Gtk::MESSAGE_WARNING);
5026 ARDOUR_UI::use_config ()
5028 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
5030 set_transport_controllable_state (*node);
5035 ARDOUR_UI::update_transport_clocks (framepos_t pos)
5037 if (UIConfiguration::instance().get_primary_clock_delta_edit_cursor()) {
5038 primary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
5040 primary_clock->set (pos);
5043 if (UIConfiguration::instance().get_secondary_clock_delta_edit_cursor()) {
5044 secondary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
5046 secondary_clock->set (pos);
5049 if (big_clock_window) {
5050 big_clock->set (pos);
5052 ARDOUR_UI::instance()->video_timeline->manual_seek_video_monitor(pos);
5056 ARDOUR_UI::step_edit_status_change (bool yn)
5058 // XXX should really store pre-step edit status of things
5059 // we make insensitive
5062 rec_button.set_active_state (Gtkmm2ext::ImplicitActive);
5063 rec_button.set_sensitive (false);
5065 rec_button.unset_active_state ();;
5066 rec_button.set_sensitive (true);
5071 ARDOUR_UI::record_state_changed ()
5073 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
5076 /* why bother - the clock isn't visible */
5080 ActionManager::set_sensitive (ActionManager::rec_sensitive_actions, !_session->actively_recording());
5082 if (big_clock_window) {
5083 if (_session->record_status () == Session::Recording && _session->have_rec_enabled_track ()) {
5084 big_clock->set_active (true);
5086 big_clock->set_active (false);
5093 ARDOUR_UI::first_idle ()
5096 _session->allow_auto_play (true);
5100 editor->first_idle();
5103 Keyboard::set_can_save_keybindings (true);
5108 ARDOUR_UI::store_clock_modes ()
5110 XMLNode* node = new XMLNode(X_("ClockModes"));
5112 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
5113 XMLNode* child = new XMLNode (X_("Clock"));
5115 child->add_property (X_("name"), (*x)->name());
5116 child->add_property (X_("mode"), enum_2_string ((*x)->mode()));
5117 child->add_property (X_("on"), ((*x)->off() ? X_("no") : X_("yes")));
5119 node->add_child_nocopy (*child);
5122 _session->add_extra_xml (*node);
5123 _session->set_dirty ();
5126 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
5127 : Controllable (name), ui (u), type(tp)
5133 ARDOUR_UI::TransportControllable::set_value (double val, PBD::Controllable::GroupControlDisposition /*group_override*/)
5136 /* do nothing: these are radio-style actions */
5140 const char *action = 0;
5144 action = X_("Roll");
5147 action = X_("Stop");
5150 action = X_("GotoStart");
5153 action = X_("GotoEnd");
5156 action = X_("Loop");
5159 action = X_("PlaySelection");
5162 action = X_("Record");
5172 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
5180 ARDOUR_UI::TransportControllable::get_value (void) const
5207 ARDOUR_UI::setup_profile ()
5209 if (gdk_screen_width() < 1200 || getenv ("ARDOUR_NARROW_SCREEN")) {
5210 Profile->set_small_screen ();
5213 if (g_getenv ("TRX")) {
5214 Profile->set_trx ();
5217 if (g_getenv ("MIXBUS")) {
5218 Profile->set_mixbus ();
5223 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
5225 MissingFileDialog dialog (s, str, type);
5230 int result = dialog.run ();
5237 return 1; // quit entire session load
5240 result = dialog.get_action ();
5246 ARDOUR_UI::ambiguous_file (std::string file, std::vector<std::string> hits)
5248 AmbiguousFileDialog dialog (file, hits);
5255 return dialog.get_which ();
5258 /** Allocate our thread-local buffers */
5260 ARDOUR_UI::get_process_buffers ()
5262 _process_thread->get_buffers ();
5265 /** Drop our thread-local buffers */
5267 ARDOUR_UI::drop_process_buffers ()
5269 _process_thread->drop_buffers ();
5273 ARDOUR_UI::feedback_detected ()
5275 _feedback_exists = true;
5279 ARDOUR_UI::successful_graph_sort ()
5281 _feedback_exists = false;
5285 ARDOUR_UI::midi_panic ()
5288 _session->midi_panic();
5293 ARDOUR_UI::session_format_mismatch (std::string xml_path, std::string backup_path)
5295 const char* start_big = "<span size=\"x-large\" weight=\"bold\">";
5296 const char* end_big = "</span>";
5297 const char* start_mono = "<tt>";
5298 const char* end_mono = "</tt>";
5300 MessageDialog msg (string_compose (_("%4This is a session from an older version of %3%5\n\n"
5301 "%3 has copied the old session file\n\n%6%1%7\n\nto\n\n%6%2%7\n\n"
5302 "From now on, use the backup copy with older versions of %3"),
5303 xml_path, backup_path, PROGRAM_NAME,
5305 start_mono, end_mono), true);
5312 ARDOUR_UI::reset_peak_display ()
5314 if (!_session || !_session->master_out() || !editor_meter) return;
5315 editor_meter->clear_meters();
5316 editor_meter_max_peak = -INFINITY;
5317 editor_meter_peak_display.set_active_state ( Gtkmm2ext::Off );
5321 ARDOUR_UI::reset_group_peak_display (RouteGroup* group)
5323 if (!_session || !_session->master_out()) return;
5324 if (group == _session->master_out()->route_group()) {
5325 reset_peak_display ();
5330 ARDOUR_UI::reset_route_peak_display (Route* route)
5332 if (!_session || !_session->master_out()) return;
5333 if (_session->master_out().get() == route) {
5334 reset_peak_display ();
5339 ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate)
5341 audio_midi_setup->set_desired_sample_rate (desired_sample_rate);
5342 audio_midi_setup->set_position (WIN_POS_CENTER);
5344 if (Config->get_try_autostart_engine () || getenv ("TRY_AUTOSTART_ENGINE")) {
5345 audio_midi_setup->try_autostart ();
5346 if (ARDOUR::AudioEngine::instance()->running()) {
5352 int response = audio_midi_setup->run();
5353 printf("RESPONSE %d\n", response);
5355 case Gtk::RESPONSE_DELETE_EVENT:
5358 if (!AudioEngine::instance()->running()) {
5361 audio_midi_setup->hide ();
5369 ARDOUR_UI::transport_numpad_timeout ()
5371 _numpad_locate_happening = false;
5372 if (_numpad_timeout_connection.connected() )
5373 _numpad_timeout_connection.disconnect();
5378 ARDOUR_UI::transport_numpad_decimal ()
5380 _numpad_timeout_connection.disconnect();
5382 if (_numpad_locate_happening) {
5383 if (editor) editor->goto_nth_marker(_pending_locate_num - 1);
5384 _numpad_locate_happening = false;
5386 _pending_locate_num = 0;
5387 _numpad_locate_happening = true;
5388 _numpad_timeout_connection = Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::transport_numpad_timeout), 2*1000);
5393 ARDOUR_UI::transport_numpad_event (int num)
5395 if ( _numpad_locate_happening ) {
5396 _pending_locate_num = _pending_locate_num*10 + num;
5399 case 0: toggle_roll(false, false); break;
5400 case 1: transport_rewind(1); break;
5401 case 2: transport_forward(1); break;
5402 case 3: transport_record(true); break;
5403 case 4: toggle_session_auto_loop(); break;
5404 case 5: transport_record(false); toggle_session_auto_loop(); break;
5405 case 6: toggle_punch(); break;
5406 case 7: toggle_click(); break;
5407 case 8: toggle_auto_return(); break;
5408 case 9: toggle_follow_edits(); break;
5414 ARDOUR_UI::set_flat_buttons ()
5416 CairoWidget::set_flat_buttons( UIConfiguration::instance().get_flat_buttons() );
5420 ARDOUR_UI::audioengine_became_silent ()
5422 MessageDialog msg (string_compose (_("This is a free/demo copy of %1. It has just switched to silent mode."), PROGRAM_NAME),
5424 Gtk::MESSAGE_WARNING,
5428 msg.set_title (string_compose (_("%1 is now silent"), PROGRAM_NAME));
5430 Gtk::Label pay_label (string_compose (_("Please consider paying for a copy of %1 - you can pay whatever you want."), PROGRAM_NAME));
5431 Gtk::Label subscribe_label (_("Better yet become a subscriber - subscriptions start at US$1 per month."));
5432 Gtk::Button pay_button (_("Pay for a copy (via the web)"));
5433 Gtk::Button subscribe_button (_("Become a subscriber (via the web)"));
5434 Gtk::HBox pay_button_box;
5435 Gtk::HBox subscribe_button_box;
5437 pay_button_box.pack_start (pay_button, true, false);
5438 subscribe_button_box.pack_start (subscribe_button, true, false);
5440 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 */
5442 pay_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://ardour.org/download")));
5443 subscribe_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://community.ardour.org/s/subscribe")));
5445 msg.get_vbox()->pack_start (pay_label);
5446 msg.get_vbox()->pack_start (pay_button_box);
5447 msg.get_vbox()->pack_start (subscribe_label);
5448 msg.get_vbox()->pack_start (subscribe_button_box);
5450 msg.get_vbox()->show_all ();
5452 msg.add_button (_("Remain silent"), Gtk::RESPONSE_CANCEL);
5453 msg.add_button (_("Save and quit"), Gtk::RESPONSE_NO);
5454 msg.add_button (_("Give me more time"), Gtk::RESPONSE_YES);
5459 case Gtk::RESPONSE_YES:
5460 AudioEngine::instance()->reset_silence_countdown ();
5463 case Gtk::RESPONSE_NO:
5465 save_state_canfail ("");
5469 case Gtk::RESPONSE_CANCEL:
5471 /* don't reset, save session and exit */
5477 ARDOUR_UI::hide_application ()
5479 Application::instance ()-> hide ();
5483 ARDOUR_UI::setup_toplevel_window (Gtk::Window& window, const string& name, void* owner)
5485 /* icons, titles, WM stuff */
5487 static list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
5489 if (window_icons.empty()) {
5490 Glib::RefPtr<Gdk::Pixbuf> icon;
5491 if ((icon = ::get_icon (PROGRAM_NAME "-icon_16px"))) {
5492 window_icons.push_back (icon);
5494 if ((icon = ::get_icon (PROGRAM_NAME "-icon_22px"))) {
5495 window_icons.push_back (icon);
5497 if ((icon = ::get_icon (PROGRAM_NAME "-icon_32px"))) {
5498 window_icons.push_back (icon);
5500 if ((icon = ::get_icon (PROGRAM_NAME "-icon_48px"))) {
5501 window_icons.push_back (icon);
5505 if (!window_icons.empty()) {
5506 window.set_default_icon_list (window_icons);
5509 Gtkmm2ext::WindowTitle title (Glib::get_application_name());
5511 if (!name.empty()) {
5515 window.set_title (title.get_string());
5516 window.set_wmclass (string_compose (X_("%1_%1"), downcase (PROGRAM_NAME), downcase (name)), PROGRAM_NAME);
5518 window.set_flags (CAN_FOCUS);
5519 window.add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
5521 /* This is a hack to ensure that GTK-accelerators continue to
5522 * work. Once we switch over to entirely native bindings, this will be
5523 * unnecessary and should be removed
5525 window.add_accel_group (ActionManager::ui_manager->get_accel_group());
5527 window.signal_configure_event().connect (sigc::mem_fun (*this, &ARDOUR_UI::configure_handler));
5528 window.signal_window_state_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::tabbed_window_state_event_handler), owner));
5529 window.signal_key_press_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5530 window.signal_key_release_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5534 ARDOUR_UI::key_event_handler (GdkEventKey* ev, Gtk::Window* event_window)
5536 Gtkmm2ext::Bindings* bindings = 0;
5537 Gtk::Window* window = 0;
5539 /* until we get ardour bindings working, we are not handling key
5543 if (ev->type != GDK_KEY_PRESS) {
5547 if (event_window == &_main_window) {
5549 window = event_window;
5551 /* find current tab contents */
5553 Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page());
5555 /* see if it uses the ardour binding system */
5558 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(w->get_data ("ardour-bindings"));
5561 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("main window key event, bindings = %1, global = %2\n", bindings, &global_bindings));
5565 window = event_window;
5567 /* see if window uses ardour binding system */
5569 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(window->get_data ("ardour-bindings"));
5572 /* An empty binding set is treated as if it doesn't exist */
5574 if (bindings && bindings->empty()) {
5578 return key_press_focus_accelerator_handler (*window, ev, bindings);
5581 static Gtkmm2ext::Bindings*
5582 get_bindings_from_widget_heirarchy (GtkWidget** w)
5587 if ((p = g_object_get_data (G_OBJECT(*w), "ardour-bindings")) != 0) {
5590 *w = gtk_widget_get_parent (*w);
5593 return reinterpret_cast<Gtkmm2ext::Bindings*> (p);
5597 ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev, Gtkmm2ext::Bindings* bindings)
5599 GtkWindow* win = window.gobj();
5600 GtkWidget* focus = gtk_window_get_focus (win);
5601 GtkWidget* binding_widget = focus;
5602 bool special_handling_of_unmodified_accelerators = false;
5603 const guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK));
5607 /* some widget has keyboard focus */
5609 if (GTK_IS_ENTRY(focus) || Keyboard::some_magic_widget_has_focus()) {
5611 /* A particular kind of focusable widget currently has keyboard
5612 * focus. All unmodified key events should go to that widget
5613 * first and not be used as an accelerator by default
5616 special_handling_of_unmodified_accelerators = true;
5620 Gtkmm2ext::Bindings* focus_bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5621 if (focus_bindings) {
5622 bindings = focus_bindings;
5623 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Switch bindings based on focus widget, now using %1\n", bindings->name()));
5628 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",
5631 Gtkmm2ext::show_gdk_event_state (ev->state),
5632 special_handling_of_unmodified_accelerators,
5633 Keyboard::some_magic_widget_has_focus(),
5635 (focus ? gtk_widget_get_name (focus) : "no focus widget"),
5636 ((ev->state & mask) ? "yes" : "no"),
5637 window.get_title()));
5639 /* This exists to allow us to override the way GTK handles
5640 key events. The normal sequence is:
5642 a) event is delivered to a GtkWindow
5643 b) accelerators/mnemonics are activated
5644 c) if (b) didn't handle the event, propagate to
5645 the focus widget and/or focus chain
5647 The problem with this is that if the accelerators include
5648 keys without modifiers, such as the space bar or the
5649 letter "e", then pressing the key while typing into
5650 a text entry widget results in the accelerator being
5651 activated, instead of the desired letter appearing
5654 There is no good way of fixing this, but this
5655 represents a compromise. The idea is that
5656 key events involving modifiers (not Shift)
5657 get routed into the activation pathway first, then
5658 get propagated to the focus widget if necessary.
5660 If the key event doesn't involve modifiers,
5661 we deliver to the focus widget first, thus allowing
5662 it to get "normal text" without interference
5665 Of course, this can also be problematic: if there
5666 is a widget with focus, then it will swallow
5667 all "normal text" accelerators.
5671 if (!special_handling_of_unmodified_accelerators || (ev->state & mask)) {
5673 /* no special handling or there are modifiers in effect: accelerate first */
5675 DEBUG_TRACE (DEBUG::Accelerators, "\tactivate, then propagate\n");
5676 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tevent send-event:%1 time:%2 length:%3 name %7 string:%4 hardware_keycode:%5 group:%6\n",
5677 ev->send_event, ev->time, ev->length, ev->string, ev->hardware_keycode, ev->group, gdk_keyval_name (ev->keyval)));
5679 DEBUG_TRACE (DEBUG::Accelerators, "\tsending to window\n");
5680 KeyboardKey k (ev->state, ev->keyval);
5684 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tusing Ardour bindings %1 @ %2 for this event\n", bindings->name(), bindings));
5686 if (bindings->activate (k, Bindings::Press)) {
5687 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5691 if (binding_widget) {
5692 binding_widget = gtk_widget_get_parent (binding_widget);
5693 if (binding_widget) {
5694 bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5703 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5705 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5706 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5710 DEBUG_TRACE (DEBUG::Accelerators, "\tnot accelerated, now propagate\n");
5712 if (gtk_window_propagate_key_event (win, ev)) {
5713 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate handled\n");
5719 /* no modifiers, propagate first */
5721 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate, then activate\n");
5723 if (gtk_window_propagate_key_event (win, ev)) {
5724 DEBUG_TRACE (DEBUG::Accelerators, "\thandled by propagate\n");
5728 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagation didn't handle, so activate\n");
5729 KeyboardKey k (ev->state, ev->keyval);
5733 DEBUG_TRACE (DEBUG::Accelerators, "\tusing Ardour bindings for this window\n");
5736 if (bindings->activate (k, Bindings::Press)) {
5737 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5741 if (binding_widget) {
5742 binding_widget = gtk_widget_get_parent (binding_widget);
5743 if (binding_widget) {
5744 bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5753 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5755 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5756 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5761 DEBUG_TRACE (DEBUG::Accelerators, "\tnot handled\n");
5766 ARDOUR_UI::load_bindings ()
5768 if ((global_bindings = Bindings::get_bindings (X_("Global"), global_actions)) == 0) {
5769 error << _("Global keybindings are missing") << endmsg;
5774 ARDOUR_UI::cancel_solo ()
5777 _session->cancel_all_solo ();
5782 ARDOUR_UI::reset_focus (Gtk::Widget* w)
5784 /* this resets focus to the first focusable parent of the given widget,
5785 * or, if there is no focusable parent, cancels focus in the toplevel
5786 * window that the given widget is packed into (if there is one).
5793 Gtk::Widget* top = w->get_toplevel();
5795 if (!top || !top->is_toplevel()) {
5799 w = w->get_parent ();
5803 if (w->is_toplevel()) {
5804 /* Setting the focus widget to a Gtk::Window causes all
5805 * subsequent calls to ::has_focus() on the nominal
5806 * focus widget in that window to return
5807 * false. Workaround: never set focus to the toplevel
5813 if (w->get_can_focus ()) {
5814 Gtk::Window* win = dynamic_cast<Gtk::Window*> (top);
5815 win->set_focus (*w);
5818 w = w->get_parent ();
5821 if (top == &_main_window) {
5825 /* no focusable parent found, cancel focus in top level window.
5826 C++ API cannot be used for this. Thanks, references.
5829 gtk_window_set_focus (GTK_WINDOW(top->gobj()), 0);