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 ProcessorEntry::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 (Gtk::Window& win)
512 if (Splash::instance()) {
513 Splash::instance()->pop_back_for (win);
518 ARDOUR_UI::configure_timeout ()
520 if (last_configure_time == 0) {
521 /* no configure events yet */
525 /* force a gap of 0.5 seconds since the last configure event
528 if (get_microseconds() - last_configure_time < 500000) {
531 have_configure_timeout = false;
532 cerr << "config event-driven save\n";
533 save_ardour_state ();
539 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
541 if (have_configure_timeout) {
542 last_configure_time = get_microseconds();
544 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
545 have_configure_timeout = true;
552 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
554 const XMLProperty* prop;
556 if ((prop = node.property ("roll")) != 0) {
557 roll_controllable->set_id (prop->value());
559 if ((prop = node.property ("stop")) != 0) {
560 stop_controllable->set_id (prop->value());
562 if ((prop = node.property ("goto-start")) != 0) {
563 goto_start_controllable->set_id (prop->value());
565 if ((prop = node.property ("goto-end")) != 0) {
566 goto_end_controllable->set_id (prop->value());
568 if ((prop = node.property ("auto-loop")) != 0) {
569 auto_loop_controllable->set_id (prop->value());
571 if ((prop = node.property ("play-selection")) != 0) {
572 play_selection_controllable->set_id (prop->value());
574 if ((prop = node.property ("rec")) != 0) {
575 rec_controllable->set_id (prop->value());
577 if ((prop = node.property ("shuttle")) != 0) {
578 shuttle_box->controllable()->set_id (prop->value());
584 ARDOUR_UI::get_transport_controllable_state ()
586 XMLNode* node = new XMLNode(X_("TransportControllables"));
589 roll_controllable->id().print (buf, sizeof (buf));
590 node->add_property (X_("roll"), buf);
591 stop_controllable->id().print (buf, sizeof (buf));
592 node->add_property (X_("stop"), buf);
593 goto_start_controllable->id().print (buf, sizeof (buf));
594 node->add_property (X_("goto_start"), buf);
595 goto_end_controllable->id().print (buf, sizeof (buf));
596 node->add_property (X_("goto_end"), buf);
597 auto_loop_controllable->id().print (buf, sizeof (buf));
598 node->add_property (X_("auto_loop"), buf);
599 play_selection_controllable->id().print (buf, sizeof (buf));
600 node->add_property (X_("play_selection"), buf);
601 rec_controllable->id().print (buf, sizeof (buf));
602 node->add_property (X_("rec"), buf);
603 shuttle_box->controllable()->id().print (buf, sizeof (buf));
604 node->add_property (X_("shuttle"), buf);
611 ARDOUR_UI::autosave_session ()
613 if (g_main_depth() > 1) {
614 /* inside a recursive main loop,
615 give up because we may not be able to
621 if (!Config->get_periodic_safety_backups()) {
626 _session->maybe_write_autosave();
633 ARDOUR_UI::update_autosave ()
635 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_autosave)
637 if (_session && _session->dirty()) {
638 if (_autosave_connection.connected()) {
639 _autosave_connection.disconnect();
642 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
643 Config->get_periodic_safety_backup_interval() * 1000);
646 if (_autosave_connection.connected()) {
647 _autosave_connection.disconnect();
653 ARDOUR_UI::backend_audio_error (bool we_set_params, Gtk::Window* toplevel)
657 title = string_compose (_("%1 could not start JACK"), PROGRAM_NAME);
659 title = string_compose (_("%1 could not connect to JACK."), PROGRAM_NAME);
662 MessageDialog win (title,
668 win.set_secondary_text(_("There are several possible reasons:\n\
670 1) You requested audio parameters that are not supported..\n\
671 2) JACK is running as another user.\n\
673 Please consider the possibilities, and perhaps try different parameters."));
675 win.set_secondary_text(_("There are several possible reasons:\n\
677 1) JACK is not running.\n\
678 2) JACK is running as another user, perhaps root.\n\
679 3) There is already another client called \"ardour\".\n\
681 Please consider the possibilities, and perhaps (re)start JACK."));
685 win.set_transient_for (*toplevel);
689 win.add_button (Stock::OK, RESPONSE_CLOSE);
691 win.add_button (Stock::QUIT, RESPONSE_CLOSE);
694 win.set_default_response (RESPONSE_CLOSE);
697 win.set_position (Gtk::WIN_POS_CENTER);
698 pop_back_splash (win);
700 /* we just don't care about the result, but we want to block */
706 ARDOUR_UI::startup ()
708 Application* app = Application::instance ();
710 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
711 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::idle_load));
714 call_the_mothership (VERSIONSTRING);
719 if (get_session_parameters (true, ARDOUR_COMMAND_LINE::new_session, ARDOUR_COMMAND_LINE::load_template)) {
725 goto_editor_window ();
727 /* Add the window proxies here; their addition may cause windows to be opened, and we want them
728 to be opened on top of the editor window that goto_editor_window() just opened.
730 add_window_proxy (location_ui);
731 add_window_proxy (big_clock_window);
732 for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) {
733 add_window_proxy (_global_port_matrix[*i]);
736 /* We have to do this here since goto_editor_window() ends up calling show_all() on the
737 * editor window, and we may want stuff to be hidden.
739 _status_bar_visibility.update ();
741 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
745 ARDOUR_UI::no_memory_warning ()
747 XMLNode node (X_("no-memory-warning"));
748 Config->add_instant_xml (node);
752 ARDOUR_UI::check_memory_locking ()
755 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
759 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
761 if (engine->is_realtime() && memory_warning_node == 0) {
763 struct rlimit limits;
765 long pages, page_size;
767 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0) {
770 ram = (int64_t) pages * (int64_t) page_size;
773 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
777 if (limits.rlim_cur != RLIM_INFINITY) {
779 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
783 _("WARNING: Your system has a limit for maximum amount of locked memory. "
784 "This might cause %1 to run out of memory before your system "
785 "runs out of memory. \n\n"
786 "You can view the memory limit with 'ulimit -l', "
787 "and it is normally controlled by /etc/security/limits.conf"),
788 PROGRAM_NAME).c_str());
790 VBox* vbox = msg.get_vbox();
792 CheckButton cb (_("Do not show this window again"));
794 cb.signal_toggled().connect (sigc::mem_fun (*this, &ARDOUR_UI::no_memory_warning));
796 hbox.pack_start (cb, true, false);
797 vbox->pack_start (hbox);
802 pop_back_splash (msg);
804 editor->ensure_float (msg);
814 ARDOUR_UI::queue_finish ()
816 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
820 ARDOUR_UI::idle_finish ()
823 return false; /* do not call again */
832 if (_session->transport_rolling() && (++tries < 8)) {
833 _session->request_stop (false, true);
837 if (_session->dirty()) {
838 vector<string> actions;
839 actions.push_back (_("Don't quit"));
840 actions.push_back (_("Just quit"));
841 actions.push_back (_("Save and quit"));
842 switch (ask_about_saving_session(actions)) {
847 /* use the default name */
848 if (save_state_canfail ("")) {
849 /* failed - don't quit */
850 MessageDialog msg (*editor,
852 Ardour was unable to save your session.\n\n\
853 If you still wish to quit, please use the\n\n\
854 \"Just quit\" option."));
855 pop_back_splash(msg);
865 second_connection.disconnect ();
866 point_one_second_connection.disconnect ();
867 point_oh_five_second_connection.disconnect ();
868 point_zero_one_second_connection.disconnect();
871 /* Save state before deleting the session, as that causes some
872 windows to be destroyed before their visible state can be
875 save_ardour_state ();
878 // _session->set_deletion_in_progress ();
879 _session->set_clean ();
880 _session->remove_pending_capture_state ();
885 ArdourDialog::close_all_dialogs ();
891 ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
893 ArdourDialog window (_("Unsaved Session"));
894 Gtk::HBox dhbox; // the hbox for the image and text
895 Gtk::Label prompt_label;
896 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
900 assert (actions.size() >= 3);
902 window.add_button (actions[0], RESPONSE_REJECT);
903 window.add_button (actions[1], RESPONSE_APPLY);
904 window.add_button (actions[2], RESPONSE_ACCEPT);
906 window.set_default_response (RESPONSE_ACCEPT);
908 Gtk::Button noquit_button (msg);
909 noquit_button.set_name ("EditorGTKButton");
913 if (_session->snap_name() == _session->name()) {
914 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?"),
915 _session->snap_name());
917 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?"),
918 _session->snap_name());
921 prompt_label.set_text (prompt);
922 prompt_label.set_name (X_("PrompterLabel"));
923 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
925 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
926 dhbox.set_homogeneous (false);
927 dhbox.pack_start (*dimage, false, false, 5);
928 dhbox.pack_start (prompt_label, true, false, 5);
929 window.get_vbox()->pack_start (dhbox);
931 window.set_name (_("Prompter"));
932 window.set_position (Gtk::WIN_POS_MOUSE);
933 window.set_modal (true);
934 window.set_resizable (false);
940 window.set_keep_above (true);
943 ResponseType r = (ResponseType) window.run();
948 case RESPONSE_ACCEPT: // save and get out of here
950 case RESPONSE_APPLY: // get out of here
960 ARDOUR_UI::every_second ()
963 update_buffer_load ();
964 update_disk_space ();
969 ARDOUR_UI::every_point_one_seconds ()
971 shuttle_box->update_speed_display ();
972 RapidScreenUpdate(); /* EMIT_SIGNAL */
977 ARDOUR_UI::every_point_zero_one_seconds ()
979 // august 2007: actual update frequency: 40Hz, not 100Hz
981 SuperRapidScreenUpdate(); /* EMIT_SIGNAL */
986 ARDOUR_UI::update_sample_rate (framecnt_t)
990 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
992 if (!engine->connected()) {
994 snprintf (buf, sizeof (buf), _("disconnected"));
998 framecnt_t rate = engine->frame_rate();
1000 if (fmod (rate, 1000.0) != 0.0) {
1001 snprintf (buf, sizeof (buf), _("JACK: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
1002 (float) rate/1000.0f,
1003 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
1005 snprintf (buf, sizeof (buf), _("JACK: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
1007 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
1011 sample_rate_label.set_markup (buf);
1015 ARDOUR_UI::update_format ()
1018 format_label.set_text ("");
1023 s << _("File:") << X_(" <span foreground=\"green\">");
1025 switch (_session->config.get_native_file_header_format ()) {
1051 switch (_session->config.get_native_file_data_format ()) {
1065 format_label.set_markup (s.str ());
1069 ARDOUR_UI::update_cpu_load ()
1073 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1074 should also be changed.
1077 float const c = engine->get_cpu_load ();
1078 snprintf (buf, sizeof (buf), _("DSP: <span foreground=\"%s\">%5.1f%%</span>"), c >= 90 ? X_("red") : X_("green"), c);
1079 cpu_load_label.set_markup (buf);
1083 ARDOUR_UI::update_buffer_load ()
1087 uint32_t const playback = _session ? _session->playback_load () : 100;
1088 uint32_t const capture = _session ? _session->capture_load () : 100;
1090 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1091 should also be changed.
1097 _("Buffers: <span foreground=\"green\">p:</span><span foreground=\"%s\">%" PRIu32 "%%</span> "
1098 "<span foreground=\"green\">c:</span><span foreground=\"%s\">%" PRIu32 "%%</span>"),
1099 playback <= 5 ? X_("red") : X_("green"),
1101 capture <= 5 ? X_("red") : X_("green"),
1105 buffer_load_label.set_markup (buf);
1107 buffer_load_label.set_text ("");
1112 ARDOUR_UI::count_recenabled_streams (Route& route)
1114 Track* track = dynamic_cast<Track*>(&route);
1115 if (track && track->record_enabled()) {
1116 rec_enabled_streams += track->n_inputs().n_total();
1121 ARDOUR_UI::update_disk_space()
1123 if (_session == 0) {
1127 framecnt_t frames = _session->available_capture_duration();
1129 framecnt_t fr = _session->frame_rate();
1131 if (frames == max_framecnt) {
1132 snprintf (buf, sizeof (buf), _("Disk: <span foreground=\"green\">24hrs+</span>"));
1134 rec_enabled_streams = 0;
1135 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams);
1137 if (rec_enabled_streams) {
1138 frames /= rec_enabled_streams;
1145 hrs = frames / (fr * 3600);
1148 snprintf (buf, sizeof (buf), _("Disk: <span foreground=\"green\">>24 hrs</span>"));
1150 frames -= hrs * fr * 3600;
1151 mins = frames / (fr * 60);
1152 frames -= mins * fr * 60;
1155 bool const low = (hrs == 0 && mins <= 30);
1159 _("Disk: <span foreground=\"%s\">%02dh:%02dm:%02ds</span>"),
1160 low ? X_("red") : X_("green"),
1166 disk_space_label.set_markup (buf);
1168 // An attempt to make the disk space label flash red when space has run out.
1170 if (frames < fr * 60 * 5) {
1171 /* disk_space_box.style ("disk_space_label_empty"); */
1173 /* disk_space_box.style ("disk_space_label"); */
1179 ARDOUR_UI::update_wall_clock ()
1186 tm_now = localtime (&now);
1188 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1189 wall_clock_label.set_text (buf);
1195 ARDOUR_UI::session_menu (GdkEventButton */*ev*/)
1197 session_popup_menu->popup (0, 0);
1202 ARDOUR_UI::redisplay_recent_sessions ()
1204 std::vector<sys::path> session_directories;
1205 RecentSessionsSorter cmp;
1207 recent_session_display.set_model (Glib::RefPtr<TreeModel>(0));
1208 recent_session_model->clear ();
1210 ARDOUR::RecentSessions rs;
1211 ARDOUR::read_recent_sessions (rs);
1214 recent_session_display.set_model (recent_session_model);
1218 // sort them alphabetically
1219 sort (rs.begin(), rs.end(), cmp);
1221 for (ARDOUR::RecentSessions::iterator i = rs.begin(); i != rs.end(); ++i) {
1222 session_directories.push_back ((*i).second);
1225 for (vector<sys::path>::const_iterator i = session_directories.begin();
1226 i != session_directories.end(); ++i)
1228 std::vector<sys::path> state_file_paths;
1230 // now get available states for this session
1232 get_state_files_in_directory (*i, state_file_paths);
1234 vector<string*>* states;
1235 vector<const gchar*> item;
1236 string fullpath = (*i).to_string();
1238 /* remove any trailing / */
1240 if (fullpath[fullpath.length()-1] == '/') {
1241 fullpath = fullpath.substr (0, fullpath.length()-1);
1244 /* check whether session still exists */
1245 if (!Glib::file_test(fullpath.c_str(), Glib::FILE_TEST_EXISTS)) {
1246 /* session doesn't exist */
1247 cerr << "skipping non-existent session " << fullpath << endl;
1251 /* now get available states for this session */
1253 if ((states = Session::possible_states (fullpath)) == 0) {
1254 /* no state file? */
1258 std::vector<string> state_file_names(get_file_names_no_extension (state_file_paths));
1260 Gtk::TreeModel::Row row = *(recent_session_model->append());
1262 row[recent_session_columns.visible_name] = Glib::path_get_basename (fullpath);
1263 row[recent_session_columns.fullpath] = fullpath;
1265 if (state_file_names.size() > 1) {
1269 for (std::vector<std::string>::iterator i2 = state_file_names.begin();
1270 i2 != state_file_names.end(); ++i2)
1273 Gtk::TreeModel::Row child_row = *(recent_session_model->append (row.children()));
1275 child_row[recent_session_columns.visible_name] = *i2;
1276 child_row[recent_session_columns.fullpath] = fullpath;
1281 recent_session_display.set_model (recent_session_model);
1285 ARDOUR_UI::build_session_selector ()
1287 session_selector_window = new ArdourDialog (_("Recent Sessions"));
1289 Gtk::ScrolledWindow *scroller = manage (new Gtk::ScrolledWindow);
1291 session_selector_window->add_button (Stock::CANCEL, RESPONSE_CANCEL);
1292 session_selector_window->add_button (Stock::OPEN, RESPONSE_ACCEPT);
1293 session_selector_window->set_default_response (RESPONSE_ACCEPT);
1294 recent_session_model = TreeStore::create (recent_session_columns);
1295 recent_session_display.set_model (recent_session_model);
1296 recent_session_display.append_column (_("Recent Sessions"), recent_session_columns.visible_name);
1297 recent_session_display.set_headers_visible (false);
1298 recent_session_display.get_selection()->set_mode (SELECTION_BROWSE);
1299 recent_session_display.signal_row_activated().connect (sigc::mem_fun (*this, &ARDOUR_UI::recent_session_row_activated));
1301 scroller->add (recent_session_display);
1302 scroller->set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
1304 session_selector_window->set_name ("SessionSelectorWindow");
1305 session_selector_window->set_size_request (200, 400);
1306 session_selector_window->get_vbox()->pack_start (*scroller);
1308 recent_session_display.show();
1310 //session_selector_window->get_vbox()->show();
1314 ARDOUR_UI::recent_session_row_activated (const TreePath& /*path*/, TreeViewColumn* /*col*/)
1316 session_selector_window->response (RESPONSE_ACCEPT);
1320 ARDOUR_UI::open_recent_session ()
1322 bool can_return = (_session != 0);
1324 if (session_selector_window == 0) {
1325 build_session_selector ();
1328 redisplay_recent_sessions ();
1332 session_selector_window->set_position (WIN_POS_MOUSE);
1334 ResponseType r = (ResponseType) session_selector_window->run ();
1337 case RESPONSE_ACCEPT:
1341 session_selector_window->hide();
1348 if (recent_session_display.get_selection()->count_selected_rows() == 0) {
1352 session_selector_window->hide();
1354 Gtk::TreeModel::iterator i = recent_session_display.get_selection()->get_selected();
1356 if (i == recent_session_model->children().end()) {
1360 std::string path = (*i)[recent_session_columns.fullpath];
1361 std::string state = (*i)[recent_session_columns.visible_name];
1363 _session_is_new = false;
1365 if (load_session (path, state) == 0) {
1374 ARDOUR_UI::check_audioengine ()
1377 if (!engine->connected()) {
1378 MessageDialog msg (string_compose (
1379 _("%1 is not connected to JACK\n"
1380 "You cannot open or close sessions in this condition"),
1382 pop_back_splash (msg);
1393 ARDOUR_UI::open_session ()
1395 if (!check_audioengine()) {
1400 /* popup selector window */
1402 if (open_session_selector == 0) {
1404 /* ardour sessions are folders */
1406 open_session_selector = new Gtk::FileChooserDialog (_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1407 open_session_selector->add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1408 open_session_selector->add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1409 open_session_selector->set_default_response(Gtk::RESPONSE_ACCEPT);
1411 FileFilter session_filter;
1412 session_filter.add_pattern ("*.ardour");
1413 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1414 open_session_selector->add_filter (session_filter);
1415 open_session_selector->set_filter (session_filter);
1418 int response = open_session_selector->run();
1419 open_session_selector->hide ();
1422 case RESPONSE_ACCEPT:
1425 open_session_selector->hide();
1429 open_session_selector->hide();
1430 string session_path = open_session_selector->get_filename();
1434 if (session_path.length() > 0) {
1435 if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1436 _session_is_new = isnew;
1437 load_session (path, name);
1444 ARDOUR_UI::session_add_midi_route (bool disk, RouteGroup* route_group, uint32_t how_many, const string& name_template, PluginInfoPtr instrument)
1446 list<boost::shared_ptr<MidiTrack> > tracks;
1448 if (_session == 0) {
1449 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1456 tracks = _session->new_midi_track (instrument, ARDOUR::Normal, route_group, how_many, name_template);
1458 if (tracks.size() != how_many) {
1459 if (how_many == 1) {
1460 error << _("could not create a new midi track") << endmsg;
1462 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));
1536 pop_back_splash (msg);
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 () && !Config->get_always_play_range()) {
1733 /* stop playing a range if we currently are */
1734 _session->request_play_range (0, true);
1737 if (Config->get_always_play_range()) {
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 (Config->get_always_play_range ()) {
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 (Config->get_always_play_range()) {
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);
2073 pop_back_splash (msg);
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);
2460 pop_back_splash (msg);
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)
2564 if (ARDOUR_COMMAND_LINE::no_splash) {
2570 splash->message (msg);
2575 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
2577 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
2579 string session_name;
2580 string session_path;
2581 string template_name;
2583 bool likely_new = false;
2585 if (!load_template.empty()) {
2586 should_be_new = true;
2587 template_name = load_template;
2592 if (!should_be_new && !ARDOUR_COMMAND_LINE::session_name.empty()) {
2594 /* if they named a specific statefile, use it, otherwise they are
2595 just giving a session folder, and we want to use it as is
2596 to find the session.
2599 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
2601 if (suffix != string::npos) {
2602 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
2603 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
2604 session_name = Glib::path_get_basename (session_name);
2606 session_path = ARDOUR_COMMAND_LINE::session_name;
2607 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
2612 bool const apply = run_startup (should_be_new, load_template);
2615 if (quit_on_cancel) {
2622 /* if we run the startup dialog again, offer more than just "new session" */
2624 should_be_new = false;
2626 session_name = _startup->session_name (likely_new);
2628 string::size_type suffix = session_name.find (statefile_suffix);
2630 if (suffix != string::npos) {
2631 session_name = session_name.substr (0, suffix);
2634 /* this shouldn't happen, but we catch it just in case it does */
2636 if (session_name.empty()) {
2640 if (_startup->use_session_template()) {
2641 template_name = _startup->session_template_name();
2642 _session_is_new = true;
2645 if (session_name[0] == G_DIR_SEPARATOR ||
2646 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
2647 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)) {
2649 /* absolute path or cwd-relative path specified for session name: infer session folder
2650 from what was given.
2653 session_path = Glib::path_get_dirname (session_name);
2654 session_name = Glib::path_get_basename (session_name);
2658 session_path = _startup->session_folder();
2660 char illegal = Session::session_name_is_legal (session_name);
2663 MessageDialog msg (*_startup,
2664 string_compose (_("To ensure compatibility with various systems\n"
2665 "session names may not contain a '%1' character"),
2668 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2674 if (create_engine ()) {
2678 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
2682 std::string existing = Glib::build_filename (session_path, session_name);
2684 if (!ask_about_loading_existing_session (existing)) {
2685 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2690 _session_is_new = false;
2695 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
2697 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2701 if (session_name.find ('/') != std::string::npos) {
2702 MessageDialog msg (*_startup,
2703 _("To ensure compatibility with various systems\n"
2704 "session names may not contain a '/' character"));
2706 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2710 if (session_name.find ('\\') != std::string::npos) {
2711 MessageDialog msg (*_startup,
2712 _("To ensure compatibility with various systems\n"
2713 "session names may not contain a '\\' character"));
2715 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2719 _session_is_new = true;
2722 if (likely_new && template_name.empty()) {
2724 ret = build_session_from_nsd (session_path, session_name);
2728 ret = load_session (session_path, session_name, template_name);
2731 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
2735 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
2736 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
2746 ARDOUR_UI::close_session()
2748 if (!check_audioengine()) {
2752 if (unload_session (true)) {
2756 ARDOUR_COMMAND_LINE::session_name = "";
2758 if (get_session_parameters (true, false)) {
2762 goto_editor_window ();
2765 /** @param snap_name Snapshot name (without .ardour suffix).
2766 * @return -2 if the load failed because we are not connected to the AudioEngine.
2769 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
2771 Session *new_session;
2775 session_loaded = false;
2777 if (!check_audioengine()) {
2781 unload_status = unload_session ();
2783 if (unload_status < 0) {
2785 } else if (unload_status > 0) {
2790 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
2793 new_session = new Session (*engine, path, snap_name, 0, mix_template);
2796 /* this one is special */
2798 catch (AudioEngine::PortRegistrationFailure& err) {
2800 MessageDialog msg (err.what(),
2803 Gtk::BUTTONS_CLOSE);
2805 msg.set_title (_("Port Registration Error"));
2806 msg.set_secondary_text (_("Click the Close button to try again."));
2807 msg.set_position (Gtk::WIN_POS_CENTER);
2808 pop_back_splash (msg);
2811 int response = msg.run ();
2816 case RESPONSE_CANCEL:
2826 MessageDialog msg (string_compose(
2827 _("Session \"%1 (snapshot %2)\" did not load successfully"),
2833 msg.set_title (_("Loading Error"));
2834 msg.set_secondary_text (_("Click the Refresh button to try again."));
2835 msg.add_button (Stock::REFRESH, 1);
2836 msg.set_position (Gtk::WIN_POS_CENTER);
2837 pop_back_splash (msg);
2840 int response = msg.run ();
2855 list<string> const u = new_session->unknown_processors ();
2857 MissingPluginDialog d (_session, u);
2862 /* Now the session been created, add the transport controls */
2863 new_session->add_controllable(roll_controllable);
2864 new_session->add_controllable(stop_controllable);
2865 new_session->add_controllable(goto_start_controllable);
2866 new_session->add_controllable(goto_end_controllable);
2867 new_session->add_controllable(auto_loop_controllable);
2868 new_session->add_controllable(play_selection_controllable);
2869 new_session->add_controllable(rec_controllable);
2871 set_session (new_session);
2873 session_loaded = true;
2875 goto_editor_window ();
2878 _session->set_clean ();
2889 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
2891 Session *new_session;
2894 if (!check_audioengine()) {
2898 session_loaded = false;
2900 x = unload_session ();
2908 _session_is_new = true;
2911 new_session = new Session (*engine, path, snap_name, &bus_profile);
2916 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
2917 pop_back_splash (msg);
2922 /* Give the new session the default GUI state, if such things exist */
2925 n = Config->instant_xml (X_("Editor"));
2927 new_session->add_instant_xml (*n, false);
2929 n = Config->instant_xml (X_("Mixer"));
2931 new_session->add_instant_xml (*n, false);
2934 /* Put the playhead at 0 and scroll fully left */
2935 n = new_session->instant_xml (X_("Editor"));
2937 n->add_property (X_("playhead"), X_("0"));
2938 n->add_property (X_("left-frame"), X_("0"));
2941 set_session (new_session);
2943 session_loaded = true;
2945 new_session->save_state(new_session->name());
2951 ARDOUR_UI::launch_chat ()
2954 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
2956 open_uri("http://webchat.freenode.net/?channels=ardour");
2961 ARDOUR_UI::show_about ()
2965 about->signal_response().connect(sigc::mem_fun (*this, &ARDOUR_UI::about_signal_response) );
2968 about->set_transient_for(*editor);
2973 ARDOUR_UI::launch_manual ()
2975 PBD::open_uri("http://ardour.org/flossmanual");
2979 ARDOUR_UI::launch_reference ()
2981 PBD::open_uri("http://ardour.org/refmanual");
2985 ARDOUR_UI::hide_about ()
2988 about->get_window()->set_cursor ();
2994 ARDOUR_UI::about_signal_response (int /*response*/)
3000 ARDOUR_UI::show_splash ()
3004 splash = new Splash;
3006 cerr << "Splash could not be created\n";
3012 splash->pop_front ();
3013 splash->queue_draw ();
3014 splash->get_window()->process_updates (true);
3019 ARDOUR_UI::hide_splash ()
3027 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title,
3028 const string& plural_msg, const string& singular_msg)
3032 removed = rep.paths.size();
3035 MessageDialog msgd (*editor,
3036 _("No files were ready for clean-up"),
3040 msgd.set_title (_("Clean-up"));
3041 msgd.set_secondary_text (_("If this seems suprising, \n\
3042 check for any existing snapshots.\n\
3043 These may still include regions that\n\
3044 require some unused files to continue to exist."));
3050 ArdourDialog results (_("Clean-up"), true, false);
3052 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
3053 CleanupResultsModelColumns() {
3057 Gtk::TreeModelColumn<std::string> visible_name;
3058 Gtk::TreeModelColumn<std::string> fullpath;
3062 CleanupResultsModelColumns results_columns;
3063 Glib::RefPtr<Gtk::ListStore> results_model;
3064 Gtk::TreeView results_display;
3066 results_model = ListStore::create (results_columns);
3067 results_display.set_model (results_model);
3068 results_display.append_column (list_title, results_columns.visible_name);
3070 results_display.set_name ("CleanupResultsList");
3071 results_display.set_headers_visible (true);
3072 results_display.set_headers_clickable (false);
3073 results_display.set_reorderable (false);
3075 Gtk::ScrolledWindow list_scroller;
3078 Gtk::HBox dhbox; // the hbox for the image and text
3079 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
3080 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
3082 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
3084 const string dead_directory = _session->session_directory().dead_path().to_string();
3087 %1 - number of files removed
3088 %2 - location of "dead"
3089 %3 - size of files affected
3090 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
3093 const char* bprefix;
3094 double space_adjusted = 0;
3096 if (rep.space < 1000) {
3098 space_adjusted = rep.space;
3099 } else if (rep.space < 1000000) {
3100 bprefix = X_("kilo");
3101 space_adjusted = truncf((float)rep.space / 1000.0);
3102 } else if (rep.space < 1000000 * 1000) {
3103 bprefix = X_("mega");
3104 space_adjusted = truncf((float)rep.space / (1000.0 * 1000.0));
3106 bprefix = X_("giga");
3107 space_adjusted = truncf((float)rep.space / (1000.0 * 1000 * 1000.0));
3111 txt.set_text (string_compose (plural_msg, removed, dead_directory, space_adjusted, bprefix));
3113 txt.set_text (string_compose (singular_msg, removed, dead_directory, space_adjusted, bprefix));
3116 dhbox.pack_start (*dimage, true, false, 5);
3117 dhbox.pack_start (txt, true, false, 5);
3119 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
3120 TreeModel::Row row = *(results_model->append());
3121 row[results_columns.visible_name] = *i;
3122 row[results_columns.fullpath] = *i;
3125 list_scroller.add (results_display);
3126 list_scroller.set_size_request (-1, 150);
3127 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
3129 dvbox.pack_start (dhbox, true, false, 5);
3130 dvbox.pack_start (list_scroller, true, false, 5);
3131 ddhbox.pack_start (dvbox, true, false, 5);
3133 results.get_vbox()->pack_start (ddhbox, true, false, 5);
3134 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
3135 results.set_default_response (RESPONSE_CLOSE);
3136 results.set_position (Gtk::WIN_POS_MOUSE);
3138 results_display.show();
3139 list_scroller.show();
3146 //results.get_vbox()->show();
3147 results.set_resizable (false);
3154 ARDOUR_UI::cleanup ()
3156 if (_session == 0) {
3157 /* shouldn't happen: menu item is insensitive */
3162 MessageDialog checker (_("Are you sure you want to clean-up?"),
3164 Gtk::MESSAGE_QUESTION,
3167 checker.set_title (_("Clean-up"));
3169 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
3170 ALL undo/redo information will be lost if you clean-up.\n\
3171 Clean-up will move all unused files to a \"dead\" location."));
3173 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3174 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
3175 checker.set_default_response (RESPONSE_CANCEL);
3177 checker.set_name (_("CleanupDialog"));
3178 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3179 checker.set_position (Gtk::WIN_POS_MOUSE);
3181 switch (checker.run()) {
3182 case RESPONSE_ACCEPT:
3188 ARDOUR::CleanupReport rep;
3190 editor->prepare_for_cleanup ();
3192 /* do not allow flush until a session is reloaded */
3194 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3196 act->set_sensitive (false);
3199 if (_session->cleanup_sources (rep)) {
3200 editor->finish_cleanup ();
3204 editor->finish_cleanup ();
3207 display_cleanup_results (rep,
3210 The following %1 files were not in use and \n\
3211 have been moved to:\n\n\
3213 After a restart of Ardour,\n\n\
3214 Session -> Clean-up -> Flush Wastebasket\n\n\
3215 will release an additional\n\
3216 %3 %4bytes of disk space.\n"),
3218 The following file was not in use and \n\
3219 has been moved to:\n \
3221 After a restart of Ardour,\n\n\
3222 Session -> Clean-up -> Flush Wastebasket\n\n\
3223 will release an additional\n\
3224 %3 %4bytes of disk space.\n"
3230 ARDOUR_UI::flush_trash ()
3232 if (_session == 0) {
3233 /* shouldn't happen: menu item is insensitive */
3237 ARDOUR::CleanupReport rep;
3239 if (_session->cleanup_trash_sources (rep)) {
3243 display_cleanup_results (rep,
3245 _("The following %1 files were deleted from\n\
3247 releasing %3 %4bytes of disk space"),
3248 _("The following file was deleted from\n\
3250 releasing %3 %4bytes of disk space"));
3254 ARDOUR_UI::add_route (Gtk::Window* float_window)
3262 if (add_route_dialog == 0) {
3263 add_route_dialog = new AddRouteDialog (_session);
3264 add_route_dialog->set_position (WIN_POS_MOUSE);
3266 add_route_dialog->set_transient_for (*float_window);
3270 if (add_route_dialog->is_visible()) {
3271 /* we're already doing this */
3275 ResponseType r = (ResponseType) add_route_dialog->run ();
3277 add_route_dialog->hide();
3280 case RESPONSE_ACCEPT:
3287 if ((count = add_route_dialog->count()) <= 0) {
3291 string template_path = add_route_dialog->track_template();
3293 if (!template_path.empty()) {
3294 _session->new_route_from_template (count, template_path);
3298 uint32_t input_chan = add_route_dialog->channels ();
3299 uint32_t output_chan;
3300 string name_template = add_route_dialog->name_template ();
3301 PluginInfoPtr instrument = add_route_dialog->requested_instrument ();
3302 RouteGroup* route_group = add_route_dialog->route_group ();
3304 AutoConnectOption oac = Config->get_output_auto_connect();
3306 if (oac & AutoConnectMaster) {
3307 output_chan = (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan);
3309 output_chan = input_chan;
3312 /* XXX do something with name template */
3314 if (add_route_dialog->midi_tracks_wanted()) {
3315 session_add_midi_track (route_group, count, name_template, instrument);
3316 } else if (add_route_dialog->audio_tracks_wanted()) {
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);
3324 ARDOUR_UI::mixer_settings () const
3329 node = _session->instant_xml(X_("Mixer"));
3331 node = Config->instant_xml(X_("Mixer"));
3335 node = new XMLNode (X_("Mixer"));
3342 ARDOUR_UI::editor_settings () const
3347 node = _session->instant_xml(X_("Editor"));
3349 node = Config->instant_xml(X_("Editor"));
3353 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
3354 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
3359 node = new XMLNode (X_("Editor"));
3366 ARDOUR_UI::keyboard_settings () const
3370 node = Config->extra_xml(X_("Keyboard"));
3373 node = new XMLNode (X_("Keyboard"));
3380 ARDOUR_UI::create_xrun_marker (framepos_t where)
3382 editor->mouse_add_new_marker (where, false, true);
3386 ARDOUR_UI::halt_on_xrun_message ()
3388 MessageDialog msg (*editor,
3389 _("Recording was stopped because your system could not keep up."));
3394 ARDOUR_UI::xrun_handler (framepos_t where)
3400 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
3402 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
3403 create_xrun_marker(where);
3406 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
3407 halt_on_xrun_message ();
3412 ARDOUR_UI::disk_overrun_handler ()
3414 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
3416 if (!have_disk_speed_dialog_displayed) {
3417 have_disk_speed_dialog_displayed = true;
3418 MessageDialog* msg = new MessageDialog (*editor, string_compose (_("\
3419 The disk system on your computer\n\
3420 was not able to keep up with %1.\n\
3422 Specifically, it failed to write data to disk\n\
3423 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
3424 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3430 ARDOUR_UI::disk_underrun_handler ()
3432 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
3434 if (!have_disk_speed_dialog_displayed) {
3435 have_disk_speed_dialog_displayed = true;
3436 MessageDialog* msg = new MessageDialog (
3437 *editor, string_compose (_("The disk system on your computer\n\
3438 was not able to keep up with %1.\n\
3440 Specifically, it failed to read data from disk\n\
3441 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
3442 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3448 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
3450 have_disk_speed_dialog_displayed = false;
3455 ARDOUR_UI::session_dialog (std::string msg)
3457 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
3462 d = new MessageDialog (*editor, msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3464 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3473 ARDOUR_UI::pending_state_dialog ()
3475 HBox* hbox = new HBox();
3476 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3477 ArdourDialog dialog (_("Crash Recovery"), true);
3479 This session appears to have been in\n\
3480 middle of recording when ardour or\n\
3481 the computer was shutdown.\n\
3483 Ardour can recover any captured audio for\n\
3484 you, or it can ignore it. Please decide\n\
3485 what you would like to do.\n"));
3486 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3487 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3488 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3489 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3490 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
3491 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
3492 dialog.set_default_response (RESPONSE_ACCEPT);
3493 dialog.set_position (WIN_POS_CENTER);
3498 switch (dialog.run ()) {
3499 case RESPONSE_ACCEPT:
3507 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
3509 HBox* hbox = new HBox();
3510 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3511 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
3512 Label message (string_compose (_("\
3513 This session was created with a sample rate of %1 Hz\n\
3515 The audioengine is currently running at %2 Hz\n"), desired, actual));
3517 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3518 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3519 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3520 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3521 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
3522 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
3523 dialog.set_default_response (RESPONSE_ACCEPT);
3524 dialog.set_position (WIN_POS_CENTER);
3529 switch (dialog.run ()) {
3530 case RESPONSE_ACCEPT:
3539 ARDOUR_UI::disconnect_from_jack ()
3542 if( engine->disconnect_from_jack ()) {
3543 MessageDialog msg (*editor, _("Could not disconnect from JACK"));
3547 update_sample_rate (0);
3552 ARDOUR_UI::reconnect_to_jack ()
3555 if (engine->reconnect_to_jack ()) {
3556 MessageDialog msg (*editor, _("Could not reconnect to JACK"));
3560 update_sample_rate (0);
3565 ARDOUR_UI::use_config ()
3567 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
3569 set_transport_controllable_state (*node);
3574 ARDOUR_UI::update_transport_clocks (framepos_t pos)
3576 if (Config->get_primary_clock_delta_edit_cursor()) {
3577 primary_clock->set (pos, false, editor->get_preferred_edit_position());
3579 primary_clock->set (pos);
3582 if (Config->get_secondary_clock_delta_edit_cursor()) {
3583 secondary_clock->set (pos, false, editor->get_preferred_edit_position());
3585 secondary_clock->set (pos);
3588 if (big_clock_window->get()) {
3589 big_clock->set (pos);
3595 ARDOUR_UI::step_edit_status_change (bool yn)
3597 // XXX should really store pre-step edit status of things
3598 // we make insensitive
3601 rec_button.set_active_state (Mid);
3602 rec_button.set_sensitive (false);
3604 rec_button.unset_active_state ();;
3605 rec_button.set_sensitive (true);
3610 ARDOUR_UI::record_state_changed ()
3612 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
3614 if (!_session || !big_clock_window->get()) {
3615 /* why bother - the clock isn't visible */
3619 if (_session->record_status () == Session::Recording && _session->have_rec_enabled_track ()) {
3620 big_clock->set_active (true);
3622 big_clock->set_active (false);
3627 ARDOUR_UI::first_idle ()
3630 _session->allow_auto_play (true);
3634 editor->first_idle();
3637 Keyboard::set_can_save_keybindings (true);
3642 ARDOUR_UI::store_clock_modes ()
3644 XMLNode* node = new XMLNode(X_("ClockModes"));
3646 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
3647 XMLNode* child = new XMLNode (X_("Clock"));
3649 child->add_property (X_("name"), (*x)->name());
3650 child->add_property (X_("mode"), enum_2_string ((*x)->mode()));
3651 child->add_property (X_("on"), ((*x)->off() ? X_("no") : X_("yes")));
3653 node->add_child_nocopy (*child);
3656 _session->add_extra_xml (*node);
3657 _session->set_dirty ();
3660 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
3661 : Controllable (name), ui (u), type(tp)
3667 ARDOUR_UI::TransportControllable::set_value (double val)
3670 /* do nothing: these are radio-style actions */
3674 const char *action = 0;
3678 action = X_("Roll");
3681 action = X_("Stop");
3684 action = X_("Goto Start");
3687 action = X_("Goto End");
3690 action = X_("Loop");
3693 action = X_("Play Selection");
3696 action = X_("Record");
3706 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
3714 ARDOUR_UI::TransportControllable::get_value (void) const
3741 ARDOUR_UI::setup_profile ()
3743 if (gdk_screen_width() < 1200) {
3744 Profile->set_small_screen ();
3748 if (getenv ("ARDOUR_SAE")) {
3749 Profile->set_sae ();
3750 Profile->set_single_package ();
3755 ARDOUR_UI::toggle_translations ()
3757 using namespace Glib;
3759 RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("EnableTranslation"));
3761 RefPtr<ToggleAction> ract = RefPtr<ToggleAction>::cast_dynamic (act);
3764 string i18n_killer = ARDOUR::translation_kill_path();
3766 bool already_enabled = !ARDOUR::translations_are_disabled ();
3768 if (ract->get_active ()) {
3769 /* we don't care about errors */
3770 int fd = ::open (i18n_killer.c_str(), O_RDONLY|O_CREAT, 0644);
3773 /* we don't care about errors */
3774 unlink (i18n_killer.c_str());
3777 if (already_enabled != ract->get_active()) {
3778 MessageDialog win (already_enabled ? _("Translations disabled") : _("Translations enabled"),
3780 Gtk::MESSAGE_WARNING,
3782 win.set_secondary_text (string_compose (_("You must restart %1 for this to take effect."), PROGRAM_NAME));
3783 win.set_position (Gtk::WIN_POS_CENTER);
3791 /** Add a window proxy to our list, so that its state will be saved.
3792 * This call also causes the window to be created and opened if its
3793 * state was saved as `visible'.
3796 ARDOUR_UI::add_window_proxy (WindowProxyBase* p)
3798 _window_proxies.push_back (p);
3802 /** Remove a window proxy from our list. Must be called if a WindowProxy
3803 * is deleted, to prevent hanging pointers.
3806 ARDOUR_UI::remove_window_proxy (WindowProxyBase* p)
3808 _window_proxies.remove (p);
3812 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
3814 MissingFileDialog dialog (s, str, type);
3819 int result = dialog.run ();
3826 return 1; // quit entire session load
3829 result = dialog.get_action ();
3835 ARDOUR_UI::ambiguous_file (std::string file, std::string /*path*/, std::vector<std::string> hits)
3837 AmbiguousFileDialog dialog (file, hits);
3843 return dialog.get_which ();
3846 /** Allocate our thread-local buffers */
3848 ARDOUR_UI::get_process_buffers ()
3850 _process_thread->get_buffers ();
3853 /** Drop our thread-local buffers */
3855 ARDOUR_UI::drop_process_buffers ()
3857 _process_thread->drop_buffers ();
3861 ARDOUR_UI::feedback_detected ()
3863 _feedback_exists = true;
3867 ARDOUR_UI::successful_graph_sort ()
3869 _feedback_exists = false;
3873 ARDOUR_UI::midi_panic ()
3876 _session->midi_panic();