2 Copyright (C) 1999-2007 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"
37 #include <sys/resource.h>
39 #include <gtkmm/messagedialog.h>
40 #include <gtkmm/accelmap.h>
42 #include "pbd/error.h"
43 #include "pbd/basename.h"
44 #include "pbd/compose.h"
45 #include "pbd/failed_constructor.h"
46 #include "pbd/enumwriter.h"
47 #include "pbd/memento_command.h"
48 #include "pbd/openuri.h"
49 #include "pbd/file_utils.h"
51 #include "gtkmm2ext/application.h"
52 #include "gtkmm2ext/bindings.h"
53 #include "gtkmm2ext/gtk_ui.h"
54 #include "gtkmm2ext/utils.h"
55 #include "gtkmm2ext/click_box.h"
56 #include "gtkmm2ext/fastmeter.h"
57 #include "gtkmm2ext/popup.h"
58 #include "gtkmm2ext/window_title.h"
60 #include "midi++/manager.h"
62 #include "ardour/ardour.h"
63 #include "ardour/callback.h"
64 #include "ardour/profile.h"
65 #include "ardour/plugin_manager.h"
66 #include "ardour/session_directory.h"
67 #include "ardour/session_route.h"
68 #include "ardour/session_state_utils.h"
69 #include "ardour/session_utils.h"
70 #include "ardour/port.h"
71 #include "ardour/audioengine.h"
72 #include "ardour/playlist.h"
73 #include "ardour/utils.h"
74 #include "ardour/audio_diskstream.h"
75 #include "ardour/audiofilesource.h"
76 #include "ardour/recent_sessions.h"
77 #include "ardour/port.h"
78 #include "ardour/audio_track.h"
79 #include "ardour/midi_track.h"
80 #include "ardour/filesystem_paths.h"
81 #include "ardour/filename_extensions.h"
82 #include "ardour/process_thread.h"
84 typedef uint64_t microseconds_t;
88 #include "add_route_dialog.h"
89 #include "ambiguous_file_dialog.h"
90 #include "ardour_ui.h"
91 #include "audio_clock.h"
92 #include "bundle_manager.h"
93 #include "engine_dialog.h"
94 #include "gain_meter.h"
95 #include "global_port_matrix.h"
96 #include "gui_object.h"
97 #include "gui_thread.h"
99 #include "location_ui.h"
100 #include "missing_file_dialog.h"
101 #include "missing_plugin_dialog.h"
102 #include "mixer_ui.h"
104 #include "processor_box.h"
105 #include "prompter.h"
106 #include "public_editor.h"
107 #include "route_time_axis.h"
108 #include "session_metadata_dialog.h"
109 #include "shuttle_control.h"
110 #include "speaker_dialog.h"
113 #include "theme_manager.h"
114 #include "time_axis_view_item.h"
116 #include "window_proxy.h"
120 using namespace ARDOUR;
122 using namespace Gtkmm2ext;
125 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
126 UIConfiguration *ARDOUR_UI::ui_config = 0;
128 sigc::signal<void,bool> ARDOUR_UI::Blink;
129 sigc::signal<void> ARDOUR_UI::RapidScreenUpdate;
130 sigc::signal<void> ARDOUR_UI::SuperRapidScreenUpdate;
131 sigc::signal<void, framepos_t, bool, framepos_t> ARDOUR_UI::Clock;
133 bool could_be_a_valid_path (const string& path);
135 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[])
137 : Gtkmm2ext::UI (PROGRAM_NAME, argcp, argvp)
139 , gui_object_state (new GUIObjectState)
140 , primary_clock (new AudioClock (X_("primary"), false, X_("transport"), true, true, false, true))
141 , secondary_clock (new AudioClock (X_("secondary"), false, X_("secondary"), true, true, false, true))
145 , big_clock (new AudioClock (X_("bigclock"), false, "big", true, true, false, false))
149 , roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll))
150 , stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop))
151 , goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart))
152 , goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd))
153 , auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop))
154 , play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection))
155 , rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable))
157 , auto_return_button (ArdourButton::led_default_elements)
158 , auto_play_button (ArdourButton::led_default_elements)
159 , auto_input_button (ArdourButton::led_default_elements)
161 , auditioning_alert_button (_("audition"))
162 , solo_alert_button (_("solo"))
163 , feedback_alert_button (_("feedback"))
165 , error_log_button (_("Errors"))
167 , _status_bar_visibility (X_("status-bar"))
168 , _feedback_exists (false)
171 using namespace Gtk::Menu_Helpers;
177 // _auto_display_errors = false;
179 * This was commented out as it wasn't defined
180 * in A3 IIRC. If this is not needed it should
181 * be completely removed.
189 if (theArdourUI == 0) {
193 ui_config = new UIConfiguration();
194 theme_manager = new ThemeManager();
202 _session_is_new = false;
203 big_clock_window = 0;
204 big_clock_height = 0;
205 big_clock_resize_in_progress = false;
206 session_selector_window = 0;
207 last_key_press_time = 0;
208 _will_create_new_session_automatically = false;
209 add_route_dialog = 0;
212 rc_option_editor = 0;
213 session_option_editor = 0;
215 open_session_selector = 0;
216 have_configure_timeout = false;
217 have_disk_speed_dialog_displayed = false;
218 session_loaded = false;
219 ignore_dual_punch = false;
220 original_big_clock_width = -1;
221 original_big_clock_height = -1;
222 original_big_clock_font_size = 0;
224 roll_button.set_controllable (roll_controllable);
225 stop_button.set_controllable (stop_controllable);
226 goto_start_button.set_controllable (goto_start_controllable);
227 goto_end_button.set_controllable (goto_end_controllable);
228 auto_loop_button.set_controllable (auto_loop_controllable);
229 play_selection_button.set_controllable (play_selection_controllable);
230 rec_button.set_controllable (rec_controllable);
232 roll_button.set_name ("transport button");
233 stop_button.set_name ("transport button");
234 goto_start_button.set_name ("transport button");
235 goto_end_button.set_name ("transport button");
236 auto_loop_button.set_name ("transport button");
237 play_selection_button.set_name ("transport button");
238 rec_button.set_name ("transport recenable button");
239 join_play_range_button.set_name ("transport button");
240 midi_panic_button.set_name ("transport button");
242 goto_start_button.set_tweaks (ArdourButton::ShowClick);
243 goto_end_button.set_tweaks (ArdourButton::ShowClick);
244 midi_panic_button.set_tweaks (ArdourButton::ShowClick);
246 last_configure_time= 0;
249 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
250 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
252 /* handle dialog requests */
254 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
256 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
258 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
260 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
262 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
264 /* handle requests to quit (coming from JACK session) */
266 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::finish, this), gui_context ());
268 /* tell the user about feedback */
270 ARDOUR::Session::FeedbackDetected.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::feedback_detected, this), gui_context ());
271 ARDOUR::Session::SuccessfulGraphSort.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::successful_graph_sort, this), gui_context ());
273 /* handle requests to deal with missing files */
275 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
277 /* and ambiguous files */
279 ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2, _3));
281 /* lets get this party started */
284 if (ARDOUR::init (ARDOUR_COMMAND_LINE::use_vst, ARDOUR_COMMAND_LINE::try_hw_optimization)) {
285 throw failed_constructor ();
288 setup_gtk_ardour_enums ();
291 GainMeter::setup_slider_pix ();
292 RouteTimeAxisView::setup_slider_pix ();
293 SendProcessorEntry::setup_slider_pix ();
294 SessionEvent::create_per_thread_pool ("GUI", 512);
296 } catch (failed_constructor& err) {
297 error << string_compose (_("could not initialize %1."), PROGRAM_NAME) << endmsg;
302 /* we like keyboards */
304 keyboard = new ArdourKeyboard(*this);
306 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
308 keyboard->set_state (*node, Stateful::loading_state_version);
311 /* we don't like certain modifiers */
312 Bindings::set_ignored_state (GDK_LOCK_MASK|GDK_MOD2_MASK|GDK_MOD3_MASK);
316 TimeAxisViewItem::set_constant_heights ();
318 /* The following must happen after ARDOUR::init() so that Config is set up */
320 location_ui = new ActionWindowProxy<LocationUIWindow> (X_("locations"), Config->extra_xml (X_("UI")), X_("ToggleLocations"));
321 big_clock_window = new ActionWindowProxy<Gtk::Window> (X_("bigclock"), Config->extra_xml (X_("UI")), X_("ToggleBigClock"));
322 speaker_config_window = new ActionWindowProxy<SpeakerDialog> (X_("speakerconf"), Config->extra_xml (X_("UI")), X_("toggle-speaker-config"));
324 for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) {
325 _global_port_matrix[*i] = new ActionWindowProxy<GlobalPortMatrixWindow> (
326 string_compose ("GlobalPortMatrix-%1", (*i).to_string()),
327 Config->extra_xml (X_("UI")),
328 string_compose ("toggle-%1-connection-manager", (*i).to_string())
334 SpeakerDialog* s = new SpeakerDialog ();
335 s->signal_unmap().connect (sigc::bind (sigc::ptr_fun (&ActionManager::uncheck_toggleaction), X_("<Actions>/Common/toggle-speaker-config")));
336 speaker_config_window->set (s);
338 starting.connect (sigc::mem_fun(*this, &ARDOUR_UI::startup));
339 stopping.connect (sigc::mem_fun(*this, &ARDOUR_UI::shutdown));
341 _process_thread = new ProcessThread ();
342 _process_thread->init ();
344 DPIReset.connect (sigc::mem_fun (*this, &ARDOUR_UI::resize_text_widgets));
347 /** @return true if a session was chosen and `apply' clicked, otherwise false if `cancel' was clicked */
349 ARDOUR_UI::run_startup (bool should_be_new, string load_template)
352 _startup = new ArdourStartup ();
354 XMLNode* audio_setup = Config->extra_xml ("AudioSetup");
356 if (audio_setup && _startup->engine_control()) {
357 _startup->engine_control()->set_state (*audio_setup);
360 _startup->set_new_only (should_be_new);
361 if (!load_template.empty()) {
362 _startup->set_load_template( load_template );
364 _startup->present ();
370 switch (_startup->response()) {
379 ARDOUR_UI::create_engine ()
381 // this gets called every time by new_session()
387 loading_message (_("Starting audio engine"));
390 engine = new ARDOUR::AudioEngine (ARDOUR_COMMAND_LINE::jack_client_name, ARDOUR_COMMAND_LINE::jack_session_uuid);
397 engine->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
398 engine->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
399 engine->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
401 engine->Halted.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
403 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
411 ARDOUR_UI::post_engine ()
413 /* Things to be done once we create the AudioEngine
416 ARDOUR::init_post_engine ();
418 /* load up the UI manager */
420 ActionManager::init ();
424 if (setup_windows ()) {
425 throw failed_constructor ();
428 /* Do this after setup_windows (), as that's when the _status_bar_visibility is created */
429 XMLNode* n = Config->extra_xml (X_("UI"));
431 _status_bar_visibility.set_state (*n);
434 check_memory_locking();
436 /* this is the first point at which all the keybindings are available */
438 if (ARDOUR_COMMAND_LINE::show_key_actions) {
439 vector<string> names;
440 vector<string> paths;
441 vector<string> tooltips;
443 vector<AccelKey> bindings;
445 ActionManager::get_all_actions (names, paths, tooltips, keys, bindings);
447 vector<string>::iterator n;
448 vector<string>::iterator k;
449 for (n = names.begin(), k = keys.begin(); n != names.end(); ++n, ++k) {
450 cerr << "Action: " << (*n) << " bound to " << (*k) << endl;
456 blink_timeout_tag = -1;
458 /* this being a GUI and all, we want peakfiles */
460 AudioFileSource::set_build_peakfiles (true);
461 AudioFileSource::set_build_missing_peakfiles (true);
463 /* set default clock modes */
465 if (Profile->get_sae()) {
466 primary_clock->set_mode (AudioClock::BBT);
467 secondary_clock->set_mode (AudioClock::MinSec);
469 primary_clock->set_mode (AudioClock::Timecode);
470 secondary_clock->set_mode (AudioClock::BBT);
473 /* start the time-of-day-clock */
476 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
477 update_wall_clock ();
478 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 60000);
481 update_disk_space ();
483 update_sample_rate (engine->frame_rate());
485 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
486 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
487 Config->map_parameters (pc);
489 /* now start and maybe save state */
491 if (do_engine_start () == 0) {
492 if (_session && _session_is_new) {
493 /* we need to retain initial visual
494 settings for a new session
496 _session->save_state ("");
501 ARDOUR_UI::~ARDOUR_UI ()
506 delete add_route_dialog;
510 ARDOUR_UI::pop_back_splash ()
512 if (Splash::instance()) {
513 // Splash::instance()->pop_back();
514 Splash::instance()->hide ();
519 ARDOUR_UI::configure_timeout ()
521 if (last_configure_time == 0) {
522 /* no configure events yet */
526 /* force a gap of 0.5 seconds since the last configure event
529 if (get_microseconds() - last_configure_time < 500000) {
532 have_configure_timeout = false;
533 cerr << "config event-driven save\n";
534 save_ardour_state ();
540 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
542 if (have_configure_timeout) {
543 last_configure_time = get_microseconds();
545 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
546 have_configure_timeout = true;
553 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
555 const XMLProperty* prop;
557 if ((prop = node.property ("roll")) != 0) {
558 roll_controllable->set_id (prop->value());
560 if ((prop = node.property ("stop")) != 0) {
561 stop_controllable->set_id (prop->value());
563 if ((prop = node.property ("goto-start")) != 0) {
564 goto_start_controllable->set_id (prop->value());
566 if ((prop = node.property ("goto-end")) != 0) {
567 goto_end_controllable->set_id (prop->value());
569 if ((prop = node.property ("auto-loop")) != 0) {
570 auto_loop_controllable->set_id (prop->value());
572 if ((prop = node.property ("play-selection")) != 0) {
573 play_selection_controllable->set_id (prop->value());
575 if ((prop = node.property ("rec")) != 0) {
576 rec_controllable->set_id (prop->value());
578 if ((prop = node.property ("shuttle")) != 0) {
579 shuttle_box->controllable()->set_id (prop->value());
585 ARDOUR_UI::get_transport_controllable_state ()
587 XMLNode* node = new XMLNode(X_("TransportControllables"));
590 roll_controllable->id().print (buf, sizeof (buf));
591 node->add_property (X_("roll"), buf);
592 stop_controllable->id().print (buf, sizeof (buf));
593 node->add_property (X_("stop"), buf);
594 goto_start_controllable->id().print (buf, sizeof (buf));
595 node->add_property (X_("goto_start"), buf);
596 goto_end_controllable->id().print (buf, sizeof (buf));
597 node->add_property (X_("goto_end"), buf);
598 auto_loop_controllable->id().print (buf, sizeof (buf));
599 node->add_property (X_("auto_loop"), buf);
600 play_selection_controllable->id().print (buf, sizeof (buf));
601 node->add_property (X_("play_selection"), buf);
602 rec_controllable->id().print (buf, sizeof (buf));
603 node->add_property (X_("rec"), buf);
604 shuttle_box->controllable()->id().print (buf, sizeof (buf));
605 node->add_property (X_("shuttle"), buf);
612 ARDOUR_UI::autosave_session ()
614 if (g_main_depth() > 1) {
615 /* inside a recursive main loop,
616 give up because we may not be able to
622 if (!Config->get_periodic_safety_backups()) {
627 _session->maybe_write_autosave();
634 ARDOUR_UI::update_autosave ()
636 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_autosave)
638 if (_session && _session->dirty()) {
639 if (_autosave_connection.connected()) {
640 _autosave_connection.disconnect();
643 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
644 Config->get_periodic_safety_backup_interval() * 1000);
647 if (_autosave_connection.connected()) {
648 _autosave_connection.disconnect();
654 ARDOUR_UI::backend_audio_error (bool we_set_params, Gtk::Window* toplevel)
658 title = string_compose (_("%1 could not start JACK"), PROGRAM_NAME);
660 title = string_compose (_("%1 could not connect to JACK."), PROGRAM_NAME);
663 MessageDialog win (title,
669 win.set_secondary_text(_("There are several possible reasons:\n\
671 1) You requested audio parameters that are not supported..\n\
672 2) JACK is running as another user.\n\
674 Please consider the possibilities, and perhaps try different parameters."));
676 win.set_secondary_text(_("There are several possible reasons:\n\
678 1) JACK is not running.\n\
679 2) JACK is running as another user, perhaps root.\n\
680 3) There is already another client called \"ardour\".\n\
682 Please consider the possibilities, and perhaps (re)start JACK."));
686 win.set_transient_for (*toplevel);
690 win.add_button (Stock::OK, RESPONSE_CLOSE);
692 win.add_button (Stock::QUIT, RESPONSE_CLOSE);
695 win.set_default_response (RESPONSE_CLOSE);
698 win.set_position (Gtk::WIN_POS_CENTER);
701 /* we just don't care about the result, but we want to block */
707 ARDOUR_UI::startup ()
709 Application* app = Application::instance ();
711 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
712 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::idle_load));
715 call_the_mothership (VERSIONSTRING);
720 if (get_session_parameters (true, ARDOUR_COMMAND_LINE::new_session, ARDOUR_COMMAND_LINE::load_template)) {
726 goto_editor_window ();
728 /* Add the window proxies here; their addition may cause windows to be opened, and we want them
729 to be opened on top of the editor window that goto_editor_window() just opened.
731 add_window_proxy (location_ui);
732 add_window_proxy (big_clock_window);
733 for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) {
734 add_window_proxy (_global_port_matrix[*i]);
737 /* We have to do this here since goto_editor_window() ends up calling show_all() on the
738 * editor window, and we may want stuff to be hidden.
740 _status_bar_visibility.update ();
742 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
746 ARDOUR_UI::no_memory_warning ()
748 XMLNode node (X_("no-memory-warning"));
749 Config->add_instant_xml (node);
753 ARDOUR_UI::check_memory_locking ()
756 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
760 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
762 if (engine->is_realtime() && memory_warning_node == 0) {
764 struct rlimit limits;
766 long pages, page_size;
768 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0) {
771 ram = (int64_t) pages * (int64_t) page_size;
774 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
778 if (limits.rlim_cur != RLIM_INFINITY) {
780 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
784 _("WARNING: Your system has a limit for maximum amount of locked memory. "
785 "This might cause %1 to run out of memory before your system "
786 "runs out of memory. \n\n"
787 "You can view the memory limit with 'ulimit -l', "
788 "and it is normally controlled by /etc/security/limits.conf"),
789 PROGRAM_NAME).c_str());
791 VBox* vbox = msg.get_vbox();
793 CheckButton cb (_("Do not show this window again"));
795 cb.signal_toggled().connect (sigc::mem_fun (*this, &ARDOUR_UI::no_memory_warning));
797 hbox.pack_start (cb, true, false);
798 vbox->pack_start (hbox);
805 editor->ensure_float (msg);
815 ARDOUR_UI::queue_finish ()
817 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
821 ARDOUR_UI::idle_finish ()
824 return false; /* do not call again */
833 if (_session->transport_rolling() && (++tries < 8)) {
834 _session->request_stop (false, true);
838 if (_session->dirty()) {
839 vector<string> actions;
840 actions.push_back (_("Don't quit"));
841 actions.push_back (_("Just quit"));
842 actions.push_back (_("Save and quit"));
843 switch (ask_about_saving_session(actions)) {
848 /* use the default name */
849 if (save_state_canfail ("")) {
850 /* failed - don't quit */
851 MessageDialog msg (*editor,
853 Ardour was unable to save your session.\n\n\
854 If you still wish to quit, please use the\n\n\
855 \"Just quit\" option."));
866 second_connection.disconnect ();
867 point_one_second_connection.disconnect ();
868 point_oh_five_second_connection.disconnect ();
869 point_zero_one_second_connection.disconnect();
872 /* Save state before deleting the session, as that causes some
873 windows to be destroyed before their visible state can be
876 save_ardour_state ();
879 // _session->set_deletion_in_progress ();
880 _session->set_clean ();
881 _session->remove_pending_capture_state ();
886 ArdourDialog::close_all_dialogs ();
892 ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
894 ArdourDialog window (_("Unsaved Session"));
895 Gtk::HBox dhbox; // the hbox for the image and text
896 Gtk::Label prompt_label;
897 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
901 assert (actions.size() >= 3);
903 window.add_button (actions[0], RESPONSE_REJECT);
904 window.add_button (actions[1], RESPONSE_APPLY);
905 window.add_button (actions[2], RESPONSE_ACCEPT);
907 window.set_default_response (RESPONSE_ACCEPT);
909 Gtk::Button noquit_button (msg);
910 noquit_button.set_name ("EditorGTKButton");
914 if (_session->snap_name() == _session->name()) {
915 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?"),
916 _session->snap_name());
918 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?"),
919 _session->snap_name());
922 prompt_label.set_text (prompt);
923 prompt_label.set_name (X_("PrompterLabel"));
924 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
926 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
927 dhbox.set_homogeneous (false);
928 dhbox.pack_start (*dimage, false, false, 5);
929 dhbox.pack_start (prompt_label, true, false, 5);
930 window.get_vbox()->pack_start (dhbox);
932 window.set_name (_("Prompter"));
933 window.set_position (Gtk::WIN_POS_MOUSE);
934 window.set_modal (true);
935 window.set_resizable (false);
941 window.set_keep_above (true);
944 ResponseType r = (ResponseType) window.run();
949 case RESPONSE_ACCEPT: // save and get out of here
951 case RESPONSE_APPLY: // get out of here
961 ARDOUR_UI::every_second ()
964 update_buffer_load ();
965 update_disk_space ();
970 ARDOUR_UI::every_point_one_seconds ()
972 shuttle_box->update_speed_display ();
973 RapidScreenUpdate(); /* EMIT_SIGNAL */
978 ARDOUR_UI::every_point_zero_one_seconds ()
980 // august 2007: actual update frequency: 40Hz, not 100Hz
982 SuperRapidScreenUpdate(); /* EMIT_SIGNAL */
987 ARDOUR_UI::update_sample_rate (framecnt_t)
991 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
993 if (!engine->connected()) {
995 snprintf (buf, sizeof (buf), _("disconnected"));
999 framecnt_t rate = engine->frame_rate();
1001 if (fmod (rate, 1000.0) != 0.0) {
1002 snprintf (buf, sizeof (buf), _("JACK: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
1003 (float) rate/1000.0f,
1004 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
1006 snprintf (buf, sizeof (buf), _("JACK: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
1008 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
1012 sample_rate_label.set_markup (buf);
1016 ARDOUR_UI::update_format ()
1019 format_label.set_text ("");
1024 s << _("File:") << X_(" <span foreground=\"green\">");
1026 switch (_session->config.get_native_file_header_format ()) {
1052 switch (_session->config.get_native_file_data_format ()) {
1066 format_label.set_markup (s.str ());
1070 ARDOUR_UI::update_cpu_load ()
1074 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1075 should also be changed.
1078 float const c = engine->get_cpu_load ();
1079 snprintf (buf, sizeof (buf), _("DSP: <span foreground=\"%s\">%5.1f%%</span>"), c >= 90 ? X_("red") : X_("green"), c);
1080 cpu_load_label.set_markup (buf);
1084 ARDOUR_UI::update_buffer_load ()
1088 uint32_t const playback = _session ? _session->playback_load () : 100;
1089 uint32_t const capture = _session ? _session->capture_load () : 100;
1091 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1092 should also be changed.
1098 _("Buffers: <span foreground=\"green\">p:</span><span foreground=\"%s\">%" PRIu32 "%%</span> "
1099 "<span foreground=\"green\">c:</span><span foreground=\"%s\">%" PRIu32 "%%</span>"),
1100 playback <= 5 ? X_("red") : X_("green"),
1102 capture <= 5 ? X_("red") : X_("green"),
1106 buffer_load_label.set_markup (buf);
1108 buffer_load_label.set_text ("");
1113 ARDOUR_UI::count_recenabled_streams (Route& route)
1115 Track* track = dynamic_cast<Track*>(&route);
1116 if (track && track->record_enabled()) {
1117 rec_enabled_streams += track->n_inputs().n_total();
1122 ARDOUR_UI::update_disk_space()
1124 if (_session == 0) {
1128 framecnt_t frames = _session->available_capture_duration();
1130 framecnt_t fr = _session->frame_rate();
1132 if (frames == max_framecnt) {
1133 snprintf (buf, sizeof (buf), _("Disk: <span foreground=\"green\">24hrs+</span>"));
1135 rec_enabled_streams = 0;
1136 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams);
1138 if (rec_enabled_streams) {
1139 frames /= rec_enabled_streams;
1146 hrs = frames / (fr * 3600);
1149 snprintf (buf, sizeof (buf), _("Disk: <span foreground=\"green\">>24 hrs</span>"));
1151 frames -= hrs * fr * 3600;
1152 mins = frames / (fr * 60);
1153 frames -= mins * fr * 60;
1156 bool const low = (hrs == 0 && mins <= 30);
1160 _("Disk: <span foreground=\"%s\">%02dh:%02dm:%02ds</span>"),
1161 low ? X_("red") : X_("green"),
1167 disk_space_label.set_markup (buf);
1169 // An attempt to make the disk space label flash red when space has run out.
1171 if (frames < fr * 60 * 5) {
1172 /* disk_space_box.style ("disk_space_label_empty"); */
1174 /* disk_space_box.style ("disk_space_label"); */
1180 ARDOUR_UI::update_wall_clock ()
1187 tm_now = localtime (&now);
1189 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1190 wall_clock_label.set_text (buf);
1196 ARDOUR_UI::session_menu (GdkEventButton */*ev*/)
1198 session_popup_menu->popup (0, 0);
1203 ARDOUR_UI::redisplay_recent_sessions ()
1205 std::vector<sys::path> session_directories;
1206 RecentSessionsSorter cmp;
1208 recent_session_display.set_model (Glib::RefPtr<TreeModel>(0));
1209 recent_session_model->clear ();
1211 ARDOUR::RecentSessions rs;
1212 ARDOUR::read_recent_sessions (rs);
1215 recent_session_display.set_model (recent_session_model);
1219 // sort them alphabetically
1220 sort (rs.begin(), rs.end(), cmp);
1222 for (ARDOUR::RecentSessions::iterator i = rs.begin(); i != rs.end(); ++i) {
1223 session_directories.push_back ((*i).second);
1226 for (vector<sys::path>::const_iterator i = session_directories.begin();
1227 i != session_directories.end(); ++i)
1229 std::vector<sys::path> state_file_paths;
1231 // now get available states for this session
1233 get_state_files_in_directory (*i, state_file_paths);
1235 vector<string*>* states;
1236 vector<const gchar*> item;
1237 string fullpath = (*i).to_string();
1239 /* remove any trailing / */
1241 if (fullpath[fullpath.length()-1] == '/') {
1242 fullpath = fullpath.substr (0, fullpath.length()-1);
1245 /* check whether session still exists */
1246 if (!Glib::file_test(fullpath.c_str(), Glib::FILE_TEST_EXISTS)) {
1247 /* session doesn't exist */
1248 cerr << "skipping non-existent session " << fullpath << endl;
1252 /* now get available states for this session */
1254 if ((states = Session::possible_states (fullpath)) == 0) {
1255 /* no state file? */
1259 std::vector<string> state_file_names(get_file_names_no_extension (state_file_paths));
1261 Gtk::TreeModel::Row row = *(recent_session_model->append());
1263 row[recent_session_columns.visible_name] = Glib::path_get_basename (fullpath);
1264 row[recent_session_columns.fullpath] = fullpath;
1266 if (state_file_names.size() > 1) {
1270 for (std::vector<std::string>::iterator i2 = state_file_names.begin();
1271 i2 != state_file_names.end(); ++i2)
1274 Gtk::TreeModel::Row child_row = *(recent_session_model->append (row.children()));
1276 child_row[recent_session_columns.visible_name] = *i2;
1277 child_row[recent_session_columns.fullpath] = fullpath;
1282 recent_session_display.set_model (recent_session_model);
1286 ARDOUR_UI::build_session_selector ()
1288 session_selector_window = new ArdourDialog (_("Recent Sessions"));
1290 Gtk::ScrolledWindow *scroller = manage (new Gtk::ScrolledWindow);
1292 session_selector_window->add_button (Stock::CANCEL, RESPONSE_CANCEL);
1293 session_selector_window->add_button (Stock::OPEN, RESPONSE_ACCEPT);
1294 session_selector_window->set_default_response (RESPONSE_ACCEPT);
1295 recent_session_model = TreeStore::create (recent_session_columns);
1296 recent_session_display.set_model (recent_session_model);
1297 recent_session_display.append_column (_("Recent Sessions"), recent_session_columns.visible_name);
1298 recent_session_display.set_headers_visible (false);
1299 recent_session_display.get_selection()->set_mode (SELECTION_BROWSE);
1300 recent_session_display.signal_row_activated().connect (sigc::mem_fun (*this, &ARDOUR_UI::recent_session_row_activated));
1302 scroller->add (recent_session_display);
1303 scroller->set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
1305 session_selector_window->set_name ("SessionSelectorWindow");
1306 session_selector_window->set_size_request (200, 400);
1307 session_selector_window->get_vbox()->pack_start (*scroller);
1309 recent_session_display.show();
1311 //session_selector_window->get_vbox()->show();
1315 ARDOUR_UI::recent_session_row_activated (const TreePath& /*path*/, TreeViewColumn* /*col*/)
1317 session_selector_window->response (RESPONSE_ACCEPT);
1321 ARDOUR_UI::open_recent_session ()
1323 bool can_return = (_session != 0);
1325 if (session_selector_window == 0) {
1326 build_session_selector ();
1329 redisplay_recent_sessions ();
1333 session_selector_window->set_position (WIN_POS_MOUSE);
1335 ResponseType r = (ResponseType) session_selector_window->run ();
1338 case RESPONSE_ACCEPT:
1342 session_selector_window->hide();
1349 if (recent_session_display.get_selection()->count_selected_rows() == 0) {
1353 session_selector_window->hide();
1355 Gtk::TreeModel::iterator i = recent_session_display.get_selection()->get_selected();
1357 if (i == recent_session_model->children().end()) {
1361 std::string path = (*i)[recent_session_columns.fullpath];
1362 std::string state = (*i)[recent_session_columns.visible_name];
1364 _session_is_new = false;
1366 if (load_session (path, state) == 0) {
1375 ARDOUR_UI::check_audioengine ()
1378 if (!engine->connected()) {
1379 MessageDialog msg (string_compose (
1380 _("%1 is not connected to JACK\n"
1381 "You cannot open or close sessions in this condition"),
1394 ARDOUR_UI::open_session ()
1396 if (!check_audioengine()) {
1401 /* popup selector window */
1403 if (open_session_selector == 0) {
1405 /* ardour sessions are folders */
1407 open_session_selector = new Gtk::FileChooserDialog (_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1408 open_session_selector->add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1409 open_session_selector->add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1410 open_session_selector->set_default_response(Gtk::RESPONSE_ACCEPT);
1412 FileFilter session_filter;
1413 session_filter.add_pattern ("*.ardour");
1414 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1415 open_session_selector->add_filter (session_filter);
1416 open_session_selector->set_filter (session_filter);
1419 int response = open_session_selector->run();
1420 open_session_selector->hide ();
1423 case RESPONSE_ACCEPT:
1426 open_session_selector->hide();
1430 open_session_selector->hide();
1431 string session_path = open_session_selector->get_filename();
1435 if (session_path.length() > 0) {
1436 if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1437 _session_is_new = isnew;
1438 load_session (path, name);
1445 ARDOUR_UI::session_add_midi_route (bool disk, RouteGroup* route_group, uint32_t how_many, string const & name_template)
1447 list<boost::shared_ptr<MidiTrack> > tracks;
1449 if (_session == 0) {
1450 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1457 tracks = _session->new_midi_track (ARDOUR::Normal, route_group, how_many, name_template);
1459 if (tracks.size() != how_many) {
1460 if (how_many == 1) {
1461 error << _("could not create a new midi track") << endmsg;
1463 error << string_compose (_("could not create %1 new midi tracks"), how_many) << endmsg;
1467 if ((route = _session->new_midi_route ()) == 0) {
1468 error << _("could not create new midi bus") << endmsg;
1474 MessageDialog msg (*editor,
1475 string_compose (_("There are insufficient JACK ports available\n\
1476 to create a new track or bus.\n\
1477 You should save %1, exit and\n\
1478 restart JACK with more ports."), PROGRAM_NAME));
1485 ARDOUR_UI::session_add_audio_route (
1487 int32_t input_channels,
1488 int32_t output_channels,
1489 ARDOUR::TrackMode mode,
1490 RouteGroup* route_group,
1492 string const & name_template
1495 list<boost::shared_ptr<AudioTrack> > tracks;
1498 if (_session == 0) {
1499 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1505 tracks = _session->new_audio_track (input_channels, output_channels, mode, route_group, how_many, name_template);
1507 if (tracks.size() != how_many) {
1508 if (how_many == 1) {
1509 error << _("could not create a new audio track") << endmsg;
1511 error << string_compose (_("could only create %1 of %2 new audio %3"),
1512 tracks.size(), how_many, (track ? _("tracks") : _("busses"))) << endmsg;
1518 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template);
1520 if (routes.size() != how_many) {
1521 if (how_many == 1) {
1522 error << _("could not create a new audio bus") << endmsg;
1524 error << string_compose (_("could not create %1 new audio busses"), how_many) << endmsg;
1531 MessageDialog msg (*editor,
1532 string_compose (_("There are insufficient JACK ports available\n\
1533 to create a new track or bus.\n\
1534 You should save %1, exit and\n\
1535 restart JACK with more ports."), PROGRAM_NAME));
1542 ARDOUR_UI::do_transport_locate (framepos_t new_position, bool with_roll)
1544 framecnt_t _preroll = 0;
1547 // XXX CONFIG_CHANGE FIX - requires AnyTime handling
1548 // _preroll = _session->convert_to_frames_at (new_position, Config->get_preroll());
1550 if (new_position > _preroll) {
1551 new_position -= _preroll;
1556 _session->request_locate (new_position, with_roll);
1561 ARDOUR_UI::transport_goto_start ()
1564 _session->goto_start();
1566 /* force displayed area in editor to start no matter
1567 what "follow playhead" setting is.
1571 editor->center_screen (_session->current_start_frame ());
1577 ARDOUR_UI::transport_goto_zero ()
1580 _session->request_locate (0);
1582 /* force displayed area in editor to start no matter
1583 what "follow playhead" setting is.
1587 editor->reset_x_origin (0);
1593 ARDOUR_UI::transport_goto_wallclock ()
1595 if (_session && editor) {
1602 localtime_r (&now, &tmnow);
1604 frames = tmnow.tm_hour * (60 * 60 * _session->frame_rate());
1605 frames += tmnow.tm_min * (60 * _session->frame_rate());
1606 frames += tmnow.tm_sec * _session->frame_rate();
1608 _session->request_locate (frames, _session->transport_rolling ());
1610 /* force displayed area in editor to start no matter
1611 what "follow playhead" setting is.
1615 editor->center_screen (frames);
1621 ARDOUR_UI::transport_goto_end ()
1624 framepos_t const frame = _session->current_end_frame();
1625 _session->request_locate (frame);
1627 /* force displayed area in editor to start no matter
1628 what "follow playhead" setting is.
1632 editor->center_screen (frame);
1638 ARDOUR_UI::transport_stop ()
1644 if (_session->is_auditioning()) {
1645 _session->cancel_audition ();
1649 _session->request_stop (false, true);
1653 ARDOUR_UI::transport_stop_and_forget_capture ()
1656 _session->request_stop (true, true);
1661 ARDOUR_UI::remove_last_capture()
1664 editor->remove_last_capture();
1669 ARDOUR_UI::transport_record (bool roll)
1673 switch (_session->record_status()) {
1674 case Session::Disabled:
1675 if (_session->ntracks() == 0) {
1676 MessageDialog msg (*editor, _("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."));
1680 _session->maybe_enable_record ();
1685 case Session::Recording:
1687 _session->request_stop();
1689 _session->disable_record (false, true);
1693 case Session::Enabled:
1694 _session->disable_record (false, true);
1697 //cerr << "ARDOUR_UI::transport_record () called roll = " << roll << " _session->record_status() = " << _session->record_status() << endl;
1701 ARDOUR_UI::transport_roll ()
1707 if (_session->is_auditioning()) {
1712 if (_session->config.get_external_sync()) {
1713 switch (_session->config.get_sync_source()) {
1717 /* transport controlled by the master */
1723 bool rolling = _session->transport_rolling();
1725 if (_session->get_play_loop()) {
1726 /* XXX it is not possible to just leave seamless loop and keep
1727 playing at present (nov 4th 2009)
1729 if (!Config->get_seamless_loop()) {
1730 _session->request_play_loop (false, true);
1732 } else if (_session->get_play_range () && !join_play_range_button.active_state()) {
1733 /* stop playing a range if we currently are */
1734 _session->request_play_range (0, true);
1737 if (join_play_range_button.active_state()) {
1738 _session->request_play_range (&editor->get_selection().time, true);
1742 _session->request_transport_speed (1.0f);
1747 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
1754 if (_session->is_auditioning()) {
1755 _session->cancel_audition ();
1759 if (_session->config.get_external_sync()) {
1760 switch (_session->config.get_sync_source()) {
1764 /* transport controlled by the master */
1769 bool rolling = _session->transport_rolling();
1770 bool affect_transport = true;
1772 if (rolling && roll_out_of_bounded_mode) {
1773 /* drop out of loop/range playback but leave transport rolling */
1774 if (_session->get_play_loop()) {
1775 if (Config->get_seamless_loop()) {
1776 /* the disk buffers contain copies of the loop - we can't
1777 just keep playing, so stop the transport. the user
1778 can restart as they wish.
1780 affect_transport = true;
1782 /* disk buffers are normal, so we can keep playing */
1783 affect_transport = false;
1785 _session->request_play_loop (false, true);
1786 } else if (_session->get_play_range ()) {
1787 affect_transport = false;
1788 _session->request_play_range (0, true);
1792 if (affect_transport) {
1794 _session->request_stop (with_abort, true);
1796 if (join_play_range_button.active_state()) {
1797 _session->request_play_range (&editor->get_selection().time, true);
1800 _session->request_transport_speed (1.0f);
1806 ARDOUR_UI::toggle_session_auto_loop ()
1812 if (_session->get_play_loop()) {
1814 if (_session->transport_rolling()) {
1816 Location * looploc = _session->locations()->auto_loop_location();
1819 _session->request_locate (looploc->start(), true);
1820 _session->request_play_loop (false);
1824 _session->request_play_loop (false);
1828 Location * looploc = _session->locations()->auto_loop_location();
1831 _session->request_play_loop (true);
1837 ARDOUR_UI::transport_play_selection ()
1843 editor->play_selection ();
1847 ARDOUR_UI::transport_rewind (int option)
1849 float current_transport_speed;
1852 current_transport_speed = _session->transport_speed();
1854 if (current_transport_speed >= 0.0f) {
1857 _session->request_transport_speed (-1.0f);
1860 _session->request_transport_speed (-4.0f);
1863 _session->request_transport_speed (-0.5f);
1868 _session->request_transport_speed (current_transport_speed * 1.5f);
1874 ARDOUR_UI::transport_forward (int option)
1876 float current_transport_speed;
1879 current_transport_speed = _session->transport_speed();
1881 if (current_transport_speed <= 0.0f) {
1884 _session->request_transport_speed (1.0f);
1887 _session->request_transport_speed (4.0f);
1890 _session->request_transport_speed (0.5f);
1895 _session->request_transport_speed (current_transport_speed * 1.5f);
1902 ARDOUR_UI::toggle_record_enable (uint32_t rid)
1904 if (_session == 0) {
1908 boost::shared_ptr<Route> r;
1910 if ((r = _session->route_by_remote_id (rid)) != 0) {
1914 if ((t = dynamic_cast<Track*>(r.get())) != 0) {
1915 t->set_record_enabled (!t->record_enabled(), this);
1918 if (_session == 0) {
1924 ARDOUR_UI::map_transport_state ()
1927 auto_loop_button.unset_active_state ();
1928 play_selection_button.unset_active_state ();
1929 roll_button.unset_active_state ();
1930 stop_button.set_active_state (Gtkmm2ext::Active);
1934 shuttle_box->map_transport_state ();
1936 float sp = _session->transport_speed();
1942 if (_session->get_play_range()) {
1944 play_selection_button.set_active_state (Gtkmm2ext::Active);
1945 roll_button.unset_active_state ();
1946 auto_loop_button.unset_active_state ();
1948 } else if (_session->get_play_loop ()) {
1950 auto_loop_button.set_active_state (Gtkmm2ext::Active);
1951 play_selection_button.unset_active_state ();
1952 roll_button.unset_active_state ();
1956 roll_button.set_active_state (Gtkmm2ext::Active);
1957 play_selection_button.unset_active_state ();
1958 auto_loop_button.unset_active_state ();
1961 if (join_play_range_button.active_state()) {
1962 /* light up both roll and play-selection if they are joined */
1963 roll_button.set_active_state (Gtkmm2ext::Active);
1964 play_selection_button.set_active_state (Gtkmm2ext::Active);
1967 stop_button.unset_active_state ();
1971 stop_button.set_active_state (Gtkmm2ext::Active);
1972 roll_button.unset_active_state ();
1973 play_selection_button.unset_active_state ();
1974 auto_loop_button.unset_active_state ();
1975 update_disk_space ();
1980 ARDOUR_UI::engine_stopped ()
1982 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
1983 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1984 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1988 ARDOUR_UI::engine_running ()
1990 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
1991 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, true);
1992 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, false);
1994 Glib::RefPtr<Action> action;
1995 const char* action_name = 0;
1997 switch (engine->frames_per_cycle()) {
1999 action_name = X_("JACKLatency32");
2002 action_name = X_("JACKLatency64");
2005 action_name = X_("JACKLatency128");
2008 action_name = X_("JACKLatency512");
2011 action_name = X_("JACKLatency1024");
2014 action_name = X_("JACKLatency2048");
2017 action_name = X_("JACKLatency4096");
2020 action_name = X_("JACKLatency8192");
2023 /* XXX can we do anything useful ? */
2029 action = ActionManager::get_action (X_("JACK"), action_name);
2032 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (action);
2033 ract->set_active ();
2039 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
2041 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
2042 /* we can't rely on the original string continuing to exist when we are called
2043 again in the GUI thread, so make a copy and note that we need to
2046 char *copy = strdup (reason);
2047 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
2051 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
2052 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
2054 update_sample_rate (0);
2058 /* if the reason is a non-empty string, it means that the backend was shutdown
2059 rather than just Ardour.
2062 if (strlen (reason)) {
2063 msgstr = string_compose (_("The audio backend (JACK) was shutdown because:\n\n%1"), reason);
2065 msgstr = string_compose (_("\
2066 JACK has either been shutdown or it\n\
2067 disconnected %1 because %1\n\
2068 was not fast enough. Try to restart\n\
2069 JACK, reconnect and save the session."), PROGRAM_NAME);
2072 MessageDialog msg (*editor, msgstr);
2077 free ((char*) reason);
2082 ARDOUR_UI::do_engine_start ()
2090 error << _("Unable to start the session running")
2100 ARDOUR_UI::setup_theme ()
2102 theme_manager->setup_theme();
2106 ARDOUR_UI::update_clocks ()
2108 if (!editor || !editor->dragging_playhead()) {
2109 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position()); /* EMIT_SIGNAL */
2114 ARDOUR_UI::start_clocking ()
2116 clock_signal_connection = RapidScreenUpdate.connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2120 ARDOUR_UI::stop_clocking ()
2122 clock_signal_connection.disconnect ();
2126 ARDOUR_UI::toggle_clocking ()
2129 if (clock_button.get_active()) {
2138 ARDOUR_UI::_blink (void *arg)
2141 ((ARDOUR_UI *) arg)->blink ();
2148 Blink (blink_on = !blink_on); /* EMIT_SIGNAL */
2152 ARDOUR_UI::start_blinking ()
2154 /* Start the blink signal. Everybody with a blinking widget
2155 uses Blink to drive the widget's state.
2158 if (blink_timeout_tag < 0) {
2160 blink_timeout_tag = g_timeout_add (240, _blink, this);
2165 ARDOUR_UI::stop_blinking ()
2167 if (blink_timeout_tag >= 0) {
2168 g_source_remove (blink_timeout_tag);
2169 blink_timeout_tag = -1;
2174 /** Ask the user for the name of a new snapshot and then take it.
2178 ARDOUR_UI::snapshot_session (bool switch_to_it)
2180 ArdourPrompter prompter (true);
2183 prompter.set_name ("Prompter");
2184 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2185 prompter.set_title (_("Take Snapshot"));
2186 prompter.set_prompt (_("Name of new snapshot"));
2188 if (!switch_to_it) {
2191 struct tm local_time;
2194 localtime_r (&n, &local_time);
2195 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2196 prompter.set_initial_text (timebuf);
2200 switch (prompter.run()) {
2201 case RESPONSE_ACCEPT:
2203 prompter.get_result (snapname);
2205 bool do_save = (snapname.length() != 0);
2208 char illegal = Session::session_name_is_legal(snapname);
2210 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2211 "snapshot names may not contain a '%1' character"), illegal));
2217 vector<sys::path> p;
2218 get_state_files_in_directory (_session->session_directory().root_path(), p);
2219 vector<string> n = get_file_names_no_extension (p);
2220 if (find (n.begin(), n.end(), snapname) != n.end()) {
2222 ArdourDialog confirm (_("Confirm Snapshot Overwrite"), true);
2223 Label m (_("A snapshot already exists with that name. Do you want to overwrite it?"));
2224 confirm.get_vbox()->pack_start (m, true, true);
2225 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2226 confirm.add_button (_("Overwrite"), Gtk::RESPONSE_ACCEPT);
2227 confirm.show_all ();
2228 switch (confirm.run()) {
2229 case RESPONSE_CANCEL:
2235 save_state (snapname, switch_to_it);
2245 /** Ask the user for a new session name and then rename the session to it.
2249 ARDOUR_UI::rename_session ()
2255 ArdourPrompter prompter (true);
2258 prompter.set_name ("Prompter");
2259 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2260 prompter.set_title (_("Rename Session"));
2261 prompter.set_prompt (_("New session name"));
2264 switch (prompter.run()) {
2265 case RESPONSE_ACCEPT:
2267 prompter.get_result (name);
2269 bool do_rename = (name.length() != 0);
2272 char illegal = Session::session_name_is_legal (name);
2275 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2276 "session names may not contain a '%1' character"), illegal));
2281 switch (_session->rename (name)) {
2283 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
2284 msg.set_position (WIN_POS_MOUSE);
2292 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
2293 msg.set_position (WIN_POS_MOUSE);
2309 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2311 XMLNode* node = new XMLNode (X_("UI"));
2313 for (list<WindowProxyBase*>::iterator i = _window_proxies.begin(); i != _window_proxies.end(); ++i) {
2314 if (!(*i)->rc_configured()) {
2315 node->add_child_nocopy (*((*i)->get_state ()));
2319 node->add_child_nocopy (gui_object_state->get_state());
2321 _session->add_extra_xml (*node);
2323 save_state_canfail (name, switch_to_it);
2327 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2332 if (name.length() == 0) {
2333 name = _session->snap_name();
2336 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2341 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2346 ARDOUR_UI::primary_clock_value_changed ()
2349 _session->request_locate (primary_clock->current_time ());
2354 ARDOUR_UI::big_clock_value_changed ()
2357 _session->request_locate (big_clock->current_time ());
2362 ARDOUR_UI::secondary_clock_value_changed ()
2365 _session->request_locate (secondary_clock->current_time ());
2370 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2372 if (_session == 0) {
2376 if (_session->step_editing()) {
2380 Session::RecordState const r = _session->record_status ();
2381 bool const h = _session->have_rec_enabled_track ();
2383 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2385 rec_button.set_active_state (Active);
2387 rec_button.set_active_state (Mid);
2389 } else if (r == Session::Recording && h) {
2390 rec_button.set_active_state (Mid);
2392 rec_button.unset_active_state ();
2397 ARDOUR_UI::save_template ()
2399 ArdourPrompter prompter (true);
2402 if (!check_audioengine()) {
2406 prompter.set_name (X_("Prompter"));
2407 prompter.set_title (_("Save Template"));
2408 prompter.set_prompt (_("Name for template:"));
2409 prompter.set_initial_text(_session->name() + _("-template"));
2410 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2412 switch (prompter.run()) {
2413 case RESPONSE_ACCEPT:
2414 prompter.get_result (name);
2416 if (name.length()) {
2417 _session->save_template (name);
2427 ARDOUR_UI::edit_metadata ()
2429 SessionMetadataEditor dialog;
2430 dialog.set_session (_session);
2431 editor->ensure_float (dialog);
2436 ARDOUR_UI::import_metadata ()
2438 SessionMetadataImporter dialog;
2439 dialog.set_session (_session);
2440 editor->ensure_float (dialog);
2445 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
2447 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2449 MessageDialog msg (str,
2451 Gtk::MESSAGE_WARNING,
2452 Gtk::BUTTONS_YES_NO,
2456 msg.set_name (X_("OpenExistingDialog"));
2457 msg.set_title (_("Open Existing Session"));
2458 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
2459 msg.set_position (Gtk::WIN_POS_MOUSE);
2462 switch (msg.run()) {
2471 ARDOUR_UI::build_session_from_nsd (const std::string& session_path, const std::string& session_name)
2473 BusProfile bus_profile;
2475 if (Profile->get_sae()) {
2477 bus_profile.master_out_channels = 2;
2478 bus_profile.input_ac = AutoConnectPhysical;
2479 bus_profile.output_ac = AutoConnectMaster;
2480 bus_profile.requested_physical_in = 0; // use all available
2481 bus_profile.requested_physical_out = 0; // use all available
2485 /* get settings from advanced section of NSD */
2487 if (_startup->create_master_bus()) {
2488 bus_profile.master_out_channels = (uint32_t) _startup->master_channel_count();
2490 bus_profile.master_out_channels = 0;
2493 if (_startup->connect_inputs()) {
2494 bus_profile.input_ac = AutoConnectPhysical;
2496 bus_profile.input_ac = AutoConnectOption (0);
2499 bus_profile.output_ac = AutoConnectOption (0);
2501 if (_startup->connect_outputs ()) {
2502 if (_startup->connect_outs_to_master()) {
2503 bus_profile.output_ac = AutoConnectMaster;
2504 } else if (_startup->connect_outs_to_physical()) {
2505 bus_profile.output_ac = AutoConnectPhysical;
2509 bus_profile.requested_physical_in = (uint32_t) _startup->input_limit_count();
2510 bus_profile.requested_physical_out = (uint32_t) _startup->output_limit_count();
2513 if (build_session (session_path, session_name, bus_profile)) {
2521 ARDOUR_UI::idle_load (const std::string& path)
2524 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2525 /* /path/to/foo => /path/to/foo, foo */
2526 load_session (path, basename_nosuffix (path));
2528 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2529 load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2533 ARDOUR_COMMAND_LINE::session_name = path;
2536 * new_session_dialog doens't exist in A3
2537 * Try to remove all references to it to
2538 * see if it will compile. NOTE: this will
2539 * likely cause a runtime issue is my somewhat
2543 //if (new_session_dialog) {
2546 /* make it break out of Dialog::run() and
2550 //new_session_dialog->response (1);
2556 ARDOUR_UI::end_loading_messages ()
2562 ARDOUR_UI::loading_message (const std::string& /*msg*/)
2565 // splash->message (msg);
2569 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
2571 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
2573 string session_name;
2574 string session_path;
2575 string template_name;
2577 bool likely_new = false;
2579 if (!load_template.empty()) {
2580 should_be_new = true;
2581 template_name = load_template;
2586 if (!should_be_new && !ARDOUR_COMMAND_LINE::session_name.empty()) {
2588 /* if they named a specific statefile, use it, otherwise they are
2589 just giving a session folder, and we want to use it as is
2590 to find the session.
2593 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
2595 if (suffix != string::npos) {
2596 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
2597 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
2598 session_name = Glib::path_get_basename (session_name);
2600 session_path = ARDOUR_COMMAND_LINE::session_name;
2601 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
2606 bool const apply = run_startup (should_be_new, load_template);
2609 if (quit_on_cancel) {
2616 /* if we run the startup dialog again, offer more than just "new session" */
2618 should_be_new = false;
2620 session_name = _startup->session_name (likely_new);
2622 string::size_type suffix = session_name.find (statefile_suffix);
2624 if (suffix != string::npos) {
2625 session_name = session_name.substr (0, suffix);
2628 /* this shouldn't happen, but we catch it just in case it does */
2630 if (session_name.empty()) {
2634 if (_startup->use_session_template()) {
2635 template_name = _startup->session_template_name();
2636 _session_is_new = true;
2639 if (session_name[0] == G_DIR_SEPARATOR ||
2640 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
2641 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)) {
2643 /* absolute path or cwd-relative path specified for session name: infer session folder
2644 from what was given.
2647 session_path = Glib::path_get_dirname (session_name);
2648 session_name = Glib::path_get_basename (session_name);
2652 session_path = _startup->session_folder();
2654 char illegal = Session::session_name_is_legal (session_name);
2657 MessageDialog msg (*_startup,
2658 string_compose (_("To ensure compatibility with various systems\n"
2659 "session names may not contain a '%1' character"),
2662 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2668 if (create_engine ()) {
2672 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
2676 std::string existing = Glib::build_filename (session_path, session_name);
2678 if (!ask_about_loading_existing_session (existing)) {
2679 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2684 _session_is_new = false;
2689 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
2691 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2695 if (session_name.find ('/') != std::string::npos) {
2696 MessageDialog msg (*_startup,
2697 _("To ensure compatibility with various systems\n"
2698 "session names may not contain a '/' character"));
2700 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2704 if (session_name.find ('\\') != std::string::npos) {
2705 MessageDialog msg (*_startup,
2706 _("To ensure compatibility with various systems\n"
2707 "session names may not contain a '\\' character"));
2709 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2713 _session_is_new = true;
2716 if (likely_new && template_name.empty()) {
2718 ret = build_session_from_nsd (session_path, session_name);
2722 ret = load_session (session_path, session_name, template_name);
2725 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
2729 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
2730 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
2740 ARDOUR_UI::close_session()
2742 if (!check_audioengine()) {
2746 if (unload_session (true)) {
2750 ARDOUR_COMMAND_LINE::session_name = "";
2752 if (get_session_parameters (true, false)) {
2756 goto_editor_window ();
2759 /** @param snap_name Snapshot name (without .ardour suffix).
2760 * @return -2 if the load failed because we are not connected to the AudioEngine.
2763 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
2765 Session *new_session;
2769 session_loaded = false;
2771 if (!check_audioengine()) {
2775 unload_status = unload_session ();
2777 if (unload_status < 0) {
2779 } else if (unload_status > 0) {
2784 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
2787 new_session = new Session (*engine, path, snap_name, 0, mix_template);
2790 /* this one is special */
2792 catch (AudioEngine::PortRegistrationFailure& err) {
2794 MessageDialog msg (err.what(),
2797 Gtk::BUTTONS_CLOSE);
2799 msg.set_title (_("Port Registration Error"));
2800 msg.set_secondary_text (_("Click the Close button to try again."));
2801 msg.set_position (Gtk::WIN_POS_CENTER);
2805 int response = msg.run ();
2810 case RESPONSE_CANCEL:
2820 MessageDialog msg (string_compose(
2821 _("Session \"%1 (snapshot %2)\" did not load successfully"),
2827 msg.set_title (_("Loading Error"));
2828 msg.set_secondary_text (_("Click the Refresh button to try again."));
2829 msg.add_button (Stock::REFRESH, 1);
2830 msg.set_position (Gtk::WIN_POS_CENTER);
2834 int response = msg.run ();
2849 list<string> const u = new_session->unknown_processors ();
2851 MissingPluginDialog d (_session, u);
2856 /* Now the session been created, add the transport controls */
2857 new_session->add_controllable(roll_controllable);
2858 new_session->add_controllable(stop_controllable);
2859 new_session->add_controllable(goto_start_controllable);
2860 new_session->add_controllable(goto_end_controllable);
2861 new_session->add_controllable(auto_loop_controllable);
2862 new_session->add_controllable(play_selection_controllable);
2863 new_session->add_controllable(rec_controllable);
2865 set_session (new_session);
2867 session_loaded = true;
2869 goto_editor_window ();
2872 _session->set_clean ();
2883 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
2885 Session *new_session;
2888 if (!check_audioengine()) {
2892 session_loaded = false;
2894 x = unload_session ();
2902 _session_is_new = true;
2905 new_session = new Session (*engine, path, snap_name, &bus_profile);
2910 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
2916 /* Give the new session the default GUI state, if such things exist */
2919 n = Config->instant_xml (X_("Editor"));
2921 new_session->add_instant_xml (*n, false);
2923 n = Config->instant_xml (X_("Mixer"));
2925 new_session->add_instant_xml (*n, false);
2928 /* Put the playhead at 0 and scroll fully left */
2929 n = new_session->instant_xml (X_("Editor"));
2931 n->add_property (X_("playhead"), X_("0"));
2932 n->add_property (X_("left-frame"), X_("0"));
2935 set_session (new_session);
2937 session_loaded = true;
2939 new_session->save_state(new_session->name());
2945 ARDOUR_UI::launch_chat ()
2948 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
2950 open_uri("http://webchat.freenode.net/?channels=ardour");
2955 ARDOUR_UI::show_about ()
2959 about->signal_response().connect(sigc::mem_fun (*this, &ARDOUR_UI::about_signal_response) );
2962 about->set_transient_for(*editor);
2967 ARDOUR_UI::launch_manual ()
2969 PBD::open_uri("http://ardour.org/flossmanual");
2973 ARDOUR_UI::launch_reference ()
2975 PBD::open_uri("http://ardour.org/refmanual");
2979 ARDOUR_UI::hide_about ()
2982 about->get_window()->set_cursor ();
2988 ARDOUR_UI::about_signal_response (int /*response*/)
2994 ARDOUR_UI::show_splash ()
2998 splash = new Splash;
3006 splash->queue_draw ();
3007 splash->get_window()->process_updates (true);
3012 ARDOUR_UI::hide_splash ()
3020 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title,
3021 const string& plural_msg, const string& singular_msg)
3025 removed = rep.paths.size();
3028 MessageDialog msgd (*editor,
3029 _("No files were ready for clean-up"),
3033 msgd.set_title (_("Clean-up"));
3034 msgd.set_secondary_text (_("If this seems suprising, \n\
3035 check for any existing snapshots.\n\
3036 These may still include regions that\n\
3037 require some unused files to continue to exist."));
3043 ArdourDialog results (_("Clean-up"), true, false);
3045 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
3046 CleanupResultsModelColumns() {
3050 Gtk::TreeModelColumn<std::string> visible_name;
3051 Gtk::TreeModelColumn<std::string> fullpath;
3055 CleanupResultsModelColumns results_columns;
3056 Glib::RefPtr<Gtk::ListStore> results_model;
3057 Gtk::TreeView results_display;
3059 results_model = ListStore::create (results_columns);
3060 results_display.set_model (results_model);
3061 results_display.append_column (list_title, results_columns.visible_name);
3063 results_display.set_name ("CleanupResultsList");
3064 results_display.set_headers_visible (true);
3065 results_display.set_headers_clickable (false);
3066 results_display.set_reorderable (false);
3068 Gtk::ScrolledWindow list_scroller;
3071 Gtk::HBox dhbox; // the hbox for the image and text
3072 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
3073 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
3075 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
3077 const string dead_directory = _session->session_directory().dead_path().to_string();
3080 %1 - number of files removed
3081 %2 - location of "dead"
3082 %3 - size of files affected
3083 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
3086 const char* bprefix;
3087 double space_adjusted = 0;
3089 if (rep.space < 1000) {
3091 space_adjusted = rep.space;
3092 } else if (rep.space < 1000000) {
3093 bprefix = X_("kilo");
3094 space_adjusted = truncf((float)rep.space / 1000.0);
3095 } else if (rep.space < 1000000 * 1000) {
3096 bprefix = X_("mega");
3097 space_adjusted = truncf((float)rep.space / (1000.0 * 1000.0));
3099 bprefix = X_("giga");
3100 space_adjusted = truncf((float)rep.space / (1000.0 * 1000 * 1000.0));
3104 txt.set_text (string_compose (plural_msg, removed, dead_directory, space_adjusted, bprefix));
3106 txt.set_text (string_compose (singular_msg, removed, dead_directory, space_adjusted, bprefix));
3109 dhbox.pack_start (*dimage, true, false, 5);
3110 dhbox.pack_start (txt, true, false, 5);
3112 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
3113 TreeModel::Row row = *(results_model->append());
3114 row[results_columns.visible_name] = *i;
3115 row[results_columns.fullpath] = *i;
3118 list_scroller.add (results_display);
3119 list_scroller.set_size_request (-1, 150);
3120 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
3122 dvbox.pack_start (dhbox, true, false, 5);
3123 dvbox.pack_start (list_scroller, true, false, 5);
3124 ddhbox.pack_start (dvbox, true, false, 5);
3126 results.get_vbox()->pack_start (ddhbox, true, false, 5);
3127 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
3128 results.set_default_response (RESPONSE_CLOSE);
3129 results.set_position (Gtk::WIN_POS_MOUSE);
3131 results_display.show();
3132 list_scroller.show();
3139 //results.get_vbox()->show();
3140 results.set_resizable (false);
3147 ARDOUR_UI::cleanup ()
3149 if (_session == 0) {
3150 /* shouldn't happen: menu item is insensitive */
3155 MessageDialog checker (_("Are you sure you want to clean-up?"),
3157 Gtk::MESSAGE_QUESTION,
3160 checker.set_title (_("Clean-up"));
3162 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
3163 ALL undo/redo information will be lost if you clean-up.\n\
3164 Clean-up will move all unused files to a \"dead\" location."));
3166 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3167 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
3168 checker.set_default_response (RESPONSE_CANCEL);
3170 checker.set_name (_("CleanupDialog"));
3171 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3172 checker.set_position (Gtk::WIN_POS_MOUSE);
3174 switch (checker.run()) {
3175 case RESPONSE_ACCEPT:
3181 ARDOUR::CleanupReport rep;
3183 editor->prepare_for_cleanup ();
3185 /* do not allow flush until a session is reloaded */
3187 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3189 act->set_sensitive (false);
3192 if (_session->cleanup_sources (rep)) {
3193 editor->finish_cleanup ();
3197 editor->finish_cleanup ();
3200 display_cleanup_results (rep,
3203 The following %1 files were not in use and \n\
3204 have been moved to:\n\n\
3206 After a restart of Ardour,\n\n\
3207 Session -> Clean-up -> Flush Wastebasket\n\n\
3208 will release an additional\n\
3209 %3 %4bytes of disk space.\n"),
3211 The following file was not in use and \n\
3212 has been moved to:\n \
3214 After a restart of Ardour,\n\n\
3215 Session -> Clean-up -> Flush Wastebasket\n\n\
3216 will release an additional\n\
3217 %3 %4bytes of disk space.\n"
3223 ARDOUR_UI::flush_trash ()
3225 if (_session == 0) {
3226 /* shouldn't happen: menu item is insensitive */
3230 ARDOUR::CleanupReport rep;
3232 if (_session->cleanup_trash_sources (rep)) {
3236 display_cleanup_results (rep,
3238 _("The following %1 files were deleted from\n\
3240 releasing %3 %4bytes of disk space"),
3241 _("The following file was deleted from\n\
3243 releasing %3 %4bytes of disk space"));
3247 ARDOUR_UI::add_route (Gtk::Window* float_window)
3255 if (add_route_dialog == 0) {
3256 add_route_dialog = new AddRouteDialog (_session);
3258 add_route_dialog->set_transient_for (*float_window);
3262 if (add_route_dialog->is_visible()) {
3263 /* we're already doing this */
3267 ResponseType r = (ResponseType) add_route_dialog->run ();
3269 add_route_dialog->hide();
3272 case RESPONSE_ACCEPT:
3279 if ((count = add_route_dialog->count()) <= 0) {
3283 string template_path = add_route_dialog->track_template();
3285 if (!template_path.empty()) {
3286 _session->new_route_from_template (count, template_path);
3290 uint32_t input_chan = add_route_dialog->channels ();
3291 uint32_t output_chan;
3292 string name_template = add_route_dialog->name_template ();
3293 bool track = add_route_dialog->track ();
3294 RouteGroup* route_group = add_route_dialog->route_group ();
3296 AutoConnectOption oac = Config->get_output_auto_connect();
3298 if (oac & AutoConnectMaster) {
3299 output_chan = (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan);
3301 output_chan = input_chan;
3304 /* XXX do something with name template */
3306 if (add_route_dialog->type() == ARDOUR::DataType::MIDI) {
3308 session_add_midi_track (route_group, count, name_template);
3310 MessageDialog msg (*editor,
3311 _("Sorry, MIDI Busses are not supported at this time."));
3313 //session_add_midi_bus();
3317 session_add_audio_track (input_chan, output_chan, add_route_dialog->mode(), route_group, count, name_template);
3319 session_add_audio_bus (input_chan, output_chan, route_group, count, name_template);
3325 ARDOUR_UI::mixer_settings () const
3330 node = _session->instant_xml(X_("Mixer"));
3332 node = Config->instant_xml(X_("Mixer"));
3336 node = new XMLNode (X_("Mixer"));
3343 ARDOUR_UI::editor_settings () const
3348 node = _session->instant_xml(X_("Editor"));
3350 node = Config->instant_xml(X_("Editor"));
3354 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
3355 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
3360 node = new XMLNode (X_("Editor"));
3367 ARDOUR_UI::keyboard_settings () const
3371 node = Config->extra_xml(X_("Keyboard"));
3374 node = new XMLNode (X_("Keyboard"));
3381 ARDOUR_UI::create_xrun_marker (framepos_t where)
3383 editor->mouse_add_new_marker (where, false, true);
3387 ARDOUR_UI::halt_on_xrun_message ()
3389 MessageDialog msg (*editor,
3390 _("Recording was stopped because your system could not keep up."));
3395 ARDOUR_UI::xrun_handler (framepos_t where)
3401 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
3403 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
3404 create_xrun_marker(where);
3407 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
3408 halt_on_xrun_message ();
3413 ARDOUR_UI::disk_overrun_handler ()
3415 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
3417 if (!have_disk_speed_dialog_displayed) {
3418 have_disk_speed_dialog_displayed = true;
3419 MessageDialog* msg = new MessageDialog (*editor, string_compose (_("\
3420 The disk system on your computer\n\
3421 was not able to keep up with %1.\n\
3423 Specifically, it failed to write data to disk\n\
3424 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
3425 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3431 ARDOUR_UI::disk_underrun_handler ()
3433 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
3435 if (!have_disk_speed_dialog_displayed) {
3436 have_disk_speed_dialog_displayed = true;
3437 MessageDialog* msg = new MessageDialog (
3438 *editor, string_compose (_("The disk system on your computer\n\
3439 was not able to keep up with %1.\n\
3441 Specifically, it failed to read data from disk\n\
3442 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
3443 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3449 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
3451 have_disk_speed_dialog_displayed = false;
3456 ARDOUR_UI::session_dialog (std::string msg)
3458 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
3463 d = new MessageDialog (*editor, msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3465 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3474 ARDOUR_UI::pending_state_dialog ()
3476 HBox* hbox = new HBox();
3477 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3478 ArdourDialog dialog (_("Crash Recovery"), true);
3480 This session appears to have been in\n\
3481 middle of recording when ardour or\n\
3482 the computer was shutdown.\n\
3484 Ardour can recover any captured audio for\n\
3485 you, or it can ignore it. Please decide\n\
3486 what you would like to do.\n"));
3487 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3488 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3489 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3490 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3491 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
3492 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
3493 dialog.set_default_response (RESPONSE_ACCEPT);
3494 dialog.set_position (WIN_POS_CENTER);
3499 switch (dialog.run ()) {
3500 case RESPONSE_ACCEPT:
3508 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
3510 HBox* hbox = new HBox();
3511 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3512 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
3513 Label message (string_compose (_("\
3514 This session was created with a sample rate of %1 Hz\n\
3516 The audioengine is currently running at %2 Hz\n"), desired, actual));
3518 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3519 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3520 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3521 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3522 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
3523 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
3524 dialog.set_default_response (RESPONSE_ACCEPT);
3525 dialog.set_position (WIN_POS_CENTER);
3530 switch (dialog.run ()) {
3531 case RESPONSE_ACCEPT:
3540 ARDOUR_UI::disconnect_from_jack ()
3543 if( engine->disconnect_from_jack ()) {
3544 MessageDialog msg (*editor, _("Could not disconnect from JACK"));
3548 update_sample_rate (0);
3553 ARDOUR_UI::reconnect_to_jack ()
3556 if (engine->reconnect_to_jack ()) {
3557 MessageDialog msg (*editor, _("Could not reconnect to JACK"));
3561 update_sample_rate (0);
3566 ARDOUR_UI::use_config ()
3568 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
3570 set_transport_controllable_state (*node);
3575 ARDOUR_UI::update_transport_clocks (framepos_t pos)
3577 if (Config->get_primary_clock_delta_edit_cursor()) {
3578 primary_clock->set (pos, false, editor->get_preferred_edit_position());
3580 primary_clock->set (pos);
3583 if (Config->get_secondary_clock_delta_edit_cursor()) {
3584 secondary_clock->set (pos, false, editor->get_preferred_edit_position());
3586 secondary_clock->set (pos);
3589 if (big_clock_window->get()) {
3590 big_clock->set (pos);
3596 ARDOUR_UI::step_edit_status_change (bool yn)
3598 // XXX should really store pre-step edit status of things
3599 // we make insensitive
3602 rec_button.set_active_state (Mid);
3603 rec_button.set_sensitive (false);
3605 rec_button.unset_active_state ();;
3606 rec_button.set_sensitive (true);
3611 ARDOUR_UI::record_state_changed ()
3613 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
3615 if (!_session || !big_clock_window->get()) {
3616 /* why bother - the clock isn't visible */
3620 if (_session->record_status () == Session::Recording && _session->have_rec_enabled_track ()) {
3621 big_clock->set_active (true);
3623 big_clock->set_active (false);
3628 ARDOUR_UI::first_idle ()
3631 _session->allow_auto_play (true);
3635 editor->first_idle();
3638 Keyboard::set_can_save_keybindings (true);
3643 ARDOUR_UI::store_clock_modes ()
3645 XMLNode* node = new XMLNode(X_("ClockModes"));
3647 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
3648 XMLNode* child = new XMLNode (X_("Clock"));
3650 child->add_property (X_("name"), (*x)->name());
3651 child->add_property (X_("mode"), enum_2_string ((*x)->mode()));
3652 child->add_property (X_("on"), ((*x)->off() ? X_("no") : X_("yes")));
3654 node->add_child_nocopy (*child);
3657 _session->add_extra_xml (*node);
3658 _session->set_dirty ();
3661 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
3662 : Controllable (name), ui (u), type(tp)
3668 ARDOUR_UI::TransportControllable::set_value (double val)
3671 /* do nothing: these are radio-style actions */
3675 const char *action = 0;
3679 action = X_("Roll");
3682 action = X_("Stop");
3685 action = X_("Goto Start");
3688 action = X_("Goto End");
3691 action = X_("Loop");
3694 action = X_("Play Selection");
3697 action = X_("Record");
3707 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
3715 ARDOUR_UI::TransportControllable::get_value (void) const
3742 ARDOUR_UI::setup_profile ()
3744 if (gdk_screen_width() < 1200) {
3745 Profile->set_small_screen ();
3749 if (getenv ("ARDOUR_SAE")) {
3750 Profile->set_sae ();
3751 Profile->set_single_package ();
3756 ARDOUR_UI::toggle_translations ()
3758 using namespace Glib;
3760 RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("EnableTranslation"));
3762 RefPtr<ToggleAction> ract = RefPtr<ToggleAction>::cast_dynamic (act);
3765 string i18n_killer = ARDOUR::translation_kill_path();
3767 bool already_enabled = !ARDOUR::translations_are_disabled ();
3769 if (ract->get_active ()) {
3770 /* we don't care about errors */
3771 int fd = ::open (i18n_killer.c_str(), O_RDONLY|O_CREAT, 0644);
3774 /* we don't care about errors */
3775 unlink (i18n_killer.c_str());
3778 if (already_enabled != ract->get_active()) {
3779 MessageDialog win (already_enabled ? _("Translations disabled") : _("Translations enabled"),
3781 Gtk::MESSAGE_WARNING,
3783 win.set_secondary_text (string_compose (_("You must restart %1 for this to take effect."), PROGRAM_NAME));
3784 win.set_position (Gtk::WIN_POS_CENTER);
3792 /** Add a window proxy to our list, so that its state will be saved.
3793 * This call also causes the window to be created and opened if its
3794 * state was saved as `visible'.
3797 ARDOUR_UI::add_window_proxy (WindowProxyBase* p)
3799 _window_proxies.push_back (p);
3803 /** Remove a window proxy from our list. Must be called if a WindowProxy
3804 * is deleted, to prevent hanging pointers.
3807 ARDOUR_UI::remove_window_proxy (WindowProxyBase* p)
3809 _window_proxies.remove (p);
3813 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
3815 MissingFileDialog dialog (s, str, type);
3820 int result = dialog.run ();
3827 return 1; // quit entire session load
3830 result = dialog.get_action ();
3836 ARDOUR_UI::ambiguous_file (std::string file, std::string /*path*/, std::vector<std::string> hits)
3838 AmbiguousFileDialog dialog (file, hits);
3844 return dialog.get_which ();
3847 /** Allocate our thread-local buffers */
3849 ARDOUR_UI::get_process_buffers ()
3851 _process_thread->get_buffers ();
3854 /** Drop our thread-local buffers */
3856 ARDOUR_UI::drop_process_buffers ()
3858 _process_thread->drop_buffers ();
3862 ARDOUR_UI::feedback_detected ()
3864 _feedback_exists = true;
3868 ARDOUR_UI::successful_graph_sort ()
3870 _feedback_exists = false;
3874 ARDOUR_UI::midi_panic ()
3877 _session->midi_panic();