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_elements (ArdourButton::Element (ArdourButton::Body|ArdourButton::Text));
225 play_selection_button.set_elements (ArdourButton::Element (ArdourButton::Body|ArdourButton::Text));
227 roll_button.set_controllable (roll_controllable);
228 stop_button.set_controllable (stop_controllable);
229 goto_start_button.set_controllable (goto_start_controllable);
230 goto_end_button.set_controllable (goto_end_controllable);
231 auto_loop_button.set_controllable (auto_loop_controllable);
232 play_selection_button.set_controllable (play_selection_controllable);
233 rec_button.set_controllable (rec_controllable);
235 roll_button.set_name ("transport button");
236 stop_button.set_name ("transport button");
237 goto_start_button.set_name ("transport button");
238 goto_end_button.set_name ("transport button");
239 auto_loop_button.set_name ("transport button");
240 play_selection_button.set_name ("transport button");
241 rec_button.set_name ("transport recenable button");
242 midi_panic_button.set_name ("transport button");
244 goto_start_button.set_tweaks (ArdourButton::ShowClick);
245 goto_end_button.set_tweaks (ArdourButton::ShowClick);
246 midi_panic_button.set_tweaks (ArdourButton::ShowClick);
248 last_configure_time= 0;
251 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
252 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
254 /* handle dialog requests */
256 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
258 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
260 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
262 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
264 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
266 /* handle requests to quit (coming from JACK session) */
268 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::finish, this), gui_context ());
270 /* tell the user about feedback */
272 ARDOUR::Session::FeedbackDetected.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::feedback_detected, this), gui_context ());
273 ARDOUR::Session::SuccessfulGraphSort.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::successful_graph_sort, this), gui_context ());
275 /* handle requests to deal with missing files */
277 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
279 /* and ambiguous files */
281 ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2, _3));
283 /* lets get this party started */
286 if (ARDOUR::init (ARDOUR_COMMAND_LINE::use_vst, ARDOUR_COMMAND_LINE::try_hw_optimization)) {
287 throw failed_constructor ();
290 setup_gtk_ardour_enums ();
293 GainMeter::setup_slider_pix ();
294 RouteTimeAxisView::setup_slider_pix ();
295 ProcessorEntry::setup_slider_pix ();
296 SessionEvent::create_per_thread_pool ("GUI", 512);
298 } catch (failed_constructor& err) {
299 error << string_compose (_("could not initialize %1."), PROGRAM_NAME) << endmsg;
304 /* we like keyboards */
306 keyboard = new ArdourKeyboard(*this);
308 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
310 keyboard->set_state (*node, Stateful::loading_state_version);
313 /* we don't like certain modifiers */
314 Bindings::set_ignored_state (GDK_LOCK_MASK|GDK_MOD2_MASK|GDK_MOD3_MASK);
318 TimeAxisViewItem::set_constant_heights ();
320 /* The following must happen after ARDOUR::init() so that Config is set up */
322 location_ui = new ActionWindowProxy<LocationUIWindow> (X_("locations"), Config->extra_xml (X_("UI")), X_("ToggleLocations"));
323 big_clock_window = new ActionWindowProxy<Gtk::Window> (X_("bigclock"), Config->extra_xml (X_("UI")), X_("ToggleBigClock"));
324 speaker_config_window = new ActionWindowProxy<SpeakerDialog> (X_("speakerconf"), Config->extra_xml (X_("UI")), X_("toggle-speaker-config"));
326 for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) {
327 _global_port_matrix[*i] = new ActionWindowProxy<GlobalPortMatrixWindow> (
328 string_compose ("GlobalPortMatrix-%1", (*i).to_string()),
329 Config->extra_xml (X_("UI")),
330 string_compose ("toggle-%1-connection-manager", (*i).to_string())
336 SpeakerDialog* s = new SpeakerDialog ();
337 s->signal_unmap().connect (sigc::bind (sigc::ptr_fun (&ActionManager::uncheck_toggleaction), X_("<Actions>/Common/toggle-speaker-config")));
338 speaker_config_window->set (s);
340 starting.connect (sigc::mem_fun(*this, &ARDOUR_UI::startup));
341 stopping.connect (sigc::mem_fun(*this, &ARDOUR_UI::shutdown));
343 _process_thread = new ProcessThread ();
344 _process_thread->init ();
346 DPIReset.connect (sigc::mem_fun (*this, &ARDOUR_UI::resize_text_widgets));
349 /** @return true if a session was chosen and `apply' clicked, otherwise false if `cancel' was clicked */
351 ARDOUR_UI::run_startup (bool should_be_new, string load_template)
354 _startup = new ArdourStartup ();
356 XMLNode* audio_setup = Config->extra_xml ("AudioSetup");
358 if (audio_setup && _startup->engine_control()) {
359 _startup->engine_control()->set_state (*audio_setup);
362 _startup->set_new_only (should_be_new);
363 if (!load_template.empty()) {
364 _startup->set_load_template( load_template );
366 _startup->present ();
372 switch (_startup->response()) {
381 ARDOUR_UI::create_engine ()
383 // this gets called every time by new_session()
389 loading_message (_("Starting audio engine"));
392 engine = new ARDOUR::AudioEngine (ARDOUR_COMMAND_LINE::jack_client_name, ARDOUR_COMMAND_LINE::jack_session_uuid);
399 engine->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
400 engine->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
401 engine->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
403 engine->Halted.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
405 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
413 ARDOUR_UI::post_engine ()
415 /* Things to be done once we create the AudioEngine
418 ARDOUR::init_post_engine ();
420 /* load up the UI manager */
422 ActionManager::init ();
426 if (setup_windows ()) {
427 throw failed_constructor ();
430 /* Do this after setup_windows (), as that's when the _status_bar_visibility is created */
431 XMLNode* n = Config->extra_xml (X_("UI"));
433 _status_bar_visibility.set_state (*n);
436 check_memory_locking();
438 /* this is the first point at which all the keybindings are available */
440 if (ARDOUR_COMMAND_LINE::show_key_actions) {
441 vector<string> names;
442 vector<string> paths;
443 vector<string> tooltips;
445 vector<AccelKey> bindings;
447 ActionManager::get_all_actions (names, paths, tooltips, keys, bindings);
449 vector<string>::iterator n;
450 vector<string>::iterator k;
451 for (n = names.begin(), k = keys.begin(); n != names.end(); ++n, ++k) {
452 cerr << "Action: " << (*n) << " bound to " << (*k) << endl;
458 blink_timeout_tag = -1;
460 /* this being a GUI and all, we want peakfiles */
462 AudioFileSource::set_build_peakfiles (true);
463 AudioFileSource::set_build_missing_peakfiles (true);
465 /* set default clock modes */
467 if (Profile->get_sae()) {
468 primary_clock->set_mode (AudioClock::BBT);
469 secondary_clock->set_mode (AudioClock::MinSec);
471 primary_clock->set_mode (AudioClock::Timecode);
472 secondary_clock->set_mode (AudioClock::BBT);
475 /* start the time-of-day-clock */
478 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
479 update_wall_clock ();
480 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 60000);
483 update_disk_space ();
485 update_sample_rate (engine->frame_rate());
487 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
488 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
489 Config->map_parameters (pc);
491 /* now start and maybe save state */
493 if (do_engine_start () == 0) {
494 if (_session && _session_is_new) {
495 /* we need to retain initial visual
496 settings for a new session
498 _session->save_state ("");
503 ARDOUR_UI::~ARDOUR_UI ()
508 delete add_route_dialog;
512 ARDOUR_UI::pop_back_splash (Gtk::Window& win)
514 if (Splash::instance()) {
515 Splash::instance()->pop_back_for (win);
520 ARDOUR_UI::configure_timeout ()
522 if (last_configure_time == 0) {
523 /* no configure events yet */
527 /* force a gap of 0.5 seconds since the last configure event
530 if (get_microseconds() - last_configure_time < 500000) {
533 have_configure_timeout = false;
534 cerr << "config event-driven save\n";
535 save_ardour_state ();
541 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
543 if (have_configure_timeout) {
544 last_configure_time = get_microseconds();
546 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
547 have_configure_timeout = true;
554 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
556 const XMLProperty* prop;
558 if ((prop = node.property ("roll")) != 0) {
559 roll_controllable->set_id (prop->value());
561 if ((prop = node.property ("stop")) != 0) {
562 stop_controllable->set_id (prop->value());
564 if ((prop = node.property ("goto-start")) != 0) {
565 goto_start_controllable->set_id (prop->value());
567 if ((prop = node.property ("goto-end")) != 0) {
568 goto_end_controllable->set_id (prop->value());
570 if ((prop = node.property ("auto-loop")) != 0) {
571 auto_loop_controllable->set_id (prop->value());
573 if ((prop = node.property ("play-selection")) != 0) {
574 play_selection_controllable->set_id (prop->value());
576 if ((prop = node.property ("rec")) != 0) {
577 rec_controllable->set_id (prop->value());
579 if ((prop = node.property ("shuttle")) != 0) {
580 shuttle_box->controllable()->set_id (prop->value());
586 ARDOUR_UI::get_transport_controllable_state ()
588 XMLNode* node = new XMLNode(X_("TransportControllables"));
591 roll_controllable->id().print (buf, sizeof (buf));
592 node->add_property (X_("roll"), buf);
593 stop_controllable->id().print (buf, sizeof (buf));
594 node->add_property (X_("stop"), buf);
595 goto_start_controllable->id().print (buf, sizeof (buf));
596 node->add_property (X_("goto_start"), buf);
597 goto_end_controllable->id().print (buf, sizeof (buf));
598 node->add_property (X_("goto_end"), buf);
599 auto_loop_controllable->id().print (buf, sizeof (buf));
600 node->add_property (X_("auto_loop"), buf);
601 play_selection_controllable->id().print (buf, sizeof (buf));
602 node->add_property (X_("play_selection"), buf);
603 rec_controllable->id().print (buf, sizeof (buf));
604 node->add_property (X_("rec"), buf);
605 shuttle_box->controllable()->id().print (buf, sizeof (buf));
606 node->add_property (X_("shuttle"), buf);
613 ARDOUR_UI::autosave_session ()
615 if (g_main_depth() > 1) {
616 /* inside a recursive main loop,
617 give up because we may not be able to
623 if (!Config->get_periodic_safety_backups()) {
628 _session->maybe_write_autosave();
635 ARDOUR_UI::update_autosave ()
637 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_autosave)
639 if (_session && _session->dirty()) {
640 if (_autosave_connection.connected()) {
641 _autosave_connection.disconnect();
644 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
645 Config->get_periodic_safety_backup_interval() * 1000);
648 if (_autosave_connection.connected()) {
649 _autosave_connection.disconnect();
655 ARDOUR_UI::backend_audio_error (bool we_set_params, Gtk::Window* toplevel)
659 title = string_compose (_("%1 could not start JACK"), PROGRAM_NAME);
661 title = string_compose (_("%1 could not connect to JACK."), PROGRAM_NAME);
664 MessageDialog win (title,
670 win.set_secondary_text(_("There are several possible reasons:\n\
672 1) You requested audio parameters that are not supported..\n\
673 2) JACK is running as another user.\n\
675 Please consider the possibilities, and perhaps try different parameters."));
677 win.set_secondary_text(_("There are several possible reasons:\n\
679 1) JACK is not running.\n\
680 2) JACK is running as another user, perhaps root.\n\
681 3) There is already another client called \"ardour\".\n\
683 Please consider the possibilities, and perhaps (re)start JACK."));
687 win.set_transient_for (*toplevel);
691 win.add_button (Stock::OK, RESPONSE_CLOSE);
693 win.add_button (Stock::QUIT, RESPONSE_CLOSE);
696 win.set_default_response (RESPONSE_CLOSE);
699 win.set_position (Gtk::WIN_POS_CENTER);
700 pop_back_splash (win);
702 /* we just don't care about the result, but we want to block */
708 ARDOUR_UI::startup ()
710 Application* app = Application::instance ();
712 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
713 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::idle_load));
716 call_the_mothership (VERSIONSTRING);
721 if (get_session_parameters (true, ARDOUR_COMMAND_LINE::new_session, ARDOUR_COMMAND_LINE::load_template)) {
727 goto_editor_window ();
729 /* Add the window proxies here; their addition may cause windows to be opened, and we want them
730 to be opened on top of the editor window that goto_editor_window() just opened.
732 add_window_proxy (location_ui);
733 add_window_proxy (big_clock_window);
734 for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) {
735 add_window_proxy (_global_port_matrix[*i]);
738 /* We have to do this here since goto_editor_window() ends up calling show_all() on the
739 * editor window, and we may want stuff to be hidden.
741 _status_bar_visibility.update ();
743 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
747 ARDOUR_UI::no_memory_warning ()
749 XMLNode node (X_("no-memory-warning"));
750 Config->add_instant_xml (node);
754 ARDOUR_UI::check_memory_locking ()
757 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
761 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
763 if (engine->is_realtime() && memory_warning_node == 0) {
765 struct rlimit limits;
767 long pages, page_size;
769 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0) {
772 ram = (int64_t) pages * (int64_t) page_size;
775 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
779 if (limits.rlim_cur != RLIM_INFINITY) {
781 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
785 _("WARNING: Your system has a limit for maximum amount of locked memory. "
786 "This might cause %1 to run out of memory before your system "
787 "runs out of memory. \n\n"
788 "You can view the memory limit with 'ulimit -l', "
789 "and it is normally controlled by /etc/security/limits.conf"),
790 PROGRAM_NAME).c_str());
792 VBox* vbox = msg.get_vbox();
794 CheckButton cb (_("Do not show this window again"));
796 cb.signal_toggled().connect (sigc::mem_fun (*this, &ARDOUR_UI::no_memory_warning));
798 hbox.pack_start (cb, true, false);
799 vbox->pack_start (hbox);
804 pop_back_splash (msg);
806 editor->ensure_float (msg);
816 ARDOUR_UI::queue_finish ()
818 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
822 ARDOUR_UI::idle_finish ()
825 return false; /* do not call again */
834 if (_session->transport_rolling() && (++tries < 8)) {
835 _session->request_stop (false, true);
839 if (_session->dirty()) {
840 vector<string> actions;
841 actions.push_back (_("Don't quit"));
842 actions.push_back (_("Just quit"));
843 actions.push_back (_("Save and quit"));
844 switch (ask_about_saving_session(actions)) {
849 /* use the default name */
850 if (save_state_canfail ("")) {
851 /* failed - don't quit */
852 MessageDialog msg (*editor,
854 Ardour was unable to save your session.\n\n\
855 If you still wish to quit, please use the\n\n\
856 \"Just quit\" option."));
857 pop_back_splash(msg);
867 second_connection.disconnect ();
868 point_one_second_connection.disconnect ();
869 point_oh_five_second_connection.disconnect ();
870 point_zero_one_second_connection.disconnect();
873 /* Save state before deleting the session, as that causes some
874 windows to be destroyed before their visible state can be
877 save_ardour_state ();
880 // _session->set_deletion_in_progress ();
881 _session->set_clean ();
882 _session->remove_pending_capture_state ();
887 ArdourDialog::close_all_dialogs ();
893 ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
895 ArdourDialog window (_("Unsaved Session"));
896 Gtk::HBox dhbox; // the hbox for the image and text
897 Gtk::Label prompt_label;
898 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
902 assert (actions.size() >= 3);
904 window.add_button (actions[0], RESPONSE_REJECT);
905 window.add_button (actions[1], RESPONSE_APPLY);
906 window.add_button (actions[2], RESPONSE_ACCEPT);
908 window.set_default_response (RESPONSE_ACCEPT);
910 Gtk::Button noquit_button (msg);
911 noquit_button.set_name ("EditorGTKButton");
915 if (_session->snap_name() == _session->name()) {
916 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?"),
917 _session->snap_name());
919 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?"),
920 _session->snap_name());
923 prompt_label.set_text (prompt);
924 prompt_label.set_name (X_("PrompterLabel"));
925 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
927 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
928 dhbox.set_homogeneous (false);
929 dhbox.pack_start (*dimage, false, false, 5);
930 dhbox.pack_start (prompt_label, true, false, 5);
931 window.get_vbox()->pack_start (dhbox);
933 window.set_name (_("Prompter"));
934 window.set_position (Gtk::WIN_POS_MOUSE);
935 window.set_modal (true);
936 window.set_resizable (false);
942 window.set_keep_above (true);
945 ResponseType r = (ResponseType) window.run();
950 case RESPONSE_ACCEPT: // save and get out of here
952 case RESPONSE_APPLY: // get out of here
962 ARDOUR_UI::every_second ()
965 update_buffer_load ();
966 update_disk_space ();
971 ARDOUR_UI::every_point_one_seconds ()
973 shuttle_box->update_speed_display ();
974 RapidScreenUpdate(); /* EMIT_SIGNAL */
979 ARDOUR_UI::every_point_zero_one_seconds ()
981 // august 2007: actual update frequency: 40Hz, not 100Hz
983 SuperRapidScreenUpdate(); /* EMIT_SIGNAL */
988 ARDOUR_UI::update_sample_rate (framecnt_t)
992 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
994 if (!engine->connected()) {
996 snprintf (buf, sizeof (buf), _("disconnected"));
1000 framecnt_t rate = engine->frame_rate();
1002 if (fmod (rate, 1000.0) != 0.0) {
1003 snprintf (buf, sizeof (buf), _("JACK: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
1004 (float) rate/1000.0f,
1005 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
1007 snprintf (buf, sizeof (buf), _("JACK: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
1009 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
1013 sample_rate_label.set_markup (buf);
1017 ARDOUR_UI::update_format ()
1020 format_label.set_text ("");
1025 s << _("File:") << X_(" <span foreground=\"green\">");
1027 switch (_session->config.get_native_file_header_format ()) {
1053 switch (_session->config.get_native_file_data_format ()) {
1067 format_label.set_markup (s.str ());
1071 ARDOUR_UI::update_cpu_load ()
1075 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1076 should also be changed.
1079 float const c = engine->get_cpu_load ();
1080 snprintf (buf, sizeof (buf), _("DSP: <span foreground=\"%s\">%5.1f%%</span>"), c >= 90 ? X_("red") : X_("green"), c);
1081 cpu_load_label.set_markup (buf);
1085 ARDOUR_UI::update_buffer_load ()
1089 uint32_t const playback = _session ? _session->playback_load () : 100;
1090 uint32_t const capture = _session ? _session->capture_load () : 100;
1092 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1093 should also be changed.
1099 _("Buffers: <span foreground=\"green\">p:</span><span foreground=\"%s\">%" PRIu32 "%%</span> "
1100 "<span foreground=\"green\">c:</span><span foreground=\"%s\">%" PRIu32 "%%</span>"),
1101 playback <= 5 ? X_("red") : X_("green"),
1103 capture <= 5 ? X_("red") : X_("green"),
1107 buffer_load_label.set_markup (buf);
1109 buffer_load_label.set_text ("");
1114 ARDOUR_UI::count_recenabled_streams (Route& route)
1116 Track* track = dynamic_cast<Track*>(&route);
1117 if (track && track->record_enabled()) {
1118 rec_enabled_streams += track->n_inputs().n_total();
1123 ARDOUR_UI::update_disk_space()
1125 if (_session == 0) {
1129 framecnt_t frames = _session->available_capture_duration();
1131 framecnt_t fr = _session->frame_rate();
1133 if (frames == max_framecnt) {
1134 snprintf (buf, sizeof (buf), _("Disk: <span foreground=\"green\">24hrs+</span>"));
1136 rec_enabled_streams = 0;
1137 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams);
1139 if (rec_enabled_streams) {
1140 frames /= rec_enabled_streams;
1147 hrs = frames / (fr * 3600);
1150 snprintf (buf, sizeof (buf), _("Disk: <span foreground=\"green\">>24 hrs</span>"));
1152 frames -= hrs * fr * 3600;
1153 mins = frames / (fr * 60);
1154 frames -= mins * fr * 60;
1157 bool const low = (hrs == 0 && mins <= 30);
1161 _("Disk: <span foreground=\"%s\">%02dh:%02dm:%02ds</span>"),
1162 low ? X_("red") : X_("green"),
1168 disk_space_label.set_markup (buf);
1170 // An attempt to make the disk space label flash red when space has run out.
1172 if (frames < fr * 60 * 5) {
1173 /* disk_space_box.style ("disk_space_label_empty"); */
1175 /* disk_space_box.style ("disk_space_label"); */
1181 ARDOUR_UI::update_wall_clock ()
1188 tm_now = localtime (&now);
1190 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1191 wall_clock_label.set_text (buf);
1197 ARDOUR_UI::session_menu (GdkEventButton */*ev*/)
1199 session_popup_menu->popup (0, 0);
1204 ARDOUR_UI::redisplay_recent_sessions ()
1206 std::vector<sys::path> session_directories;
1207 RecentSessionsSorter cmp;
1209 recent_session_display.set_model (Glib::RefPtr<TreeModel>(0));
1210 recent_session_model->clear ();
1212 ARDOUR::RecentSessions rs;
1213 ARDOUR::read_recent_sessions (rs);
1216 recent_session_display.set_model (recent_session_model);
1220 // sort them alphabetically
1221 sort (rs.begin(), rs.end(), cmp);
1223 for (ARDOUR::RecentSessions::iterator i = rs.begin(); i != rs.end(); ++i) {
1224 session_directories.push_back ((*i).second);
1227 for (vector<sys::path>::const_iterator i = session_directories.begin();
1228 i != session_directories.end(); ++i)
1230 std::vector<sys::path> state_file_paths;
1232 // now get available states for this session
1234 get_state_files_in_directory (*i, state_file_paths);
1236 vector<string*>* states;
1237 vector<const gchar*> item;
1238 string fullpath = (*i).to_string();
1240 /* remove any trailing / */
1242 if (fullpath[fullpath.length()-1] == '/') {
1243 fullpath = fullpath.substr (0, fullpath.length()-1);
1246 /* check whether session still exists */
1247 if (!Glib::file_test(fullpath.c_str(), Glib::FILE_TEST_EXISTS)) {
1248 /* session doesn't exist */
1249 cerr << "skipping non-existent session " << fullpath << endl;
1253 /* now get available states for this session */
1255 if ((states = Session::possible_states (fullpath)) == 0) {
1256 /* no state file? */
1260 std::vector<string> state_file_names(get_file_names_no_extension (state_file_paths));
1262 Gtk::TreeModel::Row row = *(recent_session_model->append());
1264 row[recent_session_columns.visible_name] = Glib::path_get_basename (fullpath);
1265 row[recent_session_columns.fullpath] = fullpath;
1267 if (state_file_names.size() > 1) {
1271 for (std::vector<std::string>::iterator i2 = state_file_names.begin();
1272 i2 != state_file_names.end(); ++i2)
1275 Gtk::TreeModel::Row child_row = *(recent_session_model->append (row.children()));
1277 child_row[recent_session_columns.visible_name] = *i2;
1278 child_row[recent_session_columns.fullpath] = fullpath;
1283 recent_session_display.set_model (recent_session_model);
1287 ARDOUR_UI::build_session_selector ()
1289 session_selector_window = new ArdourDialog (_("Recent Sessions"));
1291 Gtk::ScrolledWindow *scroller = manage (new Gtk::ScrolledWindow);
1293 session_selector_window->add_button (Stock::CANCEL, RESPONSE_CANCEL);
1294 session_selector_window->add_button (Stock::OPEN, RESPONSE_ACCEPT);
1295 session_selector_window->set_default_response (RESPONSE_ACCEPT);
1296 recent_session_model = TreeStore::create (recent_session_columns);
1297 recent_session_display.set_model (recent_session_model);
1298 recent_session_display.append_column (_("Recent Sessions"), recent_session_columns.visible_name);
1299 recent_session_display.set_headers_visible (false);
1300 recent_session_display.get_selection()->set_mode (SELECTION_BROWSE);
1301 recent_session_display.signal_row_activated().connect (sigc::mem_fun (*this, &ARDOUR_UI::recent_session_row_activated));
1303 scroller->add (recent_session_display);
1304 scroller->set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
1306 session_selector_window->set_name ("SessionSelectorWindow");
1307 session_selector_window->set_size_request (200, 400);
1308 session_selector_window->get_vbox()->pack_start (*scroller);
1310 recent_session_display.show();
1312 //session_selector_window->get_vbox()->show();
1316 ARDOUR_UI::recent_session_row_activated (const TreePath& /*path*/, TreeViewColumn* /*col*/)
1318 session_selector_window->response (RESPONSE_ACCEPT);
1322 ARDOUR_UI::open_recent_session ()
1324 bool can_return = (_session != 0);
1326 if (session_selector_window == 0) {
1327 build_session_selector ();
1330 redisplay_recent_sessions ();
1334 session_selector_window->set_position (WIN_POS_MOUSE);
1336 ResponseType r = (ResponseType) session_selector_window->run ();
1339 case RESPONSE_ACCEPT:
1343 session_selector_window->hide();
1350 if (recent_session_display.get_selection()->count_selected_rows() == 0) {
1354 session_selector_window->hide();
1356 Gtk::TreeModel::iterator i = recent_session_display.get_selection()->get_selected();
1358 if (i == recent_session_model->children().end()) {
1362 std::string path = (*i)[recent_session_columns.fullpath];
1363 std::string state = (*i)[recent_session_columns.visible_name];
1365 _session_is_new = false;
1367 if (load_session (path, state) == 0) {
1376 ARDOUR_UI::check_audioengine ()
1379 if (!engine->connected()) {
1380 MessageDialog msg (string_compose (
1381 _("%1 is not connected to JACK\n"
1382 "You cannot open or close sessions in this condition"),
1384 pop_back_splash (msg);
1395 ARDOUR_UI::open_session ()
1397 if (!check_audioengine()) {
1402 /* popup selector window */
1404 if (open_session_selector == 0) {
1406 /* ardour sessions are folders */
1408 open_session_selector = new Gtk::FileChooserDialog (_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1409 open_session_selector->add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1410 open_session_selector->add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1411 open_session_selector->set_default_response(Gtk::RESPONSE_ACCEPT);
1413 FileFilter session_filter;
1414 session_filter.add_pattern ("*.ardour");
1415 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1416 open_session_selector->add_filter (session_filter);
1417 open_session_selector->set_filter (session_filter);
1420 int response = open_session_selector->run();
1421 open_session_selector->hide ();
1424 case RESPONSE_ACCEPT:
1427 open_session_selector->hide();
1431 open_session_selector->hide();
1432 string session_path = open_session_selector->get_filename();
1436 if (session_path.length() > 0) {
1437 if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1438 _session_is_new = isnew;
1439 load_session (path, name);
1446 ARDOUR_UI::session_add_midi_route (bool disk, RouteGroup* route_group, uint32_t how_many, const string& name_template, PluginInfoPtr instrument)
1448 list<boost::shared_ptr<MidiTrack> > tracks;
1450 if (_session == 0) {
1451 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1458 tracks = _session->new_midi_track (instrument, ARDOUR::Normal, route_group, how_many, name_template);
1460 if (tracks.size() != how_many) {
1461 if (how_many == 1) {
1462 error << _("could not create a new midi track") << endmsg;
1464 error << string_compose (_("could not create %1 new midi tracks"), how_many) << endmsg;
1469 if ((route = _session->new_midi_route ()) == 0) {
1470 error << _("could not create new midi bus") << endmsg;
1476 MessageDialog msg (*editor,
1477 string_compose (_("There are insufficient JACK ports available\n\
1478 to create a new track or bus.\n\
1479 You should save %1, exit and\n\
1480 restart JACK with more ports."), PROGRAM_NAME));
1487 ARDOUR_UI::session_add_audio_route (
1489 int32_t input_channels,
1490 int32_t output_channels,
1491 ARDOUR::TrackMode mode,
1492 RouteGroup* route_group,
1494 string const & name_template
1497 list<boost::shared_ptr<AudioTrack> > tracks;
1500 if (_session == 0) {
1501 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1507 tracks = _session->new_audio_track (input_channels, output_channels, mode, route_group, how_many, name_template);
1509 if (tracks.size() != how_many) {
1510 if (how_many == 1) {
1511 error << _("could not create a new audio track") << endmsg;
1513 error << string_compose (_("could only create %1 of %2 new audio %3"),
1514 tracks.size(), how_many, (track ? _("tracks") : _("busses"))) << endmsg;
1520 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template);
1522 if (routes.size() != how_many) {
1523 if (how_many == 1) {
1524 error << _("could not create a new audio bus") << endmsg;
1526 error << string_compose (_("could not create %1 new audio busses"), how_many) << endmsg;
1533 MessageDialog msg (*editor,
1534 string_compose (_("There are insufficient JACK ports available\n\
1535 to create a new track or bus.\n\
1536 You should save %1, exit and\n\
1537 restart JACK with more ports."), PROGRAM_NAME));
1538 pop_back_splash (msg);
1544 ARDOUR_UI::do_transport_locate (framepos_t new_position, bool with_roll)
1546 framecnt_t _preroll = 0;
1549 // XXX CONFIG_CHANGE FIX - requires AnyTime handling
1550 // _preroll = _session->convert_to_frames_at (new_position, Config->get_preroll());
1552 if (new_position > _preroll) {
1553 new_position -= _preroll;
1558 _session->request_locate (new_position, with_roll);
1563 ARDOUR_UI::transport_goto_start ()
1566 _session->goto_start();
1568 /* force displayed area in editor to start no matter
1569 what "follow playhead" setting is.
1573 editor->center_screen (_session->current_start_frame ());
1579 ARDOUR_UI::transport_goto_zero ()
1582 _session->request_locate (0);
1584 /* force displayed area in editor to start no matter
1585 what "follow playhead" setting is.
1589 editor->reset_x_origin (0);
1595 ARDOUR_UI::transport_goto_wallclock ()
1597 if (_session && editor) {
1604 localtime_r (&now, &tmnow);
1606 frames = tmnow.tm_hour * (60 * 60 * _session->frame_rate());
1607 frames += tmnow.tm_min * (60 * _session->frame_rate());
1608 frames += tmnow.tm_sec * _session->frame_rate();
1610 _session->request_locate (frames, _session->transport_rolling ());
1612 /* force displayed area in editor to start no matter
1613 what "follow playhead" setting is.
1617 editor->center_screen (frames);
1623 ARDOUR_UI::transport_goto_end ()
1626 framepos_t const frame = _session->current_end_frame();
1627 _session->request_locate (frame);
1629 /* force displayed area in editor to start no matter
1630 what "follow playhead" setting is.
1634 editor->center_screen (frame);
1640 ARDOUR_UI::transport_stop ()
1646 if (_session->is_auditioning()) {
1647 _session->cancel_audition ();
1651 _session->request_stop (false, true);
1655 ARDOUR_UI::transport_stop_and_forget_capture ()
1658 _session->request_stop (true, true);
1663 ARDOUR_UI::remove_last_capture()
1666 editor->remove_last_capture();
1671 ARDOUR_UI::transport_record (bool roll)
1675 switch (_session->record_status()) {
1676 case Session::Disabled:
1677 if (_session->ntracks() == 0) {
1678 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."));
1682 _session->maybe_enable_record ();
1687 case Session::Recording:
1689 _session->request_stop();
1691 _session->disable_record (false, true);
1695 case Session::Enabled:
1696 _session->disable_record (false, true);
1699 //cerr << "ARDOUR_UI::transport_record () called roll = " << roll << " _session->record_status() = " << _session->record_status() << endl;
1703 ARDOUR_UI::transport_roll ()
1709 if (_session->is_auditioning()) {
1714 if (_session->config.get_external_sync()) {
1715 switch (_session->config.get_sync_source()) {
1719 /* transport controlled by the master */
1725 bool rolling = _session->transport_rolling();
1727 if (_session->get_play_loop()) {
1728 /* XXX it is not possible to just leave seamless loop and keep
1729 playing at present (nov 4th 2009)
1731 if (!Config->get_seamless_loop()) {
1732 _session->request_play_loop (false, true);
1734 } else if (_session->get_play_range () && !Config->get_always_play_range()) {
1735 /* stop playing a range if we currently are */
1736 _session->request_play_range (0, true);
1739 if (Config->get_always_play_range()) {
1740 _session->request_play_range (&editor->get_selection().time, true);
1744 _session->request_transport_speed (1.0f);
1749 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
1756 if (_session->is_auditioning()) {
1757 _session->cancel_audition ();
1761 if (_session->config.get_external_sync()) {
1762 switch (_session->config.get_sync_source()) {
1766 /* transport controlled by the master */
1771 bool rolling = _session->transport_rolling();
1772 bool affect_transport = true;
1774 if (rolling && roll_out_of_bounded_mode) {
1775 /* drop out of loop/range playback but leave transport rolling */
1776 if (_session->get_play_loop()) {
1777 if (Config->get_seamless_loop()) {
1778 /* the disk buffers contain copies of the loop - we can't
1779 just keep playing, so stop the transport. the user
1780 can restart as they wish.
1782 affect_transport = true;
1784 /* disk buffers are normal, so we can keep playing */
1785 affect_transport = false;
1787 _session->request_play_loop (false, true);
1788 } else if (_session->get_play_range ()) {
1789 affect_transport = false;
1790 _session->request_play_range (0, true);
1794 if (affect_transport) {
1796 _session->request_stop (with_abort, true);
1798 if (Config->get_always_play_range ()) {
1799 _session->request_play_range (&editor->get_selection().time, true);
1802 _session->request_transport_speed (1.0f);
1808 ARDOUR_UI::toggle_session_auto_loop ()
1814 if (_session->get_play_loop()) {
1816 if (_session->transport_rolling()) {
1818 Location * looploc = _session->locations()->auto_loop_location();
1821 _session->request_locate (looploc->start(), true);
1822 _session->request_play_loop (false);
1826 _session->request_play_loop (false);
1830 Location * looploc = _session->locations()->auto_loop_location();
1833 _session->request_play_loop (true);
1839 ARDOUR_UI::transport_play_selection ()
1845 editor->play_selection ();
1849 ARDOUR_UI::transport_rewind (int option)
1851 float current_transport_speed;
1854 current_transport_speed = _session->transport_speed();
1856 if (current_transport_speed >= 0.0f) {
1859 _session->request_transport_speed (-1.0f);
1862 _session->request_transport_speed (-4.0f);
1865 _session->request_transport_speed (-0.5f);
1870 _session->request_transport_speed (current_transport_speed * 1.5f);
1876 ARDOUR_UI::transport_forward (int option)
1878 float current_transport_speed;
1881 current_transport_speed = _session->transport_speed();
1883 if (current_transport_speed <= 0.0f) {
1886 _session->request_transport_speed (1.0f);
1889 _session->request_transport_speed (4.0f);
1892 _session->request_transport_speed (0.5f);
1897 _session->request_transport_speed (current_transport_speed * 1.5f);
1904 ARDOUR_UI::toggle_record_enable (uint32_t rid)
1906 if (_session == 0) {
1910 boost::shared_ptr<Route> r;
1912 if ((r = _session->route_by_remote_id (rid)) != 0) {
1916 if ((t = dynamic_cast<Track*>(r.get())) != 0) {
1917 t->set_record_enabled (!t->record_enabled(), this);
1920 if (_session == 0) {
1926 ARDOUR_UI::map_transport_state ()
1929 auto_loop_button.unset_active_state ();
1930 play_selection_button.unset_active_state ();
1931 roll_button.unset_active_state ();
1932 stop_button.set_active_state (Gtkmm2ext::ExplicitActive);
1936 shuttle_box->map_transport_state ();
1938 float sp = _session->transport_speed();
1944 if (_session->get_play_range()) {
1946 play_selection_button.set_active_state (Gtkmm2ext::ExplicitActive);
1947 roll_button.unset_active_state ();
1948 auto_loop_button.unset_active_state ();
1950 } else if (_session->get_play_loop ()) {
1952 auto_loop_button.set_active (true);
1953 play_selection_button.set_active (false);
1954 roll_button.set_active (false);
1958 roll_button.set_active (true);
1959 play_selection_button.set_active (false);
1960 auto_loop_button.set_active (false);
1963 if (Config->get_always_play_range()) {
1964 /* light up both roll and play-selection if they are joined */
1965 roll_button.set_active (true);
1966 play_selection_button.set_active (true);
1969 stop_button.set_active (false);
1973 stop_button.set_active (true);
1974 roll_button.set_active (false);
1975 play_selection_button.set_active (false);
1976 auto_loop_button.set_active (false);
1977 update_disk_space ();
1982 ARDOUR_UI::engine_stopped ()
1984 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
1985 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1986 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1990 ARDOUR_UI::engine_running ()
1992 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
1993 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, true);
1994 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, false);
1996 Glib::RefPtr<Action> action;
1997 const char* action_name = 0;
1999 switch (engine->frames_per_cycle()) {
2001 action_name = X_("JACKLatency32");
2004 action_name = X_("JACKLatency64");
2007 action_name = X_("JACKLatency128");
2010 action_name = X_("JACKLatency512");
2013 action_name = X_("JACKLatency1024");
2016 action_name = X_("JACKLatency2048");
2019 action_name = X_("JACKLatency4096");
2022 action_name = X_("JACKLatency8192");
2025 /* XXX can we do anything useful ? */
2031 action = ActionManager::get_action (X_("JACK"), action_name);
2034 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (action);
2035 ract->set_active ();
2041 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
2043 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
2044 /* we can't rely on the original string continuing to exist when we are called
2045 again in the GUI thread, so make a copy and note that we need to
2048 char *copy = strdup (reason);
2049 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
2053 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
2054 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
2056 update_sample_rate (0);
2060 /* if the reason is a non-empty string, it means that the backend was shutdown
2061 rather than just Ardour.
2064 if (strlen (reason)) {
2065 msgstr = string_compose (_("The audio backend (JACK) was shutdown because:\n\n%1"), reason);
2067 msgstr = string_compose (_("\
2068 JACK has either been shutdown or it\n\
2069 disconnected %1 because %1\n\
2070 was not fast enough. Try to restart\n\
2071 JACK, reconnect and save the session."), PROGRAM_NAME);
2074 MessageDialog msg (*editor, msgstr);
2075 pop_back_splash (msg);
2079 free ((char*) reason);
2084 ARDOUR_UI::do_engine_start ()
2092 error << _("Unable to start the session running")
2102 ARDOUR_UI::setup_theme ()
2104 theme_manager->setup_theme();
2108 ARDOUR_UI::update_clocks ()
2110 if (!editor || !editor->dragging_playhead()) {
2111 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position()); /* EMIT_SIGNAL */
2116 ARDOUR_UI::start_clocking ()
2118 clock_signal_connection = RapidScreenUpdate.connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2122 ARDOUR_UI::stop_clocking ()
2124 clock_signal_connection.disconnect ();
2128 ARDOUR_UI::toggle_clocking ()
2131 if (clock_button.get_active()) {
2140 ARDOUR_UI::_blink (void *arg)
2143 ((ARDOUR_UI *) arg)->blink ();
2150 Blink (blink_on = !blink_on); /* EMIT_SIGNAL */
2154 ARDOUR_UI::start_blinking ()
2156 /* Start the blink signal. Everybody with a blinking widget
2157 uses Blink to drive the widget's state.
2160 if (blink_timeout_tag < 0) {
2162 blink_timeout_tag = g_timeout_add (240, _blink, this);
2167 ARDOUR_UI::stop_blinking ()
2169 if (blink_timeout_tag >= 0) {
2170 g_source_remove (blink_timeout_tag);
2171 blink_timeout_tag = -1;
2176 /** Ask the user for the name of a new snapshot and then take it.
2180 ARDOUR_UI::snapshot_session (bool switch_to_it)
2182 ArdourPrompter prompter (true);
2185 prompter.set_name ("Prompter");
2186 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2187 prompter.set_title (_("Take Snapshot"));
2188 prompter.set_prompt (_("Name of new snapshot"));
2190 if (!switch_to_it) {
2193 struct tm local_time;
2196 localtime_r (&n, &local_time);
2197 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2198 prompter.set_initial_text (timebuf);
2202 switch (prompter.run()) {
2203 case RESPONSE_ACCEPT:
2205 prompter.get_result (snapname);
2207 bool do_save = (snapname.length() != 0);
2210 char illegal = Session::session_name_is_legal(snapname);
2212 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2213 "snapshot names may not contain a '%1' character"), illegal));
2219 vector<sys::path> p;
2220 get_state_files_in_directory (_session->session_directory().root_path(), p);
2221 vector<string> n = get_file_names_no_extension (p);
2222 if (find (n.begin(), n.end(), snapname) != n.end()) {
2224 ArdourDialog confirm (_("Confirm Snapshot Overwrite"), true);
2225 Label m (_("A snapshot already exists with that name. Do you want to overwrite it?"));
2226 confirm.get_vbox()->pack_start (m, true, true);
2227 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2228 confirm.add_button (_("Overwrite"), Gtk::RESPONSE_ACCEPT);
2229 confirm.show_all ();
2230 switch (confirm.run()) {
2231 case RESPONSE_CANCEL:
2237 save_state (snapname, switch_to_it);
2247 /** Ask the user for a new session name and then rename the session to it.
2251 ARDOUR_UI::rename_session ()
2257 ArdourPrompter prompter (true);
2260 prompter.set_name ("Prompter");
2261 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2262 prompter.set_title (_("Rename Session"));
2263 prompter.set_prompt (_("New session name"));
2266 switch (prompter.run()) {
2267 case RESPONSE_ACCEPT:
2269 prompter.get_result (name);
2271 bool do_rename = (name.length() != 0);
2274 char illegal = Session::session_name_is_legal (name);
2277 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2278 "session names may not contain a '%1' character"), illegal));
2283 switch (_session->rename (name)) {
2285 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
2286 msg.set_position (WIN_POS_MOUSE);
2294 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
2295 msg.set_position (WIN_POS_MOUSE);
2311 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2313 XMLNode* node = new XMLNode (X_("UI"));
2315 for (list<WindowProxyBase*>::iterator i = _window_proxies.begin(); i != _window_proxies.end(); ++i) {
2316 if (!(*i)->rc_configured()) {
2317 node->add_child_nocopy (*((*i)->get_state ()));
2321 node->add_child_nocopy (gui_object_state->get_state());
2323 _session->add_extra_xml (*node);
2325 save_state_canfail (name, switch_to_it);
2329 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2334 if (name.length() == 0) {
2335 name = _session->snap_name();
2338 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2343 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2348 ARDOUR_UI::primary_clock_value_changed ()
2351 _session->request_locate (primary_clock->current_time ());
2356 ARDOUR_UI::big_clock_value_changed ()
2359 _session->request_locate (big_clock->current_time ());
2364 ARDOUR_UI::secondary_clock_value_changed ()
2367 _session->request_locate (secondary_clock->current_time ());
2372 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2374 if (_session == 0) {
2378 if (_session->step_editing()) {
2382 Session::RecordState const r = _session->record_status ();
2383 bool const h = _session->have_rec_enabled_track ();
2385 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2387 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2389 rec_button.set_active_state (Gtkmm2ext::ImplicitActive);
2391 } else if (r == Session::Recording && h) {
2392 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2394 rec_button.unset_active_state ();
2399 ARDOUR_UI::save_template ()
2401 ArdourPrompter prompter (true);
2404 if (!check_audioengine()) {
2408 prompter.set_name (X_("Prompter"));
2409 prompter.set_title (_("Save Template"));
2410 prompter.set_prompt (_("Name for template:"));
2411 prompter.set_initial_text(_session->name() + _("-template"));
2412 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2414 switch (prompter.run()) {
2415 case RESPONSE_ACCEPT:
2416 prompter.get_result (name);
2418 if (name.length()) {
2419 _session->save_template (name);
2429 ARDOUR_UI::edit_metadata ()
2431 SessionMetadataEditor dialog;
2432 dialog.set_session (_session);
2433 editor->ensure_float (dialog);
2438 ARDOUR_UI::import_metadata ()
2440 SessionMetadataImporter dialog;
2441 dialog.set_session (_session);
2442 editor->ensure_float (dialog);
2447 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
2449 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2451 MessageDialog msg (str,
2453 Gtk::MESSAGE_WARNING,
2454 Gtk::BUTTONS_YES_NO,
2458 msg.set_name (X_("OpenExistingDialog"));
2459 msg.set_title (_("Open Existing Session"));
2460 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
2461 msg.set_position (Gtk::WIN_POS_MOUSE);
2462 pop_back_splash (msg);
2464 switch (msg.run()) {
2473 ARDOUR_UI::build_session_from_nsd (const std::string& session_path, const std::string& session_name)
2475 BusProfile bus_profile;
2477 if (Profile->get_sae()) {
2479 bus_profile.master_out_channels = 2;
2480 bus_profile.input_ac = AutoConnectPhysical;
2481 bus_profile.output_ac = AutoConnectMaster;
2482 bus_profile.requested_physical_in = 0; // use all available
2483 bus_profile.requested_physical_out = 0; // use all available
2487 /* get settings from advanced section of NSD */
2489 if (_startup->create_master_bus()) {
2490 bus_profile.master_out_channels = (uint32_t) _startup->master_channel_count();
2492 bus_profile.master_out_channels = 0;
2495 if (_startup->connect_inputs()) {
2496 bus_profile.input_ac = AutoConnectPhysical;
2498 bus_profile.input_ac = AutoConnectOption (0);
2501 bus_profile.output_ac = AutoConnectOption (0);
2503 if (_startup->connect_outputs ()) {
2504 if (_startup->connect_outs_to_master()) {
2505 bus_profile.output_ac = AutoConnectMaster;
2506 } else if (_startup->connect_outs_to_physical()) {
2507 bus_profile.output_ac = AutoConnectPhysical;
2511 bus_profile.requested_physical_in = (uint32_t) _startup->input_limit_count();
2512 bus_profile.requested_physical_out = (uint32_t) _startup->output_limit_count();
2515 if (build_session (session_path, session_name, bus_profile)) {
2523 ARDOUR_UI::idle_load (const std::string& path)
2526 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2527 /* /path/to/foo => /path/to/foo, foo */
2528 load_session (path, basename_nosuffix (path));
2530 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2531 load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2535 ARDOUR_COMMAND_LINE::session_name = path;
2538 * new_session_dialog doens't exist in A3
2539 * Try to remove all references to it to
2540 * see if it will compile. NOTE: this will
2541 * likely cause a runtime issue is my somewhat
2545 //if (new_session_dialog) {
2548 /* make it break out of Dialog::run() and
2552 //new_session_dialog->response (1);
2558 ARDOUR_UI::end_loading_messages ()
2564 ARDOUR_UI::loading_message (const std::string& msg)
2566 if (ARDOUR_COMMAND_LINE::no_splash) {
2572 splash->message (msg);
2577 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
2579 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
2581 string session_name;
2582 string session_path;
2583 string template_name;
2585 bool likely_new = false;
2587 if (!load_template.empty()) {
2588 should_be_new = true;
2589 template_name = load_template;
2594 if (!should_be_new && !ARDOUR_COMMAND_LINE::session_name.empty()) {
2596 /* if they named a specific statefile, use it, otherwise they are
2597 just giving a session folder, and we want to use it as is
2598 to find the session.
2601 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
2603 if (suffix != string::npos) {
2604 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
2605 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
2606 session_name = Glib::path_get_basename (session_name);
2608 session_path = ARDOUR_COMMAND_LINE::session_name;
2609 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
2614 bool const apply = run_startup (should_be_new, load_template);
2617 if (quit_on_cancel) {
2624 /* if we run the startup dialog again, offer more than just "new session" */
2626 should_be_new = false;
2628 session_name = _startup->session_name (likely_new);
2630 string::size_type suffix = session_name.find (statefile_suffix);
2632 if (suffix != string::npos) {
2633 session_name = session_name.substr (0, suffix);
2636 /* this shouldn't happen, but we catch it just in case it does */
2638 if (session_name.empty()) {
2642 if (_startup->use_session_template()) {
2643 template_name = _startup->session_template_name();
2644 _session_is_new = true;
2647 if (session_name[0] == G_DIR_SEPARATOR ||
2648 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
2649 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)) {
2651 /* absolute path or cwd-relative path specified for session name: infer session folder
2652 from what was given.
2655 session_path = Glib::path_get_dirname (session_name);
2656 session_name = Glib::path_get_basename (session_name);
2660 session_path = _startup->session_folder();
2662 char illegal = Session::session_name_is_legal (session_name);
2665 MessageDialog msg (*_startup,
2666 string_compose (_("To ensure compatibility with various systems\n"
2667 "session names may not contain a '%1' character"),
2670 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2676 if (create_engine ()) {
2680 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
2684 std::string existing = Glib::build_filename (session_path, session_name);
2686 if (!ask_about_loading_existing_session (existing)) {
2687 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2692 _session_is_new = false;
2697 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
2699 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2703 if (session_name.find ('/') != std::string::npos) {
2704 MessageDialog msg (*_startup,
2705 _("To ensure compatibility with various systems\n"
2706 "session names may not contain a '/' character"));
2708 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2712 if (session_name.find ('\\') != std::string::npos) {
2713 MessageDialog msg (*_startup,
2714 _("To ensure compatibility with various systems\n"
2715 "session names may not contain a '\\' character"));
2717 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2721 _session_is_new = true;
2724 if (likely_new && template_name.empty()) {
2726 ret = build_session_from_nsd (session_path, session_name);
2730 ret = load_session (session_path, session_name, template_name);
2733 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
2737 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
2738 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
2748 ARDOUR_UI::close_session()
2750 if (!check_audioengine()) {
2754 if (unload_session (true)) {
2758 ARDOUR_COMMAND_LINE::session_name = "";
2760 if (get_session_parameters (true, false)) {
2764 goto_editor_window ();
2767 /** @param snap_name Snapshot name (without .ardour suffix).
2768 * @return -2 if the load failed because we are not connected to the AudioEngine.
2771 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
2773 Session *new_session;
2777 session_loaded = false;
2779 if (!check_audioengine()) {
2783 unload_status = unload_session ();
2785 if (unload_status < 0) {
2787 } else if (unload_status > 0) {
2792 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
2795 new_session = new Session (*engine, path, snap_name, 0, mix_template);
2798 /* this one is special */
2800 catch (AudioEngine::PortRegistrationFailure& err) {
2802 MessageDialog msg (err.what(),
2805 Gtk::BUTTONS_CLOSE);
2807 msg.set_title (_("Port Registration Error"));
2808 msg.set_secondary_text (_("Click the Close button to try again."));
2809 msg.set_position (Gtk::WIN_POS_CENTER);
2810 pop_back_splash (msg);
2813 int response = msg.run ();
2818 case RESPONSE_CANCEL:
2828 MessageDialog msg (string_compose(
2829 _("Session \"%1 (snapshot %2)\" did not load successfully"),
2835 msg.set_title (_("Loading Error"));
2836 msg.set_secondary_text (_("Click the Refresh button to try again."));
2837 msg.add_button (Stock::REFRESH, 1);
2838 msg.set_position (Gtk::WIN_POS_CENTER);
2839 pop_back_splash (msg);
2842 int response = msg.run ();
2857 list<string> const u = new_session->unknown_processors ();
2859 MissingPluginDialog d (_session, u);
2864 /* Now the session been created, add the transport controls */
2865 new_session->add_controllable(roll_controllable);
2866 new_session->add_controllable(stop_controllable);
2867 new_session->add_controllable(goto_start_controllable);
2868 new_session->add_controllable(goto_end_controllable);
2869 new_session->add_controllable(auto_loop_controllable);
2870 new_session->add_controllable(play_selection_controllable);
2871 new_session->add_controllable(rec_controllable);
2873 set_session (new_session);
2875 session_loaded = true;
2877 goto_editor_window ();
2880 _session->set_clean ();
2891 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
2893 Session *new_session;
2896 if (!check_audioengine()) {
2900 session_loaded = false;
2902 x = unload_session ();
2910 _session_is_new = true;
2913 new_session = new Session (*engine, path, snap_name, &bus_profile);
2918 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
2919 pop_back_splash (msg);
2924 /* Give the new session the default GUI state, if such things exist */
2927 n = Config->instant_xml (X_("Editor"));
2929 new_session->add_instant_xml (*n, false);
2931 n = Config->instant_xml (X_("Mixer"));
2933 new_session->add_instant_xml (*n, false);
2936 /* Put the playhead at 0 and scroll fully left */
2937 n = new_session->instant_xml (X_("Editor"));
2939 n->add_property (X_("playhead"), X_("0"));
2940 n->add_property (X_("left-frame"), X_("0"));
2943 set_session (new_session);
2945 session_loaded = true;
2947 new_session->save_state(new_session->name());
2953 ARDOUR_UI::launch_chat ()
2956 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
2958 open_uri("http://webchat.freenode.net/?channels=ardour");
2963 ARDOUR_UI::show_about ()
2967 about->signal_response().connect(sigc::mem_fun (*this, &ARDOUR_UI::about_signal_response) );
2970 about->set_transient_for(*editor);
2975 ARDOUR_UI::launch_manual ()
2977 PBD::open_uri("http://ardour.org/flossmanual");
2981 ARDOUR_UI::launch_reference ()
2983 PBD::open_uri("http://ardour.org/refmanual");
2987 ARDOUR_UI::hide_about ()
2990 about->get_window()->set_cursor ();
2996 ARDOUR_UI::about_signal_response (int /*response*/)
3002 ARDOUR_UI::show_splash ()
3006 splash = new Splash;
3008 cerr << "Splash could not be created\n";
3014 splash->pop_front ();
3015 splash->queue_draw ();
3016 splash->get_window()->process_updates (true);
3021 ARDOUR_UI::hide_splash ()
3029 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title,
3030 const string& plural_msg, const string& singular_msg)
3034 removed = rep.paths.size();
3037 MessageDialog msgd (*editor,
3038 _("No files were ready for clean-up"),
3042 msgd.set_title (_("Clean-up"));
3043 msgd.set_secondary_text (_("If this seems suprising, \n\
3044 check for any existing snapshots.\n\
3045 These may still include regions that\n\
3046 require some unused files to continue to exist."));
3052 ArdourDialog results (_("Clean-up"), true, false);
3054 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
3055 CleanupResultsModelColumns() {
3059 Gtk::TreeModelColumn<std::string> visible_name;
3060 Gtk::TreeModelColumn<std::string> fullpath;
3064 CleanupResultsModelColumns results_columns;
3065 Glib::RefPtr<Gtk::ListStore> results_model;
3066 Gtk::TreeView results_display;
3068 results_model = ListStore::create (results_columns);
3069 results_display.set_model (results_model);
3070 results_display.append_column (list_title, results_columns.visible_name);
3072 results_display.set_name ("CleanupResultsList");
3073 results_display.set_headers_visible (true);
3074 results_display.set_headers_clickable (false);
3075 results_display.set_reorderable (false);
3077 Gtk::ScrolledWindow list_scroller;
3080 Gtk::HBox dhbox; // the hbox for the image and text
3081 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
3082 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
3084 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
3086 const string dead_directory = _session->session_directory().dead_path().to_string();
3089 %1 - number of files removed
3090 %2 - location of "dead"
3091 %3 - size of files affected
3092 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
3095 const char* bprefix;
3096 double space_adjusted = 0;
3098 if (rep.space < 1000) {
3100 space_adjusted = rep.space;
3101 } else if (rep.space < 1000000) {
3102 bprefix = X_("kilo");
3103 space_adjusted = truncf((float)rep.space / 1000.0);
3104 } else if (rep.space < 1000000 * 1000) {
3105 bprefix = X_("mega");
3106 space_adjusted = truncf((float)rep.space / (1000.0 * 1000.0));
3108 bprefix = X_("giga");
3109 space_adjusted = truncf((float)rep.space / (1000.0 * 1000 * 1000.0));
3113 txt.set_text (string_compose (plural_msg, removed, dead_directory, space_adjusted, bprefix));
3115 txt.set_text (string_compose (singular_msg, removed, dead_directory, space_adjusted, bprefix));
3118 dhbox.pack_start (*dimage, true, false, 5);
3119 dhbox.pack_start (txt, true, false, 5);
3121 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
3122 TreeModel::Row row = *(results_model->append());
3123 row[results_columns.visible_name] = *i;
3124 row[results_columns.fullpath] = *i;
3127 list_scroller.add (results_display);
3128 list_scroller.set_size_request (-1, 150);
3129 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
3131 dvbox.pack_start (dhbox, true, false, 5);
3132 dvbox.pack_start (list_scroller, true, false, 5);
3133 ddhbox.pack_start (dvbox, true, false, 5);
3135 results.get_vbox()->pack_start (ddhbox, true, false, 5);
3136 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
3137 results.set_default_response (RESPONSE_CLOSE);
3138 results.set_position (Gtk::WIN_POS_MOUSE);
3140 results_display.show();
3141 list_scroller.show();
3148 //results.get_vbox()->show();
3149 results.set_resizable (false);
3156 ARDOUR_UI::cleanup ()
3158 if (_session == 0) {
3159 /* shouldn't happen: menu item is insensitive */
3164 MessageDialog checker (_("Are you sure you want to clean-up?"),
3166 Gtk::MESSAGE_QUESTION,
3169 checker.set_title (_("Clean-up"));
3171 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
3172 ALL undo/redo information will be lost if you clean-up.\n\
3173 Clean-up will move all unused files to a \"dead\" location."));
3175 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3176 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
3177 checker.set_default_response (RESPONSE_CANCEL);
3179 checker.set_name (_("CleanupDialog"));
3180 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3181 checker.set_position (Gtk::WIN_POS_MOUSE);
3183 switch (checker.run()) {
3184 case RESPONSE_ACCEPT:
3190 ARDOUR::CleanupReport rep;
3192 editor->prepare_for_cleanup ();
3194 /* do not allow flush until a session is reloaded */
3196 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3198 act->set_sensitive (false);
3201 if (_session->cleanup_sources (rep)) {
3202 editor->finish_cleanup ();
3206 editor->finish_cleanup ();
3209 display_cleanup_results (rep,
3212 The following %1 files were not in use and \n\
3213 have been moved to:\n\n\
3215 After a restart of Ardour,\n\n\
3216 Session -> Clean-up -> Flush Wastebasket\n\n\
3217 will release an additional\n\
3218 %3 %4bytes of disk space.\n"),
3220 The following file was not in use and \n\
3221 has been moved to:\n \
3223 After a restart of Ardour,\n\n\
3224 Session -> Clean-up -> Flush Wastebasket\n\n\
3225 will release an additional\n\
3226 %3 %4bytes of disk space.\n"
3232 ARDOUR_UI::flush_trash ()
3234 if (_session == 0) {
3235 /* shouldn't happen: menu item is insensitive */
3239 ARDOUR::CleanupReport rep;
3241 if (_session->cleanup_trash_sources (rep)) {
3245 display_cleanup_results (rep,
3247 _("The following %1 files were deleted from\n\
3249 releasing %3 %4bytes of disk space"),
3250 _("The following file was deleted from\n\
3252 releasing %3 %4bytes of disk space"));
3256 ARDOUR_UI::add_route (Gtk::Window* float_window)
3264 if (add_route_dialog == 0) {
3265 add_route_dialog = new AddRouteDialog (_session);
3266 add_route_dialog->set_position (WIN_POS_MOUSE);
3268 add_route_dialog->set_transient_for (*float_window);
3272 if (add_route_dialog->is_visible()) {
3273 /* we're already doing this */
3277 ResponseType r = (ResponseType) add_route_dialog->run ();
3279 add_route_dialog->hide();
3282 case RESPONSE_ACCEPT:
3289 if ((count = add_route_dialog->count()) <= 0) {
3293 string template_path = add_route_dialog->track_template();
3295 if (!template_path.empty()) {
3296 _session->new_route_from_template (count, template_path);
3300 uint32_t input_chan = add_route_dialog->channels ();
3301 uint32_t output_chan;
3302 string name_template = add_route_dialog->name_template ();
3303 PluginInfoPtr instrument = add_route_dialog->requested_instrument ();
3304 RouteGroup* route_group = add_route_dialog->route_group ();
3306 AutoConnectOption oac = Config->get_output_auto_connect();
3308 if (oac & AutoConnectMaster) {
3309 output_chan = (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan);
3311 output_chan = input_chan;
3314 /* XXX do something with name template */
3316 if (add_route_dialog->midi_tracks_wanted()) {
3317 session_add_midi_track (route_group, count, name_template, instrument);
3318 } else if (add_route_dialog->audio_tracks_wanted()) {
3319 session_add_audio_track (input_chan, output_chan, add_route_dialog->mode(), route_group, count, name_template);
3321 session_add_audio_bus (input_chan, output_chan, route_group, count, name_template);
3326 ARDOUR_UI::mixer_settings () const
3331 node = _session->instant_xml(X_("Mixer"));
3333 node = Config->instant_xml(X_("Mixer"));
3337 node = new XMLNode (X_("Mixer"));
3344 ARDOUR_UI::editor_settings () const
3349 node = _session->instant_xml(X_("Editor"));
3351 node = Config->instant_xml(X_("Editor"));
3355 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
3356 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
3361 node = new XMLNode (X_("Editor"));
3368 ARDOUR_UI::keyboard_settings () const
3372 node = Config->extra_xml(X_("Keyboard"));
3375 node = new XMLNode (X_("Keyboard"));
3382 ARDOUR_UI::create_xrun_marker (framepos_t where)
3384 editor->mouse_add_new_marker (where, false, true);
3388 ARDOUR_UI::halt_on_xrun_message ()
3390 MessageDialog msg (*editor,
3391 _("Recording was stopped because your system could not keep up."));
3396 ARDOUR_UI::xrun_handler (framepos_t where)
3402 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
3404 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
3405 create_xrun_marker(where);
3408 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
3409 halt_on_xrun_message ();
3414 ARDOUR_UI::disk_overrun_handler ()
3416 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
3418 if (!have_disk_speed_dialog_displayed) {
3419 have_disk_speed_dialog_displayed = true;
3420 MessageDialog* msg = new MessageDialog (*editor, string_compose (_("\
3421 The disk system on your computer\n\
3422 was not able to keep up with %1.\n\
3424 Specifically, it failed to write data to disk\n\
3425 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
3426 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3432 ARDOUR_UI::disk_underrun_handler ()
3434 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
3436 if (!have_disk_speed_dialog_displayed) {
3437 have_disk_speed_dialog_displayed = true;
3438 MessageDialog* msg = new MessageDialog (
3439 *editor, string_compose (_("The disk system on your computer\n\
3440 was not able to keep up with %1.\n\
3442 Specifically, it failed to read data from disk\n\
3443 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
3444 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3450 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
3452 have_disk_speed_dialog_displayed = false;
3457 ARDOUR_UI::session_dialog (std::string msg)
3459 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
3464 d = new MessageDialog (*editor, msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3466 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3475 ARDOUR_UI::pending_state_dialog ()
3477 HBox* hbox = new HBox();
3478 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3479 ArdourDialog dialog (_("Crash Recovery"), true);
3481 This session appears to have been in\n\
3482 middle of recording when ardour or\n\
3483 the computer was shutdown.\n\
3485 Ardour can recover any captured audio for\n\
3486 you, or it can ignore it. Please decide\n\
3487 what you would like to do.\n"));
3488 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3489 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3490 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3491 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3492 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
3493 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
3494 dialog.set_default_response (RESPONSE_ACCEPT);
3495 dialog.set_position (WIN_POS_CENTER);
3500 switch (dialog.run ()) {
3501 case RESPONSE_ACCEPT:
3509 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
3511 HBox* hbox = new HBox();
3512 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3513 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
3514 Label message (string_compose (_("\
3515 This session was created with a sample rate of %1 Hz\n\
3517 The audioengine is currently running at %2 Hz\n"), desired, actual));
3519 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3520 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3521 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3522 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3523 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
3524 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
3525 dialog.set_default_response (RESPONSE_ACCEPT);
3526 dialog.set_position (WIN_POS_CENTER);
3531 switch (dialog.run ()) {
3532 case RESPONSE_ACCEPT:
3541 ARDOUR_UI::disconnect_from_jack ()
3544 if( engine->disconnect_from_jack ()) {
3545 MessageDialog msg (*editor, _("Could not disconnect from JACK"));
3549 update_sample_rate (0);
3554 ARDOUR_UI::reconnect_to_jack ()
3557 if (engine->reconnect_to_jack ()) {
3558 MessageDialog msg (*editor, _("Could not reconnect to JACK"));
3562 update_sample_rate (0);
3567 ARDOUR_UI::use_config ()
3569 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
3571 set_transport_controllable_state (*node);
3576 ARDOUR_UI::update_transport_clocks (framepos_t pos)
3578 if (Config->get_primary_clock_delta_edit_cursor()) {
3579 primary_clock->set (pos, false, editor->get_preferred_edit_position());
3581 primary_clock->set (pos);
3584 if (Config->get_secondary_clock_delta_edit_cursor()) {
3585 secondary_clock->set (pos, false, editor->get_preferred_edit_position());
3587 secondary_clock->set (pos);
3590 if (big_clock_window->get()) {
3591 big_clock->set (pos);
3597 ARDOUR_UI::step_edit_status_change (bool yn)
3599 // XXX should really store pre-step edit status of things
3600 // we make insensitive
3603 rec_button.set_active_state (Gtkmm2ext::ImplicitActive);
3604 rec_button.set_sensitive (false);
3606 rec_button.unset_active_state ();;
3607 rec_button.set_sensitive (true);
3612 ARDOUR_UI::record_state_changed ()
3614 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
3616 if (!_session || !big_clock_window->get()) {
3617 /* why bother - the clock isn't visible */
3621 if (_session->record_status () == Session::Recording && _session->have_rec_enabled_track ()) {
3622 big_clock->set_active (true);
3624 big_clock->set_active (false);
3629 ARDOUR_UI::first_idle ()
3632 _session->allow_auto_play (true);
3636 editor->first_idle();
3639 Keyboard::set_can_save_keybindings (true);
3644 ARDOUR_UI::store_clock_modes ()
3646 XMLNode* node = new XMLNode(X_("ClockModes"));
3648 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
3649 XMLNode* child = new XMLNode (X_("Clock"));
3651 child->add_property (X_("name"), (*x)->name());
3652 child->add_property (X_("mode"), enum_2_string ((*x)->mode()));
3653 child->add_property (X_("on"), ((*x)->off() ? X_("no") : X_("yes")));
3655 node->add_child_nocopy (*child);
3658 _session->add_extra_xml (*node);
3659 _session->set_dirty ();
3662 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
3663 : Controllable (name), ui (u), type(tp)
3669 ARDOUR_UI::TransportControllable::set_value (double val)
3672 /* do nothing: these are radio-style actions */
3676 const char *action = 0;
3680 action = X_("Roll");
3683 action = X_("Stop");
3686 action = X_("Goto Start");
3689 action = X_("Goto End");
3692 action = X_("Loop");
3695 action = X_("Play Selection");
3698 action = X_("Record");
3708 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
3716 ARDOUR_UI::TransportControllable::get_value (void) const
3743 ARDOUR_UI::setup_profile ()
3745 if (gdk_screen_width() < 1200) {
3746 Profile->set_small_screen ();
3750 if (getenv ("ARDOUR_SAE")) {
3751 Profile->set_sae ();
3752 Profile->set_single_package ();
3757 ARDOUR_UI::toggle_translations ()
3759 using namespace Glib;
3761 RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("EnableTranslation"));
3763 RefPtr<ToggleAction> ract = RefPtr<ToggleAction>::cast_dynamic (act);
3766 string i18n_killer = ARDOUR::translation_kill_path();
3768 bool already_enabled = !ARDOUR::translations_are_disabled ();
3770 if (ract->get_active ()) {
3771 /* we don't care about errors */
3772 int fd = ::open (i18n_killer.c_str(), O_RDONLY|O_CREAT, 0644);
3775 /* we don't care about errors */
3776 unlink (i18n_killer.c_str());
3779 if (already_enabled != ract->get_active()) {
3780 MessageDialog win (already_enabled ? _("Translations disabled") : _("Translations enabled"),
3782 Gtk::MESSAGE_WARNING,
3784 win.set_secondary_text (string_compose (_("You must restart %1 for this to take effect."), PROGRAM_NAME));
3785 win.set_position (Gtk::WIN_POS_CENTER);
3793 /** Add a window proxy to our list, so that its state will be saved.
3794 * This call also causes the window to be created and opened if its
3795 * state was saved as `visible'.
3798 ARDOUR_UI::add_window_proxy (WindowProxyBase* p)
3800 _window_proxies.push_back (p);
3804 /** Remove a window proxy from our list. Must be called if a WindowProxy
3805 * is deleted, to prevent hanging pointers.
3808 ARDOUR_UI::remove_window_proxy (WindowProxyBase* p)
3810 _window_proxies.remove (p);
3814 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
3816 MissingFileDialog dialog (s, str, type);
3821 int result = dialog.run ();
3828 return 1; // quit entire session load
3831 result = dialog.get_action ();
3837 ARDOUR_UI::ambiguous_file (std::string file, std::string /*path*/, std::vector<std::string> hits)
3839 AmbiguousFileDialog dialog (file, hits);
3845 return dialog.get_which ();
3848 /** Allocate our thread-local buffers */
3850 ARDOUR_UI::get_process_buffers ()
3852 _process_thread->get_buffers ();
3855 /** Drop our thread-local buffers */
3857 ARDOUR_UI::drop_process_buffers ()
3859 _process_thread->drop_buffers ();
3863 ARDOUR_UI::feedback_detected ()
3865 _feedback_exists = true;
3869 ARDOUR_UI::successful_graph_sort ()
3871 _feedback_exists = false;
3875 ARDOUR_UI::midi_panic ()
3878 _session->midi_panic();