2 Copyright (C) 1999-2013 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include "gtk2ardour-config.h"
22 #include "gtk2ardour-version.h"
32 #ifndef PLATFORM_WINDOWS
33 #include <sys/resource.h>
37 #include <sys/types.h>
38 #include <sys/sysctl.h>
48 #include "pbd/gstdio_compat.h"
50 #include <gtkmm/messagedialog.h>
51 #include <gtkmm/accelmap.h>
52 #include <gtkmm/stock.h>
54 #include "pbd/error.h"
55 #include "pbd/basename.h"
56 #include "pbd/compose.h"
57 #include "pbd/convert.h"
58 #include "pbd/failed_constructor.h"
59 #include "pbd/file_archive.h"
60 #include "pbd/enumwriter.h"
61 #include "pbd/memento_command.h"
62 #include "pbd/openuri.h"
63 #include "pbd/stl_delete.h"
64 #include "pbd/file_utils.h"
65 #include "pbd/localtime_r.h"
66 #include "pbd/pthread_utils.h"
67 #include "pbd/replace_all.h"
68 #include "pbd/xml++.h"
70 #include "gtkmm2ext/application.h"
71 #include "gtkmm2ext/bindings.h"
72 #include "gtkmm2ext/gtk_ui.h"
73 #include "gtkmm2ext/utils.h"
74 #include "gtkmm2ext/click_box.h"
75 #include "gtkmm2ext/fastmeter.h"
76 #include "gtkmm2ext/popup.h"
77 #include "gtkmm2ext/window_title.h"
79 #include "ardour/ardour.h"
80 #include "ardour/audio_backend.h"
81 #include "ardour/audio_track.h"
82 #include "ardour/audioengine.h"
83 #include "ardour/audiofilesource.h"
84 #include "ardour/automation_watch.h"
85 #include "ardour/diskstream.h"
86 #include "ardour/filename_extensions.h"
87 #include "ardour/filesystem_paths.h"
88 #include "ardour/ltc_file_reader.h"
89 #include "ardour/midi_track.h"
90 #include "ardour/port.h"
91 #include "ardour/plugin_manager.h"
92 #include "ardour/process_thread.h"
93 #include "ardour/profile.h"
94 #include "ardour/recent_sessions.h"
95 #include "ardour/record_enable_control.h"
96 #include "ardour/session_directory.h"
97 #include "ardour/session_route.h"
98 #include "ardour/session_state_utils.h"
99 #include "ardour/session_utils.h"
100 #include "ardour/source_factory.h"
101 #include "ardour/slave.h"
102 #include "ardour/system_exec.h"
103 #include "ardour/track.h"
104 #include "ardour/vca_manager.h"
105 #include "ardour/utils.h"
107 #include "LuaBridge/LuaBridge.h"
109 #ifdef WINDOWS_VST_SUPPORT
112 #ifdef AUDIOUNIT_SUPPORT
113 #include "ardour/audio_unit.h"
116 // fix for OSX (nsm.h has a check function, AU/Apple defines check)
121 #include "timecode/time.h"
123 typedef uint64_t microseconds_t;
128 #include "add_route_dialog.h"
129 #include "ambiguous_file_dialog.h"
130 #include "ardour_ui.h"
131 #include "audio_clock.h"
132 #include "audio_region_view.h"
133 #include "big_clock_window.h"
134 #include "bundle_manager.h"
135 #include "duplicate_routes_dialog.h"
137 #include "engine_dialog.h"
138 #include "export_video_dialog.h"
139 #include "export_video_infobox.h"
140 #include "gain_meter.h"
141 #include "global_port_matrix.h"
142 #include "gui_object.h"
143 #include "gui_thread.h"
144 #include "keyboard.h"
145 #include "keyeditor.h"
146 #include "location_ui.h"
147 #include "lua_script_manager.h"
148 #include "luawindow.h"
149 #include "main_clock.h"
150 #include "missing_file_dialog.h"
151 #include "missing_plugin_dialog.h"
152 #include "mixer_ui.h"
153 #include "meterbridge.h"
154 #include "mouse_cursors.h"
157 #include "pingback.h"
158 #include "processor_box.h"
159 #include "prompter.h"
160 #include "public_editor.h"
161 #include "rc_option_editor.h"
162 #include "route_time_axis.h"
163 #include "route_params_ui.h"
164 #include "save_as_dialog.h"
165 #include "script_selector.h"
166 #include "session_archive_dialog.h"
167 #include "session_dialog.h"
168 #include "session_metadata_dialog.h"
169 #include "session_option_editor.h"
170 #include "speaker_dialog.h"
173 #include "theme_manager.h"
174 #include "time_axis_view_item.h"
175 #include "time_info_box.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))
283 , auto_return_button (ArdourButton::led_default_elements)
284 , follow_edits_button (ArdourButton::led_default_elements)
285 , auto_input_button (ArdourButton::led_default_elements)
286 , auditioning_alert_button (_("Audition"))
287 , solo_alert_button (_("Solo"))
288 , feedback_alert_button (_("Feedback"))
289 , error_alert_button ( ArdourButton::just_led_default_elements )
291 , editor_meter_peak_display()
292 , _numpad_locate_happening (false)
293 , _session_is_new (false)
294 , last_key_press_time (0)
298 , rc_option_editor (0)
299 , speaker_config_window (X_("speaker-config"), _("Speaker Configuration"))
300 , add_route_dialog (X_("add-routes"), _("Add Tracks/Busses"))
301 , about (X_("about"), _("About"))
302 , location_ui (X_("locations"), S_("Ranges|Locations"))
303 , route_params (X_("inspector"), _("Tracks and Busses"))
304 , audio_midi_setup (X_("audio-midi-setup"), _("Audio/MIDI Setup"))
305 , export_video_dialog (X_("video-export"), _("Video Export Dialog"))
306 , lua_script_window (X_("script-manager"), _("Script Manager"))
307 , session_option_editor (X_("session-options-editor"), _("Properties"), boost::bind (&ARDOUR_UI::create_session_option_editor, this))
308 , add_video_dialog (X_("add-video"), _("Add Video"), boost::bind (&ARDOUR_UI::create_add_video_dialog, this))
309 , bundle_manager (X_("bundle-manager"), _("Bundle Manager"), boost::bind (&ARDOUR_UI::create_bundle_manager, this))
310 , big_clock_window (X_("big-clock"), _("Big Clock"), boost::bind (&ARDOUR_UI::create_big_clock_window, this))
311 , audio_port_matrix (X_("audio-connection-manager"), _("Audio Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::AUDIO))
312 , midi_port_matrix (X_("midi-connection-manager"), _("MIDI Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::MIDI))
313 , key_editor (X_("key-editor"), _("Bindings Editor"), boost::bind (&ARDOUR_UI::create_key_editor, this))
314 , video_server_process (0)
316 , have_configure_timeout (false)
317 , last_configure_time (0)
319 , have_disk_speed_dialog_displayed (false)
320 , _status_bar_visibility (X_("status-bar"))
321 , _feedback_exists (false)
322 , _log_not_acknowledged (LogLevelNone)
323 , duplicate_routes_dialog (0)
324 , editor_visibility_button (S_("Window|Editor"))
325 , mixer_visibility_button (S_("Window|Mixer"))
326 , prefs_visibility_button (S_("Window|Preferences"))
328 Gtkmm2ext::init (localedir);
330 UIConfiguration::instance().post_gui_init ();
332 if (ARDOUR::handle_old_configuration_files (boost::bind (ask_about_configuration_copy, _1, _2, _3))) {
333 MessageDialog msg (string_compose (_("Your configuration files were copied. You can now restart %1."), PROGRAM_NAME), true);
335 /* configuration was modified, exit immediately */
340 if (string (VERSIONSTRING).find (".pre") != string::npos) {
341 /* check this is not being run from ./ardev etc. */
342 if (!running_from_source_tree ()) {
343 pre_release_dialog ();
347 if (theArdourUI == 0) {
351 /* track main window visibility */
353 main_window_visibility = new VisibilityTracker (_main_window);
355 /* stop libxml from spewing to stdout/stderr */
357 xmlSetGenericErrorFunc (this, libxml_generic_error_func);
358 xmlSetStructuredErrorFunc (this, libxml_structured_error_func);
360 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::parameter_changed));
361 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
362 UIConfiguration::instance().map_parameters (pc);
364 roll_button.set_controllable (roll_controllable);
365 stop_button.set_controllable (stop_controllable);
366 goto_start_button.set_controllable (goto_start_controllable);
367 goto_end_button.set_controllable (goto_end_controllable);
368 auto_loop_button.set_controllable (auto_loop_controllable);
369 play_selection_button.set_controllable (play_selection_controllable);
370 rec_button.set_controllable (rec_controllable);
372 roll_button.set_name ("transport button");
373 stop_button.set_name ("transport button");
374 goto_start_button.set_name ("transport button");
375 goto_end_button.set_name ("transport button");
376 auto_loop_button.set_name ("transport button");
377 play_selection_button.set_name ("transport button");
378 rec_button.set_name ("transport recenable button");
379 midi_panic_button.set_name ("transport button");
381 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
382 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
384 ARDOUR::Session::VersionMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_format_mismatch, this, _1, _2), gui_context());
386 /* handle dialog requests */
388 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
390 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
392 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
394 /* handle Audio/MIDI setup when session requires it */
396 ARDOUR::Session::AudioEngineSetupRequired.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::do_audio_midi_setup, this, _1));
398 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
400 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
402 /* handle sr mismatch with a dialog - cross-thread from engine */
403 ARDOUR::Session::NotifyAboutSampleRateMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::sr_mismatch_message, this, _1, _2), gui_context ());
405 /* handle requests to quit (coming from JACK session) */
407 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::finish, this), gui_context ());
409 /* tell the user about feedback */
411 ARDOUR::Session::FeedbackDetected.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::feedback_detected, this), gui_context ());
412 ARDOUR::Session::SuccessfulGraphSort.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::successful_graph_sort, this), gui_context ());
414 /* handle requests to deal with missing files */
416 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
418 /* and ambiguous files */
420 ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2));
422 /* also plugin scan messages */
423 ARDOUR::PluginScanMessage.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_dialog, this, _1, _2, _3), gui_context());
424 ARDOUR::PluginScanTimeout.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_timeout, this, _1), gui_context());
426 ARDOUR::GUIIdle.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::gui_idle_handler, this), gui_context());
428 Config->ParameterChanged.connect ( forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::set_flat_buttons, this), gui_context() );
431 /* lets get this party started */
433 setup_gtk_ardour_enums ();
436 SessionEvent::create_per_thread_pool ("GUI", 4096);
438 /* we like keyboards */
440 keyboard = new ArdourKeyboard(*this);
442 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
444 keyboard->set_state (*node, Stateful::loading_state_version);
447 UIConfiguration::instance().reset_dpi ();
449 TimeAxisViewItem::set_constant_heights ();
451 /* Set this up so that our window proxies can register actions */
453 ActionManager::init ();
455 /* The following must happen after ARDOUR::init() so that Config is set up */
457 const XMLNode* ui_xml = Config->extra_xml (X_("UI"));
460 key_editor.set_state (*ui_xml, 0);
461 session_option_editor.set_state (*ui_xml, 0);
462 speaker_config_window.set_state (*ui_xml, 0);
463 about.set_state (*ui_xml, 0);
464 add_route_dialog.set_state (*ui_xml, 0);
465 add_video_dialog.set_state (*ui_xml, 0);
466 route_params.set_state (*ui_xml, 0);
467 bundle_manager.set_state (*ui_xml, 0);
468 location_ui.set_state (*ui_xml, 0);
469 big_clock_window.set_state (*ui_xml, 0);
470 audio_port_matrix.set_state (*ui_xml, 0);
471 midi_port_matrix.set_state (*ui_xml, 0);
472 export_video_dialog.set_state (*ui_xml, 0);
473 lua_script_window.set_state (*ui_xml, 0);
476 /* Separate windows */
478 WM::Manager::instance().register_window (&key_editor);
479 WM::Manager::instance().register_window (&session_option_editor);
480 WM::Manager::instance().register_window (&speaker_config_window);
481 WM::Manager::instance().register_window (&about);
482 WM::Manager::instance().register_window (&add_route_dialog);
483 WM::Manager::instance().register_window (&add_video_dialog);
484 WM::Manager::instance().register_window (&route_params);
485 WM::Manager::instance().register_window (&audio_midi_setup);
486 WM::Manager::instance().register_window (&export_video_dialog);
487 WM::Manager::instance().register_window (&lua_script_window);
488 WM::Manager::instance().register_window (&bundle_manager);
489 WM::Manager::instance().register_window (&location_ui);
490 WM::Manager::instance().register_window (&big_clock_window);
491 WM::Manager::instance().register_window (&audio_port_matrix);
492 WM::Manager::instance().register_window (&midi_port_matrix);
494 /* do not retain position for add route dialog */
495 add_route_dialog.set_state_mask (WindowProxy::Size);
497 /* Trigger setting up the color scheme and loading the GTK RC file */
499 UIConfiguration::instance().load_rc_file (false);
501 _process_thread = new ProcessThread ();
502 _process_thread->init ();
504 UIConfiguration::instance().DPIReset.connect (sigc::mem_fun (*this, &ARDOUR_UI::resize_text_widgets));
510 ARDOUR_UI::pre_release_dialog ()
512 ArdourDialog d (_("Pre-Release Warning"), true, false);
513 d.add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
515 Label* label = manage (new Label);
516 label->set_markup (string_compose (_("<b>Welcome to this pre-release build of %1 %2</b>\n\n\
517 There are still several issues and bugs to be worked on,\n\
518 as well as general workflow improvements, before this can be considered\n\
519 release software. So, a few guidelines:\n\
521 1) Please do <b>NOT</b> use this software with the expectation that it is stable or reliable\n\
522 though it may be so, depending on your workflow.\n\
523 2) Please wait for a helpful writeup of new features.\n\
524 3) <b>Please do NOT use the forums at ardour.org to report issues</b>.\n\
525 4) Please <b>DO</b> use the bugtracker at http://tracker.ardour.org/ to report issues\n\
526 making sure to note the product version number as 5.0-pre.\n\
527 5) Please <b>DO</b> use the ardour-users mailing list to discuss ideas and pass on comments.\n\
528 6) Please <b>DO</b> join us on IRC for real time discussions about %1 %2. You\n\
529 can get there directly from within the program via the Help->Chat menu option.\n\
531 Full information on all the above can be found on the support page at\n\
533 http://ardour.org/support\n\
534 "), PROGRAM_NAME, VERSIONSTRING));
536 d.get_vbox()->set_border_width (12);
537 d.get_vbox()->pack_start (*label, false, false, 12);
538 d.get_vbox()->show_all ();
543 GlobalPortMatrixWindow*
544 ARDOUR_UI::create_global_port_matrix (ARDOUR::DataType type)
549 return new GlobalPortMatrixWindow (_session, type);
553 ARDOUR_UI::attach_to_engine ()
555 AudioEngine::instance()->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
556 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
560 ARDOUR_UI::engine_stopped ()
562 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
563 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
564 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
565 update_sample_rate (0);
570 ARDOUR_UI::engine_running ()
572 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
573 if (first_time_engine_run) {
575 first_time_engine_run = false;
579 _session->reset_xrun_count ();
581 update_disk_space ();
583 update_xrun_count ();
584 update_sample_rate (AudioEngine::instance()->sample_rate());
585 update_timecode_format ();
586 update_peak_thread_work ();
587 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, true);
588 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, false);
592 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
594 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
595 /* we can't rely on the original string continuing to exist when we are called
596 again in the GUI thread, so make a copy and note that we need to
599 char *copy = strdup (reason);
600 Gtkmm2ext::UI::instance()->call_slot (MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
604 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
605 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
607 update_sample_rate (0);
611 /* if the reason is a non-empty string, it means that the backend was shutdown
612 rather than just Ardour.
615 if (strlen (reason)) {
616 msgstr = string_compose (_("The audio backend was shutdown because:\n\n%1"), reason);
618 msgstr = string_compose (_("\
619 The audio backend has either been shutdown or it\n\
620 disconnected %1 because %1\n\
621 was not fast enough. Try to restart\n\
622 the audio backend and save the session."), PROGRAM_NAME);
625 MessageDialog msg (_main_window, msgstr);
626 pop_back_splash (msg);
630 free (const_cast<char*> (reason));
635 ARDOUR_UI::post_engine ()
637 /* Things to be done once (and once ONLY) after we have a backend running in the AudioEngine
639 #ifdef AUDIOUNIT_SUPPORT
641 if (AUPluginInfo::au_get_crashlog(au_msg)) {
642 popup_error(_("Audio Unit Plugin Scan Failed. Automatic AU scanning has been disabled. Please see the log window for further details."));
643 error << _("Audio Unit Plugin Scan Failed:") << endmsg;
644 info << au_msg << endmsg;
648 ARDOUR::init_post_engine ();
650 /* connect to important signals */
652 AudioEngine::instance()->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
653 AudioEngine::instance()->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
654 AudioEngine::instance()->BufferSizeChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
655 AudioEngine::instance()->Halted.connect_same_thread (halt_connection, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
656 AudioEngine::instance()->BecameSilent.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::audioengine_became_silent, this), gui_context());
658 if (setup_windows ()) {
659 throw failed_constructor ();
662 /* Do this after setup_windows (), as that's when the _status_bar_visibility is created */
663 XMLNode* n = Config->extra_xml (X_("UI"));
665 _status_bar_visibility.set_state (*n);
668 check_memory_locking();
670 /* this is the first point at which all the possible actions are
671 * available, because some of the available actions are dependent on
672 * aspects of the engine/backend.
675 if (ARDOUR_COMMAND_LINE::show_key_actions) {
678 vector<string> paths;
679 vector<string> labels;
680 vector<string> tooltips;
682 vector<Glib::RefPtr<Gtk::Action> > actions;
684 Gtkmm2ext::ActionMap::get_all_actions (paths, labels, tooltips, keys, actions);
686 vector<string>::iterator k;
687 vector<string>::iterator p;
689 for (p = paths.begin(), k = keys.begin(); p != paths.end(); ++k, ++p) {
694 cout << *p << " => " << *k << endl;
698 halt_connection.disconnect ();
699 AudioEngine::instance()->stop ();
703 /* this being a GUI and all, we want peakfiles */
705 AudioFileSource::set_build_peakfiles (true);
706 AudioFileSource::set_build_missing_peakfiles (true);
708 /* set default clock modes */
710 primary_clock->set_mode (AudioClock::Timecode);
711 secondary_clock->set_mode (AudioClock::BBT);
713 /* start the time-of-day-clock */
716 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
717 update_wall_clock ();
718 Glib::signal_timeout().connect_seconds (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 1);
723 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
724 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
725 Config->map_parameters (pc);
727 UIConfiguration::instance().map_parameters (pc);
731 ARDOUR_UI::~ARDOUR_UI ()
733 UIConfiguration::instance().save_state();
737 if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
738 // don't bother at 'real' exit. the OS cleans up for us.
739 delete big_clock; big_clock = 0;
740 delete primary_clock; primary_clock = 0;
741 delete secondary_clock; secondary_clock = 0;
742 delete _process_thread; _process_thread = 0;
743 delete time_info_box; time_info_box = 0;
744 delete meterbridge; meterbridge = 0;
745 delete luawindow; luawindow = 0;
746 delete editor; editor = 0;
747 delete mixer; mixer = 0;
749 delete gui_object_state; gui_object_state = 0;
750 delete main_window_visibility;
751 FastMeter::flush_pattern_cache ();
752 PixFader::flush_pattern_cache ();
756 /* Small trick to flush main-thread event pool.
757 * Other thread-pools are destroyed at pthread_exit(),
758 * but tmain thread termination is too late to trigger Pool::~Pool()
760 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.
761 delete ev->event_pool();
766 ARDOUR_UI::pop_back_splash (Gtk::Window& win)
768 if (Splash::instance()) {
769 Splash::instance()->pop_back_for (win);
774 ARDOUR_UI::configure_timeout ()
776 if (last_configure_time == 0) {
777 /* no configure events yet */
781 /* force a gap of 0.5 seconds since the last configure event
784 if (get_microseconds() - last_configure_time < 500000) {
787 have_configure_timeout = false;
788 save_ardour_state ();
794 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
796 if (have_configure_timeout) {
797 last_configure_time = get_microseconds();
799 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
800 have_configure_timeout = true;
807 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
809 XMLProperty const * prop;
811 if ((prop = node.property ("roll")) != 0) {
812 roll_controllable->set_id (prop->value());
814 if ((prop = node.property ("stop")) != 0) {
815 stop_controllable->set_id (prop->value());
817 if ((prop = node.property ("goto-start")) != 0) {
818 goto_start_controllable->set_id (prop->value());
820 if ((prop = node.property ("goto-end")) != 0) {
821 goto_end_controllable->set_id (prop->value());
823 if ((prop = node.property ("auto-loop")) != 0) {
824 auto_loop_controllable->set_id (prop->value());
826 if ((prop = node.property ("play-selection")) != 0) {
827 play_selection_controllable->set_id (prop->value());
829 if ((prop = node.property ("rec")) != 0) {
830 rec_controllable->set_id (prop->value());
832 if ((prop = node.property ("shuttle")) != 0) {
833 shuttle_box.controllable()->set_id (prop->value());
838 ARDOUR_UI::get_transport_controllable_state ()
840 XMLNode* node = new XMLNode(X_("TransportControllables"));
843 roll_controllable->id().print (buf, sizeof (buf));
844 node->add_property (X_("roll"), buf);
845 stop_controllable->id().print (buf, sizeof (buf));
846 node->add_property (X_("stop"), buf);
847 goto_start_controllable->id().print (buf, sizeof (buf));
848 node->add_property (X_("goto_start"), buf);
849 goto_end_controllable->id().print (buf, sizeof (buf));
850 node->add_property (X_("goto_end"), buf);
851 auto_loop_controllable->id().print (buf, sizeof (buf));
852 node->add_property (X_("auto_loop"), buf);
853 play_selection_controllable->id().print (buf, sizeof (buf));
854 node->add_property (X_("play_selection"), buf);
855 rec_controllable->id().print (buf, sizeof (buf));
856 node->add_property (X_("rec"), buf);
857 shuttle_box.controllable()->id().print (buf, sizeof (buf));
858 node->add_property (X_("shuttle"), buf);
864 ARDOUR_UI::save_session_at_its_request (std::string snapshot_name)
867 _session->save_state (snapshot_name);
872 ARDOUR_UI::autosave_session ()
874 if (g_main_depth() > 1) {
875 /* inside a recursive main loop,
876 give up because we may not be able to
882 if (!Config->get_periodic_safety_backups()) {
887 _session->maybe_write_autosave();
894 ARDOUR_UI::session_dirty_changed ()
901 ARDOUR_UI::update_autosave ()
903 if (_session && _session->dirty()) {
904 if (_autosave_connection.connected()) {
905 _autosave_connection.disconnect();
908 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
909 Config->get_periodic_safety_backup_interval() * 1000);
912 if (_autosave_connection.connected()) {
913 _autosave_connection.disconnect();
919 ARDOUR_UI::check_announcements ()
922 string _annc_filename;
925 _annc_filename = PROGRAM_NAME "_announcements_osx_";
926 #elif defined PLATFORM_WINDOWS
927 _annc_filename = PROGRAM_NAME "_announcements_windows_";
929 _annc_filename = PROGRAM_NAME "_announcements_linux_";
931 _annc_filename.append (VERSIONSTRING);
933 _announce_string = "";
935 std::string path = Glib::build_filename (user_config_directory(), _annc_filename);
936 FILE* fin = g_fopen (path.c_str(), "rb");
938 while (!feof (fin)) {
941 if ((len = fread (tmp, sizeof(char), 1024, fin)) == 0 || ferror (fin)) {
944 _announce_string.append (tmp, len);
949 pingback (VERSIONSTRING, path);
954 _hide_splash (gpointer arg)
956 ((ARDOUR_UI*)arg)->hide_splash();
961 ARDOUR_UI::starting ()
963 Application* app = Application::instance ();
965 bool brand_new_user = ArdourStartup::required ();
967 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
968 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::load_from_application_api));
970 if (ARDOUR_COMMAND_LINE::check_announcements) {
971 check_announcements ();
976 /* we need to create this early because it may need to set the
977 * audio backend end up.
981 audio_midi_setup.get (true);
983 std::cerr << "audio-midi engine setup failed."<< std::endl;
987 if ((nsm_url = g_getenv ("NSM_URL")) != 0) {
988 nsm = new NSM_Client;
989 if (!nsm->init (nsm_url)) {
990 /* the ardour executable may have different names:
992 * waf's obj.target for distro versions: eg ardour4, ardourvst4
993 * Ardour4, Mixbus3 for bundled versions + full path on OSX & windows
994 * argv[0] does not apply since we need the wrapper-script (not the binary itself)
996 * The wrapper startup script should set the environment variable 'ARDOUR_SELF'
998 const char *process_name = g_getenv ("ARDOUR_SELF");
999 nsm->announce (PROGRAM_NAME, ":dirty:", process_name ? process_name : "ardour4");
1002 // wait for announce reply from nsm server
1003 for ( i = 0; i < 5000; ++i) {
1007 if (nsm->is_active()) {
1012 error << _("NSM server did not announce itself") << endmsg;
1015 // wait for open command from nsm server
1016 for ( i = 0; i < 5000; ++i) {
1018 Glib::usleep (1000);
1019 if (nsm->client_id ()) {
1025 error << _("NSM: no client ID provided") << endmsg;
1029 if (_session && nsm) {
1030 _session->set_nsm_state( nsm->is_active() );
1032 error << _("NSM: no session created") << endmsg;
1036 // nsm requires these actions disabled
1037 vector<string> action_names;
1038 action_names.push_back("SaveAs");
1039 action_names.push_back("Rename");
1040 action_names.push_back("New");
1041 action_names.push_back("Open");
1042 action_names.push_back("Recent");
1043 action_names.push_back("Close");
1045 for (vector<string>::const_iterator n = action_names.begin(); n != action_names.end(); ++n) {
1046 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), (*n).c_str());
1048 act->set_sensitive (false);
1055 error << _("NSM: initialization failed") << endmsg;
1061 if (brand_new_user) {
1062 _initial_verbose_plugin_scan = true;
1067 _initial_verbose_plugin_scan = false;
1068 switch (s.response ()) {
1069 case Gtk::RESPONSE_OK:
1076 // TODO: maybe IFF brand_new_user
1077 if (ARDOUR::Profile->get_mixbus () && Config->get_copy_demo_sessions ()) {
1078 std::string dspd (Config->get_default_session_parent_dir());
1079 Searchpath ds (ARDOUR::ardour_data_search_path());
1080 ds.add_subdirectory_to_paths ("sessions");
1081 vector<string> demos;
1082 find_files_matching_pattern (demos, ds, "*.tar.xz");
1084 ARDOUR::RecentSessions rs;
1085 ARDOUR::read_recent_sessions (rs);
1087 for (vector<string>::iterator i = demos.begin(); i != demos.end (); ++i) {
1088 /* "demo-session" must be inside "demo-session.tar.xz"
1091 std::string name = basename_nosuffix (basename_nosuffix (*i));
1092 std::string path = Glib::build_filename (dspd, name);
1093 /* skip if session-dir already exists */
1094 if (Glib::file_test(path.c_str(), Glib::FILE_TEST_IS_DIR)) {
1097 /* skip sessions that are already in 'recent'.
1098 * eg. a new user changed <session-default-dir> shorly after installation
1100 for (ARDOUR::RecentSessions::iterator r = rs.begin(); r != rs.end(); ++r) {
1101 if ((*r).first == name) {
1106 PBD::FileArchive ar (*i);
1107 if (0 == ar.inflate (dspd)) {
1108 store_recent_sessions (name, path);
1109 info << string_compose (_("Copied Demo Session %1."), name) << endmsg;
1115 #ifdef NO_PLUGIN_STATE
1117 ARDOUR::RecentSessions rs;
1118 ARDOUR::read_recent_sessions (rs);
1120 string path = Glib::build_filename (user_config_directory(), ".iknowaboutfreeversion");
1122 if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS) && !rs.empty()) {
1124 /* already used Ardour, have sessions ... warn about plugin state */
1126 ArdourDialog d (_("Free/Demo Version Warning"), true);
1128 Button b (string_compose (_("Subscribe and support development of %1"), PROGRAM_NAME));
1129 CheckButton c (_("Don't warn me about this again"));
1131 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"),
1132 string_compose (_("This is a free/demo version of %1"), PROGRAM_NAME),
1133 _("It will not restore OR save any plugin settings"),
1134 _("If you load an existing session with plugin settings\n"
1135 "they will not be used and will be lost."),
1136 _("To get full access to updates without this limitation\n"
1137 "consider becoming a subscriber for a low cost every month.")));
1138 l.set_justify (JUSTIFY_CENTER);
1140 b.signal_clicked().connect (mem_fun(*this, &ARDOUR_UI::launch_subscribe));
1142 d.get_vbox()->pack_start (l, true, true);
1143 d.get_vbox()->pack_start (b, false, false, 12);
1144 d.get_vbox()->pack_start (c, false, false, 12);
1146 d.add_button (_("Quit now"), RESPONSE_CANCEL);
1147 d.add_button (string_compose (_("Continue using %1"), PROGRAM_NAME), RESPONSE_OK);
1151 c.signal_toggled().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (toggle_file_existence), path)));
1153 if (d.run () != RESPONSE_OK) {
1159 /* go get a session */
1161 const bool new_session_required = (ARDOUR_COMMAND_LINE::new_session || brand_new_user);
1163 if (get_session_parameters (false, new_session_required, ARDOUR_COMMAND_LINE::load_template)) {
1164 std::cerr << "Cannot get session parameters."<< std::endl;
1171 WM::Manager::instance().show_visible ();
1173 /* We have to do this here since goto_editor_window() ends up calling show_all() on the
1174 * editor window, and we may want stuff to be hidden.
1176 _status_bar_visibility.update ();
1178 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
1180 if (splash && splash->is_visible()) {
1181 // in 1 second, hide the splash screen
1182 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
1185 /* all other dialogs are created conditionally */
1191 ARDOUR_UI::check_memory_locking ()
1193 #if defined(__APPLE__) || defined(PLATFORM_WINDOWS)
1194 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
1198 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
1200 if (AudioEngine::instance()->is_realtime() && memory_warning_node == 0) {
1202 struct rlimit limits;
1204 long pages, page_size;
1206 size_t pages_len=sizeof(pages);
1207 if ((page_size = getpagesize()) < 0 ||
1208 sysctlbyname("hw.availpages", &pages, &pages_len, NULL, 0))
1210 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0)
1215 ram = (int64_t) pages * (int64_t) page_size;
1218 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
1222 if (limits.rlim_cur != RLIM_INFINITY) {
1224 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
1228 _("WARNING: Your system has a limit for maximum amount of locked memory. "
1229 "This might cause %1 to run out of memory before your system "
1230 "runs out of memory. \n\n"
1231 "You can view the memory limit with 'ulimit -l', "
1232 "and it is normally controlled by %2"),
1235 X_("/etc/login.conf")
1237 X_(" /etc/security/limits.conf")
1241 msg.set_default_response (RESPONSE_OK);
1243 VBox* vbox = msg.get_vbox();
1245 CheckButton cb (_("Do not show this window again"));
1246 hbox.pack_start (cb, true, false);
1247 vbox->pack_start (hbox);
1252 pop_back_splash (msg);
1256 if (cb.get_active()) {
1257 XMLNode node (X_("no-memory-warning"));
1258 Config->add_instant_xml (node);
1263 #endif // !__APPLE__
1268 ARDOUR_UI::queue_finish ()
1270 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
1274 ARDOUR_UI::idle_finish ()
1277 return false; /* do not call again */
1284 ARDOUR_UI::instance()->video_timeline->sync_session_state();
1286 if (_session->dirty()) {
1287 vector<string> actions;
1288 actions.push_back (_("Don't quit"));
1289 actions.push_back (_("Just quit"));
1290 actions.push_back (_("Save and quit"));
1291 switch (ask_about_saving_session(actions)) {
1296 /* use the default name */
1297 if (save_state_canfail ("")) {
1298 /* failed - don't quit */
1299 MessageDialog msg (_main_window,
1300 string_compose (_("\
1301 %1 was unable to save your session.\n\n\
1302 If you still wish to quit, please use the\n\n\
1303 \"Just quit\" option."), PROGRAM_NAME));
1304 pop_back_splash(msg);
1314 second_connection.disconnect ();
1315 point_one_second_connection.disconnect ();
1316 point_zero_something_second_connection.disconnect();
1317 fps_connection.disconnect();
1320 delete ARDOUR_UI::instance()->video_timeline;
1321 ARDOUR_UI::instance()->video_timeline = NULL;
1322 stop_video_server();
1324 /* Save state before deleting the session, as that causes some
1325 windows to be destroyed before their visible state can be
1328 save_ardour_state ();
1330 if (key_editor.get (false)) {
1331 key_editor->disconnect ();
1334 close_all_dialogs ();
1337 _session->set_clean ();
1338 _session->remove_pending_capture_state ();
1343 halt_connection.disconnect ();
1344 AudioEngine::instance()->stop ();
1345 #ifdef WINDOWS_VST_SUPPORT
1346 fst_stop_threading();
1352 ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
1354 ArdourDialog window (_("Unsaved Session"));
1355 Gtk::HBox dhbox; // the hbox for the image and text
1356 Gtk::Label prompt_label;
1357 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
1361 assert (actions.size() >= 3);
1363 window.add_button (actions[0], RESPONSE_REJECT);
1364 window.add_button (actions[1], RESPONSE_APPLY);
1365 window.add_button (actions[2], RESPONSE_ACCEPT);
1367 window.set_default_response (RESPONSE_ACCEPT);
1369 Gtk::Button noquit_button (msg);
1370 noquit_button.set_name ("EditorGTKButton");
1374 if (_session->snap_name() == _session->name()) {
1375 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?"),
1376 _session->snap_name());
1378 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?"),
1379 _session->snap_name());
1382 prompt_label.set_text (prompt);
1383 prompt_label.set_name (X_("PrompterLabel"));
1384 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
1386 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
1387 dhbox.set_homogeneous (false);
1388 dhbox.pack_start (*dimage, false, false, 5);
1389 dhbox.pack_start (prompt_label, true, false, 5);
1390 window.get_vbox()->pack_start (dhbox);
1392 window.set_name (_("Prompter"));
1393 window.set_modal (true);
1394 window.set_resizable (false);
1397 prompt_label.show();
1402 ResponseType r = (ResponseType) window.run();
1407 case RESPONSE_ACCEPT: // save and get out of here
1409 case RESPONSE_APPLY: // get out of here
1420 ARDOUR_UI::every_second ()
1423 update_xrun_count ();
1424 update_buffer_load ();
1425 update_disk_space ();
1426 update_timecode_format ();
1427 update_peak_thread_work ();
1429 if (nsm && nsm->is_active ()) {
1432 if (!_was_dirty && _session->dirty ()) {
1436 else if (_was_dirty && !_session->dirty ()){
1444 ARDOUR_UI::every_point_one_seconds ()
1446 // TODO get rid of this..
1447 // ShuttleControl is updated directly via TransportStateChange signal
1451 ARDOUR_UI::every_point_zero_something_seconds ()
1453 // august 2007: actual update frequency: 25Hz (40ms), not 100Hz
1455 if (editor_meter && UIConfiguration::instance().get_show_editor_meter() && editor_meter_peak_display.is_mapped ()) {
1456 float mpeak = editor_meter->update_meters();
1457 if (mpeak > editor_meter_max_peak) {
1458 if (mpeak >= UIConfiguration::instance().get_meter_peak()) {
1459 editor_meter_peak_display.set_active_state ( Gtkmm2ext::ExplicitActive );
1466 ARDOUR_UI::set_fps_timeout_connection ()
1468 unsigned int interval = 40;
1469 if (!_session) return;
1470 if (_session->timecode_frames_per_second() != 0) {
1471 /* ideally we'll use a select() to sleep and not accumulate
1472 * idle time to provide a regular periodic signal.
1473 * See linux_vst_gui_support.cc 'elapsed_time_ms'.
1474 * However, that'll require a dedicated thread and cross-thread
1475 * signals to the GUI Thread..
1477 interval = floor(500. /* update twice per FPS, since Glib::signal_timeout is very irregular */
1478 * _session->frame_rate() / _session->nominal_frame_rate()
1479 / _session->timecode_frames_per_second()
1481 #ifdef PLATFORM_WINDOWS
1482 // the smallest windows scheduler time-slice is ~15ms.
1483 // periodic GUI timeouts shorter than that will cause
1484 // WaitForSingleObject to spinlock (100% of one CPU Core)
1485 // and gtk never enters idle mode.
1486 // also changing timeBeginPeriod(1) does not affect that in
1487 // any beneficial way, so we just limit the max rate for now.
1488 interval = std::max(30u, interval); // at most ~33Hz.
1490 interval = std::max(8u, interval); // at most 120Hz.
1493 fps_connection.disconnect();
1494 Timers::set_fps_interval (interval);
1498 ARDOUR_UI::update_sample_rate (framecnt_t)
1502 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
1504 if (!AudioEngine::instance()->connected()) {
1506 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1510 framecnt_t rate = AudioEngine::instance()->sample_rate();
1513 /* no sample rate available */
1514 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1517 if (fmod (rate, 1000.0) != 0.0) {
1518 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
1519 (float) rate / 1000.0f,
1520 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1522 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
1524 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1528 sample_rate_label.set_markup (buf);
1532 ARDOUR_UI::update_format ()
1535 format_label.set_text ("");
1540 s << _("File:") << X_(" <span foreground=\"green\">");
1542 switch (_session->config.get_native_file_header_format ()) {
1574 switch (_session->config.get_native_file_data_format ()) {
1588 format_label.set_markup (s.str ());
1592 ARDOUR_UI::update_xrun_count ()
1596 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1597 should also be changed.
1601 const unsigned int x = _session->get_xrun_count ();
1603 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">>10K</span>"), X_("red"));
1605 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">%u</span>"), x > 0 ? X_("red") : X_("green"), x);
1608 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">?</span>"), X_("yellow"));
1610 xrun_label.set_markup (buf);
1611 set_tip (xrun_label, _("Audio dropouts. Shift+click to reset"));
1615 ARDOUR_UI::update_cpu_load ()
1619 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1620 should also be changed.
1623 double const c = AudioEngine::instance()->get_dsp_load ();
1624 snprintf (buf, sizeof (buf), _("DSP: <span foreground=\"%s\">%5.1f%%</span>"), c >= 90 ? X_("red") : X_("green"), c);
1625 cpu_load_label.set_markup (buf);
1629 ARDOUR_UI::update_peak_thread_work ()
1632 const int c = SourceFactory::peak_work_queue_length ();
1634 snprintf (buf, sizeof (buf), _("PkBld: <span foreground=\"%s\">%d</span>"), c >= 2 ? X_("red") : X_("green"), c);
1635 peak_thread_work_label.set_markup (buf);
1637 peak_thread_work_label.set_markup (X_(""));
1642 ARDOUR_UI::update_buffer_load ()
1646 uint32_t const playback = _session ? _session->playback_load () : 100;
1647 uint32_t const capture = _session ? _session->capture_load () : 100;
1649 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1650 should also be changed.
1656 _("Buffers: <span foreground=\"green\">p:</span><span foreground=\"%s\">%" PRIu32 "%%</span> "
1657 "<span foreground=\"green\">c:</span><span foreground=\"%s\">%" PRIu32 "%%</span>"),
1658 playback <= 5 ? X_("red") : X_("green"),
1660 capture <= 5 ? X_("red") : X_("green"),
1664 buffer_load_label.set_markup (buf);
1666 buffer_load_label.set_text ("");
1671 ARDOUR_UI::count_recenabled_streams (Route& route)
1673 Track* track = dynamic_cast<Track*>(&route);
1674 if (track && track->rec_enable_control()->get_value()) {
1675 rec_enabled_streams += track->n_inputs().n_total();
1680 ARDOUR_UI::update_disk_space()
1682 if (_session == 0) {
1686 boost::optional<framecnt_t> opt_frames = _session->available_capture_duration();
1688 framecnt_t fr = _session->frame_rate();
1691 /* skip update - no SR available */
1696 /* Available space is unknown */
1697 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">Unknown</span>"));
1698 } else if (opt_frames.get_value_or (0) == max_framecnt) {
1699 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">24hrs+</span>"));
1701 rec_enabled_streams = 0;
1702 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams, false);
1704 framecnt_t frames = opt_frames.get_value_or (0);
1706 if (rec_enabled_streams) {
1707 frames /= rec_enabled_streams;
1714 hrs = frames / (fr * 3600);
1717 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">>24 hrs</span>"));
1719 frames -= hrs * fr * 3600;
1720 mins = frames / (fr * 60);
1721 frames -= mins * fr * 60;
1724 bool const low = (hrs == 0 && mins <= 30);
1728 _("Disk: <span foreground=\"%s\">%02dh:%02dm:%02ds</span>"),
1729 low ? X_("red") : X_("green"),
1735 disk_space_label.set_markup (buf);
1739 ARDOUR_UI::update_timecode_format ()
1745 TimecodeSlave* tcslave;
1746 SyncSource sync_src = Config->get_sync_source();
1748 if ((sync_src == LTC || sync_src == MTC) && (tcslave = dynamic_cast<TimecodeSlave*>(_session->slave())) != 0) {
1749 matching = (tcslave->apparent_timecode_format() == _session->config.get_timecode_format());
1754 snprintf (buf, sizeof (buf), S_("Timecode|TC: <span foreground=\"%s\">%s</span>"),
1755 matching ? X_("green") : X_("red"),
1756 Timecode::timecode_format_name (_session->config.get_timecode_format()).c_str());
1758 snprintf (buf, sizeof (buf), "TC: n/a");
1761 timecode_format_label.set_markup (buf);
1765 ARDOUR_UI::update_wall_clock ()
1769 static int last_min = -1;
1772 tm_now = localtime (&now);
1773 if (last_min != tm_now->tm_min) {
1775 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1776 wall_clock_label.set_text (buf);
1777 last_min = tm_now->tm_min;
1784 ARDOUR_UI::open_recent_session ()
1786 bool can_return = (_session != 0);
1788 SessionDialog recent_session_dialog;
1792 ResponseType r = (ResponseType) recent_session_dialog.run ();
1795 case RESPONSE_ACCEPT:
1799 recent_session_dialog.hide();
1806 recent_session_dialog.hide();
1810 std::string path = recent_session_dialog.session_folder();
1811 std::string state = recent_session_dialog.session_name (should_be_new);
1813 if (should_be_new == true) {
1817 _session_is_new = false;
1819 if (load_session (path, state) == 0) {
1825 if (splash && splash->is_visible()) {
1826 // in 1 second, hide the splash screen
1827 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
1832 ARDOUR_UI::check_audioengine (Gtk::Window& parent)
1834 if (!AudioEngine::instance()->connected()) {
1835 MessageDialog msg (parent, string_compose (
1836 _("%1 is not connected to any audio backend.\n"
1837 "You cannot open or close sessions in this condition"),
1839 pop_back_splash (msg);
1847 ARDOUR_UI::open_session ()
1849 if (!check_audioengine (_main_window)) {
1853 /* ardour sessions are folders */
1854 Gtk::FileChooserDialog open_session_selector(_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1855 open_session_selector.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1856 open_session_selector.add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1857 open_session_selector.set_default_response(Gtk::RESPONSE_ACCEPT);
1860 string session_parent_dir = Glib::path_get_dirname(_session->path());
1861 open_session_selector.set_current_folder(session_parent_dir);
1863 open_session_selector.set_current_folder(Config->get_default_session_parent_dir());
1866 Gtkmm2ext::add_volume_shortcuts (open_session_selector);
1868 /* add_shortcut_folder throws an exception if the folder being added already has a shortcut */
1869 string default_session_folder = Config->get_default_session_parent_dir();
1870 open_session_selector.add_shortcut_folder (default_session_folder);
1872 catch (Glib::Error & e) {
1873 std::cerr << "open_session_selector.add_shortcut_folder() threw Glib::Error " << e.what() << std::endl;
1876 FileFilter session_filter;
1877 session_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::statefile_suffix));
1878 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1879 open_session_selector.add_filter (session_filter);
1880 open_session_selector.set_filter (session_filter);
1882 int response = open_session_selector.run();
1883 open_session_selector.hide ();
1885 if (response == Gtk::RESPONSE_CANCEL) {
1889 string session_path = open_session_selector.get_filename();
1893 if (session_path.length() > 0) {
1894 if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1895 _session_is_new = isnew;
1896 load_session (path, name);
1902 ARDOUR_UI::session_add_vca (const string& name_template, uint32_t n)
1908 _session->vca_manager().create_vca (n, name_template);
1912 ARDOUR_UI::session_add_mixed_track (
1913 const ChanCount& input,
1914 const ChanCount& output,
1915 RouteGroup* route_group,
1917 const string& name_template,
1919 PluginInfoPtr instrument,
1920 Plugin::PresetRecord* pset,
1921 ARDOUR::PresentationInfo::order_t order)
1923 list<boost::shared_ptr<MidiTrack> > tracks;
1925 if (_session == 0) {
1926 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1931 tracks = _session->new_midi_track (input, output, instrument, pset, route_group, how_many, name_template, order, ARDOUR::Normal);
1933 if (tracks.size() != how_many) {
1934 error << string_compose(P_("could not create %1 new mixed track", "could not create %1 new mixed tracks", how_many), how_many) << endmsg;
1939 display_insufficient_ports_message ();
1944 for (list<boost::shared_ptr<MidiTrack> >::iterator i = tracks.begin(); i != tracks.end(); ++i) {
1945 (*i)->set_strict_io (true);
1951 ARDOUR_UI::session_add_midi_bus (
1952 RouteGroup* route_group,
1954 const string& name_template,
1956 PluginInfoPtr instrument,
1957 Plugin::PresetRecord* pset,
1958 ARDOUR::PresentationInfo::order_t order)
1962 if (_session == 0) {
1963 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1969 routes = _session->new_midi_route (route_group, how_many, name_template, instrument, pset, PresentationInfo::MidiBus, order);
1970 if (routes.size() != how_many) {
1971 error << string_compose(P_("could not create %1 new Midi Bus", "could not create %1 new Midi Busses", how_many), how_many) << endmsg;
1976 display_insufficient_ports_message ();
1981 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
1982 (*i)->set_strict_io (true);
1988 ARDOUR_UI::session_add_midi_route (
1990 RouteGroup* route_group,
1992 const string& name_template,
1994 PluginInfoPtr instrument,
1995 Plugin::PresetRecord* pset,
1996 ARDOUR::PresentationInfo::order_t order)
1998 ChanCount one_midi_channel;
1999 one_midi_channel.set (DataType::MIDI, 1);
2002 session_add_mixed_track (one_midi_channel, one_midi_channel, route_group, how_many, name_template, strict_io, instrument, pset, order);
2004 session_add_midi_bus (route_group, how_many, name_template, strict_io, instrument, pset, order);
2009 ARDOUR_UI::session_add_audio_route (
2011 int32_t input_channels,
2012 int32_t output_channels,
2013 ARDOUR::TrackMode mode,
2014 RouteGroup* route_group,
2016 string const & name_template,
2018 ARDOUR::PresentationInfo::order_t order)
2020 list<boost::shared_ptr<AudioTrack> > tracks;
2023 if (_session == 0) {
2024 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
2030 tracks = _session->new_audio_track (input_channels, output_channels, route_group, how_many, name_template, order, mode);
2032 if (tracks.size() != how_many) {
2033 error << string_compose (P_("could not create %1 new audio track", "could not create %1 new audio tracks", how_many), how_many)
2039 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template, PresentationInfo::AudioBus, order);
2041 if (routes.size() != how_many) {
2042 error << string_compose (P_("could not create %1 new audio bus", "could not create %1 new audio busses", how_many), how_many)
2049 display_insufficient_ports_message ();
2054 for (list<boost::shared_ptr<AudioTrack> >::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2055 (*i)->set_strict_io (true);
2057 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
2058 (*i)->set_strict_io (true);
2064 ARDOUR_UI::display_insufficient_ports_message ()
2066 MessageDialog msg (_main_window,
2067 string_compose (_("There are insufficient ports available\n\
2068 to create a new track or bus.\n\
2069 You should save %1, exit and\n\
2070 restart with more ports."), PROGRAM_NAME));
2071 pop_back_splash (msg);
2076 ARDOUR_UI::transport_goto_start ()
2079 _session->goto_start();
2081 /* force displayed area in editor to start no matter
2082 what "follow playhead" setting is.
2086 editor->center_screen (_session->current_start_frame ());
2092 ARDOUR_UI::transport_goto_zero ()
2095 _session->request_locate (0);
2097 /* force displayed area in editor to start no matter
2098 what "follow playhead" setting is.
2102 editor->reset_x_origin (0);
2108 ARDOUR_UI::transport_goto_wallclock ()
2110 if (_session && editor) {
2117 localtime_r (&now, &tmnow);
2119 framecnt_t frame_rate = _session->frame_rate();
2121 if (frame_rate == 0) {
2122 /* no frame rate available */
2126 frames = tmnow.tm_hour * (60 * 60 * frame_rate);
2127 frames += tmnow.tm_min * (60 * frame_rate);
2128 frames += tmnow.tm_sec * frame_rate;
2130 _session->request_locate (frames, _session->transport_rolling ());
2132 /* force displayed area in editor to start no matter
2133 what "follow playhead" setting is.
2137 editor->center_screen (frames);
2143 ARDOUR_UI::transport_goto_end ()
2146 framepos_t const frame = _session->current_end_frame();
2147 _session->request_locate (frame);
2149 /* force displayed area in editor to start no matter
2150 what "follow playhead" setting is.
2154 editor->center_screen (frame);
2160 ARDOUR_UI::transport_stop ()
2166 if (_session->is_auditioning()) {
2167 _session->cancel_audition ();
2171 _session->request_stop (false, true);
2174 /** Check if any tracks are record enabled. If none are, record enable all of them.
2175 * @return true if track record-enabled status was changed, false otherwise.
2178 ARDOUR_UI::trx_record_enable_all_tracks ()
2184 boost::shared_ptr<RouteList> rl = _session->get_tracks ();
2185 bool none_record_enabled = true;
2187 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
2188 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*r);
2191 if (t->rec_enable_control()->get_value()) {
2192 none_record_enabled = false;
2197 if (none_record_enabled) {
2198 _session->set_controls (route_list_to_control_list (rl, &Stripable::rec_enable_control), 1.0, Controllable::NoGroup);
2201 return none_record_enabled;
2205 ARDOUR_UI::transport_record (bool roll)
2208 switch (_session->record_status()) {
2209 case Session::Disabled:
2210 if (_session->ntracks() == 0) {
2211 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."));
2215 if (Profile->get_trx()) {
2216 roll = trx_record_enable_all_tracks ();
2218 _session->maybe_enable_record ();
2223 case Session::Recording:
2225 _session->request_stop();
2227 _session->disable_record (false, true);
2231 case Session::Enabled:
2232 _session->disable_record (false, true);
2238 ARDOUR_UI::transport_roll ()
2244 if (_session->is_auditioning()) {
2249 if (_session->config.get_external_sync()) {
2250 switch (Config->get_sync_source()) {
2254 /* transport controlled by the master */
2260 bool rolling = _session->transport_rolling();
2262 if (_session->get_play_loop()) {
2264 /* If loop playback is not a mode, then we should cancel
2265 it when this action is requested. If it is a mode
2266 we just leave it in place.
2269 if (!Config->get_loop_is_mode()) {
2270 /* XXX it is not possible to just leave seamless loop and keep
2271 playing at present (nov 4th 2009)
2273 if (!Config->get_seamless_loop()) {
2274 /* stop loop playback and stop rolling */
2275 _session->request_play_loop (false, true);
2276 } else if (rolling) {
2277 /* stop loop playback but keep rolling */
2278 _session->request_play_loop (false, false);
2282 } else if (_session->get_play_range () ) {
2283 /* stop playing a range if we currently are */
2284 _session->request_play_range (0, true);
2288 _session->request_transport_speed (1.0f);
2293 ARDOUR_UI::get_smart_mode() const
2295 return ( editor->get_smart_mode() );
2300 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
2306 if (_session->is_auditioning()) {
2307 _session->cancel_audition ();
2311 if (_session->config.get_external_sync()) {
2312 switch (Config->get_sync_source()) {
2316 /* transport controlled by the master */
2321 bool rolling = _session->transport_rolling();
2322 bool affect_transport = true;
2324 if (rolling && roll_out_of_bounded_mode) {
2325 /* drop out of loop/range playback but leave transport rolling */
2326 if (_session->get_play_loop()) {
2327 if (_session->actively_recording()) {
2329 /* just stop using the loop, then actually stop
2332 _session->request_play_loop (false, affect_transport);
2335 if (Config->get_seamless_loop()) {
2336 /* the disk buffers contain copies of the loop - we can't
2337 just keep playing, so stop the transport. the user
2338 can restart as they wish.
2340 affect_transport = true;
2342 /* disk buffers are normal, so we can keep playing */
2343 affect_transport = false;
2345 _session->request_play_loop (false, affect_transport);
2347 } else if (_session->get_play_range ()) {
2348 affect_transport = false;
2349 _session->request_play_range (0, true);
2353 if (affect_transport) {
2355 _session->request_stop (with_abort, true);
2357 } else if (!with_abort) { /* with_abort == true means the
2358 * command was intended to stop
2359 * transport, not start.
2362 /* the only external sync condition we can be in here
2363 * would be Engine (JACK) sync, in which case we still
2367 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
2368 _session->request_play_range (&editor->get_selection().time, true);
2369 _session->set_requested_return_frame( editor->get_selection().time.front().start ); //force an auto-return here
2371 _session->request_transport_speed (1.0f);
2377 ARDOUR_UI::toggle_session_auto_loop ()
2383 Location * looploc = _session->locations()->auto_loop_location();
2389 if (_session->get_play_loop()) {
2391 /* looping enabled, our job is to disable it */
2393 _session->request_play_loop (false);
2397 /* looping not enabled, our job is to enable it.
2399 loop-is-NOT-mode: this action always starts the transport rolling.
2400 loop-IS-mode: this action simply sets the loop play mechanism, but
2401 does not start transport.
2403 if (Config->get_loop_is_mode()) {
2404 _session->request_play_loop (true, false);
2406 _session->request_play_loop (true, true);
2410 //show the loop markers
2411 looploc->set_hidden (false, this);
2415 ARDOUR_UI::transport_play_selection ()
2421 editor->play_selection ();
2425 ARDOUR_UI::transport_play_preroll ()
2430 editor->play_with_preroll ();
2434 ARDOUR_UI::transport_rewind (int option)
2436 float current_transport_speed;
2439 current_transport_speed = _session->transport_speed();
2441 if (current_transport_speed >= 0.0f) {
2444 _session->request_transport_speed (-1.0f);
2447 _session->request_transport_speed (-4.0f);
2450 _session->request_transport_speed (-0.5f);
2455 _session->request_transport_speed (current_transport_speed * 1.5f);
2461 ARDOUR_UI::transport_forward (int option)
2467 float current_transport_speed = _session->transport_speed();
2469 if (current_transport_speed <= 0.0f) {
2472 _session->request_transport_speed (1.0f);
2475 _session->request_transport_speed (4.0f);
2478 _session->request_transport_speed (0.5f);
2483 _session->request_transport_speed (current_transport_speed * 1.5f);
2488 ARDOUR_UI::toggle_record_enable (uint16_t rid)
2494 boost::shared_ptr<Route> r;
2496 if ((r = _session->get_remote_nth_route (rid)) != 0) {
2498 boost::shared_ptr<Track> t;
2500 if ((t = boost::dynamic_pointer_cast<Track>(r)) != 0) {
2501 t->rec_enable_control()->set_value (!t->rec_enable_control()->get_value(), Controllable::UseGroup);
2507 ARDOUR_UI::map_transport_state ()
2510 auto_loop_button.unset_active_state ();
2511 play_selection_button.unset_active_state ();
2512 roll_button.unset_active_state ();
2513 stop_button.set_active_state (Gtkmm2ext::ExplicitActive);
2514 layered_button.set_sensitive (false);
2518 shuttle_box.map_transport_state ();
2520 float sp = _session->transport_speed();
2526 if (_session->get_play_range()) {
2528 play_selection_button.set_active_state (Gtkmm2ext::ExplicitActive);
2529 roll_button.unset_active_state ();
2530 auto_loop_button.unset_active_state ();
2532 } else if (_session->get_play_loop ()) {
2534 auto_loop_button.set_active (true);
2535 play_selection_button.set_active (false);
2536 if (Config->get_loop_is_mode()) {
2537 roll_button.set_active (true);
2539 roll_button.set_active (false);
2544 roll_button.set_active (true);
2545 play_selection_button.set_active (false);
2546 auto_loop_button.set_active (false);
2549 if (UIConfiguration::instance().get_follow_edits() && !_session->config.get_external_sync()) {
2550 /* light up both roll and play-selection if they are joined */
2551 roll_button.set_active (true);
2552 play_selection_button.set_active (true);
2554 layered_button.set_sensitive (!_session->actively_recording ());
2556 stop_button.set_active (false);
2560 layered_button.set_sensitive (true);
2561 stop_button.set_active (true);
2562 roll_button.set_active (false);
2563 play_selection_button.set_active (false);
2564 if (Config->get_loop_is_mode ()) {
2565 auto_loop_button.set_active (_session->get_play_loop());
2567 auto_loop_button.set_active (false);
2569 update_disk_space ();
2574 ARDOUR_UI::blink_handler (bool blink_on)
2576 transport_rec_enable_blink (blink_on);
2577 solo_blink (blink_on);
2578 sync_blink (blink_on);
2579 audition_blink (blink_on);
2580 feedback_blink (blink_on);
2581 error_blink (blink_on);
2585 ARDOUR_UI::update_clocks ()
2587 if (!_session) return;
2589 if (editor && !editor->dragging_playhead()) {
2590 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD)); /* EMIT_SIGNAL */
2595 ARDOUR_UI::start_clocking ()
2597 if (UIConfiguration::instance().get_super_rapid_clock_update()) {
2598 clock_signal_connection = Timers::fps_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2600 clock_signal_connection = Timers::rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2605 ARDOUR_UI::stop_clocking ()
2607 clock_signal_connection.disconnect ();
2611 ARDOUR_UI::save_as_progress_update (float fraction, int64_t cnt, int64_t total, Gtk::Label* label, Gtk::ProgressBar* bar)
2615 snprintf (buf, sizeof (buf), _("Copied %" PRId64 " of %" PRId64), cnt, total);
2617 label->set_text (buf);
2618 bar->set_fraction (fraction);
2620 /* process events, redraws, etc. */
2622 while (gtk_events_pending()) {
2623 gtk_main_iteration ();
2626 return true; /* continue with save-as */
2630 ARDOUR_UI::save_session_as ()
2636 if (!save_as_dialog) {
2637 save_as_dialog = new SaveAsDialog;
2640 save_as_dialog->set_name (_session->name());
2642 int response = save_as_dialog->run ();
2644 save_as_dialog->hide ();
2647 case Gtk::RESPONSE_OK:
2656 sa.new_parent_folder = save_as_dialog->new_parent_folder ();
2657 sa.new_name = save_as_dialog->new_name ();
2658 sa.switch_to = save_as_dialog->switch_to();
2659 sa.copy_media = save_as_dialog->copy_media();
2660 sa.copy_external = save_as_dialog->copy_external();
2661 sa.include_media = save_as_dialog->include_media ();
2663 /* Only bother with a progress dialog if we're going to copy
2664 media into the save-as target. Without that choice, this
2665 will be very fast because we're only talking about a few kB's to
2666 perhaps a couple of MB's of data.
2669 ArdourDialog progress_dialog (_("Save As"), true);
2671 if (sa.include_media && sa.copy_media) {
2674 Gtk::ProgressBar progress_bar;
2676 progress_dialog.get_vbox()->pack_start (label);
2677 progress_dialog.get_vbox()->pack_start (progress_bar);
2679 progress_bar.show ();
2681 /* this signal will be emitted from within this, the calling thread,
2682 * after every file is copied. It provides information on percentage
2683 * complete (in terms of total data to copy), the number of files
2684 * copied so far, and the total number to copy.
2689 sa.Progress.connect_same_thread (c, boost::bind (&ARDOUR_UI::save_as_progress_update, this, _1, _2, _3, &label, &progress_bar));
2691 progress_dialog.show_all ();
2692 progress_dialog.present ();
2695 if (_session->save_as (sa)) {
2697 MessageDialog msg (string_compose (_("Save As failed: %1"), sa.failure_message));
2701 if (!sa.include_media) {
2702 unload_session (false);
2703 load_session (sa.final_session_folder_name, sa.new_name);
2708 ARDOUR_UI::archive_session ()
2716 Glib::DateTime gdt (Glib::DateTime::create_now_local (n));
2718 SessionArchiveDialog sad;
2719 sad.set_name (_session->name() + gdt.format ("_%F_%H%M%S"));
2720 int response = sad.run ();
2722 if (response != Gtk::RESPONSE_OK) {
2727 if (_session->archive_session (sad.target_folder(), sad.name(), sad.encode_option (), sad.only_used_sources (), &sad)) {
2728 MessageDialog msg (_("Session Archiving failed."));
2734 ARDOUR_UI::quick_snapshot_session (bool switch_to_it)
2738 struct tm local_time;
2741 localtime_r (&n, &local_time);
2742 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2744 save_state (timebuf, switch_to_it);
2749 ARDOUR_UI::process_snapshot_session_prompter (ArdourPrompter& prompter, bool switch_to_it)
2753 prompter.get_result (snapname);
2755 bool do_save = (snapname.length() != 0);
2758 char illegal = Session::session_name_is_legal(snapname);
2760 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2761 "snapshot names may not contain a '%1' character"), illegal));
2767 vector<std::string> p;
2768 get_state_files_in_directory (_session->session_directory().root_path(), p);
2769 vector<string> n = get_file_names_no_extension (p);
2771 if (find (n.begin(), n.end(), snapname) != n.end()) {
2773 do_save = overwrite_file_dialog (prompter,
2774 _("Confirm Snapshot Overwrite"),
2775 _("A snapshot already exists with that name. Do you want to overwrite it?"));
2779 save_state (snapname, switch_to_it);
2789 /** Ask the user for the name of a new snapshot and then take it.
2793 ARDOUR_UI::snapshot_session (bool switch_to_it)
2795 ArdourPrompter prompter (true);
2797 prompter.set_name ("Prompter");
2798 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2800 prompter.set_title (_("Snapshot and switch"));
2801 prompter.set_prompt (_("New session name"));
2803 prompter.set_title (_("Take Snapshot"));
2804 prompter.set_prompt (_("Name of new snapshot"));
2808 prompter.set_initial_text (_session->snap_name());
2810 Glib::DateTime tm (g_date_time_new_now_local ());
2811 prompter.set_initial_text (tm.format ("%FT%H.%M.%S"));
2814 bool finished = false;
2816 switch (prompter.run()) {
2817 case RESPONSE_ACCEPT:
2819 finished = process_snapshot_session_prompter (prompter, switch_to_it);
2830 /** Ask the user for a new session name and then rename the session to it.
2834 ARDOUR_UI::rename_session ()
2840 ArdourPrompter prompter (true);
2843 prompter.set_name ("Prompter");
2844 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2845 prompter.set_title (_("Rename Session"));
2846 prompter.set_prompt (_("New session name"));
2849 switch (prompter.run()) {
2850 case RESPONSE_ACCEPT:
2852 prompter.get_result (name);
2854 bool do_rename = (name.length() != 0);
2857 char illegal = Session::session_name_is_legal (name);
2860 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2861 "session names may not contain a '%1' character"), illegal));
2866 switch (_session->rename (name)) {
2868 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
2869 msg.set_position (WIN_POS_MOUSE);
2877 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
2878 msg.set_position (WIN_POS_MOUSE);
2894 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2896 if (!_session || _session->deletion_in_progress()) {
2900 XMLNode* node = new XMLNode (X_("UI"));
2902 WM::Manager::instance().add_state (*node);
2904 node->add_child_nocopy (gui_object_state->get_state());
2906 _session->add_extra_xml (*node);
2908 if (export_video_dialog) {
2909 _session->add_extra_xml (export_video_dialog->get_state());
2912 save_state_canfail (name, switch_to_it);
2916 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2921 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2926 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2931 ARDOUR_UI::primary_clock_value_changed ()
2934 _session->request_locate (primary_clock->current_time ());
2939 ARDOUR_UI::big_clock_value_changed ()
2942 _session->request_locate (big_clock->current_time ());
2947 ARDOUR_UI::secondary_clock_value_changed ()
2950 _session->request_locate (secondary_clock->current_time ());
2955 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2957 if (_session == 0) {
2961 if (_session->step_editing()) {
2965 Session::RecordState const r = _session->record_status ();
2966 bool const h = _session->have_rec_enabled_track ();
2968 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2970 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2972 rec_button.set_active_state (Gtkmm2ext::Off);
2974 } else if (r == Session::Recording && h) {
2975 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2977 rec_button.unset_active_state ();
2982 ARDOUR_UI::process_save_template_prompter (ArdourPrompter& prompter)
2986 prompter.get_result (name);
2988 if (name.length()) {
2989 int failed = _session->save_template (name);
2991 if (failed == -2) { /* file already exists. */
2992 bool overwrite = overwrite_file_dialog (prompter,
2993 _("Confirm Template Overwrite"),
2994 _("A template already exists with that name. Do you want to overwrite it?"));
2997 _session->save_template (name, true);
3009 ARDOUR_UI::save_template ()
3011 ArdourPrompter prompter (true);
3013 if (!check_audioengine (_main_window)) {
3017 prompter.set_name (X_("Prompter"));
3018 prompter.set_title (_("Save Template"));
3019 prompter.set_prompt (_("Name for template:"));
3020 prompter.set_initial_text(_session->name() + _("-template"));
3021 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
3023 bool finished = false;
3025 switch (prompter.run()) {
3026 case RESPONSE_ACCEPT:
3027 finished = process_save_template_prompter (prompter);
3038 ARDOUR_UI::edit_metadata ()
3040 SessionMetadataEditor dialog;
3041 dialog.set_session (_session);
3042 dialog.grab_focus ();
3047 ARDOUR_UI::import_metadata ()
3049 SessionMetadataImporter dialog;
3050 dialog.set_session (_session);
3055 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
3057 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
3059 MessageDialog msg (str,
3061 Gtk::MESSAGE_WARNING,
3062 Gtk::BUTTONS_YES_NO,
3066 msg.set_name (X_("OpenExistingDialog"));
3067 msg.set_title (_("Open Existing Session"));
3068 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
3069 msg.set_position (Gtk::WIN_POS_CENTER);
3070 pop_back_splash (msg);
3072 switch (msg.run()) {
3081 ARDOUR_UI::build_session_from_dialog (SessionDialog& sd, const std::string& session_path, const std::string& session_name)
3083 BusProfile bus_profile;
3087 bus_profile.master_out_channels = 2;
3088 bus_profile.input_ac = AutoConnectPhysical;
3089 bus_profile.output_ac = AutoConnectMaster;
3090 bus_profile.requested_physical_in = 0; // use all available
3091 bus_profile.requested_physical_out = 0; // use all available
3095 /* get settings from advanced section of NSD */
3097 if (sd.create_master_bus()) {
3098 bus_profile.master_out_channels = (uint32_t) sd.master_channel_count();
3100 bus_profile.master_out_channels = 0;
3103 if (sd.connect_inputs()) {
3104 bus_profile.input_ac = AutoConnectPhysical;
3106 bus_profile.input_ac = AutoConnectOption (0);
3109 bus_profile.output_ac = AutoConnectOption (0);
3111 if (sd.connect_outputs ()) {
3112 if (sd.connect_outs_to_master()) {
3113 bus_profile.output_ac = AutoConnectMaster;
3114 } else if (sd.connect_outs_to_physical()) {
3115 bus_profile.output_ac = AutoConnectPhysical;
3119 bus_profile.requested_physical_in = (uint32_t) sd.input_limit_count();
3120 bus_profile.requested_physical_out = (uint32_t) sd.output_limit_count();
3123 if (build_session (session_path, session_name, bus_profile)) {
3131 ARDOUR_UI::load_from_application_api (const std::string& path)
3133 /* OS X El Capitan (and probably later) now somehow passes the command
3134 line arguments to an app via the openFile delegate protocol. Ardour
3135 already does its own command line processing, and having both
3136 pathways active causes crashes. So, if the command line was already
3137 set, do nothing here.
3140 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
3144 ARDOUR_COMMAND_LINE::session_name = path;
3146 /* Cancel SessionDialog if it's visible to make OSX delegates work.
3148 * ARDOUR_UI::starting connects app->ShouldLoad signal and then shows a SessionDialog
3150 * - ShouldLoad does not arrive in time, ARDOUR_COMMAND_LINE::session_name is empty:
3151 * -> ARDOUR_UI::get_session_parameters starts a SessionDialog.
3152 * - ShouldLoad signal arrives, this function is called and sets ARDOUR_COMMAND_LINE::session_name
3153 * -> SessionDialog is not displayed
3156 if (_session_dialog) {
3157 std::string session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3158 std::string session_path = path;
3159 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_REGULAR)) {
3160 session_path = Glib::path_get_dirname (session_path);
3162 // signal the existing dialog in ARDOUR_UI::get_session_parameters()
3163 _session_dialog->set_provided_session (session_name, session_path);
3164 _session_dialog->response (RESPONSE_NONE);
3165 _session_dialog->hide();
3170 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
3171 /* /path/to/foo => /path/to/foo, foo */
3172 rv = load_session (path, basename_nosuffix (path));
3174 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
3175 rv =load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
3178 // if load_session fails -> pop up SessionDialog.
3180 ARDOUR_COMMAND_LINE::session_name = "";
3182 if (get_session_parameters (true, false)) {
3188 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
3190 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
3192 string session_name;
3193 string session_path;
3194 string template_name;
3196 bool likely_new = false;
3197 bool cancel_not_quit;
3199 /* deal with any existing DIRTY session now, rather than later. don't
3200 * treat a non-dirty session this way, so that it stays visible
3201 * as we bring up the new session dialog.
3204 if (_session && ARDOUR_UI::instance()->video_timeline) {
3205 ARDOUR_UI::instance()->video_timeline->sync_session_state();
3208 /* if there is already a session, relabel the button
3209 on the SessionDialog so that we don't Quit directly
3211 cancel_not_quit = (_session != 0);
3213 if (_session && _session->dirty()) {
3214 if (unload_session (false)) {
3215 /* unload cancelled by user */
3218 ARDOUR_COMMAND_LINE::session_name = "";
3221 if (!load_template.empty()) {
3222 should_be_new = true;
3223 template_name = load_template;
3226 session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3227 session_path = ARDOUR_COMMAND_LINE::session_name;
3229 if (!session_path.empty()) {
3230 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_EXISTS)) {
3231 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_IS_REGULAR)) {
3232 /* session/snapshot file, change path to be dir */
3233 session_path = Glib::path_get_dirname (session_path);
3238 SessionDialog session_dialog (should_be_new, session_name, session_path, load_template, cancel_not_quit);
3240 _session_dialog = &session_dialog;
3243 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
3245 /* if they named a specific statefile, use it, otherwise they are
3246 just giving a session folder, and we want to use it as is
3247 to find the session.
3250 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
3252 if (suffix != string::npos) {
3253 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
3254 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
3255 session_name = Glib::path_get_basename (session_name);
3257 session_path = ARDOUR_COMMAND_LINE::session_name;
3258 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
3263 session_dialog.clear_given ();
3266 if (should_be_new || session_name.empty()) {
3267 /* need the dialog to get info from user */
3269 cerr << "run dialog\n";
3271 switch (session_dialog.run()) {
3272 case RESPONSE_ACCEPT:
3275 /* this is used for async * app->ShouldLoad(). */
3276 continue; // while loop
3279 if (quit_on_cancel) {
3280 // JE - Currently (July 2014) this section can only get reached if the
3281 // user quits from the main 'Session Setup' dialog (i.e. reaching this
3282 // point does NOT indicate an abnormal termination). Therefore, let's
3283 // behave gracefully (i.e. let's do some cleanup) before we call exit()
3285 pthread_cancel_all ();
3293 session_dialog.hide ();
3296 /* if we run the startup dialog again, offer more than just "new session" */
3298 should_be_new = false;
3300 session_name = session_dialog.session_name (likely_new);
3301 session_path = session_dialog.session_folder ();
3307 string::size_type suffix = session_name.find (statefile_suffix);
3309 if (suffix != string::npos) {
3310 session_name = session_name.substr (0, suffix);
3313 /* this shouldn't happen, but we catch it just in case it does */
3315 if (session_name.empty()) {
3319 if (session_dialog.use_session_template()) {
3320 template_name = session_dialog.session_template_name();
3321 _session_is_new = true;
3324 if (session_name[0] == G_DIR_SEPARATOR ||
3325 #ifdef PLATFORM_WINDOWS
3326 (session_name.length() > 3 && session_name[1] == ':' && session_name[2] == G_DIR_SEPARATOR)
3328 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
3329 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)
3334 /* absolute path or cwd-relative path specified for session name: infer session folder
3335 from what was given.
3338 session_path = Glib::path_get_dirname (session_name);
3339 session_name = Glib::path_get_basename (session_name);
3343 session_path = session_dialog.session_folder();
3345 char illegal = Session::session_name_is_legal (session_name);
3348 MessageDialog msg (session_dialog,
3349 string_compose (_("To ensure compatibility with various systems\n"
3350 "session names may not contain a '%1' character"),
3353 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3358 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
3361 if (likely_new && !nsm) {
3363 std::string existing = Glib::build_filename (session_path, session_name);
3365 if (!ask_about_loading_existing_session (existing)) {
3366 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3371 _session_is_new = false;
3376 pop_back_splash (session_dialog);
3377 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
3379 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3383 char illegal = Session::session_name_is_legal(session_name);
3386 pop_back_splash (session_dialog);
3387 MessageDialog msg (session_dialog, string_compose(_("To ensure compatibility with various systems\n"
3388 "session names may not contain a '%1' character"), illegal));
3390 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3394 _session_is_new = true;
3397 if (likely_new && template_name.empty()) {
3399 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3403 ret = load_session (session_path, session_name, template_name);
3406 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
3410 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
3411 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
3415 /* clear this to avoid endless attempts to load the
3419 ARDOUR_COMMAND_LINE::session_name = "";
3423 _session_dialog = NULL;
3429 ARDOUR_UI::close_session()
3431 if (!check_audioengine (_main_window)) {
3435 if (unload_session (true)) {
3439 ARDOUR_COMMAND_LINE::session_name = "";
3441 if (get_session_parameters (true, false)) {
3444 if (splash && splash->is_visible()) {
3445 // in 1 second, hide the splash screen
3446 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
3450 /** @param snap_name Snapshot name (without .ardour suffix).
3451 * @return -2 if the load failed because we are not connected to the AudioEngine.
3454 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
3456 Session *new_session;
3461 unload_status = unload_session ();
3463 if (unload_status < 0) {
3465 } else if (unload_status > 0) {
3471 session_loaded = false;
3473 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
3476 new_session = new Session (*AudioEngine::instance(), path, snap_name, 0, mix_template);
3479 /* this one is special */
3481 catch (AudioEngine::PortRegistrationFailure& err) {
3483 MessageDialog msg (err.what(),
3486 Gtk::BUTTONS_CLOSE);
3488 msg.set_title (_("Port Registration Error"));
3489 msg.set_secondary_text (_("Click the Close button to try again."));
3490 msg.set_position (Gtk::WIN_POS_CENTER);
3491 pop_back_splash (msg);
3494 int response = msg.run ();
3499 case RESPONSE_CANCEL:
3506 catch (SessionException e) {
3507 MessageDialog msg (string_compose(
3508 _("Session \"%1 (snapshot %2)\" did not load successfully: %3"),
3509 path, snap_name, e.what()),
3514 msg.set_title (_("Loading Error"));
3515 msg.set_position (Gtk::WIN_POS_CENTER);
3516 pop_back_splash (msg);
3528 MessageDialog msg (string_compose(
3529 _("Session \"%1 (snapshot %2)\" did not load successfully"),
3535 msg.set_title (_("Loading Error"));
3536 msg.set_position (Gtk::WIN_POS_CENTER);
3537 pop_back_splash (msg);
3549 list<string> const u = new_session->unknown_processors ();
3551 MissingPluginDialog d (_session, u);
3556 if (!new_session->writable()) {
3557 MessageDialog msg (_("This session has been opened in read-only mode.\n\nYou will not be able to record or save."),
3562 msg.set_title (_("Read-only Session"));
3563 msg.set_position (Gtk::WIN_POS_CENTER);
3564 pop_back_splash (msg);
3571 /* Now the session been created, add the transport controls */
3572 new_session->add_controllable(roll_controllable);
3573 new_session->add_controllable(stop_controllable);
3574 new_session->add_controllable(goto_start_controllable);
3575 new_session->add_controllable(goto_end_controllable);
3576 new_session->add_controllable(auto_loop_controllable);
3577 new_session->add_controllable(play_selection_controllable);
3578 new_session->add_controllable(rec_controllable);
3580 set_session (new_session);
3582 session_loaded = true;
3585 _session->set_clean ();
3588 #ifdef WINDOWS_VST_SUPPORT
3589 fst_stop_threading();
3593 Timers::TimerSuspender t;
3597 #ifdef WINDOWS_VST_SUPPORT
3598 fst_start_threading();
3607 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
3609 Session *new_session;
3612 session_loaded = false;
3613 x = unload_session ();
3621 _session_is_new = true;
3624 new_session = new Session (*AudioEngine::instance(), path, snap_name, &bus_profile);
3627 catch (SessionException e) {
3628 cerr << "Here are the errors associated with this failed session:\n";
3630 cerr << "---------\n";
3631 MessageDialog msg (string_compose(_("Could not create session in \"%1\": %2"), path, e.what()));
3632 msg.set_title (_("Loading Error"));
3633 msg.set_position (Gtk::WIN_POS_CENTER);
3634 pop_back_splash (msg);
3639 cerr << "Here are the errors associated with this failed session:\n";
3641 cerr << "---------\n";
3642 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
3643 msg.set_title (_("Loading Error"));
3644 msg.set_position (Gtk::WIN_POS_CENTER);
3645 pop_back_splash (msg);
3650 /* Give the new session the default GUI state, if such things exist */
3653 n = Config->instant_xml (X_("Editor"));
3655 n->remove_nodes_and_delete ("Selection"); // no not apply selection to new sessions.
3656 new_session->add_instant_xml (*n, false);
3658 n = Config->instant_xml (X_("Mixer"));
3660 new_session->add_instant_xml (*n, false);
3663 n = Config->instant_xml (X_("Preferences"));
3665 new_session->add_instant_xml (*n, false);
3668 /* Put the playhead at 0 and scroll fully left */
3669 n = new_session->instant_xml (X_("Editor"));
3671 n->add_property (X_("playhead"), X_("0"));
3672 n->add_property (X_("left-frame"), X_("0"));
3675 set_session (new_session);
3677 session_loaded = true;
3679 new_session->save_state(new_session->name());
3685 ARDOUR_UI::launch_chat ()
3687 MessageDialog dialog(_("<b>Just ask and wait for an answer.\nIt may take from minutes to hours.</b>"), true);
3689 dialog.set_title (_("About the Chat"));
3690 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."));
3692 switch (dialog.run()) {
3695 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
3696 #elif defined PLATFORM_WINDOWS
3697 open_uri("http://webchat.freenode.net/?channels=ardour-windows");
3699 open_uri("http://webchat.freenode.net/?channels=ardour");
3708 ARDOUR_UI::launch_manual ()
3710 PBD::open_uri (Config->get_tutorial_manual_url());
3714 ARDOUR_UI::launch_reference ()
3716 PBD::open_uri (Config->get_reference_manual_url());
3720 ARDOUR_UI::launch_tracker ()
3722 PBD::open_uri ("http://tracker.ardour.org");
3726 ARDOUR_UI::launch_subscribe ()
3728 PBD::open_uri ("https://community.ardour.org/s/subscribe");
3732 ARDOUR_UI::launch_cheat_sheet ()
3735 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheat_sheet_osx.pdf");
3737 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheatsheet.pdf");
3742 ARDOUR_UI::launch_website ()
3744 PBD::open_uri ("http://ardour.org");
3748 ARDOUR_UI::launch_website_dev ()
3750 PBD::open_uri ("http://ardour.org/development.html");
3754 ARDOUR_UI::launch_forums ()
3756 PBD::open_uri ("https://community.ardour.org/forums");
3760 ARDOUR_UI::launch_howto_report ()
3762 PBD::open_uri ("http://ardour.org/reporting_bugs");
3766 ARDOUR_UI::loading_message (const std::string& msg)
3768 if (ARDOUR_COMMAND_LINE::no_splash) {
3776 splash->message (msg);
3780 ARDOUR_UI::show_splash ()
3784 splash = new Splash;
3794 ARDOUR_UI::hide_splash ()
3801 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title, const bool msg_delete)
3805 removed = rep.paths.size();
3808 MessageDialog msgd (_main_window,
3809 _("No files were ready for clean-up"),
3813 msgd.set_title (_("Clean-up"));
3814 msgd.set_secondary_text (_("If this seems suprising, \n\
3815 check for any existing snapshots.\n\
3816 These may still include regions that\n\
3817 require some unused files to continue to exist."));
3823 ArdourDialog results (_("Clean-up"), true, false);
3825 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
3826 CleanupResultsModelColumns() {
3830 Gtk::TreeModelColumn<std::string> visible_name;
3831 Gtk::TreeModelColumn<std::string> fullpath;
3835 CleanupResultsModelColumns results_columns;
3836 Glib::RefPtr<Gtk::ListStore> results_model;
3837 Gtk::TreeView results_display;
3839 results_model = ListStore::create (results_columns);
3840 results_display.set_model (results_model);
3841 results_display.append_column (list_title, results_columns.visible_name);
3843 results_display.set_name ("CleanupResultsList");
3844 results_display.set_headers_visible (true);
3845 results_display.set_headers_clickable (false);
3846 results_display.set_reorderable (false);
3848 Gtk::ScrolledWindow list_scroller;
3851 Gtk::HBox dhbox; // the hbox for the image and text
3852 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
3853 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
3855 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
3857 const string dead_directory = _session->session_directory().dead_path();
3860 %1 - number of files removed
3861 %2 - location of "dead"
3862 %3 - size of files affected
3863 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
3866 const char* bprefix;
3867 double space_adjusted = 0;
3869 if (rep.space < 1000) {
3871 space_adjusted = rep.space;
3872 } else if (rep.space < 1000000) {
3873 bprefix = _("kilo");
3874 space_adjusted = floorf((float)rep.space / 1000.0);
3875 } else if (rep.space < 1000000 * 1000) {
3876 bprefix = _("mega");
3877 space_adjusted = floorf((float)rep.space / (1000.0 * 1000.0));
3879 bprefix = _("giga");
3880 space_adjusted = floorf((float)rep.space / (1000.0 * 1000 * 1000.0));
3884 txt.set_markup (string_compose (P_("\
3885 The following file was deleted from %2,\n\
3886 releasing %3 %4bytes of disk space", "\
3887 The following %1 files were deleted from %2,\n\
3888 releasing %3 %4bytes of disk space", removed),
3889 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3891 txt.set_markup (string_compose (P_("\
3892 The following file was not in use and \n\
3893 has been moved to: %2\n\n\
3894 After a restart of %5\n\n\
3895 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3896 will release an additional %3 %4bytes of disk space.\n", "\
3897 The following %1 files were not in use and \n\
3898 have been moved to: %2\n\n\
3899 After a restart of %5\n\n\
3900 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3901 will release an additional %3 %4bytes of disk space.\n", removed),
3902 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3905 dhbox.pack_start (*dimage, true, false, 5);
3906 dhbox.pack_start (txt, true, false, 5);
3908 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
3909 TreeModel::Row row = *(results_model->append());
3910 row[results_columns.visible_name] = *i;
3911 row[results_columns.fullpath] = *i;
3914 list_scroller.add (results_display);
3915 list_scroller.set_size_request (-1, 150);
3916 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
3918 dvbox.pack_start (dhbox, true, false, 5);
3919 dvbox.pack_start (list_scroller, true, false, 5);
3920 ddhbox.pack_start (dvbox, true, false, 5);
3922 results.get_vbox()->pack_start (ddhbox, true, false, 5);
3923 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
3924 results.set_default_response (RESPONSE_CLOSE);
3925 results.set_position (Gtk::WIN_POS_MOUSE);
3927 results_display.show();
3928 list_scroller.show();
3935 //results.get_vbox()->show();
3936 results.set_resizable (false);
3943 ARDOUR_UI::cleanup ()
3945 if (_session == 0) {
3946 /* shouldn't happen: menu item is insensitive */
3951 MessageDialog checker (_("Are you sure you want to clean-up?"),
3953 Gtk::MESSAGE_QUESTION,
3956 checker.set_title (_("Clean-up"));
3958 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
3959 ALL undo/redo information will be lost if you clean-up.\n\
3960 Clean-up will move all unused files to a \"dead\" location."));
3962 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3963 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
3964 checker.set_default_response (RESPONSE_CANCEL);
3966 checker.set_name (_("CleanupDialog"));
3967 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3968 checker.set_position (Gtk::WIN_POS_MOUSE);
3970 switch (checker.run()) {
3971 case RESPONSE_ACCEPT:
3977 ARDOUR::CleanupReport rep;
3979 editor->prepare_for_cleanup ();
3981 /* do not allow flush until a session is reloaded */
3983 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3985 act->set_sensitive (false);
3988 if (_session->cleanup_sources (rep)) {
3989 editor->finish_cleanup ();
3993 editor->finish_cleanup ();
3996 display_cleanup_results (rep, _("Cleaned Files"), false);
4000 ARDOUR_UI::flush_trash ()
4002 if (_session == 0) {
4003 /* shouldn't happen: menu item is insensitive */
4007 ARDOUR::CleanupReport rep;
4009 if (_session->cleanup_trash_sources (rep)) {
4013 display_cleanup_results (rep, _("deleted file"), true);
4017 ARDOUR_UI::cleanup_peakfiles ()
4019 if (_session == 0) {
4020 /* shouldn't happen: menu item is insensitive */
4024 if (! _session->can_cleanup_peakfiles ()) {
4028 // get all region-views in this session
4030 TrackViewList empty;
4032 editor->get_regions_after(rs, (framepos_t) 0, empty);
4033 std::list<RegionView*> views = rs.by_layer();
4035 // remove displayed audio-region-views waveforms
4036 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
4037 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
4038 if (!arv) { continue ; }
4039 arv->delete_waves();
4042 // cleanup peak files:
4043 // - stop pending peakfile threads
4044 // - close peakfiles if any
4045 // - remove peak dir in session
4046 // - setup peakfiles (background thread)
4047 _session->cleanup_peakfiles ();
4049 // re-add waves to ARV
4050 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
4051 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
4052 if (!arv) { continue ; }
4053 arv->create_waves();
4057 PresentationInfo::order_t
4058 ARDOUR_UI::translate_order (RouteDialogs::InsertAt place)
4060 if (editor->get_selection().tracks.empty()) {
4061 return PresentationInfo::max_order;
4064 PresentationInfo::order_t order_hint = PresentationInfo::max_order;
4067 we want the new routes to have their order keys set starting from
4068 the highest order key in the selection + 1 (if available).
4071 if (place == RouteDialogs::AfterSelection) {
4072 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.back());
4074 order_hint = rtav->route()->presentation_info().order();
4077 } else if (place == RouteDialogs::BeforeSelection) {
4078 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.front());
4080 order_hint = rtav->route()->presentation_info().order();
4082 } else if (place == RouteDialogs::First) {
4085 /* leave order_hint at max_order */
4092 ARDOUR_UI::start_duplicate_routes ()
4094 if (!duplicate_routes_dialog) {
4095 duplicate_routes_dialog = new DuplicateRouteDialog;
4098 if (duplicate_routes_dialog->restart (_session)) {
4102 duplicate_routes_dialog->present ();
4106 ARDOUR_UI::add_route ()
4108 if (!add_route_dialog.get (false)) {
4109 add_route_dialog->signal_response().connect (sigc::mem_fun (*this, &ARDOUR_UI::add_route_dialog_finished));
4116 if (add_route_dialog->is_visible()) {
4117 /* we're already doing this */
4121 add_route_dialog->set_position (WIN_POS_MOUSE);
4122 add_route_dialog->present();
4126 ARDOUR_UI::add_route_dialog_finished (int r)
4130 add_route_dialog->hide();
4133 case RESPONSE_ACCEPT:
4140 if ((count = add_route_dialog->count()) <= 0) {
4144 PresentationInfo::order_t order = translate_order (add_route_dialog->insert_at());
4145 string template_path = add_route_dialog->track_template();
4146 DisplaySuspender ds;
4148 if (!template_path.empty()) {
4149 if (add_route_dialog->name_template_is_default()) {
4150 _session->new_route_from_template (count, order, template_path, string());
4152 _session->new_route_from_template (count, order, template_path, add_route_dialog->name_template());
4157 ChanCount input_chan= add_route_dialog->channels ();
4158 ChanCount output_chan;
4159 string name_template = add_route_dialog->name_template ();
4160 PluginInfoPtr instrument = add_route_dialog->requested_instrument ();
4161 RouteGroup* route_group = add_route_dialog->route_group ();
4162 AutoConnectOption oac = Config->get_output_auto_connect();
4163 bool strict_io = add_route_dialog->use_strict_io ();
4165 if (oac & AutoConnectMaster) {
4166 output_chan.set (DataType::AUDIO, (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan.n_audio()));
4167 output_chan.set (DataType::MIDI, 0);
4169 output_chan = input_chan;
4172 /* XXX do something with name template */
4174 Session::ProcessorChangeBlocker pcb (_session);
4176 switch (add_route_dialog->type_wanted()) {
4177 case AddRouteDialog::AudioTrack:
4178 session_add_audio_track (input_chan.n_audio(), output_chan.n_audio(), add_route_dialog->mode(), route_group, count, name_template, strict_io, order);
4180 case AddRouteDialog::MidiTrack:
4181 session_add_midi_track (route_group, count, name_template, strict_io, instrument, 0, order);
4183 case AddRouteDialog::MixedTrack:
4184 session_add_mixed_track (input_chan, output_chan, route_group, count, name_template, strict_io, instrument, 0, order);
4186 case AddRouteDialog::AudioBus:
4187 session_add_audio_bus (input_chan.n_audio(), output_chan.n_audio(), route_group, count, name_template, strict_io, order);
4189 case AddRouteDialog::MidiBus:
4190 session_add_midi_bus (route_group, count, name_template, strict_io, instrument, 0, order);
4192 case AddRouteDialog::VCAMaster:
4193 session_add_vca (name_template, count);
4199 ARDOUR_UI::add_lua_script ()
4205 LuaScriptInfoPtr spi;
4206 ScriptSelector ss ("Add Lua Session Script", LuaScriptInfo::Session);
4207 switch (ss.run ()) {
4208 case Gtk::RESPONSE_ACCEPT:
4216 std::string script = "";
4219 script = Glib::file_get_contents (spi->path);
4220 } catch (Glib::FileError e) {
4221 string msg = string_compose (_("Cannot read session script '%1': %2"), spi->path, e.what());
4222 MessageDialog am (msg);
4227 LuaScriptParamList lsp = LuaScriptParams::script_params (spi, "sess_params");
4228 std::vector<std::string> reg = _session->registered_lua_functions ();
4230 ScriptParameterDialog spd (_("Set Script Parameters"), spi, reg, lsp);
4231 switch (spd.run ()) {
4232 case Gtk::RESPONSE_ACCEPT:
4239 _session->register_lua_function (spd.name(), script, lsp);
4240 } catch (luabridge::LuaException const& e) {
4241 string msg = string_compose (_("Session script '%1' instantiation failed: %2"), spd.name(), e.what ());
4242 MessageDialog am (msg);
4244 } catch (SessionException e) {
4245 string msg = string_compose (_("Loading Session script '%1' failed: %2"), spd.name(), e.what ());
4246 MessageDialog am (msg);
4252 ARDOUR_UI::remove_lua_script ()
4257 if (_session->registered_lua_function_count () == 0) {
4258 string msg = _("There are no active Lua session scripts present in this session.");
4259 MessageDialog am (msg);
4264 std::vector<std::string> reg = _session->registered_lua_functions ();
4265 SessionScriptManager sm ("Remove Lua Session Script", reg);
4266 switch (sm.run ()) {
4267 case Gtk::RESPONSE_ACCEPT:
4273 _session->unregister_lua_function (sm.name());
4274 } catch (luabridge::LuaException const& e) {
4275 string msg = string_compose (_("Session script '%1' removal failed: %2"), sm.name(), e.what ());
4276 MessageDialog am (msg);
4282 ARDOUR_UI::stop_video_server (bool ask_confirm)
4284 if (!video_server_process && ask_confirm) {
4285 warning << string_compose (_("Video-Server was not launched by %1. The request to stop it is ignored."), PROGRAM_NAME) << endmsg;
4287 if (video_server_process) {
4289 ArdourDialog confirm (_("Stop Video-Server"), true);
4290 Label m (_("Do you really want to stop the Video Server?"));
4291 confirm.get_vbox()->pack_start (m, true, true);
4292 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
4293 confirm.add_button (_("Yes, Stop It"), Gtk::RESPONSE_ACCEPT);
4294 confirm.show_all ();
4295 if (confirm.run() == RESPONSE_CANCEL) {
4299 delete video_server_process;
4300 video_server_process =0;
4305 ARDOUR_UI::start_video_server_menu (Gtk::Window* float_window)
4307 ARDOUR_UI::start_video_server( float_window, true);
4311 ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg)
4317 if (ARDOUR_UI::instance()->video_timeline->check_server()) {
4318 if (video_server_process) {
4319 popup_error(_("The Video Server is already started."));
4321 popup_error(_("An external Video Server is configured and can be reached. Not starting a new instance."));
4327 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4329 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4331 VideoServerDialog *video_server_dialog = new VideoServerDialog (_session);
4333 video_server_dialog->set_transient_for (*float_window);
4336 if (!Config->get_show_video_server_dialog() && firsttime < 2) {
4337 video_server_dialog->hide();
4339 ResponseType r = (ResponseType) video_server_dialog->run ();
4340 video_server_dialog->hide();
4341 if (r != RESPONSE_ACCEPT) { return false; }
4342 if (video_server_dialog->show_again()) {
4343 Config->set_show_video_server_dialog(false);
4347 std::string icsd_exec = video_server_dialog->get_exec_path();
4348 std::string icsd_docroot = video_server_dialog->get_docroot();
4349 if (icsd_docroot.empty()) {
4350 #ifndef PLATFORM_WINDOWS
4351 icsd_docroot = X_("/");
4353 icsd_docroot = X_("C:\\");
4358 if (g_lstat (icsd_docroot.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode)) {
4359 warning << _("Specified docroot is not an existing directory.") << endmsg;
4362 #ifndef PLATFORM_WINDOWS
4363 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4364 || (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0 ) {
4365 warning << _("Given Video Server is not an executable file.") << endmsg;
4369 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4370 || (sb.st_mode & (S_IXUSR)) == 0 ) {
4371 warning << _("Given Video Server is not an executable file.") << endmsg;
4377 argp=(char**) calloc(9,sizeof(char*));
4378 argp[0] = strdup(icsd_exec.c_str());
4379 argp[1] = strdup("-P");
4380 argp[2] = (char*) calloc(16,sizeof(char)); snprintf(argp[2], 16, "%s", video_server_dialog->get_listenaddr().c_str());
4381 argp[3] = strdup("-p");
4382 argp[4] = (char*) calloc(6,sizeof(char)); snprintf(argp[4], 6, "%i", video_server_dialog->get_listenport());
4383 argp[5] = strdup("-C");
4384 argp[6] = (char*) calloc(6,sizeof(char)); snprintf(argp[6], 6, "%i", video_server_dialog->get_cachesize());
4385 argp[7] = strdup(icsd_docroot.c_str());
4387 stop_video_server();
4389 if (icsd_docroot == X_("/") || icsd_docroot == X_("C:\\")) {
4390 Config->set_video_advanced_setup(false);
4392 std::ostringstream osstream;
4393 osstream << "http://127.0.0.1:" << video_server_dialog->get_listenport() << "/";
4394 Config->set_video_server_url(osstream.str());
4395 Config->set_video_server_docroot(icsd_docroot);
4396 Config->set_video_advanced_setup(true);
4399 if (video_server_process) {
4400 delete video_server_process;
4403 video_server_process = new ARDOUR::SystemExec(icsd_exec, argp);
4404 if (video_server_process->start()) {
4405 warning << _("Cannot launch the video-server") << endmsg;
4408 int timeout = 120; // 6 sec
4409 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4410 Glib::usleep (50000);
4412 if (--timeout <= 0 || !video_server_process->is_running()) break;
4415 warning << _("Video-server was started but does not respond to requests...") << endmsg;
4417 if (!ARDOUR_UI::instance()->video_timeline->check_server_docroot()) {
4418 delete video_server_process;
4419 video_server_process = 0;
4427 ARDOUR_UI::add_video (Gtk::Window* float_window)
4433 if (!start_video_server(float_window, false)) {
4434 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4439 add_video_dialog->set_transient_for (*float_window);
4442 if (add_video_dialog->is_visible()) {
4443 /* we're already doing this */
4447 ResponseType r = (ResponseType) add_video_dialog->run ();
4448 add_video_dialog->hide();
4449 if (r != RESPONSE_ACCEPT) { return; }
4451 bool local_file, orig_local_file;
4452 std::string path = add_video_dialog->file_name(local_file);
4454 std::string orig_path = path;
4455 orig_local_file = local_file;
4457 bool auto_set_session_fps = add_video_dialog->auto_set_session_fps();
4459 if (local_file && !Glib::file_test(path, Glib::FILE_TEST_EXISTS)) {
4460 warning << string_compose(_("could not open %1"), path) << endmsg;
4463 if (!local_file && path.length() == 0) {
4464 warning << _("no video-file selected") << endmsg;
4468 std::string audio_from_video;
4469 bool detect_ltc = false;
4471 switch (add_video_dialog->import_option()) {
4472 case VTL_IMPORT_TRANSCODE:
4474 TranscodeVideoDialog *transcode_video_dialog;
4475 transcode_video_dialog = new TranscodeVideoDialog (_session, path);
4476 ResponseType r = (ResponseType) transcode_video_dialog->run ();
4477 transcode_video_dialog->hide();
4478 if (r != RESPONSE_ACCEPT) {
4479 delete transcode_video_dialog;
4483 audio_from_video = transcode_video_dialog->get_audiofile();
4485 if (!audio_from_video.empty() && transcode_video_dialog->detect_ltc()) {
4488 else if (!audio_from_video.empty()) {
4489 editor->embed_audio_from_video(
4491 video_timeline->get_offset(),
4492 (transcode_video_dialog->import_option() != VTL_IMPORT_NO_VIDEO)
4495 switch (transcode_video_dialog->import_option()) {
4496 case VTL_IMPORT_TRANSCODED:
4497 path = transcode_video_dialog->get_filename();
4500 case VTL_IMPORT_REFERENCE:
4503 delete transcode_video_dialog;
4506 delete transcode_video_dialog;
4510 case VTL_IMPORT_NONE:
4514 /* strip _session->session_directory().video_path() from video file if possible */
4515 if (local_file && !path.compare(0, _session->session_directory().video_path().size(), _session->session_directory().video_path())) {
4516 path=path.substr(_session->session_directory().video_path().size());
4517 if (path.at(0) == G_DIR_SEPARATOR) {
4518 path=path.substr(1);
4522 video_timeline->set_update_session_fps(auto_set_session_fps);
4524 if (video_timeline->video_file_info(path, local_file)) {
4525 XMLNode* node = new XMLNode(X_("Videotimeline"));
4526 node->add_property (X_("Filename"), path);
4527 node->add_property (X_("AutoFPS"), auto_set_session_fps?X_("1"):X_("0"));
4528 node->add_property (X_("LocalFile"), local_file?X_("1"):X_("0"));
4529 if (orig_local_file) {
4530 node->add_property (X_("OriginalVideoFile"), orig_path);
4532 node->remove_property (X_("OriginalVideoFile"));
4534 _session->add_extra_xml (*node);
4535 _session->set_dirty ();
4537 if (!audio_from_video.empty() && detect_ltc) {
4538 std::vector<LTCFileReader::LTCMap> ltc_seq;
4541 /* TODO ask user about TV standard (LTC alignment if any) */
4542 LTCFileReader ltcr (audio_from_video, video_timeline->get_video_file_fps());
4543 /* TODO ASK user which channel: 0 .. ltcr->channels() - 1 */
4545 ltc_seq = ltcr.read_ltc (/*channel*/ 0, /*max LTC frames to decode*/ 15);
4547 /* TODO seek near end of file, and read LTC until end.
4548 * if it fails to find any LTC frames, scan complete file
4550 * calculate drift of LTC compared to video-duration,
4551 * ask user for reference (timecode from start/mid/end)
4554 // LTCFileReader will have written error messages
4557 ::g_unlink(audio_from_video.c_str());
4559 if (ltc_seq.size() == 0) {
4560 PBD::error << _("No LTC detected, video will not be aligned.") << endmsg;
4562 /* the very first TC in the file is somteimes not aligned properly */
4563 int i = ltc_seq.size() -1;
4564 ARDOUR::frameoffset_t video_start_offset =
4565 _session->nominal_frame_rate() * (ltc_seq[i].timecode_sec - ltc_seq[i].framepos_sec);
4566 PBD::info << string_compose (_("Align video-start to %1 [samples]"), video_start_offset) << endmsg;
4567 video_timeline->set_offset(video_start_offset);
4571 _session->maybe_update_session_range(
4572 std::max(video_timeline->get_offset(), (ARDOUR::frameoffset_t) 0),
4573 std::max(video_timeline->get_offset() + video_timeline->get_duration(), (ARDOUR::frameoffset_t) 0));
4576 if (add_video_dialog->launch_xjadeo() && local_file) {
4577 editor->set_xjadeo_sensitive(true);
4578 editor->toggle_xjadeo_proc(1);
4580 editor->toggle_xjadeo_proc(0);
4582 editor->toggle_ruler_video(true);
4587 ARDOUR_UI::remove_video ()
4589 video_timeline->close_session();
4590 editor->toggle_ruler_video(false);
4593 video_timeline->set_offset_locked(false);
4594 video_timeline->set_offset(0);
4596 /* delete session state */
4597 XMLNode* node = new XMLNode(X_("Videotimeline"));
4598 _session->add_extra_xml(*node);
4599 node = new XMLNode(X_("Videomonitor"));
4600 _session->add_extra_xml(*node);
4601 node = new XMLNode(X_("Videoexport"));
4602 _session->add_extra_xml(*node);
4603 stop_video_server();
4607 ARDOUR_UI::flush_videotimeline_cache (bool localcacheonly)
4609 if (localcacheonly) {
4610 video_timeline->vmon_update();
4612 video_timeline->flush_cache();
4614 editor->queue_visual_videotimeline_update();
4618 ARDOUR_UI::export_video (bool range)
4620 if (ARDOUR::Config->get_show_video_export_info()) {
4621 ExportVideoInfobox infobox (_session);
4622 Gtk::ResponseType rv = (Gtk::ResponseType) infobox.run();
4623 if (infobox.show_again()) {
4624 ARDOUR::Config->set_show_video_export_info(false);
4627 case GTK_RESPONSE_YES:
4628 PBD::open_uri (ARDOUR::Config->get_reference_manual_url() + "/video-timeline/operations/#export");
4634 export_video_dialog->set_session (_session);
4635 export_video_dialog->apply_state(editor->get_selection().time, range);
4636 export_video_dialog->run ();
4637 export_video_dialog->hide ();
4641 ARDOUR_UI::preferences_settings () const
4646 node = _session->instant_xml(X_("Preferences"));
4648 node = Config->instant_xml(X_("Preferences"));
4652 node = new XMLNode (X_("Preferences"));
4659 ARDOUR_UI::mixer_settings () const
4664 node = _session->instant_xml(X_("Mixer"));
4666 node = Config->instant_xml(X_("Mixer"));
4670 node = new XMLNode (X_("Mixer"));
4677 ARDOUR_UI::main_window_settings () const
4682 node = _session->instant_xml(X_("Main"));
4684 node = Config->instant_xml(X_("Main"));
4688 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4689 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4694 node = new XMLNode (X_("Main"));
4701 ARDOUR_UI::editor_settings () const
4706 node = _session->instant_xml(X_("Editor"));
4708 node = Config->instant_xml(X_("Editor"));
4712 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4713 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4718 node = new XMLNode (X_("Editor"));
4725 ARDOUR_UI::keyboard_settings () const
4729 node = Config->extra_xml(X_("Keyboard"));
4732 node = new XMLNode (X_("Keyboard"));
4739 ARDOUR_UI::create_xrun_marker (framepos_t where)
4742 Location *location = new Location (*_session, where, where, _("xrun"), Location::IsMark);
4743 _session->locations()->add (location);
4748 ARDOUR_UI::halt_on_xrun_message ()
4750 cerr << "HALT on xrun\n";
4751 MessageDialog msg (_main_window, _("Recording was stopped because your system could not keep up."));
4756 ARDOUR_UI::xrun_handler (framepos_t where)
4762 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
4764 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
4765 create_xrun_marker(where);
4768 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
4769 halt_on_xrun_message ();
4774 ARDOUR_UI::disk_overrun_handler ()
4776 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
4778 if (!have_disk_speed_dialog_displayed) {
4779 have_disk_speed_dialog_displayed = true;
4780 MessageDialog* msg = new MessageDialog (_main_window, string_compose (_("\
4781 The disk system on your computer\n\
4782 was not able to keep up with %1.\n\
4784 Specifically, it failed to write data to disk\n\
4785 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
4786 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4792 /* TODO: this is getting elaborate enough to warrant being split into a dedicated class */
4793 static MessageDialog *scan_dlg = NULL;
4794 static ProgressBar *scan_pbar = NULL;
4795 static HBox *scan_tbox = NULL;
4796 static Gtk::Button *scan_timeout_button;
4799 ARDOUR_UI::cancel_plugin_scan ()
4801 PluginManager::instance().cancel_plugin_scan();
4805 ARDOUR_UI::cancel_plugin_timeout ()
4807 PluginManager::instance().cancel_plugin_timeout();
4808 scan_timeout_button->set_sensitive (false);
4812 ARDOUR_UI::plugin_scan_timeout (int timeout)
4814 if (!scan_dlg || !scan_dlg->is_mapped() || !scan_pbar) {
4818 scan_pbar->set_sensitive (false);
4819 scan_timeout_button->set_sensitive (true);
4820 scan_pbar->set_fraction ((float) timeout / (float) Config->get_vst_scan_timeout());
4823 scan_pbar->set_sensitive (false);
4824 scan_timeout_button->set_sensitive (false);
4830 ARDOUR_UI::plugin_scan_dialog (std::string type, std::string plugin, bool can_cancel)
4832 if (type == X_("closeme") && !(scan_dlg && scan_dlg->is_mapped())) {
4836 const bool cancelled = PluginManager::instance().cancelled();
4837 if (type != X_("closeme") && (!UIConfiguration::instance().get_show_plugin_scan_window()) && !_initial_verbose_plugin_scan) {
4838 if (cancelled && scan_dlg->is_mapped()) {
4843 if (cancelled || !can_cancel) {
4848 static Gtk::Button *cancel_button;
4850 scan_dlg = new MessageDialog("", false, MESSAGE_INFO, BUTTONS_NONE); // TODO manage
4851 VBox* vbox = scan_dlg->get_vbox();
4852 vbox->set_size_request(400,-1);
4853 scan_dlg->set_title (_("Scanning for plugins"));
4855 cancel_button = manage(new Gtk::Button(_("Cancel plugin scan")));
4856 cancel_button->set_name ("EditorGTKButton");
4857 cancel_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_scan) );
4858 cancel_button->show();
4860 scan_dlg->get_vbox()->pack_start ( *cancel_button, PACK_SHRINK);
4862 scan_tbox = manage( new HBox() );
4864 scan_timeout_button = manage(new Gtk::Button(_("Stop Timeout")));
4865 scan_timeout_button->set_name ("EditorGTKButton");
4866 scan_timeout_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_timeout) );
4867 scan_timeout_button->show();
4869 scan_pbar = manage(new ProgressBar());
4870 scan_pbar->set_orientation(Gtk::PROGRESS_RIGHT_TO_LEFT);
4871 scan_pbar->set_text(_("Scan Timeout"));
4874 scan_tbox->pack_start (*scan_pbar, PACK_EXPAND_WIDGET, 4);
4875 scan_tbox->pack_start (*scan_timeout_button, PACK_SHRINK, 4);
4877 scan_dlg->get_vbox()->pack_start (*scan_tbox, PACK_SHRINK, 4);
4880 assert(scan_dlg && scan_tbox && cancel_button);
4882 if (type == X_("closeme")) {
4886 scan_dlg->set_message(type + ": " + Glib::path_get_basename(plugin));
4889 if (!can_cancel || !cancelled) {
4890 scan_timeout_button->set_sensitive(false);
4892 cancel_button->set_sensitive(can_cancel && !cancelled);
4898 ARDOUR_UI::gui_idle_handler ()
4901 /* due to idle calls, gtk_events_pending() may always return true */
4902 while (gtk_events_pending() && --timeout) {
4903 gtk_main_iteration ();
4908 ARDOUR_UI::disk_underrun_handler ()
4910 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
4912 if (!have_disk_speed_dialog_displayed) {
4913 have_disk_speed_dialog_displayed = true;
4914 MessageDialog* msg = new MessageDialog (
4915 _main_window, string_compose (_("The disk system on your computer\n\
4916 was not able to keep up with %1.\n\
4918 Specifically, it failed to read data from disk\n\
4919 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
4920 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4926 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
4928 have_disk_speed_dialog_displayed = false;
4933 ARDOUR_UI::session_dialog (std::string msg)
4935 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
4939 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
4946 ARDOUR_UI::pending_state_dialog ()
4948 HBox* hbox = manage (new HBox());
4949 Image* image = manage (new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG));
4950 ArdourDialog dialog (_("Crash Recovery"), true);
4951 Label message (string_compose (_("\
4952 This session appears to have been in the\n\
4953 middle of recording when %1 or\n\
4954 the computer was shutdown.\n\
4956 %1 can recover any captured audio for\n\
4957 you, or it can ignore it. Please decide\n\
4958 what you would like to do.\n"), PROGRAM_NAME));
4959 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4960 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4961 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4962 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4963 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
4964 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
4965 dialog.set_default_response (RESPONSE_ACCEPT);
4966 dialog.set_position (WIN_POS_CENTER);
4971 switch (dialog.run ()) {
4972 case RESPONSE_ACCEPT:
4980 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
4982 HBox* hbox = new HBox();
4983 Image* image = new Image (Stock::DIALOG_WARNING, ICON_SIZE_DIALOG);
4984 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
4985 Label message (string_compose (_("\
4986 This session was created with a sample rate of %1 Hz, but\n\
4987 %2 is currently running at %3 Hz. If you load this session,\n\
4988 audio may be played at the wrong sample rate.\n"), desired, PROGRAM_NAME, actual));
4990 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4991 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4992 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4993 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4994 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
4995 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
4996 dialog.set_default_response (RESPONSE_ACCEPT);
4997 dialog.set_position (WIN_POS_CENTER);
5002 switch (dialog.run()) {
5003 case RESPONSE_ACCEPT:
5013 ARDOUR_UI::sr_mismatch_message (framecnt_t desired, framecnt_t actual)
5015 MessageDialog msg (string_compose (_("\
5016 This session was created with a sample rate of %1 Hz, but\n\
5017 %2 is currently running at %3 Hz.\n\
5018 Audio will be recorded and played at the wrong sample rate.\n\
5019 Re-Configure the Audio Engine in\n\
5020 Menu > Window > Audio/Midi Setup"),
5021 desired, PROGRAM_NAME, actual),
5023 Gtk::MESSAGE_WARNING);
5028 ARDOUR_UI::use_config ()
5030 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
5032 set_transport_controllable_state (*node);
5037 ARDOUR_UI::update_transport_clocks (framepos_t pos)
5039 if (UIConfiguration::instance().get_primary_clock_delta_edit_cursor()) {
5040 primary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
5042 primary_clock->set (pos);
5045 if (UIConfiguration::instance().get_secondary_clock_delta_edit_cursor()) {
5046 secondary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
5048 secondary_clock->set (pos);
5051 if (big_clock_window) {
5052 big_clock->set (pos);
5054 ARDOUR_UI::instance()->video_timeline->manual_seek_video_monitor(pos);
5058 ARDOUR_UI::step_edit_status_change (bool yn)
5060 // XXX should really store pre-step edit status of things
5061 // we make insensitive
5064 rec_button.set_active_state (Gtkmm2ext::ImplicitActive);
5065 rec_button.set_sensitive (false);
5067 rec_button.unset_active_state ();;
5068 rec_button.set_sensitive (true);
5073 ARDOUR_UI::record_state_changed ()
5075 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
5078 /* why bother - the clock isn't visible */
5082 ActionManager::set_sensitive (ActionManager::rec_sensitive_actions, !_session->actively_recording());
5084 if (big_clock_window) {
5085 if (_session->record_status () == Session::Recording && _session->have_rec_enabled_track ()) {
5086 big_clock->set_active (true);
5088 big_clock->set_active (false);
5095 ARDOUR_UI::first_idle ()
5098 _session->allow_auto_play (true);
5102 editor->first_idle();
5105 Keyboard::set_can_save_keybindings (true);
5110 ARDOUR_UI::store_clock_modes ()
5112 XMLNode* node = new XMLNode(X_("ClockModes"));
5114 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
5115 XMLNode* child = new XMLNode (X_("Clock"));
5117 child->add_property (X_("name"), (*x)->name());
5118 child->add_property (X_("mode"), enum_2_string ((*x)->mode()));
5119 child->add_property (X_("on"), ((*x)->off() ? X_("no") : X_("yes")));
5121 node->add_child_nocopy (*child);
5124 _session->add_extra_xml (*node);
5125 _session->set_dirty ();
5128 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
5129 : Controllable (name), ui (u), type(tp)
5135 ARDOUR_UI::TransportControllable::set_value (double val, PBD::Controllable::GroupControlDisposition /*group_override*/)
5138 /* do nothing: these are radio-style actions */
5142 const char *action = 0;
5146 action = X_("Roll");
5149 action = X_("Stop");
5152 action = X_("GotoStart");
5155 action = X_("GotoEnd");
5158 action = X_("Loop");
5161 action = X_("PlaySelection");
5164 action = X_("Record");
5174 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
5182 ARDOUR_UI::TransportControllable::get_value (void) const
5209 ARDOUR_UI::setup_profile ()
5211 if (gdk_screen_width() < 1200 || getenv ("ARDOUR_NARROW_SCREEN")) {
5212 Profile->set_small_screen ();
5215 if (g_getenv ("TRX")) {
5216 Profile->set_trx ();
5219 if (g_getenv ("MIXBUS")) {
5220 Profile->set_mixbus ();
5225 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
5227 MissingFileDialog dialog (s, str, type);
5232 int result = dialog.run ();
5239 return 1; // quit entire session load
5242 result = dialog.get_action ();
5248 ARDOUR_UI::ambiguous_file (std::string file, std::vector<std::string> hits)
5250 AmbiguousFileDialog dialog (file, hits);
5257 return dialog.get_which ();
5260 /** Allocate our thread-local buffers */
5262 ARDOUR_UI::get_process_buffers ()
5264 _process_thread->get_buffers ();
5267 /** Drop our thread-local buffers */
5269 ARDOUR_UI::drop_process_buffers ()
5271 _process_thread->drop_buffers ();
5275 ARDOUR_UI::feedback_detected ()
5277 _feedback_exists = true;
5281 ARDOUR_UI::successful_graph_sort ()
5283 _feedback_exists = false;
5287 ARDOUR_UI::midi_panic ()
5290 _session->midi_panic();
5295 ARDOUR_UI::session_format_mismatch (std::string xml_path, std::string backup_path)
5297 const char* start_big = "<span size=\"x-large\" weight=\"bold\">";
5298 const char* end_big = "</span>";
5299 const char* start_mono = "<tt>";
5300 const char* end_mono = "</tt>";
5302 MessageDialog msg (string_compose (_("%4This is a session from an older version of %3%5\n\n"
5303 "%3 has copied the old session file\n\n%6%1%7\n\nto\n\n%6%2%7\n\n"
5304 "From now on, use the backup copy with older versions of %3"),
5305 xml_path, backup_path, PROGRAM_NAME,
5307 start_mono, end_mono), true);
5314 ARDOUR_UI::reset_peak_display ()
5316 if (!_session || !_session->master_out() || !editor_meter) return;
5317 editor_meter->clear_meters();
5318 editor_meter_max_peak = -INFINITY;
5319 editor_meter_peak_display.set_active_state ( Gtkmm2ext::Off );
5323 ARDOUR_UI::reset_group_peak_display (RouteGroup* group)
5325 if (!_session || !_session->master_out()) return;
5326 if (group == _session->master_out()->route_group()) {
5327 reset_peak_display ();
5332 ARDOUR_UI::reset_route_peak_display (Route* route)
5334 if (!_session || !_session->master_out()) return;
5335 if (_session->master_out().get() == route) {
5336 reset_peak_display ();
5341 ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate)
5343 audio_midi_setup->set_desired_sample_rate (desired_sample_rate);
5344 audio_midi_setup->set_position (WIN_POS_CENTER);
5346 if (Config->get_try_autostart_engine () || getenv ("TRY_AUTOSTART_ENGINE")) {
5347 audio_midi_setup->try_autostart ();
5348 if (ARDOUR::AudioEngine::instance()->running()) {
5354 int response = audio_midi_setup->run();
5355 printf("RESPONSE %d\n", response);
5357 case Gtk::RESPONSE_DELETE_EVENT:
5360 if (!AudioEngine::instance()->running()) {
5363 audio_midi_setup->hide ();
5371 ARDOUR_UI::transport_numpad_timeout ()
5373 _numpad_locate_happening = false;
5374 if (_numpad_timeout_connection.connected() )
5375 _numpad_timeout_connection.disconnect();
5380 ARDOUR_UI::transport_numpad_decimal ()
5382 _numpad_timeout_connection.disconnect();
5384 if (_numpad_locate_happening) {
5385 if (editor) editor->goto_nth_marker(_pending_locate_num - 1);
5386 _numpad_locate_happening = false;
5388 _pending_locate_num = 0;
5389 _numpad_locate_happening = true;
5390 _numpad_timeout_connection = Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::transport_numpad_timeout), 2*1000);
5395 ARDOUR_UI::transport_numpad_event (int num)
5397 if ( _numpad_locate_happening ) {
5398 _pending_locate_num = _pending_locate_num*10 + num;
5401 case 0: toggle_roll(false, false); break;
5402 case 1: transport_rewind(1); break;
5403 case 2: transport_forward(1); break;
5404 case 3: transport_record(true); break;
5405 case 4: toggle_session_auto_loop(); break;
5406 case 5: transport_record(false); toggle_session_auto_loop(); break;
5407 case 6: toggle_punch(); break;
5408 case 7: toggle_click(); break;
5409 case 8: toggle_auto_return(); break;
5410 case 9: toggle_follow_edits(); break;
5416 ARDOUR_UI::set_flat_buttons ()
5418 CairoWidget::set_flat_buttons( UIConfiguration::instance().get_flat_buttons() );
5422 ARDOUR_UI::audioengine_became_silent ()
5424 MessageDialog msg (string_compose (_("This is a free/demo copy of %1. It has just switched to silent mode."), PROGRAM_NAME),
5426 Gtk::MESSAGE_WARNING,
5430 msg.set_title (string_compose (_("%1 is now silent"), PROGRAM_NAME));
5432 Gtk::Label pay_label (string_compose (_("Please consider paying for a copy of %1 - you can pay whatever you want."), PROGRAM_NAME));
5433 Gtk::Label subscribe_label (_("Better yet become a subscriber - subscriptions start at US$1 per month."));
5434 Gtk::Button pay_button (_("Pay for a copy (via the web)"));
5435 Gtk::Button subscribe_button (_("Become a subscriber (via the web)"));
5436 Gtk::HBox pay_button_box;
5437 Gtk::HBox subscribe_button_box;
5439 pay_button_box.pack_start (pay_button, true, false);
5440 subscribe_button_box.pack_start (subscribe_button, true, false);
5442 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 */
5444 pay_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://ardour.org/download")));
5445 subscribe_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://community.ardour.org/s/subscribe")));
5447 msg.get_vbox()->pack_start (pay_label);
5448 msg.get_vbox()->pack_start (pay_button_box);
5449 msg.get_vbox()->pack_start (subscribe_label);
5450 msg.get_vbox()->pack_start (subscribe_button_box);
5452 msg.get_vbox()->show_all ();
5454 msg.add_button (_("Remain silent"), Gtk::RESPONSE_CANCEL);
5455 msg.add_button (_("Save and quit"), Gtk::RESPONSE_NO);
5456 msg.add_button (_("Give me more time"), Gtk::RESPONSE_YES);
5461 case Gtk::RESPONSE_YES:
5462 AudioEngine::instance()->reset_silence_countdown ();
5465 case Gtk::RESPONSE_NO:
5467 save_state_canfail ("");
5471 case Gtk::RESPONSE_CANCEL:
5473 /* don't reset, save session and exit */
5479 ARDOUR_UI::hide_application ()
5481 Application::instance ()-> hide ();
5485 ARDOUR_UI::setup_toplevel_window (Gtk::Window& window, const string& name, void* owner)
5487 /* icons, titles, WM stuff */
5489 static list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
5491 if (window_icons.empty()) {
5492 Glib::RefPtr<Gdk::Pixbuf> icon;
5493 if ((icon = ::get_icon (PROGRAM_NAME "-icon_16px"))) {
5494 window_icons.push_back (icon);
5496 if ((icon = ::get_icon (PROGRAM_NAME "-icon_22px"))) {
5497 window_icons.push_back (icon);
5499 if ((icon = ::get_icon (PROGRAM_NAME "-icon_32px"))) {
5500 window_icons.push_back (icon);
5502 if ((icon = ::get_icon (PROGRAM_NAME "-icon_48px"))) {
5503 window_icons.push_back (icon);
5507 if (!window_icons.empty()) {
5508 window.set_default_icon_list (window_icons);
5511 Gtkmm2ext::WindowTitle title (Glib::get_application_name());
5513 if (!name.empty()) {
5517 window.set_title (title.get_string());
5518 window.set_wmclass (string_compose (X_("%1_%1"), downcase (PROGRAM_NAME), downcase (name)), PROGRAM_NAME);
5520 window.set_flags (CAN_FOCUS);
5521 window.add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
5523 /* This is a hack to ensure that GTK-accelerators continue to
5524 * work. Once we switch over to entirely native bindings, this will be
5525 * unnecessary and should be removed
5527 window.add_accel_group (ActionManager::ui_manager->get_accel_group());
5529 window.signal_configure_event().connect (sigc::mem_fun (*this, &ARDOUR_UI::configure_handler));
5530 window.signal_window_state_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::tabbed_window_state_event_handler), owner));
5531 window.signal_key_press_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5532 window.signal_key_release_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5536 ARDOUR_UI::key_event_handler (GdkEventKey* ev, Gtk::Window* event_window)
5538 Gtkmm2ext::Bindings* bindings = 0;
5539 Gtk::Window* window = 0;
5541 /* until we get ardour bindings working, we are not handling key
5545 if (ev->type != GDK_KEY_PRESS) {
5549 if (event_window == &_main_window) {
5551 window = event_window;
5553 /* find current tab contents */
5555 Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page());
5557 /* see if it uses the ardour binding system */
5560 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(w->get_data ("ardour-bindings"));
5563 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("main window key event, bindings = %1, global = %2\n", bindings, &global_bindings));
5567 window = event_window;
5569 /* see if window uses ardour binding system */
5571 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(window->get_data ("ardour-bindings"));
5574 /* An empty binding set is treated as if it doesn't exist */
5576 if (bindings && bindings->empty()) {
5580 return key_press_focus_accelerator_handler (*window, ev, bindings);
5583 static Gtkmm2ext::Bindings*
5584 get_bindings_from_widget_heirarchy (GtkWidget** w)
5589 if ((p = g_object_get_data (G_OBJECT(*w), "ardour-bindings")) != 0) {
5592 *w = gtk_widget_get_parent (*w);
5595 return reinterpret_cast<Gtkmm2ext::Bindings*> (p);
5599 ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev, Gtkmm2ext::Bindings* bindings)
5601 GtkWindow* win = window.gobj();
5602 GtkWidget* focus = gtk_window_get_focus (win);
5603 GtkWidget* binding_widget = focus;
5604 bool special_handling_of_unmodified_accelerators = false;
5605 const guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK));
5609 /* some widget has keyboard focus */
5611 if (GTK_IS_ENTRY(focus) || Keyboard::some_magic_widget_has_focus()) {
5613 /* A particular kind of focusable widget currently has keyboard
5614 * focus. All unmodified key events should go to that widget
5615 * first and not be used as an accelerator by default
5618 special_handling_of_unmodified_accelerators = true;
5622 Gtkmm2ext::Bindings* focus_bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5623 if (focus_bindings) {
5624 bindings = focus_bindings;
5625 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Switch bindings based on focus widget, now using %1\n", bindings->name()));
5630 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",
5633 Gtkmm2ext::show_gdk_event_state (ev->state),
5634 special_handling_of_unmodified_accelerators,
5635 Keyboard::some_magic_widget_has_focus(),
5637 (focus ? gtk_widget_get_name (focus) : "no focus widget"),
5638 ((ev->state & mask) ? "yes" : "no"),
5639 window.get_title()));
5641 /* This exists to allow us to override the way GTK handles
5642 key events. The normal sequence is:
5644 a) event is delivered to a GtkWindow
5645 b) accelerators/mnemonics are activated
5646 c) if (b) didn't handle the event, propagate to
5647 the focus widget and/or focus chain
5649 The problem with this is that if the accelerators include
5650 keys without modifiers, such as the space bar or the
5651 letter "e", then pressing the key while typing into
5652 a text entry widget results in the accelerator being
5653 activated, instead of the desired letter appearing
5656 There is no good way of fixing this, but this
5657 represents a compromise. The idea is that
5658 key events involving modifiers (not Shift)
5659 get routed into the activation pathway first, then
5660 get propagated to the focus widget if necessary.
5662 If the key event doesn't involve modifiers,
5663 we deliver to the focus widget first, thus allowing
5664 it to get "normal text" without interference
5667 Of course, this can also be problematic: if there
5668 is a widget with focus, then it will swallow
5669 all "normal text" accelerators.
5673 if (!special_handling_of_unmodified_accelerators || (ev->state & mask)) {
5675 /* no special handling or there are modifiers in effect: accelerate first */
5677 DEBUG_TRACE (DEBUG::Accelerators, "\tactivate, then propagate\n");
5678 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tevent send-event:%1 time:%2 length:%3 name %7 string:%4 hardware_keycode:%5 group:%6\n",
5679 ev->send_event, ev->time, ev->length, ev->string, ev->hardware_keycode, ev->group, gdk_keyval_name (ev->keyval)));
5681 DEBUG_TRACE (DEBUG::Accelerators, "\tsending to window\n");
5682 KeyboardKey k (ev->state, ev->keyval);
5686 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tusing Ardour bindings %1 @ %2 for this event\n", bindings->name(), bindings));
5688 if (bindings->activate (k, Bindings::Press)) {
5689 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5693 if (binding_widget) {
5694 binding_widget = gtk_widget_get_parent (binding_widget);
5695 if (binding_widget) {
5696 bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5705 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5707 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5708 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5712 DEBUG_TRACE (DEBUG::Accelerators, "\tnot accelerated, now propagate\n");
5714 if (gtk_window_propagate_key_event (win, ev)) {
5715 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate handled\n");
5721 /* no modifiers, propagate first */
5723 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate, then activate\n");
5725 if (gtk_window_propagate_key_event (win, ev)) {
5726 DEBUG_TRACE (DEBUG::Accelerators, "\thandled by propagate\n");
5730 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagation didn't handle, so activate\n");
5731 KeyboardKey k (ev->state, ev->keyval);
5735 DEBUG_TRACE (DEBUG::Accelerators, "\tusing Ardour bindings for this window\n");
5738 if (bindings->activate (k, Bindings::Press)) {
5739 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5743 if (binding_widget) {
5744 binding_widget = gtk_widget_get_parent (binding_widget);
5745 if (binding_widget) {
5746 bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5755 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5757 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5758 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5763 DEBUG_TRACE (DEBUG::Accelerators, "\tnot handled\n");
5768 ARDOUR_UI::load_bindings ()
5770 if ((global_bindings = Bindings::get_bindings (X_("Global"), global_actions)) == 0) {
5771 error << _("Global keybindings are missing") << endmsg;
5776 ARDOUR_UI::cancel_solo ()
5779 _session->cancel_all_solo ();
5784 ARDOUR_UI::reset_focus (Gtk::Widget* w)
5786 /* this resets focus to the first focusable parent of the given widget,
5787 * or, if there is no focusable parent, cancels focus in the toplevel
5788 * window that the given widget is packed into (if there is one).
5795 Gtk::Widget* top = w->get_toplevel();
5797 if (!top || !top->is_toplevel()) {
5801 w = w->get_parent ();
5805 if (w->is_toplevel()) {
5806 /* Setting the focus widget to a Gtk::Window causes all
5807 * subsequent calls to ::has_focus() on the nominal
5808 * focus widget in that window to return
5809 * false. Workaround: never set focus to the toplevel
5815 if (w->get_can_focus ()) {
5816 Gtk::Window* win = dynamic_cast<Gtk::Window*> (top);
5817 win->set_focus (*w);
5820 w = w->get_parent ();
5823 if (top == &_main_window) {
5827 /* no focusable parent found, cancel focus in top level window.
5828 C++ API cannot be used for this. Thanks, references.
5831 gtk_window_set_focus (GTK_WINDOW(top->gobj()), 0);