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, string const & name_template)
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 (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;
1466 if ((route = _session->new_midi_route ()) == 0) {
1467 error << _("could not create new midi bus") << endmsg;
1473 MessageDialog msg (*editor,
1474 string_compose (_("There are insufficient JACK ports available\n\
1475 to create a new track or bus.\n\
1476 You should save %1, exit and\n\
1477 restart JACK with more ports."), PROGRAM_NAME));
1484 ARDOUR_UI::session_add_audio_route (
1486 int32_t input_channels,
1487 int32_t output_channels,
1488 ARDOUR::TrackMode mode,
1489 RouteGroup* route_group,
1491 string const & name_template
1494 list<boost::shared_ptr<AudioTrack> > tracks;
1497 if (_session == 0) {
1498 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1504 tracks = _session->new_audio_track (input_channels, output_channels, mode, route_group, how_many, name_template);
1506 if (tracks.size() != how_many) {
1507 if (how_many == 1) {
1508 error << _("could not create a new audio track") << endmsg;
1510 error << string_compose (_("could only create %1 of %2 new audio %3"),
1511 tracks.size(), how_many, (track ? _("tracks") : _("busses"))) << endmsg;
1517 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template);
1519 if (routes.size() != how_many) {
1520 if (how_many == 1) {
1521 error << _("could not create a new audio bus") << endmsg;
1523 error << string_compose (_("could not create %1 new audio busses"), how_many) << endmsg;
1530 MessageDialog msg (*editor,
1531 string_compose (_("There are insufficient JACK ports available\n\
1532 to create a new track or bus.\n\
1533 You should save %1, exit and\n\
1534 restart JACK with more ports."), PROGRAM_NAME));
1535 pop_back_splash (msg);
1541 ARDOUR_UI::do_transport_locate (framepos_t new_position, bool with_roll)
1543 framecnt_t _preroll = 0;
1546 // XXX CONFIG_CHANGE FIX - requires AnyTime handling
1547 // _preroll = _session->convert_to_frames_at (new_position, Config->get_preroll());
1549 if (new_position > _preroll) {
1550 new_position -= _preroll;
1555 _session->request_locate (new_position, with_roll);
1560 ARDOUR_UI::transport_goto_start ()
1563 _session->goto_start();
1565 /* force displayed area in editor to start no matter
1566 what "follow playhead" setting is.
1570 editor->center_screen (_session->current_start_frame ());
1576 ARDOUR_UI::transport_goto_zero ()
1579 _session->request_locate (0);
1581 /* force displayed area in editor to start no matter
1582 what "follow playhead" setting is.
1586 editor->reset_x_origin (0);
1592 ARDOUR_UI::transport_goto_wallclock ()
1594 if (_session && editor) {
1601 localtime_r (&now, &tmnow);
1603 frames = tmnow.tm_hour * (60 * 60 * _session->frame_rate());
1604 frames += tmnow.tm_min * (60 * _session->frame_rate());
1605 frames += tmnow.tm_sec * _session->frame_rate();
1607 _session->request_locate (frames, _session->transport_rolling ());
1609 /* force displayed area in editor to start no matter
1610 what "follow playhead" setting is.
1614 editor->center_screen (frames);
1620 ARDOUR_UI::transport_goto_end ()
1623 framepos_t const frame = _session->current_end_frame();
1624 _session->request_locate (frame);
1626 /* force displayed area in editor to start no matter
1627 what "follow playhead" setting is.
1631 editor->center_screen (frame);
1637 ARDOUR_UI::transport_stop ()
1643 if (_session->is_auditioning()) {
1644 _session->cancel_audition ();
1648 _session->request_stop (false, true);
1652 ARDOUR_UI::transport_stop_and_forget_capture ()
1655 _session->request_stop (true, true);
1660 ARDOUR_UI::remove_last_capture()
1663 editor->remove_last_capture();
1668 ARDOUR_UI::transport_record (bool roll)
1672 switch (_session->record_status()) {
1673 case Session::Disabled:
1674 if (_session->ntracks() == 0) {
1675 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."));
1679 _session->maybe_enable_record ();
1684 case Session::Recording:
1686 _session->request_stop();
1688 _session->disable_record (false, true);
1692 case Session::Enabled:
1693 _session->disable_record (false, true);
1696 //cerr << "ARDOUR_UI::transport_record () called roll = " << roll << " _session->record_status() = " << _session->record_status() << endl;
1700 ARDOUR_UI::transport_roll ()
1706 if (_session->is_auditioning()) {
1711 if (_session->config.get_external_sync()) {
1712 switch (_session->config.get_sync_source()) {
1716 /* transport controlled by the master */
1722 bool rolling = _session->transport_rolling();
1724 if (_session->get_play_loop()) {
1725 /* XXX it is not possible to just leave seamless loop and keep
1726 playing at present (nov 4th 2009)
1728 if (!Config->get_seamless_loop()) {
1729 _session->request_play_loop (false, true);
1731 } else if (_session->get_play_range () && !join_play_range_button.active_state()) {
1732 /* stop playing a range if we currently are */
1733 _session->request_play_range (0, true);
1736 if (join_play_range_button.active_state()) {
1737 _session->request_play_range (&editor->get_selection().time, true);
1741 _session->request_transport_speed (1.0f);
1746 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
1753 if (_session->is_auditioning()) {
1754 _session->cancel_audition ();
1758 if (_session->config.get_external_sync()) {
1759 switch (_session->config.get_sync_source()) {
1763 /* transport controlled by the master */
1768 bool rolling = _session->transport_rolling();
1769 bool affect_transport = true;
1771 if (rolling && roll_out_of_bounded_mode) {
1772 /* drop out of loop/range playback but leave transport rolling */
1773 if (_session->get_play_loop()) {
1774 if (Config->get_seamless_loop()) {
1775 /* the disk buffers contain copies of the loop - we can't
1776 just keep playing, so stop the transport. the user
1777 can restart as they wish.
1779 affect_transport = true;
1781 /* disk buffers are normal, so we can keep playing */
1782 affect_transport = false;
1784 _session->request_play_loop (false, true);
1785 } else if (_session->get_play_range ()) {
1786 affect_transport = false;
1787 _session->request_play_range (0, true);
1791 if (affect_transport) {
1793 _session->request_stop (with_abort, true);
1795 if (join_play_range_button.active_state()) {
1796 _session->request_play_range (&editor->get_selection().time, true);
1799 _session->request_transport_speed (1.0f);
1805 ARDOUR_UI::toggle_session_auto_loop ()
1811 if (_session->get_play_loop()) {
1813 if (_session->transport_rolling()) {
1815 Location * looploc = _session->locations()->auto_loop_location();
1818 _session->request_locate (looploc->start(), true);
1819 _session->request_play_loop (false);
1823 _session->request_play_loop (false);
1827 Location * looploc = _session->locations()->auto_loop_location();
1830 _session->request_play_loop (true);
1836 ARDOUR_UI::transport_play_selection ()
1842 editor->play_selection ();
1846 ARDOUR_UI::transport_rewind (int option)
1848 float current_transport_speed;
1851 current_transport_speed = _session->transport_speed();
1853 if (current_transport_speed >= 0.0f) {
1856 _session->request_transport_speed (-1.0f);
1859 _session->request_transport_speed (-4.0f);
1862 _session->request_transport_speed (-0.5f);
1867 _session->request_transport_speed (current_transport_speed * 1.5f);
1873 ARDOUR_UI::transport_forward (int option)
1875 float current_transport_speed;
1878 current_transport_speed = _session->transport_speed();
1880 if (current_transport_speed <= 0.0f) {
1883 _session->request_transport_speed (1.0f);
1886 _session->request_transport_speed (4.0f);
1889 _session->request_transport_speed (0.5f);
1894 _session->request_transport_speed (current_transport_speed * 1.5f);
1901 ARDOUR_UI::toggle_record_enable (uint32_t rid)
1903 if (_session == 0) {
1907 boost::shared_ptr<Route> r;
1909 if ((r = _session->route_by_remote_id (rid)) != 0) {
1913 if ((t = dynamic_cast<Track*>(r.get())) != 0) {
1914 t->set_record_enabled (!t->record_enabled(), this);
1917 if (_session == 0) {
1923 ARDOUR_UI::map_transport_state ()
1926 auto_loop_button.unset_active_state ();
1927 play_selection_button.unset_active_state ();
1928 roll_button.unset_active_state ();
1929 stop_button.set_active_state (Gtkmm2ext::Active);
1933 shuttle_box->map_transport_state ();
1935 float sp = _session->transport_speed();
1941 if (_session->get_play_range()) {
1943 play_selection_button.set_active_state (Gtkmm2ext::Active);
1944 roll_button.unset_active_state ();
1945 auto_loop_button.unset_active_state ();
1947 } else if (_session->get_play_loop ()) {
1949 auto_loop_button.set_active_state (Gtkmm2ext::Active);
1950 play_selection_button.unset_active_state ();
1951 roll_button.unset_active_state ();
1955 roll_button.set_active_state (Gtkmm2ext::Active);
1956 play_selection_button.unset_active_state ();
1957 auto_loop_button.unset_active_state ();
1960 if (join_play_range_button.active_state()) {
1961 /* light up both roll and play-selection if they are joined */
1962 roll_button.set_active_state (Gtkmm2ext::Active);
1963 play_selection_button.set_active_state (Gtkmm2ext::Active);
1966 stop_button.unset_active_state ();
1970 stop_button.set_active_state (Gtkmm2ext::Active);
1971 roll_button.unset_active_state ();
1972 play_selection_button.unset_active_state ();
1973 auto_loop_button.unset_active_state ();
1974 update_disk_space ();
1979 ARDOUR_UI::engine_stopped ()
1981 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
1982 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1983 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1987 ARDOUR_UI::engine_running ()
1989 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
1990 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, true);
1991 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, false);
1993 Glib::RefPtr<Action> action;
1994 const char* action_name = 0;
1996 switch (engine->frames_per_cycle()) {
1998 action_name = X_("JACKLatency32");
2001 action_name = X_("JACKLatency64");
2004 action_name = X_("JACKLatency128");
2007 action_name = X_("JACKLatency512");
2010 action_name = X_("JACKLatency1024");
2013 action_name = X_("JACKLatency2048");
2016 action_name = X_("JACKLatency4096");
2019 action_name = X_("JACKLatency8192");
2022 /* XXX can we do anything useful ? */
2028 action = ActionManager::get_action (X_("JACK"), action_name);
2031 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (action);
2032 ract->set_active ();
2038 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
2040 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
2041 /* we can't rely on the original string continuing to exist when we are called
2042 again in the GUI thread, so make a copy and note that we need to
2045 char *copy = strdup (reason);
2046 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
2050 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
2051 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
2053 update_sample_rate (0);
2057 /* if the reason is a non-empty string, it means that the backend was shutdown
2058 rather than just Ardour.
2061 if (strlen (reason)) {
2062 msgstr = string_compose (_("The audio backend (JACK) was shutdown because:\n\n%1"), reason);
2064 msgstr = string_compose (_("\
2065 JACK has either been shutdown or it\n\
2066 disconnected %1 because %1\n\
2067 was not fast enough. Try to restart\n\
2068 JACK, reconnect and save the session."), PROGRAM_NAME);
2071 MessageDialog msg (*editor, msgstr);
2072 pop_back_splash (msg);
2076 free ((char*) reason);
2081 ARDOUR_UI::do_engine_start ()
2089 error << _("Unable to start the session running")
2099 ARDOUR_UI::setup_theme ()
2101 theme_manager->setup_theme();
2105 ARDOUR_UI::update_clocks ()
2107 if (!editor || !editor->dragging_playhead()) {
2108 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position()); /* EMIT_SIGNAL */
2113 ARDOUR_UI::start_clocking ()
2115 clock_signal_connection = RapidScreenUpdate.connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2119 ARDOUR_UI::stop_clocking ()
2121 clock_signal_connection.disconnect ();
2125 ARDOUR_UI::toggle_clocking ()
2128 if (clock_button.get_active()) {
2137 ARDOUR_UI::_blink (void *arg)
2140 ((ARDOUR_UI *) arg)->blink ();
2147 Blink (blink_on = !blink_on); /* EMIT_SIGNAL */
2151 ARDOUR_UI::start_blinking ()
2153 /* Start the blink signal. Everybody with a blinking widget
2154 uses Blink to drive the widget's state.
2157 if (blink_timeout_tag < 0) {
2159 blink_timeout_tag = g_timeout_add (240, _blink, this);
2164 ARDOUR_UI::stop_blinking ()
2166 if (blink_timeout_tag >= 0) {
2167 g_source_remove (blink_timeout_tag);
2168 blink_timeout_tag = -1;
2173 /** Ask the user for the name of a new snapshot and then take it.
2177 ARDOUR_UI::snapshot_session (bool switch_to_it)
2179 ArdourPrompter prompter (true);
2182 prompter.set_name ("Prompter");
2183 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2184 prompter.set_title (_("Take Snapshot"));
2185 prompter.set_prompt (_("Name of new snapshot"));
2187 if (!switch_to_it) {
2190 struct tm local_time;
2193 localtime_r (&n, &local_time);
2194 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2195 prompter.set_initial_text (timebuf);
2199 switch (prompter.run()) {
2200 case RESPONSE_ACCEPT:
2202 prompter.get_result (snapname);
2204 bool do_save = (snapname.length() != 0);
2207 char illegal = Session::session_name_is_legal(snapname);
2209 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2210 "snapshot names may not contain a '%1' character"), illegal));
2216 vector<sys::path> p;
2217 get_state_files_in_directory (_session->session_directory().root_path(), p);
2218 vector<string> n = get_file_names_no_extension (p);
2219 if (find (n.begin(), n.end(), snapname) != n.end()) {
2221 ArdourDialog confirm (_("Confirm Snapshot Overwrite"), true);
2222 Label m (_("A snapshot already exists with that name. Do you want to overwrite it?"));
2223 confirm.get_vbox()->pack_start (m, true, true);
2224 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2225 confirm.add_button (_("Overwrite"), Gtk::RESPONSE_ACCEPT);
2226 confirm.show_all ();
2227 switch (confirm.run()) {
2228 case RESPONSE_CANCEL:
2234 save_state (snapname, switch_to_it);
2244 /** Ask the user for a new session name and then rename the session to it.
2248 ARDOUR_UI::rename_session ()
2254 ArdourPrompter prompter (true);
2257 prompter.set_name ("Prompter");
2258 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2259 prompter.set_title (_("Rename Session"));
2260 prompter.set_prompt (_("New session name"));
2263 switch (prompter.run()) {
2264 case RESPONSE_ACCEPT:
2266 prompter.get_result (name);
2268 bool do_rename = (name.length() != 0);
2271 char illegal = Session::session_name_is_legal (name);
2274 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2275 "session names may not contain a '%1' character"), illegal));
2280 switch (_session->rename (name)) {
2282 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
2283 msg.set_position (WIN_POS_MOUSE);
2291 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
2292 msg.set_position (WIN_POS_MOUSE);
2308 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2310 XMLNode* node = new XMLNode (X_("UI"));
2312 for (list<WindowProxyBase*>::iterator i = _window_proxies.begin(); i != _window_proxies.end(); ++i) {
2313 if (!(*i)->rc_configured()) {
2314 node->add_child_nocopy (*((*i)->get_state ()));
2318 node->add_child_nocopy (gui_object_state->get_state());
2320 _session->add_extra_xml (*node);
2322 save_state_canfail (name, switch_to_it);
2326 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2331 if (name.length() == 0) {
2332 name = _session->snap_name();
2335 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2340 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2345 ARDOUR_UI::primary_clock_value_changed ()
2348 _session->request_locate (primary_clock->current_time ());
2353 ARDOUR_UI::big_clock_value_changed ()
2356 _session->request_locate (big_clock->current_time ());
2361 ARDOUR_UI::secondary_clock_value_changed ()
2364 _session->request_locate (secondary_clock->current_time ());
2369 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2371 if (_session == 0) {
2375 if (_session->step_editing()) {
2379 Session::RecordState const r = _session->record_status ();
2380 bool const h = _session->have_rec_enabled_track ();
2382 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2384 rec_button.set_active_state (Active);
2386 rec_button.set_active_state (Mid);
2388 } else if (r == Session::Recording && h) {
2389 rec_button.set_active_state (Mid);
2391 rec_button.unset_active_state ();
2396 ARDOUR_UI::save_template ()
2398 ArdourPrompter prompter (true);
2401 if (!check_audioengine()) {
2405 prompter.set_name (X_("Prompter"));
2406 prompter.set_title (_("Save Template"));
2407 prompter.set_prompt (_("Name for template:"));
2408 prompter.set_initial_text(_session->name() + _("-template"));
2409 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2411 switch (prompter.run()) {
2412 case RESPONSE_ACCEPT:
2413 prompter.get_result (name);
2415 if (name.length()) {
2416 _session->save_template (name);
2426 ARDOUR_UI::edit_metadata ()
2428 SessionMetadataEditor dialog;
2429 dialog.set_session (_session);
2430 editor->ensure_float (dialog);
2435 ARDOUR_UI::import_metadata ()
2437 SessionMetadataImporter dialog;
2438 dialog.set_session (_session);
2439 editor->ensure_float (dialog);
2444 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
2446 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2448 MessageDialog msg (str,
2450 Gtk::MESSAGE_WARNING,
2451 Gtk::BUTTONS_YES_NO,
2455 msg.set_name (X_("OpenExistingDialog"));
2456 msg.set_title (_("Open Existing Session"));
2457 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
2458 msg.set_position (Gtk::WIN_POS_MOUSE);
2459 pop_back_splash (msg);
2461 switch (msg.run()) {
2470 ARDOUR_UI::build_session_from_nsd (const std::string& session_path, const std::string& session_name)
2472 BusProfile bus_profile;
2474 if (Profile->get_sae()) {
2476 bus_profile.master_out_channels = 2;
2477 bus_profile.input_ac = AutoConnectPhysical;
2478 bus_profile.output_ac = AutoConnectMaster;
2479 bus_profile.requested_physical_in = 0; // use all available
2480 bus_profile.requested_physical_out = 0; // use all available
2484 /* get settings from advanced section of NSD */
2486 if (_startup->create_master_bus()) {
2487 bus_profile.master_out_channels = (uint32_t) _startup->master_channel_count();
2489 bus_profile.master_out_channels = 0;
2492 if (_startup->connect_inputs()) {
2493 bus_profile.input_ac = AutoConnectPhysical;
2495 bus_profile.input_ac = AutoConnectOption (0);
2498 bus_profile.output_ac = AutoConnectOption (0);
2500 if (_startup->connect_outputs ()) {
2501 if (_startup->connect_outs_to_master()) {
2502 bus_profile.output_ac = AutoConnectMaster;
2503 } else if (_startup->connect_outs_to_physical()) {
2504 bus_profile.output_ac = AutoConnectPhysical;
2508 bus_profile.requested_physical_in = (uint32_t) _startup->input_limit_count();
2509 bus_profile.requested_physical_out = (uint32_t) _startup->output_limit_count();
2512 if (build_session (session_path, session_name, bus_profile)) {
2520 ARDOUR_UI::idle_load (const std::string& path)
2523 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2524 /* /path/to/foo => /path/to/foo, foo */
2525 load_session (path, basename_nosuffix (path));
2527 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2528 load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2532 ARDOUR_COMMAND_LINE::session_name = path;
2535 * new_session_dialog doens't exist in A3
2536 * Try to remove all references to it to
2537 * see if it will compile. NOTE: this will
2538 * likely cause a runtime issue is my somewhat
2542 //if (new_session_dialog) {
2545 /* make it break out of Dialog::run() and
2549 //new_session_dialog->response (1);
2555 ARDOUR_UI::end_loading_messages ()
2561 ARDOUR_UI::loading_message (const std::string& msg)
2563 if (ARDOUR_COMMAND_LINE::no_splash) {
2569 splash->message (msg);
2574 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
2576 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
2578 string session_name;
2579 string session_path;
2580 string template_name;
2582 bool likely_new = false;
2584 if (!load_template.empty()) {
2585 should_be_new = true;
2586 template_name = load_template;
2591 if (!should_be_new && !ARDOUR_COMMAND_LINE::session_name.empty()) {
2593 /* if they named a specific statefile, use it, otherwise they are
2594 just giving a session folder, and we want to use it as is
2595 to find the session.
2598 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
2600 if (suffix != string::npos) {
2601 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
2602 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
2603 session_name = Glib::path_get_basename (session_name);
2605 session_path = ARDOUR_COMMAND_LINE::session_name;
2606 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
2611 bool const apply = run_startup (should_be_new, load_template);
2614 if (quit_on_cancel) {
2621 /* if we run the startup dialog again, offer more than just "new session" */
2623 should_be_new = false;
2625 session_name = _startup->session_name (likely_new);
2627 string::size_type suffix = session_name.find (statefile_suffix);
2629 if (suffix != string::npos) {
2630 session_name = session_name.substr (0, suffix);
2633 /* this shouldn't happen, but we catch it just in case it does */
2635 if (session_name.empty()) {
2639 if (_startup->use_session_template()) {
2640 template_name = _startup->session_template_name();
2641 _session_is_new = true;
2644 if (session_name[0] == G_DIR_SEPARATOR ||
2645 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
2646 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)) {
2648 /* absolute path or cwd-relative path specified for session name: infer session folder
2649 from what was given.
2652 session_path = Glib::path_get_dirname (session_name);
2653 session_name = Glib::path_get_basename (session_name);
2657 session_path = _startup->session_folder();
2659 char illegal = Session::session_name_is_legal (session_name);
2662 MessageDialog msg (*_startup,
2663 string_compose (_("To ensure compatibility with various systems\n"
2664 "session names may not contain a '%1' character"),
2667 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2673 if (create_engine ()) {
2677 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
2681 std::string existing = Glib::build_filename (session_path, session_name);
2683 if (!ask_about_loading_existing_session (existing)) {
2684 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2689 _session_is_new = false;
2694 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
2696 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2700 if (session_name.find ('/') != std::string::npos) {
2701 MessageDialog msg (*_startup,
2702 _("To ensure compatibility with various systems\n"
2703 "session names may not contain a '/' character"));
2705 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2709 if (session_name.find ('\\') != std::string::npos) {
2710 MessageDialog msg (*_startup,
2711 _("To ensure compatibility with various systems\n"
2712 "session names may not contain a '\\' character"));
2714 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2718 _session_is_new = true;
2721 if (likely_new && template_name.empty()) {
2723 ret = build_session_from_nsd (session_path, session_name);
2727 ret = load_session (session_path, session_name, template_name);
2730 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
2734 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
2735 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
2745 ARDOUR_UI::close_session()
2747 if (!check_audioengine()) {
2751 if (unload_session (true)) {
2755 ARDOUR_COMMAND_LINE::session_name = "";
2757 if (get_session_parameters (true, false)) {
2761 goto_editor_window ();
2764 /** @param snap_name Snapshot name (without .ardour suffix).
2765 * @return -2 if the load failed because we are not connected to the AudioEngine.
2768 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
2770 Session *new_session;
2774 session_loaded = false;
2776 if (!check_audioengine()) {
2780 unload_status = unload_session ();
2782 if (unload_status < 0) {
2784 } else if (unload_status > 0) {
2789 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
2792 new_session = new Session (*engine, path, snap_name, 0, mix_template);
2795 /* this one is special */
2797 catch (AudioEngine::PortRegistrationFailure& err) {
2799 MessageDialog msg (err.what(),
2802 Gtk::BUTTONS_CLOSE);
2804 msg.set_title (_("Port Registration Error"));
2805 msg.set_secondary_text (_("Click the Close button to try again."));
2806 msg.set_position (Gtk::WIN_POS_CENTER);
2807 pop_back_splash (msg);
2810 int response = msg.run ();
2815 case RESPONSE_CANCEL:
2825 MessageDialog msg (string_compose(
2826 _("Session \"%1 (snapshot %2)\" did not load successfully"),
2832 msg.set_title (_("Loading Error"));
2833 msg.set_secondary_text (_("Click the Refresh button to try again."));
2834 msg.add_button (Stock::REFRESH, 1);
2835 msg.set_position (Gtk::WIN_POS_CENTER);
2836 pop_back_splash (msg);
2839 int response = msg.run ();
2854 list<string> const u = new_session->unknown_processors ();
2856 MissingPluginDialog d (_session, u);
2861 /* Now the session been created, add the transport controls */
2862 new_session->add_controllable(roll_controllable);
2863 new_session->add_controllable(stop_controllable);
2864 new_session->add_controllable(goto_start_controllable);
2865 new_session->add_controllable(goto_end_controllable);
2866 new_session->add_controllable(auto_loop_controllable);
2867 new_session->add_controllable(play_selection_controllable);
2868 new_session->add_controllable(rec_controllable);
2870 set_session (new_session);
2872 session_loaded = true;
2874 goto_editor_window ();
2877 _session->set_clean ();
2888 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
2890 Session *new_session;
2893 if (!check_audioengine()) {
2897 session_loaded = false;
2899 x = unload_session ();
2907 _session_is_new = true;
2910 new_session = new Session (*engine, path, snap_name, &bus_profile);
2915 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
2916 pop_back_splash (msg);
2921 /* Give the new session the default GUI state, if such things exist */
2924 n = Config->instant_xml (X_("Editor"));
2926 new_session->add_instant_xml (*n, false);
2928 n = Config->instant_xml (X_("Mixer"));
2930 new_session->add_instant_xml (*n, false);
2933 /* Put the playhead at 0 and scroll fully left */
2934 n = new_session->instant_xml (X_("Editor"));
2936 n->add_property (X_("playhead"), X_("0"));
2937 n->add_property (X_("left-frame"), X_("0"));
2940 set_session (new_session);
2942 session_loaded = true;
2944 new_session->save_state(new_session->name());
2950 ARDOUR_UI::launch_chat ()
2953 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
2955 open_uri("http://webchat.freenode.net/?channels=ardour");
2960 ARDOUR_UI::show_about ()
2964 about->signal_response().connect(sigc::mem_fun (*this, &ARDOUR_UI::about_signal_response) );
2967 about->set_transient_for(*editor);
2972 ARDOUR_UI::launch_manual ()
2974 PBD::open_uri("http://ardour.org/flossmanual");
2978 ARDOUR_UI::launch_reference ()
2980 PBD::open_uri("http://ardour.org/refmanual");
2984 ARDOUR_UI::hide_about ()
2987 about->get_window()->set_cursor ();
2993 ARDOUR_UI::about_signal_response (int /*response*/)
2999 ARDOUR_UI::show_splash ()
3003 splash = new Splash;
3005 cerr << "Splash could not be created\n";
3011 splash->pop_front ();
3012 splash->queue_draw ();
3013 splash->get_window()->process_updates (true);
3018 ARDOUR_UI::hide_splash ()
3026 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title,
3027 const string& plural_msg, const string& singular_msg)
3031 removed = rep.paths.size();
3034 MessageDialog msgd (*editor,
3035 _("No files were ready for clean-up"),
3039 msgd.set_title (_("Clean-up"));
3040 msgd.set_secondary_text (_("If this seems suprising, \n\
3041 check for any existing snapshots.\n\
3042 These may still include regions that\n\
3043 require some unused files to continue to exist."));
3049 ArdourDialog results (_("Clean-up"), true, false);
3051 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
3052 CleanupResultsModelColumns() {
3056 Gtk::TreeModelColumn<std::string> visible_name;
3057 Gtk::TreeModelColumn<std::string> fullpath;
3061 CleanupResultsModelColumns results_columns;
3062 Glib::RefPtr<Gtk::ListStore> results_model;
3063 Gtk::TreeView results_display;
3065 results_model = ListStore::create (results_columns);
3066 results_display.set_model (results_model);
3067 results_display.append_column (list_title, results_columns.visible_name);
3069 results_display.set_name ("CleanupResultsList");
3070 results_display.set_headers_visible (true);
3071 results_display.set_headers_clickable (false);
3072 results_display.set_reorderable (false);
3074 Gtk::ScrolledWindow list_scroller;
3077 Gtk::HBox dhbox; // the hbox for the image and text
3078 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
3079 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
3081 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
3083 const string dead_directory = _session->session_directory().dead_path().to_string();
3086 %1 - number of files removed
3087 %2 - location of "dead"
3088 %3 - size of files affected
3089 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
3092 const char* bprefix;
3093 double space_adjusted = 0;
3095 if (rep.space < 1000) {
3097 space_adjusted = rep.space;
3098 } else if (rep.space < 1000000) {
3099 bprefix = X_("kilo");
3100 space_adjusted = truncf((float)rep.space / 1000.0);
3101 } else if (rep.space < 1000000 * 1000) {
3102 bprefix = X_("mega");
3103 space_adjusted = truncf((float)rep.space / (1000.0 * 1000.0));
3105 bprefix = X_("giga");
3106 space_adjusted = truncf((float)rep.space / (1000.0 * 1000 * 1000.0));
3110 txt.set_text (string_compose (plural_msg, removed, dead_directory, space_adjusted, bprefix));
3112 txt.set_text (string_compose (singular_msg, removed, dead_directory, space_adjusted, bprefix));
3115 dhbox.pack_start (*dimage, true, false, 5);
3116 dhbox.pack_start (txt, true, false, 5);
3118 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
3119 TreeModel::Row row = *(results_model->append());
3120 row[results_columns.visible_name] = *i;
3121 row[results_columns.fullpath] = *i;
3124 list_scroller.add (results_display);
3125 list_scroller.set_size_request (-1, 150);
3126 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
3128 dvbox.pack_start (dhbox, true, false, 5);
3129 dvbox.pack_start (list_scroller, true, false, 5);
3130 ddhbox.pack_start (dvbox, true, false, 5);
3132 results.get_vbox()->pack_start (ddhbox, true, false, 5);
3133 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
3134 results.set_default_response (RESPONSE_CLOSE);
3135 results.set_position (Gtk::WIN_POS_MOUSE);
3137 results_display.show();
3138 list_scroller.show();
3145 //results.get_vbox()->show();
3146 results.set_resizable (false);
3153 ARDOUR_UI::cleanup ()
3155 if (_session == 0) {
3156 /* shouldn't happen: menu item is insensitive */
3161 MessageDialog checker (_("Are you sure you want to clean-up?"),
3163 Gtk::MESSAGE_QUESTION,
3166 checker.set_title (_("Clean-up"));
3168 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
3169 ALL undo/redo information will be lost if you clean-up.\n\
3170 Clean-up will move all unused files to a \"dead\" location."));
3172 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3173 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
3174 checker.set_default_response (RESPONSE_CANCEL);
3176 checker.set_name (_("CleanupDialog"));
3177 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3178 checker.set_position (Gtk::WIN_POS_MOUSE);
3180 switch (checker.run()) {
3181 case RESPONSE_ACCEPT:
3187 ARDOUR::CleanupReport rep;
3189 editor->prepare_for_cleanup ();
3191 /* do not allow flush until a session is reloaded */
3193 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3195 act->set_sensitive (false);
3198 if (_session->cleanup_sources (rep)) {
3199 editor->finish_cleanup ();
3203 editor->finish_cleanup ();
3206 display_cleanup_results (rep,
3209 The following %1 files were not in use and \n\
3210 have been moved to:\n\n\
3212 After a restart of Ardour,\n\n\
3213 Session -> Clean-up -> Flush Wastebasket\n\n\
3214 will release an additional\n\
3215 %3 %4bytes of disk space.\n"),
3217 The following file was not in use and \n\
3218 has been moved to:\n \
3220 After a restart of Ardour,\n\n\
3221 Session -> Clean-up -> Flush Wastebasket\n\n\
3222 will release an additional\n\
3223 %3 %4bytes of disk space.\n"
3229 ARDOUR_UI::flush_trash ()
3231 if (_session == 0) {
3232 /* shouldn't happen: menu item is insensitive */
3236 ARDOUR::CleanupReport rep;
3238 if (_session->cleanup_trash_sources (rep)) {
3242 display_cleanup_results (rep,
3244 _("The following %1 files were deleted from\n\
3246 releasing %3 %4bytes of disk space"),
3247 _("The following file was deleted from\n\
3249 releasing %3 %4bytes of disk space"));
3253 ARDOUR_UI::add_route (Gtk::Window* float_window)
3261 if (add_route_dialog == 0) {
3262 add_route_dialog = new AddRouteDialog (_session);
3263 add_route_dialog->set_position (WIN_POS_MOUSE);
3265 add_route_dialog->set_transient_for (*float_window);
3269 if (add_route_dialog->is_visible()) {
3270 /* we're already doing this */
3274 ResponseType r = (ResponseType) add_route_dialog->run ();
3276 add_route_dialog->hide();
3279 case RESPONSE_ACCEPT:
3286 if ((count = add_route_dialog->count()) <= 0) {
3290 string template_path = add_route_dialog->track_template();
3292 if (!template_path.empty()) {
3293 _session->new_route_from_template (count, template_path);
3297 uint32_t input_chan = add_route_dialog->channels ();
3298 uint32_t output_chan;
3299 string name_template = add_route_dialog->name_template ();
3300 RouteGroup* route_group = add_route_dialog->route_group ();
3302 AutoConnectOption oac = Config->get_output_auto_connect();
3304 if (oac & AutoConnectMaster) {
3305 output_chan = (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan);
3307 output_chan = input_chan;
3310 /* XXX do something with name template */
3312 if (add_route_dialog->midi_tracks_wanted()) {
3313 session_add_midi_track (route_group, count, name_template);
3314 } else if (add_route_dialog->audio_tracks_wanted()) {
3315 session_add_audio_track (input_chan, output_chan, add_route_dialog->mode(), route_group, count, name_template);
3317 session_add_audio_bus (input_chan, output_chan, route_group, count, name_template);
3322 ARDOUR_UI::mixer_settings () const
3327 node = _session->instant_xml(X_("Mixer"));
3329 node = Config->instant_xml(X_("Mixer"));
3333 node = new XMLNode (X_("Mixer"));
3340 ARDOUR_UI::editor_settings () const
3345 node = _session->instant_xml(X_("Editor"));
3347 node = Config->instant_xml(X_("Editor"));
3351 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
3352 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
3357 node = new XMLNode (X_("Editor"));
3364 ARDOUR_UI::keyboard_settings () const
3368 node = Config->extra_xml(X_("Keyboard"));
3371 node = new XMLNode (X_("Keyboard"));
3378 ARDOUR_UI::create_xrun_marker (framepos_t where)
3380 editor->mouse_add_new_marker (where, false, true);
3384 ARDOUR_UI::halt_on_xrun_message ()
3386 MessageDialog msg (*editor,
3387 _("Recording was stopped because your system could not keep up."));
3392 ARDOUR_UI::xrun_handler (framepos_t where)
3398 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
3400 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
3401 create_xrun_marker(where);
3404 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
3405 halt_on_xrun_message ();
3410 ARDOUR_UI::disk_overrun_handler ()
3412 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
3414 if (!have_disk_speed_dialog_displayed) {
3415 have_disk_speed_dialog_displayed = true;
3416 MessageDialog* msg = new MessageDialog (*editor, string_compose (_("\
3417 The disk system on your computer\n\
3418 was not able to keep up with %1.\n\
3420 Specifically, it failed to write data to disk\n\
3421 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
3422 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3428 ARDOUR_UI::disk_underrun_handler ()
3430 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
3432 if (!have_disk_speed_dialog_displayed) {
3433 have_disk_speed_dialog_displayed = true;
3434 MessageDialog* msg = new MessageDialog (
3435 *editor, string_compose (_("The disk system on your computer\n\
3436 was not able to keep up with %1.\n\
3438 Specifically, it failed to read data from disk\n\
3439 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
3440 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3446 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
3448 have_disk_speed_dialog_displayed = false;
3453 ARDOUR_UI::session_dialog (std::string msg)
3455 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
3460 d = new MessageDialog (*editor, msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3462 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3471 ARDOUR_UI::pending_state_dialog ()
3473 HBox* hbox = new HBox();
3474 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3475 ArdourDialog dialog (_("Crash Recovery"), true);
3477 This session appears to have been in\n\
3478 middle of recording when ardour or\n\
3479 the computer was shutdown.\n\
3481 Ardour can recover any captured audio for\n\
3482 you, or it can ignore it. Please decide\n\
3483 what you would like to do.\n"));
3484 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3485 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3486 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3487 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3488 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
3489 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
3490 dialog.set_default_response (RESPONSE_ACCEPT);
3491 dialog.set_position (WIN_POS_CENTER);
3496 switch (dialog.run ()) {
3497 case RESPONSE_ACCEPT:
3505 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
3507 HBox* hbox = new HBox();
3508 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3509 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
3510 Label message (string_compose (_("\
3511 This session was created with a sample rate of %1 Hz\n\
3513 The audioengine is currently running at %2 Hz\n"), desired, actual));
3515 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3516 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3517 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3518 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3519 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
3520 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
3521 dialog.set_default_response (RESPONSE_ACCEPT);
3522 dialog.set_position (WIN_POS_CENTER);
3527 switch (dialog.run ()) {
3528 case RESPONSE_ACCEPT:
3537 ARDOUR_UI::disconnect_from_jack ()
3540 if( engine->disconnect_from_jack ()) {
3541 MessageDialog msg (*editor, _("Could not disconnect from JACK"));
3545 update_sample_rate (0);
3550 ARDOUR_UI::reconnect_to_jack ()
3553 if (engine->reconnect_to_jack ()) {
3554 MessageDialog msg (*editor, _("Could not reconnect to JACK"));
3558 update_sample_rate (0);
3563 ARDOUR_UI::use_config ()
3565 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
3567 set_transport_controllable_state (*node);
3572 ARDOUR_UI::update_transport_clocks (framepos_t pos)
3574 if (Config->get_primary_clock_delta_edit_cursor()) {
3575 primary_clock->set (pos, false, editor->get_preferred_edit_position());
3577 primary_clock->set (pos);
3580 if (Config->get_secondary_clock_delta_edit_cursor()) {
3581 secondary_clock->set (pos, false, editor->get_preferred_edit_position());
3583 secondary_clock->set (pos);
3586 if (big_clock_window->get()) {
3587 big_clock->set (pos);
3593 ARDOUR_UI::step_edit_status_change (bool yn)
3595 // XXX should really store pre-step edit status of things
3596 // we make insensitive
3599 rec_button.set_active_state (Mid);
3600 rec_button.set_sensitive (false);
3602 rec_button.unset_active_state ();;
3603 rec_button.set_sensitive (true);
3608 ARDOUR_UI::record_state_changed ()
3610 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
3612 if (!_session || !big_clock_window->get()) {
3613 /* why bother - the clock isn't visible */
3617 if (_session->record_status () == Session::Recording && _session->have_rec_enabled_track ()) {
3618 big_clock->set_active (true);
3620 big_clock->set_active (false);
3625 ARDOUR_UI::first_idle ()
3628 _session->allow_auto_play (true);
3632 editor->first_idle();
3635 Keyboard::set_can_save_keybindings (true);
3640 ARDOUR_UI::store_clock_modes ()
3642 XMLNode* node = new XMLNode(X_("ClockModes"));
3644 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
3645 XMLNode* child = new XMLNode (X_("Clock"));
3647 child->add_property (X_("name"), (*x)->name());
3648 child->add_property (X_("mode"), enum_2_string ((*x)->mode()));
3649 child->add_property (X_("on"), ((*x)->off() ? X_("no") : X_("yes")));
3651 node->add_child_nocopy (*child);
3654 _session->add_extra_xml (*node);
3655 _session->set_dirty ();
3658 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
3659 : Controllable (name), ui (u), type(tp)
3665 ARDOUR_UI::TransportControllable::set_value (double val)
3668 /* do nothing: these are radio-style actions */
3672 const char *action = 0;
3676 action = X_("Roll");
3679 action = X_("Stop");
3682 action = X_("Goto Start");
3685 action = X_("Goto End");
3688 action = X_("Loop");
3691 action = X_("Play Selection");
3694 action = X_("Record");
3704 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
3712 ARDOUR_UI::TransportControllable::get_value (void) const
3739 ARDOUR_UI::setup_profile ()
3741 if (gdk_screen_width() < 1200) {
3742 Profile->set_small_screen ();
3746 if (getenv ("ARDOUR_SAE")) {
3747 Profile->set_sae ();
3748 Profile->set_single_package ();
3753 ARDOUR_UI::toggle_translations ()
3755 using namespace Glib;
3757 RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("EnableTranslation"));
3759 RefPtr<ToggleAction> ract = RefPtr<ToggleAction>::cast_dynamic (act);
3762 string i18n_killer = ARDOUR::translation_kill_path();
3764 bool already_enabled = !ARDOUR::translations_are_disabled ();
3766 if (ract->get_active ()) {
3767 /* we don't care about errors */
3768 int fd = ::open (i18n_killer.c_str(), O_RDONLY|O_CREAT, 0644);
3771 /* we don't care about errors */
3772 unlink (i18n_killer.c_str());
3775 if (already_enabled != ract->get_active()) {
3776 MessageDialog win (already_enabled ? _("Translations disabled") : _("Translations enabled"),
3778 Gtk::MESSAGE_WARNING,
3780 win.set_secondary_text (string_compose (_("You must restart %1 for this to take effect."), PROGRAM_NAME));
3781 win.set_position (Gtk::WIN_POS_CENTER);
3789 /** Add a window proxy to our list, so that its state will be saved.
3790 * This call also causes the window to be created and opened if its
3791 * state was saved as `visible'.
3794 ARDOUR_UI::add_window_proxy (WindowProxyBase* p)
3796 _window_proxies.push_back (p);
3800 /** Remove a window proxy from our list. Must be called if a WindowProxy
3801 * is deleted, to prevent hanging pointers.
3804 ARDOUR_UI::remove_window_proxy (WindowProxyBase* p)
3806 _window_proxies.remove (p);
3810 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
3812 MissingFileDialog dialog (s, str, type);
3817 int result = dialog.run ();
3824 return 1; // quit entire session load
3827 result = dialog.get_action ();
3833 ARDOUR_UI::ambiguous_file (std::string file, std::string /*path*/, std::vector<std::string> hits)
3835 AmbiguousFileDialog dialog (file, hits);
3841 return dialog.get_which ();
3844 /** Allocate our thread-local buffers */
3846 ARDOUR_UI::get_process_buffers ()
3848 _process_thread->get_buffers ();
3851 /** Drop our thread-local buffers */
3853 ARDOUR_UI::drop_process_buffers ()
3855 _process_thread->drop_buffers ();
3859 ARDOUR_UI::feedback_detected ()
3861 _feedback_exists = true;
3865 ARDOUR_UI::successful_graph_sort ()
3867 _feedback_exists = false;
3871 ARDOUR_UI::midi_panic ()
3874 _session->midi_panic();