2 Copyright (C) 1999-2013 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include "gtk2ardour-config.h"
22 #include "gtk2ardour-version.h"
32 #ifndef PLATFORM_WINDOWS
33 #include <sys/resource.h>
37 #include <sys/types.h>
38 #include <sys/sysctl.h>
48 #include "pbd/gstdio_compat.h"
50 #include <gtkmm/messagedialog.h>
51 #include <gtkmm/accelmap.h>
52 #include <gtkmm/stock.h>
54 #include "pbd/error.h"
55 #include "pbd/basename.h"
56 #include "pbd/compose.h"
57 #include "pbd/convert.h"
58 #include "pbd/failed_constructor.h"
59 #include "pbd/file_archive.h"
60 #include "pbd/enumwriter.h"
61 #include "pbd/memento_command.h"
62 #include "pbd/openuri.h"
63 #include "pbd/stl_delete.h"
64 #include "pbd/file_utils.h"
65 #include "pbd/localtime_r.h"
66 #include "pbd/pthread_utils.h"
67 #include "pbd/replace_all.h"
68 #include "pbd/xml++.h"
70 #include "gtkmm2ext/application.h"
71 #include "gtkmm2ext/bindings.h"
72 #include "gtkmm2ext/gtk_ui.h"
73 #include "gtkmm2ext/utils.h"
74 #include "gtkmm2ext/click_box.h"
75 #include "gtkmm2ext/fastmeter.h"
76 #include "gtkmm2ext/popup.h"
77 #include "gtkmm2ext/window_title.h"
79 #include "ardour/ardour.h"
80 #include "ardour/audio_backend.h"
81 #include "ardour/audio_track.h"
82 #include "ardour/audioengine.h"
83 #include "ardour/audiofilesource.h"
84 #include "ardour/automation_watch.h"
85 #include "ardour/diskstream.h"
86 #include "ardour/filename_extensions.h"
87 #include "ardour/filesystem_paths.h"
88 #include "ardour/ltc_file_reader.h"
89 #include "ardour/midi_track.h"
90 #include "ardour/port.h"
91 #include "ardour/plugin_manager.h"
92 #include "ardour/process_thread.h"
93 #include "ardour/profile.h"
94 #include "ardour/recent_sessions.h"
95 #include "ardour/record_enable_control.h"
96 #include "ardour/session_directory.h"
97 #include "ardour/session_route.h"
98 #include "ardour/session_state_utils.h"
99 #include "ardour/session_utils.h"
100 #include "ardour/source_factory.h"
101 #include "ardour/slave.h"
102 #include "ardour/system_exec.h"
103 #include "ardour/track.h"
104 #include "ardour/vca_manager.h"
105 #include "ardour/utils.h"
107 #include "LuaBridge/LuaBridge.h"
109 #ifdef WINDOWS_VST_SUPPORT
112 #ifdef AUDIOUNIT_SUPPORT
113 #include "ardour/audio_unit.h"
116 // fix for OSX (nsm.h has a check function, AU/Apple defines check)
121 #include "timecode/time.h"
123 typedef uint64_t microseconds_t;
128 #include "add_route_dialog.h"
129 #include "ambiguous_file_dialog.h"
130 #include "ardour_ui.h"
131 #include "audio_clock.h"
132 #include "audio_region_view.h"
133 #include "big_clock_window.h"
134 #include "bundle_manager.h"
135 #include "duplicate_routes_dialog.h"
137 #include "engine_dialog.h"
138 #include "export_video_dialog.h"
139 #include "export_video_infobox.h"
140 #include "gain_meter.h"
141 #include "global_port_matrix.h"
142 #include "gui_object.h"
143 #include "gui_thread.h"
144 #include "keyboard.h"
145 #include "keyeditor.h"
146 #include "location_ui.h"
147 #include "lua_script_manager.h"
148 #include "luawindow.h"
149 #include "main_clock.h"
150 #include "missing_file_dialog.h"
151 #include "missing_plugin_dialog.h"
152 #include "mixer_ui.h"
153 #include "meterbridge.h"
154 #include "mouse_cursors.h"
157 #include "pingback.h"
158 #include "processor_box.h"
159 #include "prompter.h"
160 #include "public_editor.h"
161 #include "rc_option_editor.h"
162 #include "route_time_axis.h"
163 #include "route_params_ui.h"
164 #include "save_as_dialog.h"
165 #include "script_selector.h"
166 #include "session_archive_dialog.h"
167 #include "session_dialog.h"
168 #include "session_metadata_dialog.h"
169 #include "session_option_editor.h"
170 #include "speaker_dialog.h"
173 #include "time_axis_view_item.h"
174 #include "time_info_box.h"
177 #include "utils_videotl.h"
178 #include "video_server_dialog.h"
179 #include "add_video_dialog.h"
180 #include "transcode_video_dialog.h"
182 #include "pbd/i18n.h"
184 using namespace ARDOUR;
185 using namespace ARDOUR_UI_UTILS;
187 using namespace Gtkmm2ext;
190 using namespace Editing;
192 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
194 sigc::signal<void, framepos_t, bool, framepos_t> ARDOUR_UI::Clock;
195 sigc::signal<void> ARDOUR_UI::CloseAllDialogs;
198 ask_about_configuration_copy (string const & old_dir, string const & new_dir, int version)
200 MessageDialog msg (string_compose (_("%1 %2.x has discovered configuration files from %1 %3.x.\n\n"
201 "Would you like these files to be copied and used for %1 %2.x?\n\n"
202 "(This will require you to restart %1.)"),
203 PROGRAM_NAME, PROGRAM_VERSION, version),
204 false, /* no markup */
207 true /* modal, though it hardly matters since it is the only window */
210 msg.set_default_response (Gtk::RESPONSE_YES);
213 return (msg.run() == Gtk::RESPONSE_YES);
217 libxml_generic_error_func (void* /* parsing_context*/,
225 vsnprintf (buf, sizeof (buf), msg, ap);
226 error << buf << endmsg;
231 libxml_structured_error_func (void* /* parsing_context*/,
239 replace_all (msg, "\n", "");
242 if (err->file && err->line) {
243 error << X_("XML error: ") << msg << " in " << err->file << " at line " << err->line;
246 error << ':' << err->int2;
251 error << X_("XML error: ") << msg << endmsg;
257 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
258 : Gtkmm2ext::UI (PROGRAM_NAME, X_("gui"), argcp, argvp)
259 , session_loaded (false)
260 , gui_object_state (new GUIObjectState)
261 , primary_clock (new MainClock (X_("primary"), X_("transport"), true ))
262 , secondary_clock (new MainClock (X_("secondary"), X_("secondary"), false))
263 , big_clock (new AudioClock (X_("bigclock"), false, "big", true, true, false, false))
265 , global_actions (X_("global"))
266 , ignore_dual_punch (false)
267 , main_window_visibility (0)
272 , _mixer_on_top (false)
273 , _initial_verbose_plugin_scan (false)
274 , first_time_engine_run (true)
275 , secondary_clock_spacer (0)
276 , roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll))
277 , stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop))
278 , goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart))
279 , goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd))
280 , auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop))
281 , play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection))
282 , rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable))
283 , auto_input_button (ArdourButton::led_default_elements)
285 , auto_return_button (ArdourButton::led_default_elements)
286 , follow_edits_button (ArdourButton::led_default_elements)
287 , auditioning_alert_button (_("Audition"))
288 , solo_alert_button (_("Solo"))
289 , feedback_alert_button (_("Feedback"))
290 , error_alert_button ( ArdourButton::just_led_default_elements )
292 , editor_meter_peak_display()
293 , _numpad_locate_happening (false)
294 , _session_is_new (false)
295 , last_key_press_time (0)
299 , rc_option_editor (0)
300 , speaker_config_window (X_("speaker-config"), _("Speaker Configuration"))
301 , add_route_dialog (X_("add-routes"), _("Add Tracks/Busses"))
302 , about (X_("about"), _("About"))
303 , location_ui (X_("locations"), S_("Ranges|Locations"))
304 , route_params (X_("inspector"), _("Tracks and Busses"))
305 , audio_midi_setup (X_("audio-midi-setup"), _("Audio/MIDI Setup"))
306 , export_video_dialog (X_("video-export"), _("Video Export Dialog"))
307 , lua_script_window (X_("script-manager"), _("Script Manager"))
308 , session_option_editor (X_("session-options-editor"), _("Properties"), boost::bind (&ARDOUR_UI::create_session_option_editor, this))
309 , add_video_dialog (X_("add-video"), _("Add Video"), boost::bind (&ARDOUR_UI::create_add_video_dialog, this))
310 , bundle_manager (X_("bundle-manager"), _("Bundle Manager"), boost::bind (&ARDOUR_UI::create_bundle_manager, this))
311 , big_clock_window (X_("big-clock"), _("Big Clock"), boost::bind (&ARDOUR_UI::create_big_clock_window, this))
312 , audio_port_matrix (X_("audio-connection-manager"), _("Audio Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::AUDIO))
313 , midi_port_matrix (X_("midi-connection-manager"), _("MIDI Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::MIDI))
314 , key_editor (X_("key-editor"), _("Keyboard Shortcuts"), boost::bind (&ARDOUR_UI::create_key_editor, this))
315 , video_server_process (0)
317 , have_configure_timeout (false)
318 , last_configure_time (0)
320 , have_disk_speed_dialog_displayed (false)
321 , _status_bar_visibility (X_("status-bar"))
322 , _feedback_exists (false)
323 , _log_not_acknowledged (LogLevelNone)
324 , duplicate_routes_dialog (0)
325 , editor_visibility_button (S_("Window|Editor"))
326 , mixer_visibility_button (S_("Window|Mixer"))
327 , prefs_visibility_button (S_("Window|Preferences"))
329 Gtkmm2ext::init (localedir);
331 UIConfiguration::instance().post_gui_init ();
333 if (ARDOUR::handle_old_configuration_files (boost::bind (ask_about_configuration_copy, _1, _2, _3))) {
334 MessageDialog msg (string_compose (_("Your configuration files were copied. You can now restart %1."), PROGRAM_NAME), true);
336 /* configuration was modified, exit immediately */
341 if (string (VERSIONSTRING).find (".pre") != string::npos) {
342 /* check this is not being run from ./ardev etc. */
343 if (!running_from_source_tree ()) {
344 pre_release_dialog ();
348 if (theArdourUI == 0) {
352 /* track main window visibility */
354 main_window_visibility = new VisibilityTracker (_main_window);
356 /* stop libxml from spewing to stdout/stderr */
358 xmlSetGenericErrorFunc (this, libxml_generic_error_func);
359 xmlSetStructuredErrorFunc (this, libxml_structured_error_func);
361 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::parameter_changed));
362 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
363 UIConfiguration::instance().map_parameters (pc);
365 roll_button.set_controllable (roll_controllable);
366 stop_button.set_controllable (stop_controllable);
367 goto_start_button.set_controllable (goto_start_controllable);
368 goto_end_button.set_controllable (goto_end_controllable);
369 auto_loop_button.set_controllable (auto_loop_controllable);
370 play_selection_button.set_controllable (play_selection_controllable);
371 rec_button.set_controllable (rec_controllable);
373 roll_button.set_name ("transport button");
374 stop_button.set_name ("transport button");
375 goto_start_button.set_name ("transport button");
376 goto_end_button.set_name ("transport button");
377 auto_loop_button.set_name ("transport button");
378 play_selection_button.set_name ("transport button");
379 rec_button.set_name ("transport recenable button");
380 midi_panic_button.set_name ("transport button");
382 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
383 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
385 ARDOUR::Session::VersionMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_format_mismatch, this, _1, _2), gui_context());
387 /* handle dialog requests */
389 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
391 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
393 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
395 /* handle Audio/MIDI setup when session requires it */
397 ARDOUR::Session::AudioEngineSetupRequired.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::do_audio_midi_setup, this, _1));
399 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
401 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
403 /* handle sr mismatch with a dialog - cross-thread from engine */
404 ARDOUR::Session::NotifyAboutSampleRateMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::sr_mismatch_message, this, _1, _2), gui_context ());
406 /* handle requests to quit (coming from JACK session) */
408 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::finish, this), gui_context ());
410 /* tell the user about feedback */
412 ARDOUR::Session::FeedbackDetected.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::feedback_detected, this), gui_context ());
413 ARDOUR::Session::SuccessfulGraphSort.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::successful_graph_sort, this), gui_context ());
415 /* handle requests to deal with missing files */
417 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
419 /* and ambiguous files */
421 ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2));
423 /* also plugin scan messages */
424 ARDOUR::PluginScanMessage.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_dialog, this, _1, _2, _3), gui_context());
425 ARDOUR::PluginScanTimeout.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_timeout, this, _1), gui_context());
427 ARDOUR::GUIIdle.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::gui_idle_handler, this), gui_context());
429 Config->ParameterChanged.connect ( forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::set_flat_buttons, this), gui_context() );
432 /* lets get this party started */
434 setup_gtk_ardour_enums ();
437 SessionEvent::create_per_thread_pool ("GUI", 4096);
439 /* we like keyboards */
441 keyboard = new ArdourKeyboard(*this);
443 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
445 keyboard->set_state (*node, Stateful::loading_state_version);
448 UIConfiguration::instance().reset_dpi ();
450 TimeAxisViewItem::set_constant_heights ();
452 /* Set this up so that our window proxies can register actions */
454 ActionManager::init ();
456 /* The following must happen after ARDOUR::init() so that Config is set up */
458 const XMLNode* ui_xml = Config->extra_xml (X_("UI"));
461 key_editor.set_state (*ui_xml, 0);
462 session_option_editor.set_state (*ui_xml, 0);
463 speaker_config_window.set_state (*ui_xml, 0);
464 about.set_state (*ui_xml, 0);
465 add_route_dialog.set_state (*ui_xml, 0);
466 add_video_dialog.set_state (*ui_xml, 0);
467 route_params.set_state (*ui_xml, 0);
468 bundle_manager.set_state (*ui_xml, 0);
469 location_ui.set_state (*ui_xml, 0);
470 big_clock_window.set_state (*ui_xml, 0);
471 audio_port_matrix.set_state (*ui_xml, 0);
472 midi_port_matrix.set_state (*ui_xml, 0);
473 export_video_dialog.set_state (*ui_xml, 0);
474 lua_script_window.set_state (*ui_xml, 0);
477 /* Separate windows */
479 WM::Manager::instance().register_window (&key_editor);
480 WM::Manager::instance().register_window (&session_option_editor);
481 WM::Manager::instance().register_window (&speaker_config_window);
482 WM::Manager::instance().register_window (&about);
483 WM::Manager::instance().register_window (&add_route_dialog);
484 WM::Manager::instance().register_window (&add_video_dialog);
485 WM::Manager::instance().register_window (&route_params);
486 WM::Manager::instance().register_window (&audio_midi_setup);
487 WM::Manager::instance().register_window (&export_video_dialog);
488 WM::Manager::instance().register_window (&lua_script_window);
489 WM::Manager::instance().register_window (&bundle_manager);
490 WM::Manager::instance().register_window (&location_ui);
491 WM::Manager::instance().register_window (&big_clock_window);
492 WM::Manager::instance().register_window (&audio_port_matrix);
493 WM::Manager::instance().register_window (&midi_port_matrix);
495 /* do not retain position for add route dialog */
496 add_route_dialog.set_state_mask (WindowProxy::Size);
498 /* Trigger setting up the color scheme and loading the GTK RC file */
500 UIConfiguration::instance().load_rc_file (false);
502 _process_thread = new ProcessThread ();
503 _process_thread->init ();
505 UIConfiguration::instance().DPIReset.connect (sigc::mem_fun (*this, &ARDOUR_UI::resize_text_widgets));
511 ARDOUR_UI::pre_release_dialog ()
513 ArdourDialog d (_("Pre-Release Warning"), true, false);
514 d.add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
516 Label* label = manage (new Label);
517 label->set_markup (string_compose (_("<b>Welcome to this pre-release build of %1 %2</b>\n\n\
518 There are still several issues and bugs to be worked on,\n\
519 as well as general workflow improvements, before this can be considered\n\
520 release software. So, a few guidelines:\n\
522 1) Please do <b>NOT</b> use this software with the expectation that it is stable or reliable\n\
523 though it may be so, depending on your workflow.\n\
524 2) Please wait for a helpful writeup of new features.\n\
525 3) <b>Please do NOT use the forums at ardour.org to report issues</b>.\n\
526 4) Please <b>DO</b> use the bugtracker at http://tracker.ardour.org/ to report issues\n\
527 making sure to note the product version number as 5.0-pre.\n\
528 5) Please <b>DO</b> use the ardour-users mailing list to discuss ideas and pass on comments.\n\
529 6) Please <b>DO</b> join us on IRC for real time discussions about %1 %2. You\n\
530 can get there directly from within the program via the Help->Chat menu option.\n\
532 Full information on all the above can be found on the support page at\n\
534 http://ardour.org/support\n\
535 "), PROGRAM_NAME, VERSIONSTRING));
537 d.get_vbox()->set_border_width (12);
538 d.get_vbox()->pack_start (*label, false, false, 12);
539 d.get_vbox()->show_all ();
544 GlobalPortMatrixWindow*
545 ARDOUR_UI::create_global_port_matrix (ARDOUR::DataType type)
550 return new GlobalPortMatrixWindow (_session, type);
554 ARDOUR_UI::attach_to_engine ()
556 AudioEngine::instance()->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
557 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
561 ARDOUR_UI::engine_stopped ()
563 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
564 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
565 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
566 update_sample_rate (0);
571 ARDOUR_UI::engine_running ()
573 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
574 if (first_time_engine_run) {
576 first_time_engine_run = false;
580 _session->reset_xrun_count ();
582 update_disk_space ();
584 update_xrun_count ();
585 update_sample_rate (AudioEngine::instance()->sample_rate());
586 update_timecode_format ();
587 update_peak_thread_work ();
588 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, true);
589 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, false);
593 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
595 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
596 /* we can't rely on the original string continuing to exist when we are called
597 again in the GUI thread, so make a copy and note that we need to
600 char *copy = strdup (reason);
601 Gtkmm2ext::UI::instance()->call_slot (MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
605 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
606 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
608 update_sample_rate (0);
612 /* if the reason is a non-empty string, it means that the backend was shutdown
613 rather than just Ardour.
616 if (strlen (reason)) {
617 msgstr = string_compose (_("The audio backend was shutdown because:\n\n%1"), reason);
619 msgstr = string_compose (_("\
620 The audio backend has either been shutdown or it\n\
621 disconnected %1 because %1\n\
622 was not fast enough. Try to restart\n\
623 the audio backend and save the session."), PROGRAM_NAME);
626 MessageDialog msg (_main_window, msgstr);
627 pop_back_splash (msg);
631 free (const_cast<char*> (reason));
636 ARDOUR_UI::post_engine ()
638 /* Things to be done once (and once ONLY) after we have a backend running in the AudioEngine
640 #ifdef AUDIOUNIT_SUPPORT
642 if (AUPluginInfo::au_get_crashlog(au_msg)) {
643 popup_error(_("Audio Unit Plugin Scan Failed. Automatic AU scanning has been disabled. Please see the log window for further details."));
644 error << _("Audio Unit Plugin Scan Failed:") << endmsg;
645 info << au_msg << endmsg;
649 ARDOUR::init_post_engine ();
651 /* connect to important signals */
653 AudioEngine::instance()->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
654 AudioEngine::instance()->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
655 AudioEngine::instance()->BufferSizeChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
656 AudioEngine::instance()->Halted.connect_same_thread (halt_connection, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
657 AudioEngine::instance()->BecameSilent.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::audioengine_became_silent, this), gui_context());
659 if (setup_windows ()) {
660 throw failed_constructor ();
663 /* Do this after setup_windows (), as that's when the _status_bar_visibility is created */
664 XMLNode* n = Config->extra_xml (X_("UI"));
666 _status_bar_visibility.set_state (*n);
669 check_memory_locking();
671 /* this is the first point at which all the possible actions are
672 * available, because some of the available actions are dependent on
673 * aspects of the engine/backend.
676 if (ARDOUR_COMMAND_LINE::show_key_actions) {
679 vector<string> paths;
680 vector<string> labels;
681 vector<string> tooltips;
683 vector<Glib::RefPtr<Gtk::Action> > actions;
685 Gtkmm2ext::ActionMap::get_all_actions (paths, labels, tooltips, keys, actions);
687 vector<string>::iterator k;
688 vector<string>::iterator p;
690 for (p = paths.begin(), k = keys.begin(); p != paths.end(); ++k, ++p) {
695 cout << *p << " => " << *k << endl;
699 halt_connection.disconnect ();
700 AudioEngine::instance()->stop ();
704 /* this being a GUI and all, we want peakfiles */
706 AudioFileSource::set_build_peakfiles (true);
707 AudioFileSource::set_build_missing_peakfiles (true);
709 /* set default clock modes */
711 primary_clock->set_mode (AudioClock::Timecode);
712 secondary_clock->set_mode (AudioClock::BBT);
714 /* start the time-of-day-clock */
717 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
718 update_wall_clock ();
719 Glib::signal_timeout().connect_seconds (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 1);
724 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
725 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
726 Config->map_parameters (pc);
728 UIConfiguration::instance().map_parameters (pc);
732 ARDOUR_UI::~ARDOUR_UI ()
734 UIConfiguration::instance().save_state();
738 if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
739 // don't bother at 'real' exit. the OS cleans up for us.
740 delete big_clock; big_clock = 0;
741 delete primary_clock; primary_clock = 0;
742 delete secondary_clock; secondary_clock = 0;
743 delete _process_thread; _process_thread = 0;
744 delete time_info_box; time_info_box = 0;
745 delete meterbridge; meterbridge = 0;
746 delete luawindow; luawindow = 0;
747 delete editor; editor = 0;
748 delete mixer; mixer = 0;
749 delete rc_option_editor; rc_option_editor = 0; // failed to wrap object warning
751 delete gui_object_state; gui_object_state = 0;
752 delete main_window_visibility;
753 FastMeter::flush_pattern_cache ();
754 PixFader::flush_pattern_cache ();
758 /* Small trick to flush main-thread event pool.
759 * Other thread-pools are destroyed at pthread_exit(),
760 * but tmain thread termination is too late to trigger Pool::~Pool()
762 SessionEvent* ev = new SessionEvent (SessionEvent::SetTransportSpeed, SessionEvent::Clear, SessionEvent::Immediate, 0, 0); // get the pool reference, values don't matter since the event is never queued.
763 delete ev->event_pool();
768 ARDOUR_UI::pop_back_splash (Gtk::Window& win)
770 if (Splash::instance()) {
771 Splash::instance()->pop_back_for (win);
776 ARDOUR_UI::configure_timeout ()
778 if (last_configure_time == 0) {
779 /* no configure events yet */
783 /* force a gap of 0.5 seconds since the last configure event
786 if (get_microseconds() - last_configure_time < 500000) {
789 have_configure_timeout = false;
790 save_ardour_state ();
796 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
798 if (have_configure_timeout) {
799 last_configure_time = get_microseconds();
801 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
802 have_configure_timeout = true;
809 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
811 XMLProperty const * prop;
813 if ((prop = node.property ("roll")) != 0) {
814 roll_controllable->set_id (prop->value());
816 if ((prop = node.property ("stop")) != 0) {
817 stop_controllable->set_id (prop->value());
819 if ((prop = node.property ("goto-start")) != 0) {
820 goto_start_controllable->set_id (prop->value());
822 if ((prop = node.property ("goto-end")) != 0) {
823 goto_end_controllable->set_id (prop->value());
825 if ((prop = node.property ("auto-loop")) != 0) {
826 auto_loop_controllable->set_id (prop->value());
828 if ((prop = node.property ("play-selection")) != 0) {
829 play_selection_controllable->set_id (prop->value());
831 if ((prop = node.property ("rec")) != 0) {
832 rec_controllable->set_id (prop->value());
834 if ((prop = node.property ("shuttle")) != 0) {
835 shuttle_box.controllable()->set_id (prop->value());
840 ARDOUR_UI::get_transport_controllable_state ()
842 XMLNode* node = new XMLNode(X_("TransportControllables"));
845 roll_controllable->id().print (buf, sizeof (buf));
846 node->add_property (X_("roll"), buf);
847 stop_controllable->id().print (buf, sizeof (buf));
848 node->add_property (X_("stop"), buf);
849 goto_start_controllable->id().print (buf, sizeof (buf));
850 node->add_property (X_("goto_start"), buf);
851 goto_end_controllable->id().print (buf, sizeof (buf));
852 node->add_property (X_("goto_end"), buf);
853 auto_loop_controllable->id().print (buf, sizeof (buf));
854 node->add_property (X_("auto_loop"), buf);
855 play_selection_controllable->id().print (buf, sizeof (buf));
856 node->add_property (X_("play_selection"), buf);
857 rec_controllable->id().print (buf, sizeof (buf));
858 node->add_property (X_("rec"), buf);
859 shuttle_box.controllable()->id().print (buf, sizeof (buf));
860 node->add_property (X_("shuttle"), buf);
866 ARDOUR_UI::save_session_at_its_request (std::string snapshot_name)
869 _session->save_state (snapshot_name);
874 ARDOUR_UI::autosave_session ()
876 if (g_main_depth() > 1) {
877 /* inside a recursive main loop,
878 give up because we may not be able to
884 if (!Config->get_periodic_safety_backups()) {
889 _session->maybe_write_autosave();
896 ARDOUR_UI::session_dirty_changed ()
903 ARDOUR_UI::update_autosave ()
905 if (_session && _session->dirty()) {
906 if (_autosave_connection.connected()) {
907 _autosave_connection.disconnect();
910 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
911 Config->get_periodic_safety_backup_interval() * 1000);
914 if (_autosave_connection.connected()) {
915 _autosave_connection.disconnect();
921 ARDOUR_UI::check_announcements ()
924 string _annc_filename;
927 _annc_filename = PROGRAM_NAME "_announcements_osx_";
928 #elif defined PLATFORM_WINDOWS
929 _annc_filename = PROGRAM_NAME "_announcements_windows_";
931 _annc_filename = PROGRAM_NAME "_announcements_linux_";
933 _annc_filename.append (VERSIONSTRING);
935 _announce_string = "";
937 std::string path = Glib::build_filename (user_config_directory(), _annc_filename);
938 FILE* fin = g_fopen (path.c_str(), "rb");
940 while (!feof (fin)) {
943 if ((len = fread (tmp, sizeof(char), 1024, fin)) == 0 || ferror (fin)) {
946 _announce_string.append (tmp, len);
951 pingback (VERSIONSTRING, path);
956 _hide_splash (gpointer arg)
958 ((ARDOUR_UI*)arg)->hide_splash();
963 ARDOUR_UI::starting ()
965 Application* app = Application::instance ();
967 bool brand_new_user = ArdourStartup::required ();
969 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
970 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::load_from_application_api));
972 if (ARDOUR_COMMAND_LINE::check_announcements) {
973 check_announcements ();
978 /* we need to create this early because it may need to set the
979 * audio backend end up.
983 audio_midi_setup.get (true);
985 std::cerr << "audio-midi engine setup failed."<< std::endl;
989 if ((nsm_url = g_getenv ("NSM_URL")) != 0) {
990 nsm = new NSM_Client;
991 if (!nsm->init (nsm_url)) {
992 /* the ardour executable may have different names:
994 * waf's obj.target for distro versions: eg ardour4, ardourvst4
995 * Ardour4, Mixbus3 for bundled versions + full path on OSX & windows
996 * argv[0] does not apply since we need the wrapper-script (not the binary itself)
998 * The wrapper startup script should set the environment variable 'ARDOUR_SELF'
1000 const char *process_name = g_getenv ("ARDOUR_SELF");
1001 nsm->announce (PROGRAM_NAME, ":dirty:", process_name ? process_name : "ardour4");
1004 // wait for announce reply from nsm server
1005 for ( i = 0; i < 5000; ++i) {
1009 if (nsm->is_active()) {
1014 error << _("NSM server did not announce itself") << endmsg;
1017 // wait for open command from nsm server
1018 for ( i = 0; i < 5000; ++i) {
1020 Glib::usleep (1000);
1021 if (nsm->client_id ()) {
1027 error << _("NSM: no client ID provided") << endmsg;
1031 if (_session && nsm) {
1032 _session->set_nsm_state( nsm->is_active() );
1034 error << _("NSM: no session created") << endmsg;
1038 // nsm requires these actions disabled
1039 vector<string> action_names;
1040 action_names.push_back("SaveAs");
1041 action_names.push_back("Rename");
1042 action_names.push_back("New");
1043 action_names.push_back("Open");
1044 action_names.push_back("Recent");
1045 action_names.push_back("Close");
1047 for (vector<string>::const_iterator n = action_names.begin(); n != action_names.end(); ++n) {
1048 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), (*n).c_str());
1050 act->set_sensitive (false);
1057 error << _("NSM: initialization failed") << endmsg;
1063 if (brand_new_user) {
1064 _initial_verbose_plugin_scan = true;
1069 _initial_verbose_plugin_scan = false;
1070 switch (s.response ()) {
1071 case Gtk::RESPONSE_OK:
1078 // TODO: maybe IFF brand_new_user
1079 if (ARDOUR::Profile->get_mixbus () && Config->get_copy_demo_sessions ()) {
1080 std::string dspd (Config->get_default_session_parent_dir());
1081 Searchpath ds (ARDOUR::ardour_data_search_path());
1082 ds.add_subdirectory_to_paths ("sessions");
1083 vector<string> demos;
1084 find_files_matching_pattern (demos, ds, "*.tar.xz");
1086 ARDOUR::RecentSessions rs;
1087 ARDOUR::read_recent_sessions (rs);
1089 for (vector<string>::iterator i = demos.begin(); i != demos.end (); ++i) {
1090 /* "demo-session" must be inside "demo-session.tar.xz"
1093 std::string name = basename_nosuffix (basename_nosuffix (*i));
1094 std::string path = Glib::build_filename (dspd, name);
1095 /* skip if session-dir already exists */
1096 if (Glib::file_test(path.c_str(), Glib::FILE_TEST_IS_DIR)) {
1099 /* skip sessions that are already in 'recent'.
1100 * eg. a new user changed <session-default-dir> shorly after installation
1102 for (ARDOUR::RecentSessions::iterator r = rs.begin(); r != rs.end(); ++r) {
1103 if ((*r).first == name) {
1108 PBD::FileArchive ar (*i);
1109 if (0 == ar.inflate (dspd)) {
1110 store_recent_sessions (name, path);
1111 info << string_compose (_("Copied Demo Session %1."), name) << endmsg;
1117 #ifdef NO_PLUGIN_STATE
1119 ARDOUR::RecentSessions rs;
1120 ARDOUR::read_recent_sessions (rs);
1122 string path = Glib::build_filename (user_config_directory(), ".iknowaboutfreeversion");
1124 if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS) && !rs.empty()) {
1126 /* already used Ardour, have sessions ... warn about plugin state */
1128 ArdourDialog d (_("Free/Demo Version Warning"), true);
1130 Button b (string_compose (_("Subscribe and support development of %1"), PROGRAM_NAME));
1131 CheckButton c (_("Don't warn me about this again"));
1133 l.set_markup (string_compose (_("<span weight=\"bold\" size=\"large\">%1</span>\n\n<b>%2</b>\n\n<i>%3</i>\n\n%4"),
1134 string_compose (_("This is a free/demo version of %1"), PROGRAM_NAME),
1135 _("It will not restore OR save any plugin settings"),
1136 _("If you load an existing session with plugin settings\n"
1137 "they will not be used and will be lost."),
1138 _("To get full access to updates without this limitation\n"
1139 "consider becoming a subscriber for a low cost every month.")));
1140 l.set_justify (JUSTIFY_CENTER);
1142 b.signal_clicked().connect (mem_fun(*this, &ARDOUR_UI::launch_subscribe));
1144 d.get_vbox()->pack_start (l, true, true);
1145 d.get_vbox()->pack_start (b, false, false, 12);
1146 d.get_vbox()->pack_start (c, false, false, 12);
1148 d.add_button (_("Quit now"), RESPONSE_CANCEL);
1149 d.add_button (string_compose (_("Continue using %1"), PROGRAM_NAME), RESPONSE_OK);
1153 c.signal_toggled().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (toggle_file_existence), path)));
1155 if (d.run () != RESPONSE_OK) {
1161 /* go get a session */
1163 const bool new_session_required = (ARDOUR_COMMAND_LINE::new_session || brand_new_user);
1165 if (get_session_parameters (false, new_session_required, ARDOUR_COMMAND_LINE::load_template)) {
1166 std::cerr << "Cannot get session parameters."<< std::endl;
1173 WM::Manager::instance().show_visible ();
1175 /* We have to do this here since goto_editor_window() ends up calling show_all() on the
1176 * editor window, and we may want stuff to be hidden.
1178 _status_bar_visibility.update ();
1180 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
1182 if (splash && splash->is_visible()) {
1183 // in 1 second, hide the splash screen
1184 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
1187 /* all other dialogs are created conditionally */
1193 ARDOUR_UI::check_memory_locking ()
1195 #if defined(__APPLE__) || defined(PLATFORM_WINDOWS)
1196 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
1200 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
1202 if (AudioEngine::instance()->is_realtime() && memory_warning_node == 0) {
1204 struct rlimit limits;
1206 long pages, page_size;
1208 size_t pages_len=sizeof(pages);
1209 if ((page_size = getpagesize()) < 0 ||
1210 sysctlbyname("hw.availpages", &pages, &pages_len, NULL, 0))
1212 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0)
1217 ram = (int64_t) pages * (int64_t) page_size;
1220 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
1224 if (limits.rlim_cur != RLIM_INFINITY) {
1226 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
1230 _("WARNING: Your system has a limit for maximum amount of locked memory. "
1231 "This might cause %1 to run out of memory before your system "
1232 "runs out of memory. \n\n"
1233 "You can view the memory limit with 'ulimit -l', "
1234 "and it is normally controlled by %2"),
1237 X_("/etc/login.conf")
1239 X_(" /etc/security/limits.conf")
1243 msg.set_default_response (RESPONSE_OK);
1245 VBox* vbox = msg.get_vbox();
1247 CheckButton cb (_("Do not show this window again"));
1248 hbox.pack_start (cb, true, false);
1249 vbox->pack_start (hbox);
1254 pop_back_splash (msg);
1258 if (cb.get_active()) {
1259 XMLNode node (X_("no-memory-warning"));
1260 Config->add_instant_xml (node);
1265 #endif // !__APPLE__
1270 ARDOUR_UI::queue_finish ()
1272 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
1276 ARDOUR_UI::idle_finish ()
1279 return false; /* do not call again */
1286 ARDOUR_UI::instance()->video_timeline->sync_session_state();
1288 if (_session->dirty()) {
1289 vector<string> actions;
1290 actions.push_back (_("Don't quit"));
1291 actions.push_back (_("Just quit"));
1292 actions.push_back (_("Save and quit"));
1293 switch (ask_about_saving_session(actions)) {
1298 /* use the default name */
1299 if (save_state_canfail ("")) {
1300 /* failed - don't quit */
1301 MessageDialog msg (_main_window,
1302 string_compose (_("\
1303 %1 was unable to save your session.\n\n\
1304 If you still wish to quit, please use the\n\n\
1305 \"Just quit\" option."), PROGRAM_NAME));
1306 pop_back_splash(msg);
1316 second_connection.disconnect ();
1317 point_one_second_connection.disconnect ();
1318 point_zero_something_second_connection.disconnect();
1319 fps_connection.disconnect();
1322 delete ARDOUR_UI::instance()->video_timeline;
1323 ARDOUR_UI::instance()->video_timeline = NULL;
1324 stop_video_server();
1326 /* Save state before deleting the session, as that causes some
1327 windows to be destroyed before their visible state can be
1330 save_ardour_state ();
1332 if (key_editor.get (false)) {
1333 key_editor->disconnect ();
1336 close_all_dialogs ();
1339 _session->set_clean ();
1340 _session->remove_pending_capture_state ();
1345 halt_connection.disconnect ();
1346 AudioEngine::instance()->stop ();
1347 #ifdef WINDOWS_VST_SUPPORT
1348 fst_stop_threading();
1354 ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
1356 ArdourDialog window (_("Unsaved Session"));
1357 Gtk::HBox dhbox; // the hbox for the image and text
1358 Gtk::Label prompt_label;
1359 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
1363 assert (actions.size() >= 3);
1365 window.add_button (actions[0], RESPONSE_REJECT);
1366 window.add_button (actions[1], RESPONSE_APPLY);
1367 window.add_button (actions[2], RESPONSE_ACCEPT);
1369 window.set_default_response (RESPONSE_ACCEPT);
1371 Gtk::Button noquit_button (msg);
1372 noquit_button.set_name ("EditorGTKButton");
1376 if (_session->snap_name() == _session->name()) {
1377 prompt = string_compose(_("The session \"%1\"\nhas not been saved.\n\nAny changes made this time\nwill be lost unless you save it.\n\nWhat do you want to do?"),
1378 _session->snap_name());
1380 prompt = string_compose(_("The snapshot \"%1\"\nhas not been saved.\n\nAny changes made this time\nwill be lost unless you save it.\n\nWhat do you want to do?"),
1381 _session->snap_name());
1384 prompt_label.set_text (prompt);
1385 prompt_label.set_name (X_("PrompterLabel"));
1386 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
1388 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
1389 dhbox.set_homogeneous (false);
1390 dhbox.pack_start (*dimage, false, false, 5);
1391 dhbox.pack_start (prompt_label, true, false, 5);
1392 window.get_vbox()->pack_start (dhbox);
1394 window.set_name (_("Prompter"));
1395 window.set_modal (true);
1396 window.set_resizable (false);
1399 prompt_label.show();
1404 ResponseType r = (ResponseType) window.run();
1409 case RESPONSE_ACCEPT: // save and get out of here
1411 case RESPONSE_APPLY: // get out of here
1422 ARDOUR_UI::every_second ()
1425 update_xrun_count ();
1426 update_buffer_load ();
1427 update_disk_space ();
1428 update_timecode_format ();
1429 update_peak_thread_work ();
1431 if (nsm && nsm->is_active ()) {
1434 if (!_was_dirty && _session->dirty ()) {
1438 else if (_was_dirty && !_session->dirty ()){
1446 ARDOUR_UI::every_point_one_seconds ()
1448 // TODO get rid of this..
1449 // ShuttleControl is updated directly via TransportStateChange signal
1453 ARDOUR_UI::every_point_zero_something_seconds ()
1455 // august 2007: actual update frequency: 25Hz (40ms), not 100Hz
1457 if (editor_meter && UIConfiguration::instance().get_show_editor_meter() && editor_meter_peak_display.is_mapped ()) {
1458 float mpeak = editor_meter->update_meters();
1459 if (mpeak > editor_meter_max_peak) {
1460 if (mpeak >= UIConfiguration::instance().get_meter_peak()) {
1461 editor_meter_peak_display.set_active_state ( Gtkmm2ext::ExplicitActive );
1468 ARDOUR_UI::set_fps_timeout_connection ()
1470 unsigned int interval = 40;
1471 if (!_session) return;
1472 if (_session->timecode_frames_per_second() != 0) {
1473 /* ideally we'll use a select() to sleep and not accumulate
1474 * idle time to provide a regular periodic signal.
1475 * See linux_vst_gui_support.cc 'elapsed_time_ms'.
1476 * However, that'll require a dedicated thread and cross-thread
1477 * signals to the GUI Thread..
1479 interval = floor(500. /* update twice per FPS, since Glib::signal_timeout is very irregular */
1480 * _session->frame_rate() / _session->nominal_frame_rate()
1481 / _session->timecode_frames_per_second()
1483 #ifdef PLATFORM_WINDOWS
1484 // the smallest windows scheduler time-slice is ~15ms.
1485 // periodic GUI timeouts shorter than that will cause
1486 // WaitForSingleObject to spinlock (100% of one CPU Core)
1487 // and gtk never enters idle mode.
1488 // also changing timeBeginPeriod(1) does not affect that in
1489 // any beneficial way, so we just limit the max rate for now.
1490 interval = std::max(30u, interval); // at most ~33Hz.
1492 interval = std::max(8u, interval); // at most 120Hz.
1495 fps_connection.disconnect();
1496 Timers::set_fps_interval (interval);
1500 ARDOUR_UI::update_sample_rate (framecnt_t)
1504 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
1506 if (!AudioEngine::instance()->connected()) {
1508 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1512 framecnt_t rate = AudioEngine::instance()->sample_rate();
1515 /* no sample rate available */
1516 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1519 if (fmod (rate, 1000.0) != 0.0) {
1520 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
1521 (float) rate / 1000.0f,
1522 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1524 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
1526 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1530 sample_rate_label.set_markup (buf);
1534 ARDOUR_UI::update_format ()
1537 format_label.set_text ("");
1542 s << _("File:") << X_(" <span foreground=\"green\">");
1544 switch (_session->config.get_native_file_header_format ()) {
1576 switch (_session->config.get_native_file_data_format ()) {
1590 format_label.set_markup (s.str ());
1594 ARDOUR_UI::update_xrun_count ()
1598 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1599 should also be changed.
1603 const unsigned int x = _session->get_xrun_count ();
1605 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">>10K</span>"), X_("red"));
1607 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">%u</span>"), x > 0 ? X_("red") : X_("green"), x);
1610 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">?</span>"), X_("yellow"));
1612 xrun_label.set_markup (buf);
1613 set_tip (xrun_label, _("Audio dropouts. Shift+click to reset"));
1617 ARDOUR_UI::update_cpu_load ()
1621 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1622 should also be changed.
1625 double const c = AudioEngine::instance()->get_dsp_load ();
1626 snprintf (buf, sizeof (buf), _("DSP: <span foreground=\"%s\">%5.1f%%</span>"), c >= 90 ? X_("red") : X_("green"), c);
1627 cpu_load_label.set_markup (buf);
1631 ARDOUR_UI::update_peak_thread_work ()
1634 const int c = SourceFactory::peak_work_queue_length ();
1636 snprintf (buf, sizeof (buf), _("PkBld: <span foreground=\"%s\">%d</span>"), c >= 2 ? X_("red") : X_("green"), c);
1637 peak_thread_work_label.set_markup (buf);
1639 peak_thread_work_label.set_markup (X_(""));
1644 ARDOUR_UI::update_buffer_load ()
1648 uint32_t const playback = _session ? _session->playback_load () : 100;
1649 uint32_t const capture = _session ? _session->capture_load () : 100;
1651 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1652 should also be changed.
1658 _("Buffers: <span foreground=\"green\">p:</span><span foreground=\"%s\">%" PRIu32 "%%</span> "
1659 "<span foreground=\"green\">c:</span><span foreground=\"%s\">%" PRIu32 "%%</span>"),
1660 playback <= 5 ? X_("red") : X_("green"),
1662 capture <= 5 ? X_("red") : X_("green"),
1666 buffer_load_label.set_markup (buf);
1668 buffer_load_label.set_text ("");
1673 ARDOUR_UI::count_recenabled_streams (Route& route)
1675 Track* track = dynamic_cast<Track*>(&route);
1676 if (track && track->rec_enable_control()->get_value()) {
1677 rec_enabled_streams += track->n_inputs().n_total();
1682 ARDOUR_UI::update_disk_space()
1684 if (_session == 0) {
1688 boost::optional<framecnt_t> opt_frames = _session->available_capture_duration();
1690 framecnt_t fr = _session->frame_rate();
1693 /* skip update - no SR available */
1698 /* Available space is unknown */
1699 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">Unknown</span>"));
1700 } else if (opt_frames.get_value_or (0) == max_framecnt) {
1701 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">24hrs+</span>"));
1703 rec_enabled_streams = 0;
1704 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams, false);
1706 framecnt_t frames = opt_frames.get_value_or (0);
1708 if (rec_enabled_streams) {
1709 frames /= rec_enabled_streams;
1716 hrs = frames / (fr * 3600);
1719 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">>24 hrs</span>"));
1721 frames -= hrs * fr * 3600;
1722 mins = frames / (fr * 60);
1723 frames -= mins * fr * 60;
1726 bool const low = (hrs == 0 && mins <= 30);
1730 _("Disk: <span foreground=\"%s\">%02dh:%02dm:%02ds</span>"),
1731 low ? X_("red") : X_("green"),
1737 disk_space_label.set_markup (buf);
1741 ARDOUR_UI::update_timecode_format ()
1747 TimecodeSlave* tcslave;
1748 SyncSource sync_src = Config->get_sync_source();
1750 if ((sync_src == LTC || sync_src == MTC) && (tcslave = dynamic_cast<TimecodeSlave*>(_session->slave())) != 0) {
1751 matching = (tcslave->apparent_timecode_format() == _session->config.get_timecode_format());
1756 snprintf (buf, sizeof (buf), S_("Timecode|TC: <span foreground=\"%s\">%s</span>"),
1757 matching ? X_("green") : X_("red"),
1758 Timecode::timecode_format_name (_session->config.get_timecode_format()).c_str());
1760 snprintf (buf, sizeof (buf), "TC: n/a");
1763 timecode_format_label.set_markup (buf);
1767 ARDOUR_UI::update_wall_clock ()
1771 static int last_min = -1;
1774 tm_now = localtime (&now);
1775 if (last_min != tm_now->tm_min) {
1777 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1778 wall_clock_label.set_text (buf);
1779 last_min = tm_now->tm_min;
1786 ARDOUR_UI::open_recent_session ()
1788 bool can_return = (_session != 0);
1790 SessionDialog recent_session_dialog;
1794 ResponseType r = (ResponseType) recent_session_dialog.run ();
1797 case RESPONSE_ACCEPT:
1801 recent_session_dialog.hide();
1808 recent_session_dialog.hide();
1812 std::string path = recent_session_dialog.session_folder();
1813 std::string state = recent_session_dialog.session_name (should_be_new);
1815 if (should_be_new == true) {
1819 _session_is_new = false;
1821 if (load_session (path, state) == 0) {
1827 if (splash && splash->is_visible()) {
1828 // in 1 second, hide the splash screen
1829 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
1834 ARDOUR_UI::check_audioengine (Gtk::Window& parent)
1836 if (!AudioEngine::instance()->connected()) {
1837 MessageDialog msg (parent, string_compose (
1838 _("%1 is not connected to any audio backend.\n"
1839 "You cannot open or close sessions in this condition"),
1841 pop_back_splash (msg);
1849 ARDOUR_UI::open_session ()
1851 if (!check_audioengine (_main_window)) {
1855 /* ardour sessions are folders */
1856 Gtk::FileChooserDialog open_session_selector(_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1857 open_session_selector.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1858 open_session_selector.add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1859 open_session_selector.set_default_response(Gtk::RESPONSE_ACCEPT);
1862 string session_parent_dir = Glib::path_get_dirname(_session->path());
1863 open_session_selector.set_current_folder(session_parent_dir);
1865 open_session_selector.set_current_folder(Config->get_default_session_parent_dir());
1868 Gtkmm2ext::add_volume_shortcuts (open_session_selector);
1870 /* add_shortcut_folder throws an exception if the folder being added already has a shortcut */
1871 string default_session_folder = Config->get_default_session_parent_dir();
1872 open_session_selector.add_shortcut_folder (default_session_folder);
1874 catch (Glib::Error & e) {
1875 std::cerr << "open_session_selector.add_shortcut_folder() threw Glib::Error " << e.what() << std::endl;
1878 FileFilter session_filter;
1879 session_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::statefile_suffix));
1880 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1881 open_session_selector.add_filter (session_filter);
1883 FileFilter archive_filter;
1884 archive_filter.add_pattern (X_("*.tar.xz"));
1885 archive_filter.set_name (_("Session Archives"));
1887 open_session_selector.add_filter (archive_filter);
1889 open_session_selector.set_filter (session_filter);
1891 int response = open_session_selector.run();
1892 open_session_selector.hide ();
1894 if (response == Gtk::RESPONSE_CANCEL) {
1898 string session_path = open_session_selector.get_filename();
1902 if (session_path.length() > 0) {
1903 int rv = ARDOUR::inflate_session (session_path,
1904 Config->get_default_session_parent_dir(), path, name);
1906 _session_is_new = false;
1907 load_session (path, name);
1910 MessageDialog msg (_main_window,
1911 string_compose (_("Extracting session-archive failed: %1"), inflate_error (rv)));
1914 else if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1915 _session_is_new = isnew;
1916 load_session (path, name);
1922 ARDOUR_UI::session_add_vca (const string& name_template, uint32_t n)
1928 _session->vca_manager().create_vca (n, name_template);
1932 ARDOUR_UI::session_add_mixed_track (
1933 const ChanCount& input,
1934 const ChanCount& output,
1935 RouteGroup* route_group,
1937 const string& name_template,
1939 PluginInfoPtr instrument,
1940 Plugin::PresetRecord* pset,
1941 ARDOUR::PresentationInfo::order_t order)
1943 list<boost::shared_ptr<MidiTrack> > tracks;
1945 if (_session == 0) {
1946 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1951 tracks = _session->new_midi_track (input, output, instrument, pset, route_group, how_many, name_template, order, ARDOUR::Normal);
1953 if (tracks.size() != how_many) {
1954 error << string_compose(P_("could not create %1 new mixed track", "could not create %1 new mixed tracks", how_many), how_many) << endmsg;
1959 display_insufficient_ports_message ();
1964 for (list<boost::shared_ptr<MidiTrack> >::iterator i = tracks.begin(); i != tracks.end(); ++i) {
1965 (*i)->set_strict_io (true);
1971 ARDOUR_UI::session_add_midi_bus (
1972 RouteGroup* route_group,
1974 const string& name_template,
1976 PluginInfoPtr instrument,
1977 Plugin::PresetRecord* pset,
1978 ARDOUR::PresentationInfo::order_t order)
1982 if (_session == 0) {
1983 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1989 routes = _session->new_midi_route (route_group, how_many, name_template, instrument, pset, PresentationInfo::MidiBus, order);
1990 if (routes.size() != how_many) {
1991 error << string_compose(P_("could not create %1 new Midi Bus", "could not create %1 new Midi Busses", how_many), how_many) << endmsg;
1996 display_insufficient_ports_message ();
2001 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
2002 (*i)->set_strict_io (true);
2008 ARDOUR_UI::session_add_midi_route (
2010 RouteGroup* route_group,
2012 const string& name_template,
2014 PluginInfoPtr instrument,
2015 Plugin::PresetRecord* pset,
2016 ARDOUR::PresentationInfo::order_t order)
2018 ChanCount one_midi_channel;
2019 one_midi_channel.set (DataType::MIDI, 1);
2022 session_add_mixed_track (one_midi_channel, one_midi_channel, route_group, how_many, name_template, strict_io, instrument, pset, order);
2024 session_add_midi_bus (route_group, how_many, name_template, strict_io, instrument, pset, order);
2029 ARDOUR_UI::session_add_audio_route (
2031 int32_t input_channels,
2032 int32_t output_channels,
2033 ARDOUR::TrackMode mode,
2034 RouteGroup* route_group,
2036 string const & name_template,
2038 ARDOUR::PresentationInfo::order_t order)
2040 list<boost::shared_ptr<AudioTrack> > tracks;
2043 if (_session == 0) {
2044 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
2050 tracks = _session->new_audio_track (input_channels, output_channels, route_group, how_many, name_template, order, mode);
2052 if (tracks.size() != how_many) {
2053 error << string_compose (P_("could not create %1 new audio track", "could not create %1 new audio tracks", how_many), how_many)
2059 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template, PresentationInfo::AudioBus, order);
2061 if (routes.size() != how_many) {
2062 error << string_compose (P_("could not create %1 new audio bus", "could not create %1 new audio busses", how_many), how_many)
2069 display_insufficient_ports_message ();
2074 for (list<boost::shared_ptr<AudioTrack> >::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2075 (*i)->set_strict_io (true);
2077 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
2078 (*i)->set_strict_io (true);
2084 ARDOUR_UI::display_insufficient_ports_message ()
2086 MessageDialog msg (_main_window,
2087 string_compose (_("There are insufficient ports available\n\
2088 to create a new track or bus.\n\
2089 You should save %1, exit and\n\
2090 restart with more ports."), PROGRAM_NAME));
2091 pop_back_splash (msg);
2096 ARDOUR_UI::transport_goto_start ()
2099 _session->goto_start();
2101 /* force displayed area in editor to start no matter
2102 what "follow playhead" setting is.
2106 editor->center_screen (_session->current_start_frame ());
2112 ARDOUR_UI::transport_goto_zero ()
2115 _session->request_locate (0);
2117 /* force displayed area in editor to start no matter
2118 what "follow playhead" setting is.
2122 editor->reset_x_origin (0);
2128 ARDOUR_UI::transport_goto_wallclock ()
2130 if (_session && editor) {
2137 localtime_r (&now, &tmnow);
2139 framecnt_t frame_rate = _session->frame_rate();
2141 if (frame_rate == 0) {
2142 /* no frame rate available */
2146 frames = tmnow.tm_hour * (60 * 60 * frame_rate);
2147 frames += tmnow.tm_min * (60 * frame_rate);
2148 frames += tmnow.tm_sec * frame_rate;
2150 _session->request_locate (frames, _session->transport_rolling ());
2152 /* force displayed area in editor to start no matter
2153 what "follow playhead" setting is.
2157 editor->center_screen (frames);
2163 ARDOUR_UI::transport_goto_end ()
2166 framepos_t const frame = _session->current_end_frame();
2167 _session->request_locate (frame);
2169 /* force displayed area in editor to start no matter
2170 what "follow playhead" setting is.
2174 editor->center_screen (frame);
2180 ARDOUR_UI::transport_stop ()
2186 if (_session->is_auditioning()) {
2187 _session->cancel_audition ();
2191 _session->request_stop (false, true);
2194 /** Check if any tracks are record enabled. If none are, record enable all of them.
2195 * @return true if track record-enabled status was changed, false otherwise.
2198 ARDOUR_UI::trx_record_enable_all_tracks ()
2204 boost::shared_ptr<RouteList> rl = _session->get_tracks ();
2205 bool none_record_enabled = true;
2207 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
2208 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*r);
2211 if (t->rec_enable_control()->get_value()) {
2212 none_record_enabled = false;
2217 if (none_record_enabled) {
2218 _session->set_controls (route_list_to_control_list (rl, &Stripable::rec_enable_control), 1.0, Controllable::NoGroup);
2221 return none_record_enabled;
2225 ARDOUR_UI::transport_record (bool roll)
2228 switch (_session->record_status()) {
2229 case Session::Disabled:
2230 if (_session->ntracks() == 0) {
2231 MessageDialog msg (_main_window, _("Please create one or more tracks before trying to record.\nYou can do this with the \"Add Track or Bus\" option in the Session menu."));
2235 if (Profile->get_trx()) {
2236 roll = trx_record_enable_all_tracks ();
2238 _session->maybe_enable_record ();
2243 case Session::Recording:
2245 _session->request_stop();
2247 _session->disable_record (false, true);
2251 case Session::Enabled:
2252 _session->disable_record (false, true);
2258 ARDOUR_UI::transport_roll ()
2264 if (_session->is_auditioning()) {
2269 if (_session->config.get_external_sync()) {
2270 switch (Config->get_sync_source()) {
2274 /* transport controlled by the master */
2280 bool rolling = _session->transport_rolling();
2282 if (_session->get_play_loop()) {
2284 /* If loop playback is not a mode, then we should cancel
2285 it when this action is requested. If it is a mode
2286 we just leave it in place.
2289 if (!Config->get_loop_is_mode()) {
2290 /* XXX it is not possible to just leave seamless loop and keep
2291 playing at present (nov 4th 2009)
2293 if (!Config->get_seamless_loop()) {
2294 /* stop loop playback and stop rolling */
2295 _session->request_play_loop (false, true);
2296 } else if (rolling) {
2297 /* stop loop playback but keep rolling */
2298 _session->request_play_loop (false, false);
2302 } else if (_session->get_play_range () ) {
2303 /* stop playing a range if we currently are */
2304 _session->request_play_range (0, true);
2308 _session->request_transport_speed (1.0f);
2313 ARDOUR_UI::get_smart_mode() const
2315 return ( editor->get_smart_mode() );
2320 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
2326 if (_session->is_auditioning()) {
2327 _session->cancel_audition ();
2331 if (_session->config.get_external_sync()) {
2332 switch (Config->get_sync_source()) {
2336 /* transport controlled by the master */
2341 bool rolling = _session->transport_rolling();
2342 bool affect_transport = true;
2344 if (rolling && roll_out_of_bounded_mode) {
2345 /* drop out of loop/range playback but leave transport rolling */
2346 if (_session->get_play_loop()) {
2347 if (_session->actively_recording()) {
2349 /* just stop using the loop, then actually stop
2352 _session->request_play_loop (false, affect_transport);
2355 if (Config->get_seamless_loop()) {
2356 /* the disk buffers contain copies of the loop - we can't
2357 just keep playing, so stop the transport. the user
2358 can restart as they wish.
2360 affect_transport = true;
2362 /* disk buffers are normal, so we can keep playing */
2363 affect_transport = false;
2365 _session->request_play_loop (false, affect_transport);
2367 } else if (_session->get_play_range ()) {
2368 affect_transport = false;
2369 _session->request_play_range (0, true);
2373 if (affect_transport) {
2375 _session->request_stop (with_abort, true);
2377 } else if (!with_abort) { /* with_abort == true means the
2378 * command was intended to stop
2379 * transport, not start.
2382 /* the only external sync condition we can be in here
2383 * would be Engine (JACK) sync, in which case we still
2387 if (UIConfiguration::instance().get_follow_edits() && ( editor->get_selection().time.front().start == _session->transport_frame() ) ) { //if playhead is exactly at the start of a range, we can assume it was placed there by follow_edits
2388 _session->request_play_range (&editor->get_selection().time, true);
2389 _session->set_requested_return_frame( editor->get_selection().time.front().start ); //force an auto-return here
2391 _session->request_transport_speed (1.0f);
2397 ARDOUR_UI::toggle_session_auto_loop ()
2403 Location * looploc = _session->locations()->auto_loop_location();
2409 if (_session->get_play_loop()) {
2411 /* looping enabled, our job is to disable it */
2413 _session->request_play_loop (false);
2417 /* looping not enabled, our job is to enable it.
2419 loop-is-NOT-mode: this action always starts the transport rolling.
2420 loop-IS-mode: this action simply sets the loop play mechanism, but
2421 does not start transport.
2423 if (Config->get_loop_is_mode()) {
2424 _session->request_play_loop (true, false);
2426 _session->request_play_loop (true, true);
2430 //show the loop markers
2431 looploc->set_hidden (false, this);
2435 ARDOUR_UI::transport_play_selection ()
2441 editor->play_selection ();
2445 ARDOUR_UI::transport_play_preroll ()
2450 editor->play_with_preroll ();
2454 ARDOUR_UI::transport_rec_preroll ()
2459 editor->rec_with_preroll ();
2463 ARDOUR_UI::transport_rewind (int option)
2465 float current_transport_speed;
2468 current_transport_speed = _session->transport_speed();
2470 if (current_transport_speed >= 0.0f) {
2473 _session->request_transport_speed (-1.0f);
2476 _session->request_transport_speed (-4.0f);
2479 _session->request_transport_speed (-0.5f);
2484 _session->request_transport_speed (current_transport_speed * 1.5f);
2490 ARDOUR_UI::transport_forward (int option)
2496 float current_transport_speed = _session->transport_speed();
2498 if (current_transport_speed <= 0.0f) {
2501 _session->request_transport_speed (1.0f);
2504 _session->request_transport_speed (4.0f);
2507 _session->request_transport_speed (0.5f);
2512 _session->request_transport_speed (current_transport_speed * 1.5f);
2517 ARDOUR_UI::toggle_record_enable (uint16_t rid)
2523 boost::shared_ptr<Route> r;
2525 if ((r = _session->get_remote_nth_route (rid)) != 0) {
2527 boost::shared_ptr<Track> t;
2529 if ((t = boost::dynamic_pointer_cast<Track>(r)) != 0) {
2530 t->rec_enable_control()->set_value (!t->rec_enable_control()->get_value(), Controllable::UseGroup);
2536 ARDOUR_UI::map_transport_state ()
2539 auto_loop_button.unset_active_state ();
2540 play_selection_button.unset_active_state ();
2541 roll_button.unset_active_state ();
2542 stop_button.set_active_state (Gtkmm2ext::ExplicitActive);
2543 layered_button.set_sensitive (false);
2547 shuttle_box.map_transport_state ();
2549 float sp = _session->transport_speed();
2555 if (_session->get_play_range()) {
2557 play_selection_button.set_active_state (Gtkmm2ext::ExplicitActive);
2558 roll_button.unset_active_state ();
2559 auto_loop_button.unset_active_state ();
2561 } else if (_session->get_play_loop ()) {
2563 auto_loop_button.set_active (true);
2564 play_selection_button.set_active (false);
2565 if (Config->get_loop_is_mode()) {
2566 roll_button.set_active (true);
2568 roll_button.set_active (false);
2573 roll_button.set_active (true);
2574 play_selection_button.set_active (false);
2575 auto_loop_button.set_active (false);
2578 if (UIConfiguration::instance().get_follow_edits() && !_session->config.get_external_sync()) {
2579 /* light up both roll and play-selection if they are joined */
2580 roll_button.set_active (true);
2581 play_selection_button.set_active (true);
2583 layered_button.set_sensitive (!_session->actively_recording ());
2585 stop_button.set_active (false);
2589 layered_button.set_sensitive (true);
2590 stop_button.set_active (true);
2591 roll_button.set_active (false);
2592 play_selection_button.set_active (false);
2593 if (Config->get_loop_is_mode ()) {
2594 auto_loop_button.set_active (_session->get_play_loop());
2596 auto_loop_button.set_active (false);
2598 update_disk_space ();
2603 ARDOUR_UI::blink_handler (bool blink_on)
2605 transport_rec_enable_blink (blink_on);
2606 solo_blink (blink_on);
2607 sync_blink (blink_on);
2608 audition_blink (blink_on);
2609 feedback_blink (blink_on);
2610 error_blink (blink_on);
2614 ARDOUR_UI::update_clocks ()
2616 if (!_session) return;
2618 if (editor && !editor->dragging_playhead()) {
2619 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD)); /* EMIT_SIGNAL */
2624 ARDOUR_UI::start_clocking ()
2626 if (UIConfiguration::instance().get_super_rapid_clock_update()) {
2627 clock_signal_connection = Timers::fps_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2629 clock_signal_connection = Timers::rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2634 ARDOUR_UI::stop_clocking ()
2636 clock_signal_connection.disconnect ();
2640 ARDOUR_UI::save_as_progress_update (float fraction, int64_t cnt, int64_t total, Gtk::Label* label, Gtk::ProgressBar* bar)
2644 snprintf (buf, sizeof (buf), _("Copied %" PRId64 " of %" PRId64), cnt, total);
2646 label->set_text (buf);
2647 bar->set_fraction (fraction);
2649 /* process events, redraws, etc. */
2651 while (gtk_events_pending()) {
2652 gtk_main_iteration ();
2655 return true; /* continue with save-as */
2659 ARDOUR_UI::save_session_as ()
2665 if (!save_as_dialog) {
2666 save_as_dialog = new SaveAsDialog;
2669 save_as_dialog->set_name (_session->name());
2671 int response = save_as_dialog->run ();
2673 save_as_dialog->hide ();
2676 case Gtk::RESPONSE_OK:
2685 sa.new_parent_folder = save_as_dialog->new_parent_folder ();
2686 sa.new_name = save_as_dialog->new_name ();
2687 sa.switch_to = save_as_dialog->switch_to();
2688 sa.copy_media = save_as_dialog->copy_media();
2689 sa.copy_external = save_as_dialog->copy_external();
2690 sa.include_media = save_as_dialog->include_media ();
2692 /* Only bother with a progress dialog if we're going to copy
2693 media into the save-as target. Without that choice, this
2694 will be very fast because we're only talking about a few kB's to
2695 perhaps a couple of MB's of data.
2698 ArdourDialog progress_dialog (_("Save As"), true);
2700 if (sa.include_media && sa.copy_media) {
2703 Gtk::ProgressBar progress_bar;
2705 progress_dialog.get_vbox()->pack_start (label);
2706 progress_dialog.get_vbox()->pack_start (progress_bar);
2708 progress_bar.show ();
2710 /* this signal will be emitted from within this, the calling thread,
2711 * after every file is copied. It provides information on percentage
2712 * complete (in terms of total data to copy), the number of files
2713 * copied so far, and the total number to copy.
2718 sa.Progress.connect_same_thread (c, boost::bind (&ARDOUR_UI::save_as_progress_update, this, _1, _2, _3, &label, &progress_bar));
2720 progress_dialog.show_all ();
2721 progress_dialog.present ();
2724 if (_session->save_as (sa)) {
2726 MessageDialog msg (string_compose (_("Save As failed: %1"), sa.failure_message));
2730 if (!sa.include_media) {
2731 unload_session (false);
2732 load_session (sa.final_session_folder_name, sa.new_name);
2737 ARDOUR_UI::archive_session ()
2745 Glib::DateTime gdt (Glib::DateTime::create_now_local (n));
2747 SessionArchiveDialog sad;
2748 sad.set_name (_session->name() + gdt.format ("_%F_%H%M%S"));
2749 int response = sad.run ();
2751 if (response != Gtk::RESPONSE_OK) {
2756 if (_session->archive_session (sad.target_folder(), sad.name(), sad.encode_option (), sad.only_used_sources (), &sad)) {
2757 MessageDialog msg (_("Session Archiving failed."));
2763 ARDOUR_UI::quick_snapshot_session (bool switch_to_it)
2767 struct tm local_time;
2770 localtime_r (&n, &local_time);
2771 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2773 save_state (timebuf, switch_to_it);
2778 ARDOUR_UI::process_snapshot_session_prompter (ArdourPrompter& prompter, bool switch_to_it)
2782 prompter.get_result (snapname);
2784 bool do_save = (snapname.length() != 0);
2787 char illegal = Session::session_name_is_legal(snapname);
2789 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2790 "snapshot names may not contain a '%1' character"), illegal));
2796 vector<std::string> p;
2797 get_state_files_in_directory (_session->session_directory().root_path(), p);
2798 vector<string> n = get_file_names_no_extension (p);
2800 if (find (n.begin(), n.end(), snapname) != n.end()) {
2802 do_save = overwrite_file_dialog (prompter,
2803 _("Confirm Snapshot Overwrite"),
2804 _("A snapshot already exists with that name. Do you want to overwrite it?"));
2808 save_state (snapname, switch_to_it);
2818 /** Ask the user for the name of a new snapshot and then take it.
2822 ARDOUR_UI::snapshot_session (bool switch_to_it)
2824 ArdourPrompter prompter (true);
2826 prompter.set_name ("Prompter");
2827 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2829 prompter.set_title (_("Snapshot and switch"));
2830 prompter.set_prompt (_("New session name"));
2832 prompter.set_title (_("Take Snapshot"));
2833 prompter.set_prompt (_("Name of new snapshot"));
2837 prompter.set_initial_text (_session->snap_name());
2839 Glib::DateTime tm (g_date_time_new_now_local ());
2840 prompter.set_initial_text (tm.format ("%FT%H.%M.%S"));
2843 bool finished = false;
2845 switch (prompter.run()) {
2846 case RESPONSE_ACCEPT:
2848 finished = process_snapshot_session_prompter (prompter, switch_to_it);
2859 /** Ask the user for a new session name and then rename the session to it.
2863 ARDOUR_UI::rename_session ()
2869 ArdourPrompter prompter (true);
2872 prompter.set_name ("Prompter");
2873 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2874 prompter.set_title (_("Rename Session"));
2875 prompter.set_prompt (_("New session name"));
2878 switch (prompter.run()) {
2879 case RESPONSE_ACCEPT:
2881 prompter.get_result (name);
2883 bool do_rename = (name.length() != 0);
2886 char illegal = Session::session_name_is_legal (name);
2889 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2890 "session names may not contain a '%1' character"), illegal));
2895 switch (_session->rename (name)) {
2897 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
2898 msg.set_position (WIN_POS_MOUSE);
2906 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
2907 msg.set_position (WIN_POS_MOUSE);
2923 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2925 if (!_session || _session->deletion_in_progress()) {
2929 XMLNode* node = new XMLNode (X_("UI"));
2931 WM::Manager::instance().add_state (*node);
2933 node->add_child_nocopy (gui_object_state->get_state());
2935 _session->add_extra_xml (*node);
2937 if (export_video_dialog) {
2938 _session->add_extra_xml (export_video_dialog->get_state());
2941 save_state_canfail (name, switch_to_it);
2945 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2950 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2955 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2960 ARDOUR_UI::primary_clock_value_changed ()
2963 _session->request_locate (primary_clock->current_time ());
2968 ARDOUR_UI::big_clock_value_changed ()
2971 _session->request_locate (big_clock->current_time ());
2976 ARDOUR_UI::secondary_clock_value_changed ()
2979 _session->request_locate (secondary_clock->current_time ());
2984 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2986 if (_session == 0) {
2990 if (_session->step_editing()) {
2994 Session::RecordState const r = _session->record_status ();
2995 bool const h = _session->have_rec_enabled_track ();
2997 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2999 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
3001 rec_button.set_active_state (Gtkmm2ext::Off);
3003 } else if (r == Session::Recording && h) {
3004 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
3006 rec_button.unset_active_state ();
3011 ARDOUR_UI::process_save_template_prompter (ArdourPrompter& prompter)
3015 prompter.get_result (name);
3017 if (name.length()) {
3018 int failed = _session->save_template (name);
3020 if (failed == -2) { /* file already exists. */
3021 bool overwrite = overwrite_file_dialog (prompter,
3022 _("Confirm Template Overwrite"),
3023 _("A template already exists with that name. Do you want to overwrite it?"));
3026 _session->save_template (name, true);
3038 ARDOUR_UI::save_template ()
3040 ArdourPrompter prompter (true);
3042 if (!check_audioengine (_main_window)) {
3046 prompter.set_name (X_("Prompter"));
3047 prompter.set_title (_("Save Template"));
3048 prompter.set_prompt (_("Name for template:"));
3049 prompter.set_initial_text(_session->name() + _("-template"));
3050 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
3052 bool finished = false;
3054 switch (prompter.run()) {
3055 case RESPONSE_ACCEPT:
3056 finished = process_save_template_prompter (prompter);
3067 ARDOUR_UI::edit_metadata ()
3069 SessionMetadataEditor dialog;
3070 dialog.set_session (_session);
3071 dialog.grab_focus ();
3076 ARDOUR_UI::import_metadata ()
3078 SessionMetadataImporter dialog;
3079 dialog.set_session (_session);
3084 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
3086 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
3088 MessageDialog msg (str,
3090 Gtk::MESSAGE_WARNING,
3091 Gtk::BUTTONS_YES_NO,
3095 msg.set_name (X_("OpenExistingDialog"));
3096 msg.set_title (_("Open Existing Session"));
3097 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
3098 msg.set_position (Gtk::WIN_POS_CENTER);
3099 pop_back_splash (msg);
3101 switch (msg.run()) {
3110 ARDOUR_UI::build_session_from_dialog (SessionDialog& sd, const std::string& session_path, const std::string& session_name)
3112 BusProfile bus_profile;
3116 bus_profile.master_out_channels = 2;
3117 bus_profile.input_ac = AutoConnectPhysical;
3118 bus_profile.output_ac = AutoConnectMaster;
3119 bus_profile.requested_physical_in = 0; // use all available
3120 bus_profile.requested_physical_out = 0; // use all available
3124 /* get settings from advanced section of NSD */
3126 if (sd.create_master_bus()) {
3127 bus_profile.master_out_channels = (uint32_t) sd.master_channel_count();
3129 bus_profile.master_out_channels = 0;
3132 if (sd.connect_inputs()) {
3133 bus_profile.input_ac = AutoConnectPhysical;
3135 bus_profile.input_ac = AutoConnectOption (0);
3138 bus_profile.output_ac = AutoConnectOption (0);
3140 if (sd.connect_outputs ()) {
3141 if (sd.connect_outs_to_master()) {
3142 bus_profile.output_ac = AutoConnectMaster;
3143 } else if (sd.connect_outs_to_physical()) {
3144 bus_profile.output_ac = AutoConnectPhysical;
3148 bus_profile.requested_physical_in = (uint32_t) sd.input_limit_count();
3149 bus_profile.requested_physical_out = (uint32_t) sd.output_limit_count();
3152 if (build_session (session_path, session_name, bus_profile)) {
3160 ARDOUR_UI::load_from_application_api (const std::string& path)
3162 /* OS X El Capitan (and probably later) now somehow passes the command
3163 line arguments to an app via the openFile delegate protocol. Ardour
3164 already does its own command line processing, and having both
3165 pathways active causes crashes. So, if the command line was already
3166 set, do nothing here.
3169 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
3173 ARDOUR_COMMAND_LINE::session_name = path;
3175 /* Cancel SessionDialog if it's visible to make OSX delegates work.
3177 * ARDOUR_UI::starting connects app->ShouldLoad signal and then shows a SessionDialog
3179 * - ShouldLoad does not arrive in time, ARDOUR_COMMAND_LINE::session_name is empty:
3180 * -> ARDOUR_UI::get_session_parameters starts a SessionDialog.
3181 * - ShouldLoad signal arrives, this function is called and sets ARDOUR_COMMAND_LINE::session_name
3182 * -> SessionDialog is not displayed
3185 if (_session_dialog) {
3186 std::string session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3187 std::string session_path = path;
3188 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_REGULAR)) {
3189 session_path = Glib::path_get_dirname (session_path);
3191 // signal the existing dialog in ARDOUR_UI::get_session_parameters()
3192 _session_dialog->set_provided_session (session_name, session_path);
3193 _session_dialog->response (RESPONSE_NONE);
3194 _session_dialog->hide();
3199 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
3200 /* /path/to/foo => /path/to/foo, foo */
3201 rv = load_session (path, basename_nosuffix (path));
3203 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
3204 rv =load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
3207 // if load_session fails -> pop up SessionDialog.
3209 ARDOUR_COMMAND_LINE::session_name = "";
3211 if (get_session_parameters (true, false)) {
3217 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
3219 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
3221 string session_name;
3222 string session_path;
3223 string template_name;
3225 bool likely_new = false;
3226 bool cancel_not_quit;
3228 /* deal with any existing DIRTY session now, rather than later. don't
3229 * treat a non-dirty session this way, so that it stays visible
3230 * as we bring up the new session dialog.
3233 if (_session && ARDOUR_UI::instance()->video_timeline) {
3234 ARDOUR_UI::instance()->video_timeline->sync_session_state();
3237 /* if there is already a session, relabel the button
3238 on the SessionDialog so that we don't Quit directly
3240 cancel_not_quit = (_session != 0);
3242 if (_session && _session->dirty()) {
3243 if (unload_session (false)) {
3244 /* unload cancelled by user */
3247 ARDOUR_COMMAND_LINE::session_name = "";
3250 if (!load_template.empty()) {
3251 should_be_new = true;
3252 template_name = load_template;
3255 session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
3256 session_path = ARDOUR_COMMAND_LINE::session_name;
3258 if (!session_path.empty()) {
3259 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_EXISTS)) {
3260 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_IS_REGULAR)) {
3261 /* session/snapshot file, change path to be dir */
3262 session_path = Glib::path_get_dirname (session_path);
3267 SessionDialog session_dialog (should_be_new, session_name, session_path, load_template, cancel_not_quit);
3269 _session_dialog = &session_dialog;
3272 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
3274 /* if they named a specific statefile, use it, otherwise they are
3275 just giving a session folder, and we want to use it as is
3276 to find the session.
3279 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
3281 if (suffix != string::npos) {
3282 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
3283 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
3284 session_name = Glib::path_get_basename (session_name);
3286 session_path = ARDOUR_COMMAND_LINE::session_name;
3287 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
3292 session_dialog.clear_given ();
3295 if (should_be_new || session_name.empty()) {
3296 /* need the dialog to get info from user */
3298 cerr << "run dialog\n";
3300 switch (session_dialog.run()) {
3301 case RESPONSE_ACCEPT:
3304 /* this is used for async * app->ShouldLoad(). */
3305 continue; // while loop
3308 if (quit_on_cancel) {
3309 // JE - Currently (July 2014) this section can only get reached if the
3310 // user quits from the main 'Session Setup' dialog (i.e. reaching this
3311 // point does NOT indicate an abnormal termination). Therefore, let's
3312 // behave gracefully (i.e. let's do some cleanup) before we call exit()
3314 pthread_cancel_all ();
3322 session_dialog.hide ();
3325 /* if we run the startup dialog again, offer more than just "new session" */
3327 should_be_new = false;
3329 session_name = session_dialog.session_name (likely_new);
3330 session_path = session_dialog.session_folder ();
3337 int rv = ARDOUR::inflate_session (session_name,
3338 Config->get_default_session_parent_dir(), session_path, session_name);
3340 MessageDialog msg (session_dialog,
3341 string_compose (_("Extracting session-archive failed: %1"), inflate_error (rv)));
3346 session_dialog.set_provided_session (session_name, session_path);
3350 // XXX check archive, inflate
3351 string::size_type suffix = session_name.find (statefile_suffix);
3353 if (suffix != string::npos) {
3354 session_name = session_name.substr (0, suffix);
3357 /* this shouldn't happen, but we catch it just in case it does */
3359 if (session_name.empty()) {
3363 if (session_dialog.use_session_template()) {
3364 template_name = session_dialog.session_template_name();
3365 _session_is_new = true;
3368 if (session_name[0] == G_DIR_SEPARATOR ||
3369 #ifdef PLATFORM_WINDOWS
3370 (session_name.length() > 3 && session_name[1] == ':' && session_name[2] == G_DIR_SEPARATOR)
3372 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
3373 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)
3378 /* absolute path or cwd-relative path specified for session name: infer session folder
3379 from what was given.
3382 session_path = Glib::path_get_dirname (session_name);
3383 session_name = Glib::path_get_basename (session_name);
3387 session_path = session_dialog.session_folder();
3389 char illegal = Session::session_name_is_legal (session_name);
3392 MessageDialog msg (session_dialog,
3393 string_compose (_("To ensure compatibility with various systems\n"
3394 "session names may not contain a '%1' character"),
3397 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3402 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
3405 if (likely_new && !nsm) {
3407 std::string existing = Glib::build_filename (session_path, session_name);
3409 if (!ask_about_loading_existing_session (existing)) {
3410 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3415 _session_is_new = false;
3420 pop_back_splash (session_dialog);
3421 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
3423 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3427 char illegal = Session::session_name_is_legal(session_name);
3430 pop_back_splash (session_dialog);
3431 MessageDialog msg (session_dialog, string_compose(_("To ensure compatibility with various systems\n"
3432 "session names may not contain a '%1' character"), illegal));
3434 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3438 _session_is_new = true;
3441 if (likely_new && template_name.empty()) {
3443 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3447 ret = load_session (session_path, session_name, template_name);
3450 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
3454 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
3455 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
3459 /* clear this to avoid endless attempts to load the
3463 ARDOUR_COMMAND_LINE::session_name = "";
3467 _session_dialog = NULL;
3473 ARDOUR_UI::close_session()
3475 if (!check_audioengine (_main_window)) {
3479 if (unload_session (true)) {
3483 ARDOUR_COMMAND_LINE::session_name = "";
3485 if (get_session_parameters (true, false)) {
3488 if (splash && splash->is_visible()) {
3489 // in 1 second, hide the splash screen
3490 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
3494 /** @param snap_name Snapshot name (without .ardour suffix).
3495 * @return -2 if the load failed because we are not connected to the AudioEngine.
3498 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
3500 Session *new_session;
3505 unload_status = unload_session ();
3507 if (unload_status < 0) {
3509 } else if (unload_status > 0) {
3515 session_loaded = false;
3517 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
3520 new_session = new Session (*AudioEngine::instance(), path, snap_name, 0, mix_template);
3523 /* this one is special */
3525 catch (AudioEngine::PortRegistrationFailure& err) {
3527 MessageDialog msg (err.what(),
3530 Gtk::BUTTONS_CLOSE);
3532 msg.set_title (_("Port Registration Error"));
3533 msg.set_secondary_text (_("Click the Close button to try again."));
3534 msg.set_position (Gtk::WIN_POS_CENTER);
3535 pop_back_splash (msg);
3538 int response = msg.run ();
3543 case RESPONSE_CANCEL:
3550 catch (SessionException e) {
3551 MessageDialog msg (string_compose(
3552 _("Session \"%1 (snapshot %2)\" did not load successfully: %3"),
3553 path, snap_name, e.what()),
3558 msg.set_title (_("Loading Error"));
3559 msg.set_position (Gtk::WIN_POS_CENTER);
3560 pop_back_splash (msg);
3572 MessageDialog msg (string_compose(
3573 _("Session \"%1 (snapshot %2)\" did not load successfully"),
3579 msg.set_title (_("Loading Error"));
3580 msg.set_position (Gtk::WIN_POS_CENTER);
3581 pop_back_splash (msg);
3593 list<string> const u = new_session->unknown_processors ();
3595 MissingPluginDialog d (_session, u);
3600 if (!new_session->writable()) {
3601 MessageDialog msg (_("This session has been opened in read-only mode.\n\nYou will not be able to record or save."),
3606 msg.set_title (_("Read-only Session"));
3607 msg.set_position (Gtk::WIN_POS_CENTER);
3608 pop_back_splash (msg);
3615 /* Now the session been created, add the transport controls */
3616 new_session->add_controllable(roll_controllable);
3617 new_session->add_controllable(stop_controllable);
3618 new_session->add_controllable(goto_start_controllable);
3619 new_session->add_controllable(goto_end_controllable);
3620 new_session->add_controllable(auto_loop_controllable);
3621 new_session->add_controllable(play_selection_controllable);
3622 new_session->add_controllable(rec_controllable);
3624 set_session (new_session);
3626 session_loaded = true;
3629 _session->set_clean ();
3632 #ifdef WINDOWS_VST_SUPPORT
3633 fst_stop_threading();
3637 Timers::TimerSuspender t;
3641 #ifdef WINDOWS_VST_SUPPORT
3642 fst_start_threading();
3651 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
3653 Session *new_session;
3656 session_loaded = false;
3657 x = unload_session ();
3665 _session_is_new = true;
3668 new_session = new Session (*AudioEngine::instance(), path, snap_name, &bus_profile);
3671 catch (SessionException e) {
3672 cerr << "Here are the errors associated with this failed session:\n";
3674 cerr << "---------\n";
3675 MessageDialog msg (string_compose(_("Could not create session in \"%1\": %2"), path, e.what()));
3676 msg.set_title (_("Loading Error"));
3677 msg.set_position (Gtk::WIN_POS_CENTER);
3678 pop_back_splash (msg);
3683 cerr << "Here are the errors associated with this failed session:\n";
3685 cerr << "---------\n";
3686 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
3687 msg.set_title (_("Loading Error"));
3688 msg.set_position (Gtk::WIN_POS_CENTER);
3689 pop_back_splash (msg);
3694 /* Give the new session the default GUI state, if such things exist */
3697 n = Config->instant_xml (X_("Editor"));
3699 n->remove_nodes_and_delete ("Selection"); // no not apply selection to new sessions.
3700 new_session->add_instant_xml (*n, false);
3702 n = Config->instant_xml (X_("Mixer"));
3704 new_session->add_instant_xml (*n, false);
3707 n = Config->instant_xml (X_("Preferences"));
3709 new_session->add_instant_xml (*n, false);
3712 /* Put the playhead at 0 and scroll fully left */
3713 n = new_session->instant_xml (X_("Editor"));
3715 n->add_property (X_("playhead"), X_("0"));
3716 n->add_property (X_("left-frame"), X_("0"));
3719 set_session (new_session);
3721 session_loaded = true;
3723 new_session->save_state(new_session->name());
3729 ARDOUR_UI::launch_chat ()
3731 MessageDialog dialog(_("<b>Just ask and wait for an answer.\nIt may take from minutes to hours.</b>"), true);
3733 dialog.set_title (_("About the Chat"));
3734 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."));
3736 switch (dialog.run()) {
3739 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
3740 #elif defined PLATFORM_WINDOWS
3741 open_uri("http://webchat.freenode.net/?channels=ardour-windows");
3743 open_uri("http://webchat.freenode.net/?channels=ardour");
3752 ARDOUR_UI::launch_manual ()
3754 PBD::open_uri (Config->get_tutorial_manual_url());
3758 ARDOUR_UI::launch_reference ()
3760 PBD::open_uri (Config->get_reference_manual_url());
3764 ARDOUR_UI::launch_tracker ()
3766 PBD::open_uri ("http://tracker.ardour.org");
3770 ARDOUR_UI::launch_subscribe ()
3772 PBD::open_uri ("https://community.ardour.org/s/subscribe");
3776 ARDOUR_UI::launch_cheat_sheet ()
3779 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheat_sheet_osx.pdf");
3781 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheatsheet.pdf");
3786 ARDOUR_UI::launch_website ()
3788 PBD::open_uri ("http://ardour.org");
3792 ARDOUR_UI::launch_website_dev ()
3794 PBD::open_uri ("http://ardour.org/development.html");
3798 ARDOUR_UI::launch_forums ()
3800 PBD::open_uri ("https://community.ardour.org/forums");
3804 ARDOUR_UI::launch_howto_report ()
3806 PBD::open_uri ("http://ardour.org/reporting_bugs");
3810 ARDOUR_UI::loading_message (const std::string& msg)
3812 if (ARDOUR_COMMAND_LINE::no_splash) {
3820 splash->message (msg);
3824 ARDOUR_UI::show_splash ()
3828 splash = new Splash;
3838 ARDOUR_UI::hide_splash ()
3845 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title, const bool msg_delete)
3849 removed = rep.paths.size();
3852 MessageDialog msgd (_main_window,
3853 _("No files were ready for clean-up"),
3857 msgd.set_title (_("Clean-up"));
3858 msgd.set_secondary_text (_("If this seems suprising, \n\
3859 check for any existing snapshots.\n\
3860 These may still include regions that\n\
3861 require some unused files to continue to exist."));
3867 ArdourDialog results (_("Clean-up"), true, false);
3869 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
3870 CleanupResultsModelColumns() {
3874 Gtk::TreeModelColumn<std::string> visible_name;
3875 Gtk::TreeModelColumn<std::string> fullpath;
3879 CleanupResultsModelColumns results_columns;
3880 Glib::RefPtr<Gtk::ListStore> results_model;
3881 Gtk::TreeView results_display;
3883 results_model = ListStore::create (results_columns);
3884 results_display.set_model (results_model);
3885 results_display.append_column (list_title, results_columns.visible_name);
3887 results_display.set_name ("CleanupResultsList");
3888 results_display.set_headers_visible (true);
3889 results_display.set_headers_clickable (false);
3890 results_display.set_reorderable (false);
3892 Gtk::ScrolledWindow list_scroller;
3895 Gtk::HBox dhbox; // the hbox for the image and text
3896 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
3897 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
3899 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
3901 const string dead_directory = _session->session_directory().dead_path();
3904 %1 - number of files removed
3905 %2 - location of "dead"
3906 %3 - size of files affected
3907 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
3910 const char* bprefix;
3911 double space_adjusted = 0;
3913 if (rep.space < 1000) {
3915 space_adjusted = rep.space;
3916 } else if (rep.space < 1000000) {
3917 bprefix = _("kilo");
3918 space_adjusted = floorf((float)rep.space / 1000.0);
3919 } else if (rep.space < 1000000 * 1000) {
3920 bprefix = _("mega");
3921 space_adjusted = floorf((float)rep.space / (1000.0 * 1000.0));
3923 bprefix = _("giga");
3924 space_adjusted = floorf((float)rep.space / (1000.0 * 1000 * 1000.0));
3928 txt.set_markup (string_compose (P_("\
3929 The following file was deleted from %2,\n\
3930 releasing %3 %4bytes of disk space", "\
3931 The following %1 files were deleted from %2,\n\
3932 releasing %3 %4bytes of disk space", removed),
3933 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3935 txt.set_markup (string_compose (P_("\
3936 The following file was not in use and \n\
3937 has been moved to: %2\n\n\
3938 After a restart of %5\n\n\
3939 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3940 will release an additional %3 %4bytes of disk space.\n", "\
3941 The following %1 files were not in use and \n\
3942 have been moved to: %2\n\n\
3943 After a restart of %5\n\n\
3944 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3945 will release an additional %3 %4bytes of disk space.\n", removed),
3946 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3949 dhbox.pack_start (*dimage, true, false, 5);
3950 dhbox.pack_start (txt, true, false, 5);
3952 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
3953 TreeModel::Row row = *(results_model->append());
3954 row[results_columns.visible_name] = *i;
3955 row[results_columns.fullpath] = *i;
3958 list_scroller.add (results_display);
3959 list_scroller.set_size_request (-1, 150);
3960 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
3962 dvbox.pack_start (dhbox, true, false, 5);
3963 dvbox.pack_start (list_scroller, true, false, 5);
3964 ddhbox.pack_start (dvbox, true, false, 5);
3966 results.get_vbox()->pack_start (ddhbox, true, false, 5);
3967 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
3968 results.set_default_response (RESPONSE_CLOSE);
3969 results.set_position (Gtk::WIN_POS_MOUSE);
3971 results_display.show();
3972 list_scroller.show();
3979 //results.get_vbox()->show();
3980 results.set_resizable (false);
3987 ARDOUR_UI::cleanup ()
3989 if (_session == 0) {
3990 /* shouldn't happen: menu item is insensitive */
3995 MessageDialog checker (_("Are you sure you want to clean-up?"),
3997 Gtk::MESSAGE_QUESTION,
4000 checker.set_title (_("Clean-up"));
4002 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
4003 ALL undo/redo information will be lost if you clean-up.\n\
4004 Clean-up will move all unused files to a \"dead\" location."));
4006 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
4007 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
4008 checker.set_default_response (RESPONSE_CANCEL);
4010 checker.set_name (_("CleanupDialog"));
4011 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
4012 checker.set_position (Gtk::WIN_POS_MOUSE);
4014 switch (checker.run()) {
4015 case RESPONSE_ACCEPT:
4021 ARDOUR::CleanupReport rep;
4023 editor->prepare_for_cleanup ();
4025 /* do not allow flush until a session is reloaded */
4027 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
4029 act->set_sensitive (false);
4032 if (_session->cleanup_sources (rep)) {
4033 editor->finish_cleanup ();
4037 editor->finish_cleanup ();
4040 display_cleanup_results (rep, _("Cleaned Files"), false);
4044 ARDOUR_UI::flush_trash ()
4046 if (_session == 0) {
4047 /* shouldn't happen: menu item is insensitive */
4051 ARDOUR::CleanupReport rep;
4053 if (_session->cleanup_trash_sources (rep)) {
4057 display_cleanup_results (rep, _("deleted file"), true);
4061 ARDOUR_UI::cleanup_peakfiles ()
4063 if (_session == 0) {
4064 /* shouldn't happen: menu item is insensitive */
4068 if (! _session->can_cleanup_peakfiles ()) {
4072 // get all region-views in this session
4074 TrackViewList empty;
4076 editor->get_regions_after(rs, (framepos_t) 0, empty);
4077 std::list<RegionView*> views = rs.by_layer();
4079 // remove displayed audio-region-views waveforms
4080 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
4081 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
4082 if (!arv) { continue ; }
4083 arv->delete_waves();
4086 // cleanup peak files:
4087 // - stop pending peakfile threads
4088 // - close peakfiles if any
4089 // - remove peak dir in session
4090 // - setup peakfiles (background thread)
4091 _session->cleanup_peakfiles ();
4093 // re-add waves to ARV
4094 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
4095 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
4096 if (!arv) { continue ; }
4097 arv->create_waves();
4101 PresentationInfo::order_t
4102 ARDOUR_UI::translate_order (RouteDialogs::InsertAt place)
4104 if (editor->get_selection().tracks.empty()) {
4105 return PresentationInfo::max_order;
4108 PresentationInfo::order_t order_hint = PresentationInfo::max_order;
4111 we want the new routes to have their order keys set starting from
4112 the highest order key in the selection + 1 (if available).
4115 if (place == RouteDialogs::AfterSelection) {
4116 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.back());
4118 order_hint = rtav->route()->presentation_info().order();
4121 } else if (place == RouteDialogs::BeforeSelection) {
4122 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.front());
4124 order_hint = rtav->route()->presentation_info().order();
4126 } else if (place == RouteDialogs::First) {
4129 /* leave order_hint at max_order */
4136 ARDOUR_UI::start_duplicate_routes ()
4138 if (!duplicate_routes_dialog) {
4139 duplicate_routes_dialog = new DuplicateRouteDialog;
4142 if (duplicate_routes_dialog->restart (_session)) {
4146 duplicate_routes_dialog->present ();
4150 ARDOUR_UI::add_route ()
4152 if (!add_route_dialog.get (false)) {
4153 add_route_dialog->signal_response().connect (sigc::mem_fun (*this, &ARDOUR_UI::add_route_dialog_finished));
4160 if (add_route_dialog->is_visible()) {
4161 /* we're already doing this */
4165 add_route_dialog->set_position (WIN_POS_MOUSE);
4166 add_route_dialog->present();
4170 ARDOUR_UI::add_route_dialog_finished (int r)
4174 add_route_dialog->hide();
4177 case RESPONSE_ACCEPT:
4184 if ((count = add_route_dialog->count()) <= 0) {
4188 PresentationInfo::order_t order = translate_order (add_route_dialog->insert_at());
4189 string template_path = add_route_dialog->track_template();
4190 DisplaySuspender ds;
4192 if (!template_path.empty()) {
4193 if (add_route_dialog->name_template_is_default()) {
4194 _session->new_route_from_template (count, order, template_path, string());
4196 _session->new_route_from_template (count, order, template_path, add_route_dialog->name_template());
4201 ChanCount input_chan= add_route_dialog->channels ();
4202 ChanCount output_chan;
4203 string name_template = add_route_dialog->name_template ();
4204 PluginInfoPtr instrument = add_route_dialog->requested_instrument ();
4205 RouteGroup* route_group = add_route_dialog->route_group ();
4206 AutoConnectOption oac = Config->get_output_auto_connect();
4207 bool strict_io = add_route_dialog->use_strict_io ();
4209 if (oac & AutoConnectMaster) {
4210 output_chan.set (DataType::AUDIO, (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan.n_audio()));
4211 output_chan.set (DataType::MIDI, 0);
4213 output_chan = input_chan;
4216 /* XXX do something with name template */
4218 Session::ProcessorChangeBlocker pcb (_session);
4220 switch (add_route_dialog->type_wanted()) {
4221 case AddRouteDialog::AudioTrack:
4222 session_add_audio_track (input_chan.n_audio(), output_chan.n_audio(), add_route_dialog->mode(), route_group, count, name_template, strict_io, order);
4224 case AddRouteDialog::MidiTrack:
4225 session_add_midi_track (route_group, count, name_template, strict_io, instrument, 0, order);
4227 case AddRouteDialog::MixedTrack:
4228 session_add_mixed_track (input_chan, output_chan, route_group, count, name_template, strict_io, instrument, 0, order);
4230 case AddRouteDialog::AudioBus:
4231 session_add_audio_bus (input_chan.n_audio(), output_chan.n_audio(), route_group, count, name_template, strict_io, order);
4233 case AddRouteDialog::MidiBus:
4234 session_add_midi_bus (route_group, count, name_template, strict_io, instrument, 0, order);
4236 case AddRouteDialog::VCAMaster:
4237 session_add_vca (name_template, count);
4243 ARDOUR_UI::add_lua_script ()
4249 LuaScriptInfoPtr spi;
4250 ScriptSelector ss ("Add Lua Session Script", LuaScriptInfo::Session);
4251 switch (ss.run ()) {
4252 case Gtk::RESPONSE_ACCEPT:
4260 std::string script = "";
4263 script = Glib::file_get_contents (spi->path);
4264 } catch (Glib::FileError e) {
4265 string msg = string_compose (_("Cannot read session script '%1': %2"), spi->path, e.what());
4266 MessageDialog am (msg);
4271 LuaScriptParamList lsp = LuaScriptParams::script_params (spi, "sess_params");
4272 std::vector<std::string> reg = _session->registered_lua_functions ();
4274 ScriptParameterDialog spd (_("Set Script Parameters"), spi, reg, lsp);
4275 switch (spd.run ()) {
4276 case Gtk::RESPONSE_ACCEPT:
4283 _session->register_lua_function (spd.name(), script, lsp);
4284 } catch (luabridge::LuaException const& e) {
4285 string msg = string_compose (_("Session script '%1' instantiation failed: %2"), spd.name(), e.what ());
4286 MessageDialog am (msg);
4288 } catch (SessionException e) {
4289 string msg = string_compose (_("Loading Session script '%1' failed: %2"), spd.name(), e.what ());
4290 MessageDialog am (msg);
4296 ARDOUR_UI::remove_lua_script ()
4301 if (_session->registered_lua_function_count () == 0) {
4302 string msg = _("There are no active Lua session scripts present in this session.");
4303 MessageDialog am (msg);
4308 std::vector<std::string> reg = _session->registered_lua_functions ();
4309 SessionScriptManager sm ("Remove Lua Session Script", reg);
4310 switch (sm.run ()) {
4311 case Gtk::RESPONSE_ACCEPT:
4317 _session->unregister_lua_function (sm.name());
4318 } catch (luabridge::LuaException const& e) {
4319 string msg = string_compose (_("Session script '%1' removal failed: %2"), sm.name(), e.what ());
4320 MessageDialog am (msg);
4326 ARDOUR_UI::stop_video_server (bool ask_confirm)
4328 if (!video_server_process && ask_confirm) {
4329 warning << string_compose (_("Video-Server was not launched by %1. The request to stop it is ignored."), PROGRAM_NAME) << endmsg;
4331 if (video_server_process) {
4333 ArdourDialog confirm (_("Stop Video-Server"), true);
4334 Label m (_("Do you really want to stop the Video Server?"));
4335 confirm.get_vbox()->pack_start (m, true, true);
4336 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
4337 confirm.add_button (_("Yes, Stop It"), Gtk::RESPONSE_ACCEPT);
4338 confirm.show_all ();
4339 if (confirm.run() == RESPONSE_CANCEL) {
4343 delete video_server_process;
4344 video_server_process =0;
4349 ARDOUR_UI::start_video_server_menu (Gtk::Window* float_window)
4351 ARDOUR_UI::start_video_server( float_window, true);
4355 ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg)
4361 if (ARDOUR_UI::instance()->video_timeline->check_server()) {
4362 if (video_server_process) {
4363 popup_error(_("The Video Server is already started."));
4365 popup_error(_("An external Video Server is configured and can be reached. Not starting a new instance."));
4371 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4373 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4375 VideoServerDialog *video_server_dialog = new VideoServerDialog (_session);
4377 video_server_dialog->set_transient_for (*float_window);
4380 if (!Config->get_show_video_server_dialog() && firsttime < 2) {
4381 video_server_dialog->hide();
4383 ResponseType r = (ResponseType) video_server_dialog->run ();
4384 video_server_dialog->hide();
4385 if (r != RESPONSE_ACCEPT) { return false; }
4386 if (video_server_dialog->show_again()) {
4387 Config->set_show_video_server_dialog(false);
4391 std::string icsd_exec = video_server_dialog->get_exec_path();
4392 std::string icsd_docroot = video_server_dialog->get_docroot();
4393 #ifndef PLATFORM_WINDOWS
4394 if (icsd_docroot.empty()) {
4395 icsd_docroot = VideoUtils::video_get_docroot (Config);
4400 #ifdef PLATFORM_WINDOWS
4401 if (VideoUtils::harvid_version >= 0x000802 && icsd_docroot.empty()) {
4402 /* OK, allow all drive letters */
4405 if (g_lstat (icsd_docroot.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode)) {
4406 warning << _("Specified docroot is not an existing directory.") << endmsg;
4409 #ifndef PLATFORM_WINDOWS
4410 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4411 || (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0 ) {
4412 warning << _("Given Video Server is not an executable file.") << endmsg;
4416 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4417 || (sb.st_mode & (S_IXUSR)) == 0 ) {
4418 warning << _("Given Video Server is not an executable file.") << endmsg;
4424 argp=(char**) calloc(9,sizeof(char*));
4425 argp[0] = strdup(icsd_exec.c_str());
4426 argp[1] = strdup("-P");
4427 argp[2] = (char*) calloc(16,sizeof(char)); snprintf(argp[2], 16, "%s", video_server_dialog->get_listenaddr().c_str());
4428 argp[3] = strdup("-p");
4429 argp[4] = (char*) calloc(6,sizeof(char)); snprintf(argp[4], 6, "%i", video_server_dialog->get_listenport());
4430 argp[5] = strdup("-C");
4431 argp[6] = (char*) calloc(6,sizeof(char)); snprintf(argp[6], 6, "%i", video_server_dialog->get_cachesize());
4432 argp[7] = strdup(icsd_docroot.c_str());
4434 stop_video_server();
4436 #ifdef PLATFORM_WINDOWS
4437 if (VideoUtils::harvid_version >= 0x000802 && icsd_docroot.empty()) {
4438 /* OK, allow all drive letters */
4441 if (icsd_docroot == X_("/") || icsd_docroot == X_("C:\\")) {
4442 Config->set_video_advanced_setup(false);
4444 std::ostringstream osstream;
4445 osstream << "http://127.0.0.1:" << video_server_dialog->get_listenport() << "/";
4446 Config->set_video_server_url(osstream.str());
4447 Config->set_video_server_docroot(icsd_docroot);
4448 Config->set_video_advanced_setup(true);
4451 if (video_server_process) {
4452 delete video_server_process;
4455 video_server_process = new ARDOUR::SystemExec(icsd_exec, argp);
4456 if (video_server_process->start()) {
4457 warning << _("Cannot launch the video-server") << endmsg;
4460 int timeout = 120; // 6 sec
4461 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4462 Glib::usleep (50000);
4464 if (--timeout <= 0 || !video_server_process->is_running()) break;
4467 warning << _("Video-server was started but does not respond to requests...") << endmsg;
4469 if (!ARDOUR_UI::instance()->video_timeline->check_server_docroot()) {
4470 delete video_server_process;
4471 video_server_process = 0;
4479 ARDOUR_UI::add_video (Gtk::Window* float_window)
4485 if (!start_video_server(float_window, false)) {
4486 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4491 add_video_dialog->set_transient_for (*float_window);
4494 if (add_video_dialog->is_visible()) {
4495 /* we're already doing this */
4499 ResponseType r = (ResponseType) add_video_dialog->run ();
4500 add_video_dialog->hide();
4501 if (r != RESPONSE_ACCEPT) { return; }
4503 bool local_file, orig_local_file;
4504 std::string path = add_video_dialog->file_name(local_file);
4506 std::string orig_path = path;
4507 orig_local_file = local_file;
4509 bool auto_set_session_fps = add_video_dialog->auto_set_session_fps();
4511 if (local_file && !Glib::file_test(path, Glib::FILE_TEST_EXISTS)) {
4512 warning << string_compose(_("could not open %1"), path) << endmsg;
4515 if (!local_file && path.length() == 0) {
4516 warning << _("no video-file selected") << endmsg;
4520 std::string audio_from_video;
4521 bool detect_ltc = false;
4523 switch (add_video_dialog->import_option()) {
4524 case VTL_IMPORT_TRANSCODE:
4526 TranscodeVideoDialog *transcode_video_dialog;
4527 transcode_video_dialog = new TranscodeVideoDialog (_session, path);
4528 ResponseType r = (ResponseType) transcode_video_dialog->run ();
4529 transcode_video_dialog->hide();
4530 if (r != RESPONSE_ACCEPT) {
4531 delete transcode_video_dialog;
4535 audio_from_video = transcode_video_dialog->get_audiofile();
4537 if (!audio_from_video.empty() && transcode_video_dialog->detect_ltc()) {
4540 else if (!audio_from_video.empty()) {
4541 editor->embed_audio_from_video(
4543 video_timeline->get_offset(),
4544 (transcode_video_dialog->import_option() != VTL_IMPORT_NO_VIDEO)
4547 switch (transcode_video_dialog->import_option()) {
4548 case VTL_IMPORT_TRANSCODED:
4549 path = transcode_video_dialog->get_filename();
4552 case VTL_IMPORT_REFERENCE:
4555 delete transcode_video_dialog;
4558 delete transcode_video_dialog;
4562 case VTL_IMPORT_NONE:
4566 /* strip _session->session_directory().video_path() from video file if possible */
4567 if (local_file && !path.compare(0, _session->session_directory().video_path().size(), _session->session_directory().video_path())) {
4568 path=path.substr(_session->session_directory().video_path().size());
4569 if (path.at(0) == G_DIR_SEPARATOR) {
4570 path=path.substr(1);
4574 video_timeline->set_update_session_fps(auto_set_session_fps);
4576 if (video_timeline->video_file_info(path, local_file)) {
4577 XMLNode* node = new XMLNode(X_("Videotimeline"));
4578 node->add_property (X_("Filename"), path);
4579 node->add_property (X_("AutoFPS"), auto_set_session_fps?X_("1"):X_("0"));
4580 node->add_property (X_("LocalFile"), local_file?X_("1"):X_("0"));
4581 if (orig_local_file) {
4582 node->add_property (X_("OriginalVideoFile"), orig_path);
4584 node->remove_property (X_("OriginalVideoFile"));
4586 _session->add_extra_xml (*node);
4587 _session->set_dirty ();
4589 if (!audio_from_video.empty() && detect_ltc) {
4590 std::vector<LTCFileReader::LTCMap> ltc_seq;
4593 /* TODO ask user about TV standard (LTC alignment if any) */
4594 LTCFileReader ltcr (audio_from_video, video_timeline->get_video_file_fps());
4595 /* TODO ASK user which channel: 0 .. ltcr->channels() - 1 */
4597 ltc_seq = ltcr.read_ltc (/*channel*/ 0, /*max LTC frames to decode*/ 15);
4599 /* TODO seek near end of file, and read LTC until end.
4600 * if it fails to find any LTC frames, scan complete file
4602 * calculate drift of LTC compared to video-duration,
4603 * ask user for reference (timecode from start/mid/end)
4606 // LTCFileReader will have written error messages
4609 ::g_unlink(audio_from_video.c_str());
4611 if (ltc_seq.size() == 0) {
4612 PBD::error << _("No LTC detected, video will not be aligned.") << endmsg;
4614 /* the very first TC in the file is somteimes not aligned properly */
4615 int i = ltc_seq.size() -1;
4616 ARDOUR::frameoffset_t video_start_offset =
4617 _session->nominal_frame_rate() * (ltc_seq[i].timecode_sec - ltc_seq[i].framepos_sec);
4618 PBD::info << string_compose (_("Align video-start to %1 [samples]"), video_start_offset) << endmsg;
4619 video_timeline->set_offset(video_start_offset);
4623 _session->maybe_update_session_range(
4624 std::max(video_timeline->get_offset(), (ARDOUR::frameoffset_t) 0),
4625 std::max(video_timeline->get_offset() + video_timeline->get_duration(), (ARDOUR::frameoffset_t) 0));
4628 if (add_video_dialog->launch_xjadeo() && local_file) {
4629 editor->set_xjadeo_sensitive(true);
4630 editor->toggle_xjadeo_proc(1);
4632 editor->toggle_xjadeo_proc(0);
4634 editor->toggle_ruler_video(true);
4639 ARDOUR_UI::remove_video ()
4641 video_timeline->close_session();
4642 editor->toggle_ruler_video(false);
4645 video_timeline->set_offset_locked(false);
4646 video_timeline->set_offset(0);
4648 /* delete session state */
4649 XMLNode* node = new XMLNode(X_("Videotimeline"));
4650 _session->add_extra_xml(*node);
4651 node = new XMLNode(X_("Videomonitor"));
4652 _session->add_extra_xml(*node);
4653 node = new XMLNode(X_("Videoexport"));
4654 _session->add_extra_xml(*node);
4655 stop_video_server();
4659 ARDOUR_UI::flush_videotimeline_cache (bool localcacheonly)
4661 if (localcacheonly) {
4662 video_timeline->vmon_update();
4664 video_timeline->flush_cache();
4666 editor->queue_visual_videotimeline_update();
4670 ARDOUR_UI::export_video (bool range)
4672 if (ARDOUR::Config->get_show_video_export_info()) {
4673 ExportVideoInfobox infobox (_session);
4674 Gtk::ResponseType rv = (Gtk::ResponseType) infobox.run();
4675 if (infobox.show_again()) {
4676 ARDOUR::Config->set_show_video_export_info(false);
4679 case GTK_RESPONSE_YES:
4680 PBD::open_uri (ARDOUR::Config->get_reference_manual_url() + "/video-timeline/operations/#export");
4686 export_video_dialog->set_session (_session);
4687 export_video_dialog->apply_state(editor->get_selection().time, range);
4688 export_video_dialog->run ();
4689 export_video_dialog->hide ();
4693 ARDOUR_UI::preferences_settings () const
4698 node = _session->instant_xml(X_("Preferences"));
4700 node = Config->instant_xml(X_("Preferences"));
4704 node = new XMLNode (X_("Preferences"));
4711 ARDOUR_UI::mixer_settings () const
4716 node = _session->instant_xml(X_("Mixer"));
4718 node = Config->instant_xml(X_("Mixer"));
4722 node = new XMLNode (X_("Mixer"));
4729 ARDOUR_UI::main_window_settings () const
4734 node = _session->instant_xml(X_("Main"));
4736 node = Config->instant_xml(X_("Main"));
4740 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4741 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4746 node = new XMLNode (X_("Main"));
4753 ARDOUR_UI::editor_settings () const
4758 node = _session->instant_xml(X_("Editor"));
4760 node = Config->instant_xml(X_("Editor"));
4764 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4765 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4770 node = new XMLNode (X_("Editor"));
4777 ARDOUR_UI::keyboard_settings () const
4781 node = Config->extra_xml(X_("Keyboard"));
4784 node = new XMLNode (X_("Keyboard"));
4791 ARDOUR_UI::create_xrun_marker (framepos_t where)
4794 Location *location = new Location (*_session, where, where, _("xrun"), Location::IsMark, 0);
4795 _session->locations()->add (location);
4800 ARDOUR_UI::halt_on_xrun_message ()
4802 cerr << "HALT on xrun\n";
4803 MessageDialog msg (_main_window, _("Recording was stopped because your system could not keep up."));
4808 ARDOUR_UI::xrun_handler (framepos_t where)
4814 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
4816 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
4817 create_xrun_marker(where);
4820 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
4821 halt_on_xrun_message ();
4826 ARDOUR_UI::disk_overrun_handler ()
4828 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
4830 if (!have_disk_speed_dialog_displayed) {
4831 have_disk_speed_dialog_displayed = true;
4832 MessageDialog* msg = new MessageDialog (_main_window, string_compose (_("\
4833 The disk system on your computer\n\
4834 was not able to keep up with %1.\n\
4836 Specifically, it failed to write data to disk\n\
4837 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
4838 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4844 /* TODO: this is getting elaborate enough to warrant being split into a dedicated class */
4845 static MessageDialog *scan_dlg = NULL;
4846 static ProgressBar *scan_pbar = NULL;
4847 static HBox *scan_tbox = NULL;
4848 static Gtk::Button *scan_timeout_button;
4851 ARDOUR_UI::cancel_plugin_scan ()
4853 PluginManager::instance().cancel_plugin_scan();
4857 ARDOUR_UI::cancel_plugin_timeout ()
4859 PluginManager::instance().cancel_plugin_timeout();
4860 scan_timeout_button->set_sensitive (false);
4864 ARDOUR_UI::plugin_scan_timeout (int timeout)
4866 if (!scan_dlg || !scan_dlg->is_mapped() || !scan_pbar) {
4870 scan_pbar->set_sensitive (false);
4871 scan_timeout_button->set_sensitive (true);
4872 scan_pbar->set_fraction ((float) timeout / (float) Config->get_vst_scan_timeout());
4875 scan_pbar->set_sensitive (false);
4876 scan_timeout_button->set_sensitive (false);
4882 ARDOUR_UI::plugin_scan_dialog (std::string type, std::string plugin, bool can_cancel)
4884 if (type == X_("closeme") && !(scan_dlg && scan_dlg->is_mapped())) {
4888 const bool cancelled = PluginManager::instance().cancelled();
4889 if (type != X_("closeme") && (!UIConfiguration::instance().get_show_plugin_scan_window()) && !_initial_verbose_plugin_scan) {
4890 if (cancelled && scan_dlg->is_mapped()) {
4895 if (cancelled || !can_cancel) {
4900 static Gtk::Button *cancel_button;
4902 scan_dlg = new MessageDialog("", false, MESSAGE_INFO, BUTTONS_NONE); // TODO manage
4903 VBox* vbox = scan_dlg->get_vbox();
4904 vbox->set_size_request(400,-1);
4905 scan_dlg->set_title (_("Scanning for plugins"));
4907 cancel_button = manage(new Gtk::Button(_("Cancel plugin scan")));
4908 cancel_button->set_name ("EditorGTKButton");
4909 cancel_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_scan) );
4910 cancel_button->show();
4912 scan_dlg->get_vbox()->pack_start ( *cancel_button, PACK_SHRINK);
4914 scan_tbox = manage( new HBox() );
4916 scan_timeout_button = manage(new Gtk::Button(_("Stop Timeout")));
4917 scan_timeout_button->set_name ("EditorGTKButton");
4918 scan_timeout_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_timeout) );
4919 scan_timeout_button->show();
4921 scan_pbar = manage(new ProgressBar());
4922 scan_pbar->set_orientation(Gtk::PROGRESS_RIGHT_TO_LEFT);
4923 scan_pbar->set_text(_("Scan Timeout"));
4926 scan_tbox->pack_start (*scan_pbar, PACK_EXPAND_WIDGET, 4);
4927 scan_tbox->pack_start (*scan_timeout_button, PACK_SHRINK, 4);
4929 scan_dlg->get_vbox()->pack_start (*scan_tbox, PACK_SHRINK, 4);
4932 assert(scan_dlg && scan_tbox && cancel_button);
4934 if (type == X_("closeme")) {
4938 scan_dlg->set_message(type + ": " + Glib::path_get_basename(plugin));
4941 if (!can_cancel || !cancelled) {
4942 scan_timeout_button->set_sensitive(false);
4944 cancel_button->set_sensitive(can_cancel && !cancelled);
4950 ARDOUR_UI::gui_idle_handler ()
4953 /* due to idle calls, gtk_events_pending() may always return true */
4954 while (gtk_events_pending() && --timeout) {
4955 gtk_main_iteration ();
4960 ARDOUR_UI::disk_underrun_handler ()
4962 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
4964 if (!have_disk_speed_dialog_displayed) {
4965 have_disk_speed_dialog_displayed = true;
4966 MessageDialog* msg = new MessageDialog (
4967 _main_window, string_compose (_("The disk system on your computer\n\
4968 was not able to keep up with %1.\n\
4970 Specifically, it failed to read data from disk\n\
4971 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
4972 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4978 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
4980 have_disk_speed_dialog_displayed = false;
4985 ARDOUR_UI::session_dialog (std::string msg)
4987 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
4991 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
4998 ARDOUR_UI::pending_state_dialog ()
5000 HBox* hbox = manage (new HBox());
5001 Image* image = manage (new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG));
5002 ArdourDialog dialog (_("Crash Recovery"), true);
5003 Label message (string_compose (_("\
5004 This session appears to have been in the\n\
5005 middle of recording when %1 or\n\
5006 the computer was shutdown.\n\
5008 %1 can recover any captured audio for\n\
5009 you, or it can ignore it. Please decide\n\
5010 what you would like to do.\n"), PROGRAM_NAME));
5011 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
5012 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
5013 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
5014 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
5015 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
5016 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
5017 dialog.set_default_response (RESPONSE_ACCEPT);
5018 dialog.set_position (WIN_POS_CENTER);
5023 switch (dialog.run ()) {
5024 case RESPONSE_ACCEPT:
5032 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
5034 HBox* hbox = new HBox();
5035 Image* image = new Image (Stock::DIALOG_WARNING, ICON_SIZE_DIALOG);
5036 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
5037 Label message (string_compose (_("\
5038 This session was created with a sample rate of %1 Hz, but\n\
5039 %2 is currently running at %3 Hz. If you load this session,\n\
5040 audio may be played at the wrong sample rate.\n"), desired, PROGRAM_NAME, actual));
5042 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
5043 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
5044 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
5045 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
5046 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
5047 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
5048 dialog.set_default_response (RESPONSE_ACCEPT);
5049 dialog.set_position (WIN_POS_CENTER);
5054 switch (dialog.run()) {
5055 case RESPONSE_ACCEPT:
5065 ARDOUR_UI::sr_mismatch_message (framecnt_t desired, framecnt_t actual)
5067 MessageDialog msg (string_compose (_("\
5068 This session was created with a sample rate of %1 Hz, but\n\
5069 %2 is currently running at %3 Hz.\n\
5070 Audio will be recorded and played at the wrong sample rate.\n\
5071 Re-Configure the Audio Engine in\n\
5072 Menu > Window > Audio/Midi Setup"),
5073 desired, PROGRAM_NAME, actual),
5075 Gtk::MESSAGE_WARNING);
5080 ARDOUR_UI::use_config ()
5082 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
5084 set_transport_controllable_state (*node);
5089 ARDOUR_UI::update_transport_clocks (framepos_t pos)
5091 if (UIConfiguration::instance().get_primary_clock_delta_edit_cursor()) {
5092 primary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
5094 primary_clock->set (pos);
5097 if (UIConfiguration::instance().get_secondary_clock_delta_edit_cursor()) {
5098 secondary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
5100 secondary_clock->set (pos);
5103 if (big_clock_window) {
5104 big_clock->set (pos);
5106 ARDOUR_UI::instance()->video_timeline->manual_seek_video_monitor(pos);
5110 ARDOUR_UI::step_edit_status_change (bool yn)
5112 // XXX should really store pre-step edit status of things
5113 // we make insensitive
5116 rec_button.set_active_state (Gtkmm2ext::ImplicitActive);
5117 rec_button.set_sensitive (false);
5119 rec_button.unset_active_state ();;
5120 rec_button.set_sensitive (true);
5125 ARDOUR_UI::record_state_changed ()
5127 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
5130 /* why bother - the clock isn't visible */
5134 ActionManager::set_sensitive (ActionManager::rec_sensitive_actions, !_session->actively_recording());
5136 if (big_clock_window) {
5137 if (_session->record_status () == Session::Recording && _session->have_rec_enabled_track ()) {
5138 big_clock->set_active (true);
5140 big_clock->set_active (false);
5147 ARDOUR_UI::first_idle ()
5150 _session->allow_auto_play (true);
5154 editor->first_idle();
5157 Keyboard::set_can_save_keybindings (true);
5162 ARDOUR_UI::store_clock_modes ()
5164 XMLNode* node = new XMLNode(X_("ClockModes"));
5166 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
5167 XMLNode* child = new XMLNode (X_("Clock"));
5169 child->add_property (X_("name"), (*x)->name());
5170 child->add_property (X_("mode"), enum_2_string ((*x)->mode()));
5171 child->add_property (X_("on"), ((*x)->off() ? X_("no") : X_("yes")));
5173 node->add_child_nocopy (*child);
5176 _session->add_extra_xml (*node);
5177 _session->set_dirty ();
5180 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
5181 : Controllable (name), ui (u), type(tp)
5187 ARDOUR_UI::TransportControllable::set_value (double val, PBD::Controllable::GroupControlDisposition /*group_override*/)
5190 /* do nothing: these are radio-style actions */
5194 const char *action = 0;
5198 action = X_("Roll");
5201 action = X_("Stop");
5204 action = X_("GotoStart");
5207 action = X_("GotoEnd");
5210 action = X_("Loop");
5213 action = X_("PlaySelection");
5216 action = X_("Record");
5226 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
5234 ARDOUR_UI::TransportControllable::get_value (void) const
5261 ARDOUR_UI::setup_profile ()
5263 if (gdk_screen_width() < 1200 || getenv ("ARDOUR_NARROW_SCREEN")) {
5264 Profile->set_small_screen ();
5267 if (g_getenv ("TRX")) {
5268 Profile->set_trx ();
5271 if (g_getenv ("MIXBUS")) {
5272 Profile->set_mixbus ();
5277 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
5279 MissingFileDialog dialog (s, str, type);
5284 int result = dialog.run ();
5291 return 1; // quit entire session load
5294 result = dialog.get_action ();
5300 ARDOUR_UI::ambiguous_file (std::string file, std::vector<std::string> hits)
5302 AmbiguousFileDialog dialog (file, hits);
5309 return dialog.get_which ();
5312 /** Allocate our thread-local buffers */
5314 ARDOUR_UI::get_process_buffers ()
5316 _process_thread->get_buffers ();
5319 /** Drop our thread-local buffers */
5321 ARDOUR_UI::drop_process_buffers ()
5323 _process_thread->drop_buffers ();
5327 ARDOUR_UI::feedback_detected ()
5329 _feedback_exists = true;
5333 ARDOUR_UI::successful_graph_sort ()
5335 _feedback_exists = false;
5339 ARDOUR_UI::midi_panic ()
5342 _session->midi_panic();
5347 ARDOUR_UI::session_format_mismatch (std::string xml_path, std::string backup_path)
5349 const char* start_big = "<span size=\"x-large\" weight=\"bold\">";
5350 const char* end_big = "</span>";
5351 const char* start_mono = "<tt>";
5352 const char* end_mono = "</tt>";
5354 MessageDialog msg (string_compose (_("%4This is a session from an older version of %3%5\n\n"
5355 "%3 has copied the old session file\n\n%6%1%7\n\nto\n\n%6%2%7\n\n"
5356 "From now on, use the backup copy with older versions of %3"),
5357 xml_path, backup_path, PROGRAM_NAME,
5359 start_mono, end_mono), true);
5366 ARDOUR_UI::reset_peak_display ()
5368 if (!_session || !_session->master_out() || !editor_meter) return;
5369 editor_meter->clear_meters();
5370 editor_meter_max_peak = -INFINITY;
5371 editor_meter_peak_display.set_active_state ( Gtkmm2ext::Off );
5375 ARDOUR_UI::reset_group_peak_display (RouteGroup* group)
5377 if (!_session || !_session->master_out()) return;
5378 if (group == _session->master_out()->route_group()) {
5379 reset_peak_display ();
5384 ARDOUR_UI::reset_route_peak_display (Route* route)
5386 if (!_session || !_session->master_out()) return;
5387 if (_session->master_out().get() == route) {
5388 reset_peak_display ();
5393 ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate)
5395 audio_midi_setup->set_desired_sample_rate (desired_sample_rate);
5396 audio_midi_setup->set_position (WIN_POS_CENTER);
5398 if (Config->get_try_autostart_engine () || getenv ("TRY_AUTOSTART_ENGINE")) {
5399 audio_midi_setup->try_autostart ();
5400 if (ARDOUR::AudioEngine::instance()->running()) {
5406 int response = audio_midi_setup->run();
5407 printf("RESPONSE %d\n", response);
5409 case Gtk::RESPONSE_DELETE_EVENT:
5412 if (!AudioEngine::instance()->running()) {
5415 audio_midi_setup->hide ();
5423 ARDOUR_UI::transport_numpad_timeout ()
5425 _numpad_locate_happening = false;
5426 if (_numpad_timeout_connection.connected() )
5427 _numpad_timeout_connection.disconnect();
5432 ARDOUR_UI::transport_numpad_decimal ()
5434 _numpad_timeout_connection.disconnect();
5436 if (_numpad_locate_happening) {
5437 if (editor) editor->goto_nth_marker(_pending_locate_num - 1);
5438 _numpad_locate_happening = false;
5440 _pending_locate_num = 0;
5441 _numpad_locate_happening = true;
5442 _numpad_timeout_connection = Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::transport_numpad_timeout), 2*1000);
5447 ARDOUR_UI::transport_numpad_event (int num)
5449 if ( _numpad_locate_happening ) {
5450 _pending_locate_num = _pending_locate_num*10 + num;
5453 case 0: toggle_roll(false, false); break;
5454 case 1: transport_rewind(1); break;
5455 case 2: transport_forward(1); break;
5456 case 3: transport_record(true); break;
5457 case 4: toggle_session_auto_loop(); break;
5458 case 5: transport_record(false); toggle_session_auto_loop(); break;
5459 case 6: toggle_punch(); break;
5460 case 7: toggle_click(); break;
5461 case 8: toggle_auto_return(); break;
5462 case 9: toggle_follow_edits(); break;
5468 ARDOUR_UI::set_flat_buttons ()
5470 CairoWidget::set_flat_buttons( UIConfiguration::instance().get_flat_buttons() );
5474 ARDOUR_UI::audioengine_became_silent ()
5476 MessageDialog msg (string_compose (_("This is a free/demo copy of %1. It has just switched to silent mode."), PROGRAM_NAME),
5478 Gtk::MESSAGE_WARNING,
5482 msg.set_title (string_compose (_("%1 is now silent"), PROGRAM_NAME));
5484 Gtk::Label pay_label (string_compose (_("Please consider paying for a copy of %1 - you can pay whatever you want."), PROGRAM_NAME));
5485 Gtk::Label subscribe_label (_("Better yet become a subscriber - subscriptions start at US$1 per month."));
5486 Gtk::Button pay_button (_("Pay for a copy (via the web)"));
5487 Gtk::Button subscribe_button (_("Become a subscriber (via the web)"));
5488 Gtk::HBox pay_button_box;
5489 Gtk::HBox subscribe_button_box;
5491 pay_button_box.pack_start (pay_button, true, false);
5492 subscribe_button_box.pack_start (subscribe_button, true, false);
5494 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 */
5496 pay_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://ardour.org/download")));
5497 subscribe_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://community.ardour.org/s/subscribe")));
5499 msg.get_vbox()->pack_start (pay_label);
5500 msg.get_vbox()->pack_start (pay_button_box);
5501 msg.get_vbox()->pack_start (subscribe_label);
5502 msg.get_vbox()->pack_start (subscribe_button_box);
5504 msg.get_vbox()->show_all ();
5506 msg.add_button (_("Remain silent"), Gtk::RESPONSE_CANCEL);
5507 msg.add_button (_("Save and quit"), Gtk::RESPONSE_NO);
5508 msg.add_button (_("Give me more time"), Gtk::RESPONSE_YES);
5513 case Gtk::RESPONSE_YES:
5514 AudioEngine::instance()->reset_silence_countdown ();
5517 case Gtk::RESPONSE_NO:
5519 save_state_canfail ("");
5523 case Gtk::RESPONSE_CANCEL:
5525 /* don't reset, save session and exit */
5531 ARDOUR_UI::hide_application ()
5533 Application::instance ()-> hide ();
5537 ARDOUR_UI::setup_toplevel_window (Gtk::Window& window, const string& name, void* owner)
5539 /* icons, titles, WM stuff */
5541 static list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
5543 if (window_icons.empty()) {
5544 Glib::RefPtr<Gdk::Pixbuf> icon;
5545 if ((icon = ::get_icon (PROGRAM_NAME "-icon_16px"))) {
5546 window_icons.push_back (icon);
5548 if ((icon = ::get_icon (PROGRAM_NAME "-icon_22px"))) {
5549 window_icons.push_back (icon);
5551 if ((icon = ::get_icon (PROGRAM_NAME "-icon_32px"))) {
5552 window_icons.push_back (icon);
5554 if ((icon = ::get_icon (PROGRAM_NAME "-icon_48px"))) {
5555 window_icons.push_back (icon);
5559 if (!window_icons.empty()) {
5560 window.set_default_icon_list (window_icons);
5563 Gtkmm2ext::WindowTitle title (Glib::get_application_name());
5565 if (!name.empty()) {
5569 window.set_title (title.get_string());
5570 window.set_wmclass (string_compose (X_("%1_%1"), downcase (std::string(PROGRAM_NAME)), downcase (name)), PROGRAM_NAME);
5572 window.set_flags (CAN_FOCUS);
5573 window.add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
5575 /* This is a hack to ensure that GTK-accelerators continue to
5576 * work. Once we switch over to entirely native bindings, this will be
5577 * unnecessary and should be removed
5579 window.add_accel_group (ActionManager::ui_manager->get_accel_group());
5581 window.signal_configure_event().connect (sigc::mem_fun (*this, &ARDOUR_UI::configure_handler));
5582 window.signal_window_state_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::tabbed_window_state_event_handler), owner));
5583 window.signal_key_press_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5584 window.signal_key_release_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5588 ARDOUR_UI::key_event_handler (GdkEventKey* ev, Gtk::Window* event_window)
5590 Gtkmm2ext::Bindings* bindings = 0;
5591 Gtk::Window* window = 0;
5593 /* until we get ardour bindings working, we are not handling key
5597 if (ev->type != GDK_KEY_PRESS) {
5601 if (event_window == &_main_window) {
5603 window = event_window;
5605 /* find current tab contents */
5607 Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page());
5609 /* see if it uses the ardour binding system */
5612 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(w->get_data ("ardour-bindings"));
5615 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("main window key event, bindings = %1, global = %2\n", bindings, &global_bindings));
5619 window = event_window;
5621 /* see if window uses ardour binding system */
5623 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(window->get_data ("ardour-bindings"));
5626 /* An empty binding set is treated as if it doesn't exist */
5628 if (bindings && bindings->empty()) {
5632 return key_press_focus_accelerator_handler (*window, ev, bindings);
5635 static Gtkmm2ext::Bindings*
5636 get_bindings_from_widget_heirarchy (GtkWidget** w)
5641 if ((p = g_object_get_data (G_OBJECT(*w), "ardour-bindings")) != 0) {
5644 *w = gtk_widget_get_parent (*w);
5647 return reinterpret_cast<Gtkmm2ext::Bindings*> (p);
5651 ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev, Gtkmm2ext::Bindings* bindings)
5653 GtkWindow* win = window.gobj();
5654 GtkWidget* focus = gtk_window_get_focus (win);
5655 GtkWidget* binding_widget = focus;
5656 bool special_handling_of_unmodified_accelerators = false;
5657 const guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK));
5661 /* some widget has keyboard focus */
5663 if (GTK_IS_ENTRY(focus) || Keyboard::some_magic_widget_has_focus()) {
5665 /* A particular kind of focusable widget currently has keyboard
5666 * focus. All unmodified key events should go to that widget
5667 * first and not be used as an accelerator by default
5670 special_handling_of_unmodified_accelerators = true;
5674 Gtkmm2ext::Bindings* focus_bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5675 if (focus_bindings) {
5676 bindings = focus_bindings;
5677 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Switch bindings based on focus widget, now using %1\n", bindings->name()));
5682 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",
5685 Gtkmm2ext::show_gdk_event_state (ev->state),
5686 special_handling_of_unmodified_accelerators,
5687 Keyboard::some_magic_widget_has_focus(),
5689 (focus ? gtk_widget_get_name (focus) : "no focus widget"),
5690 ((ev->state & mask) ? "yes" : "no"),
5691 window.get_title()));
5693 /* This exists to allow us to override the way GTK handles
5694 key events. The normal sequence is:
5696 a) event is delivered to a GtkWindow
5697 b) accelerators/mnemonics are activated
5698 c) if (b) didn't handle the event, propagate to
5699 the focus widget and/or focus chain
5701 The problem with this is that if the accelerators include
5702 keys without modifiers, such as the space bar or the
5703 letter "e", then pressing the key while typing into
5704 a text entry widget results in the accelerator being
5705 activated, instead of the desired letter appearing
5708 There is no good way of fixing this, but this
5709 represents a compromise. The idea is that
5710 key events involving modifiers (not Shift)
5711 get routed into the activation pathway first, then
5712 get propagated to the focus widget if necessary.
5714 If the key event doesn't involve modifiers,
5715 we deliver to the focus widget first, thus allowing
5716 it to get "normal text" without interference
5719 Of course, this can also be problematic: if there
5720 is a widget with focus, then it will swallow
5721 all "normal text" accelerators.
5725 if (!special_handling_of_unmodified_accelerators || (ev->state & mask)) {
5727 /* no special handling or there are modifiers in effect: accelerate first */
5729 DEBUG_TRACE (DEBUG::Accelerators, "\tactivate, then propagate\n");
5730 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tevent send-event:%1 time:%2 length:%3 name %7 string:%4 hardware_keycode:%5 group:%6\n",
5731 ev->send_event, ev->time, ev->length, ev->string, ev->hardware_keycode, ev->group, gdk_keyval_name (ev->keyval)));
5733 DEBUG_TRACE (DEBUG::Accelerators, "\tsending to window\n");
5734 KeyboardKey k (ev->state, ev->keyval);
5738 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tusing Ardour bindings %1 @ %2 for this event\n", bindings->name(), bindings));
5740 if (bindings->activate (k, Bindings::Press)) {
5741 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5745 if (binding_widget) {
5746 binding_widget = gtk_widget_get_parent (binding_widget);
5747 if (binding_widget) {
5748 bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5757 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5759 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5760 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5764 DEBUG_TRACE (DEBUG::Accelerators, "\tnot accelerated, now propagate\n");
5766 if (gtk_window_propagate_key_event (win, ev)) {
5767 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate handled\n");
5773 /* no modifiers, propagate first */
5775 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate, then activate\n");
5777 if (gtk_window_propagate_key_event (win, ev)) {
5778 DEBUG_TRACE (DEBUG::Accelerators, "\thandled by propagate\n");
5782 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagation didn't handle, so activate\n");
5783 KeyboardKey k (ev->state, ev->keyval);
5787 DEBUG_TRACE (DEBUG::Accelerators, "\tusing Ardour bindings for this window\n");
5790 if (bindings->activate (k, Bindings::Press)) {
5791 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5795 if (binding_widget) {
5796 binding_widget = gtk_widget_get_parent (binding_widget);
5797 if (binding_widget) {
5798 bindings = get_bindings_from_widget_heirarchy (&binding_widget);
5807 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5809 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5810 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5815 DEBUG_TRACE (DEBUG::Accelerators, "\tnot handled\n");
5820 ARDOUR_UI::load_bindings ()
5822 if ((global_bindings = Bindings::get_bindings (X_("Global"), global_actions)) == 0) {
5823 error << _("Global keybindings are missing") << endmsg;
5828 ARDOUR_UI::cancel_solo ()
5831 _session->cancel_all_solo ();
5836 ARDOUR_UI::reset_focus (Gtk::Widget* w)
5838 /* this resets focus to the first focusable parent of the given widget,
5839 * or, if there is no focusable parent, cancels focus in the toplevel
5840 * window that the given widget is packed into (if there is one).
5847 Gtk::Widget* top = w->get_toplevel();
5849 if (!top || !top->is_toplevel()) {
5853 w = w->get_parent ();
5857 if (w->is_toplevel()) {
5858 /* Setting the focus widget to a Gtk::Window causes all
5859 * subsequent calls to ::has_focus() on the nominal
5860 * focus widget in that window to return
5861 * false. Workaround: never set focus to the toplevel
5867 if (w->get_can_focus ()) {
5868 Gtk::Window* win = dynamic_cast<Gtk::Window*> (top);
5869 win->set_focus (*w);
5872 w = w->get_parent ();
5875 if (top == &_main_window) {
5879 /* no focusable parent found, cancel focus in top level window.
5880 C++ API cannot be used for this. Thanks, references.
5883 gtk_window_set_focus (GTK_WINDOW(top->gobj()), 0);