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_("TransportClockDisplay"), true, true, false, true))
141 , secondary_clock (new AudioClock (X_("secondary"), false, X_("SecondaryClockDisplay"), true, true, false, true))
145 , big_clock (new AudioClock (X_("bigclock"), false, "BigClockNonRecording", true, true, false, false))
149 , roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll))
150 , stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop))
151 , goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart))
152 , goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd))
153 , auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop))
154 , play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection))
155 , rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable))
157 , auto_return_button (ArdourButton::led_default_elements)
158 , auto_play_button (ArdourButton::led_default_elements)
159 , auto_input_button (ArdourButton::led_default_elements)
161 , auditioning_alert_button (_("audition"))
162 , solo_alert_button (_("solo"))
163 , feedback_alert_button (_("feedback"))
165 , error_log_button (_("Errors"))
167 , _status_bar_visibility (X_("status-bar"))
168 , _feedback_exists (false)
171 using namespace Gtk::Menu_Helpers;
177 // _auto_display_errors = false;
179 * This was commented out as it wasn't defined
180 * in A3 IIRC. If this is not needed it should
181 * be completely removed.
189 if (theArdourUI == 0) {
193 ui_config = new UIConfiguration();
194 theme_manager = new ThemeManager();
202 _session_is_new = false;
203 big_clock_window = 0;
204 big_clock_height = 0;
205 big_clock_resize_in_progress = false;
206 session_selector_window = 0;
207 last_key_press_time = 0;
208 _will_create_new_session_automatically = false;
209 add_route_dialog = 0;
212 rc_option_editor = 0;
213 session_option_editor = 0;
215 open_session_selector = 0;
216 have_configure_timeout = false;
217 have_disk_speed_dialog_displayed = false;
218 session_loaded = false;
219 ignore_dual_punch = false;
220 original_big_clock_width = -1;
221 original_big_clock_height = -1;
222 original_big_clock_font_size = 0;
224 roll_button.set_controllable (roll_controllable);
225 stop_button.set_controllable (stop_controllable);
226 goto_start_button.set_controllable (goto_start_controllable);
227 goto_end_button.set_controllable (goto_end_controllable);
228 auto_loop_button.set_controllable (auto_loop_controllable);
229 play_selection_button.set_controllable (play_selection_controllable);
230 rec_button.set_controllable (rec_controllable);
232 roll_button.set_name ("transport button");
233 stop_button.set_name ("transport button");
234 goto_start_button.set_name ("transport button");
235 goto_end_button.set_name ("transport button");
236 auto_loop_button.set_name ("transport button");
237 play_selection_button.set_name ("transport button");
238 rec_button.set_name ("transport recenable button");
239 join_play_range_button.set_name ("transport button");
240 midi_panic_button.set_name ("transport button");
242 goto_start_button.set_tweaks (ArdourButton::ShowClick);
243 goto_end_button.set_tweaks (ArdourButton::ShowClick);
244 midi_panic_button.set_tweaks (ArdourButton::ShowClick);
246 last_configure_time= 0;
249 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
250 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
252 /* handle dialog requests */
254 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
256 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
258 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
260 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
262 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
264 /* handle requests to quit (coming from JACK session) */
266 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::finish, this), gui_context ());
268 /* tell the user about feedback */
270 ARDOUR::Session::FeedbackDetected.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::feedback_detected, this), gui_context ());
271 ARDOUR::Session::SuccessfulGraphSort.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::successful_graph_sort, this), gui_context ());
273 /* handle requests to deal with missing files */
275 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
277 /* and ambiguous files */
279 ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2, _3));
281 /* lets get this party started */
284 if (ARDOUR::init (ARDOUR_COMMAND_LINE::use_vst, ARDOUR_COMMAND_LINE::try_hw_optimization)) {
285 throw failed_constructor ();
288 setup_gtk_ardour_enums ();
291 GainMeter::setup_slider_pix ();
292 RouteTimeAxisView::setup_slider_pix ();
293 SendProcessorEntry::setup_slider_pix ();
294 SessionEvent::create_per_thread_pool ("GUI", 512);
296 } catch (failed_constructor& err) {
297 error << string_compose (_("could not initialize %1."), PROGRAM_NAME) << endmsg;
302 /* we like keyboards */
304 keyboard = new ArdourKeyboard(*this);
306 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
308 keyboard->set_state (*node, Stateful::loading_state_version);
311 /* we don't like certain modifiers */
312 Bindings::set_ignored_state (GDK_LOCK_MASK|GDK_MOD2_MASK|GDK_MOD3_MASK);
316 TimeAxisViewItem::set_constant_heights ();
318 /* The following must happen after ARDOUR::init() so that Config is set up */
320 location_ui = new ActionWindowProxy<LocationUIWindow> (X_("locations"), Config->extra_xml (X_("UI")), X_("ToggleLocations"));
321 big_clock_window = new ActionWindowProxy<Gtk::Window> (X_("bigclock"), Config->extra_xml (X_("UI")), X_("ToggleBigClock"));
322 speaker_config_window = new ActionWindowProxy<SpeakerDialog> (X_("speakerconf"), Config->extra_xml (X_("UI")), X_("toggle-speaker-config"));
324 for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) {
325 _global_port_matrix[*i] = new ActionWindowProxy<GlobalPortMatrixWindow> (
326 string_compose ("GlobalPortMatrix-%1", (*i).to_string()),
327 Config->extra_xml (X_("UI")),
328 string_compose ("toggle-%1-connection-manager", (*i).to_string())
334 SpeakerDialog* s = new SpeakerDialog ();
335 s->signal_unmap().connect (sigc::bind (sigc::ptr_fun (&ActionManager::uncheck_toggleaction), X_("<Actions>/Common/toggle-speaker-config")));
336 speaker_config_window->set (s);
338 starting.connect (sigc::mem_fun(*this, &ARDOUR_UI::startup));
339 stopping.connect (sigc::mem_fun(*this, &ARDOUR_UI::shutdown));
341 _process_thread = new ProcessThread ();
342 _process_thread->init ();
344 DPIReset.connect (sigc::mem_fun (*this, &ARDOUR_UI::resize_text_widgets));
347 /** @return true if a session was chosen and `apply' clicked, otherwise false if `cancel' was clicked */
349 ARDOUR_UI::run_startup (bool should_be_new, string load_template)
352 _startup = new ArdourStartup ();
354 XMLNode* audio_setup = Config->extra_xml ("AudioSetup");
356 if (audio_setup && _startup->engine_control()) {
357 _startup->engine_control()->set_state (*audio_setup);
360 _startup->set_new_only (should_be_new);
361 if (!load_template.empty()) {
362 _startup->set_load_template( load_template );
364 _startup->present ();
370 switch (_startup->response()) {
379 ARDOUR_UI::create_engine ()
381 // this gets called every time by new_session()
387 loading_message (_("Starting audio engine"));
390 engine = new ARDOUR::AudioEngine (ARDOUR_COMMAND_LINE::jack_client_name, ARDOUR_COMMAND_LINE::jack_session_uuid);
397 engine->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
398 engine->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
399 engine->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
401 engine->Halted.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
403 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
411 ARDOUR_UI::post_engine ()
413 /* Things to be done once we create the AudioEngine
416 ARDOUR::init_post_engine ();
418 /* load up the UI manager */
420 ActionManager::init ();
424 if (setup_windows ()) {
425 throw failed_constructor ();
428 /* Do this after setup_windows (), as that's when the _status_bar_visibility is created */
429 XMLNode* n = Config->extra_xml (X_("UI"));
431 _status_bar_visibility.set_state (*n);
434 check_memory_locking();
436 /* this is the first point at which all the keybindings are available */
438 if (ARDOUR_COMMAND_LINE::show_key_actions) {
439 vector<string> names;
440 vector<string> paths;
441 vector<string> tooltips;
443 vector<AccelKey> bindings;
445 ActionManager::get_all_actions (names, paths, tooltips, keys, bindings);
447 vector<string>::iterator n;
448 vector<string>::iterator k;
449 for (n = names.begin(), k = keys.begin(); n != names.end(); ++n, ++k) {
450 cerr << "Action: " << (*n) << " bound to " << (*k) << endl;
456 blink_timeout_tag = -1;
458 /* this being a GUI and all, we want peakfiles */
460 AudioFileSource::set_build_peakfiles (true);
461 AudioFileSource::set_build_missing_peakfiles (true);
463 /* set default clock modes */
465 if (Profile->get_sae()) {
466 primary_clock->set_mode (AudioClock::BBT);
467 secondary_clock->set_mode (AudioClock::MinSec);
469 primary_clock->set_mode (AudioClock::Timecode);
470 secondary_clock->set_mode (AudioClock::BBT);
473 /* start the time-of-day-clock */
476 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
477 update_wall_clock ();
478 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 60000);
481 update_disk_space ();
483 update_sample_rate (engine->frame_rate());
485 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
486 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
487 Config->map_parameters (pc);
489 /* now start and maybe save state */
491 if (do_engine_start () == 0) {
492 if (_session && _session_is_new) {
493 /* we need to retain initial visual
494 settings for a new session
496 _session->save_state ("");
501 ARDOUR_UI::~ARDOUR_UI ()
506 delete add_route_dialog;
510 ARDOUR_UI::pop_back_splash ()
512 if (Splash::instance()) {
513 // Splash::instance()->pop_back();
514 Splash::instance()->hide ();
519 ARDOUR_UI::configure_timeout ()
521 if (last_configure_time == 0) {
522 /* no configure events yet */
526 /* force a gap of 0.5 seconds since the last configure event
529 if (get_microseconds() - last_configure_time < 500000) {
532 have_configure_timeout = false;
533 cerr << "config event-driven save\n";
534 save_ardour_state ();
540 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
542 if (have_configure_timeout) {
543 last_configure_time = get_microseconds();
545 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
546 have_configure_timeout = true;
553 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
555 const XMLProperty* prop;
557 if ((prop = node.property ("roll")) != 0) {
558 roll_controllable->set_id (prop->value());
560 if ((prop = node.property ("stop")) != 0) {
561 stop_controllable->set_id (prop->value());
563 if ((prop = node.property ("goto-start")) != 0) {
564 goto_start_controllable->set_id (prop->value());
566 if ((prop = node.property ("goto-end")) != 0) {
567 goto_end_controllable->set_id (prop->value());
569 if ((prop = node.property ("auto-loop")) != 0) {
570 auto_loop_controllable->set_id (prop->value());
572 if ((prop = node.property ("play-selection")) != 0) {
573 play_selection_controllable->set_id (prop->value());
575 if ((prop = node.property ("rec")) != 0) {
576 rec_controllable->set_id (prop->value());
578 if ((prop = node.property ("shuttle")) != 0) {
579 shuttle_box->controllable()->set_id (prop->value());
585 ARDOUR_UI::get_transport_controllable_state ()
587 XMLNode* node = new XMLNode(X_("TransportControllables"));
590 roll_controllable->id().print (buf, sizeof (buf));
591 node->add_property (X_("roll"), buf);
592 stop_controllable->id().print (buf, sizeof (buf));
593 node->add_property (X_("stop"), buf);
594 goto_start_controllable->id().print (buf, sizeof (buf));
595 node->add_property (X_("goto_start"), buf);
596 goto_end_controllable->id().print (buf, sizeof (buf));
597 node->add_property (X_("goto_end"), buf);
598 auto_loop_controllable->id().print (buf, sizeof (buf));
599 node->add_property (X_("auto_loop"), buf);
600 play_selection_controllable->id().print (buf, sizeof (buf));
601 node->add_property (X_("play_selection"), buf);
602 rec_controllable->id().print (buf, sizeof (buf));
603 node->add_property (X_("rec"), buf);
604 shuttle_box->controllable()->id().print (buf, sizeof (buf));
605 node->add_property (X_("shuttle"), buf);
612 ARDOUR_UI::autosave_session ()
614 if (g_main_depth() > 1) {
615 /* inside a recursive main loop,
616 give up because we may not be able to
622 if (!Config->get_periodic_safety_backups()) {
627 _session->maybe_write_autosave();
634 ARDOUR_UI::update_autosave ()
636 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_autosave)
638 if (_session && _session->dirty()) {
639 if (_autosave_connection.connected()) {
640 _autosave_connection.disconnect();
643 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
644 Config->get_periodic_safety_backup_interval() * 1000);
647 if (_autosave_connection.connected()) {
648 _autosave_connection.disconnect();
654 ARDOUR_UI::backend_audio_error (bool we_set_params, Gtk::Window* toplevel)
658 title = string_compose (_("%1 could not start JACK"), PROGRAM_NAME);
660 title = string_compose (_("%1 could not connect to JACK."), PROGRAM_NAME);
663 MessageDialog win (title,
669 win.set_secondary_text(_("There are several possible reasons:\n\
671 1) You requested audio parameters that are not supported..\n\
672 2) JACK is running as another user.\n\
674 Please consider the possibilities, and perhaps try different parameters."));
676 win.set_secondary_text(_("There are several possible reasons:\n\
678 1) JACK is not running.\n\
679 2) JACK is running as another user, perhaps root.\n\
680 3) There is already another client called \"ardour\".\n\
682 Please consider the possibilities, and perhaps (re)start JACK."));
686 win.set_transient_for (*toplevel);
690 win.add_button (Stock::OK, RESPONSE_CLOSE);
692 win.add_button (Stock::QUIT, RESPONSE_CLOSE);
695 win.set_default_response (RESPONSE_CLOSE);
698 win.set_position (Gtk::WIN_POS_CENTER);
701 /* we just don't care about the result, but we want to block */
707 ARDOUR_UI::startup ()
709 Application* app = Application::instance ();
711 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
712 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::idle_load));
715 call_the_mothership (VERSIONSTRING);
720 if (get_session_parameters (true, ARDOUR_COMMAND_LINE::new_session, ARDOUR_COMMAND_LINE::load_template)) {
726 goto_editor_window ();
728 /* Add the window proxies here; their addition may cause windows to be opened, and we want them
729 to be opened on top of the editor window that goto_editor_window() just opened.
731 add_window_proxy (location_ui);
732 add_window_proxy (big_clock_window);
733 for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) {
734 add_window_proxy (_global_port_matrix[*i]);
737 /* We have to do this here since goto_editor_window() ends up calling show_all() on the
738 * editor window, and we may want stuff to be hidden.
740 _status_bar_visibility.update ();
742 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
746 ARDOUR_UI::no_memory_warning ()
748 XMLNode node (X_("no-memory-warning"));
749 Config->add_instant_xml (node);
753 ARDOUR_UI::check_memory_locking ()
756 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
760 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
762 if (engine->is_realtime() && memory_warning_node == 0) {
764 struct rlimit limits;
766 long pages, page_size;
768 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0) {
771 ram = (int64_t) pages * (int64_t) page_size;
774 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
778 if (limits.rlim_cur != RLIM_INFINITY) {
780 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
784 _("WARNING: Your system has a limit for maximum amount of locked memory. "
785 "This might cause %1 to run out of memory before your system "
786 "runs out of memory. \n\n"
787 "You can view the memory limit with 'ulimit -l', "
788 "and it is normally controlled by /etc/security/limits.conf"),
789 PROGRAM_NAME).c_str());
791 VBox* vbox = msg.get_vbox();
793 CheckButton cb (_("Do not show this window again"));
795 cb.signal_toggled().connect (sigc::mem_fun (*this, &ARDOUR_UI::no_memory_warning));
797 hbox.pack_start (cb, true, false);
798 vbox->pack_start (hbox);
805 editor->ensure_float (msg);
815 ARDOUR_UI::queue_finish ()
817 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
821 ARDOUR_UI::idle_finish ()
824 return false; /* do not call again */
833 if (_session->transport_rolling() && (++tries < 8)) {
834 _session->request_stop (false, true);
838 if (_session->dirty()) {
839 vector<string> actions;
840 actions.push_back (_("Don't quit"));
841 actions.push_back (_("Just quit"));
842 actions.push_back (_("Save and quit"));
843 switch (ask_about_saving_session(actions)) {
848 /* use the default name */
849 if (save_state_canfail ("")) {
850 /* failed - don't quit */
851 MessageDialog msg (*editor,
853 Ardour was unable to save your session.\n\n\
854 If you still wish to quit, please use the\n\n\
855 \"Just quit\" option."));
866 second_connection.disconnect ();
867 point_one_second_connection.disconnect ();
868 point_oh_five_second_connection.disconnect ();
869 point_zero_one_second_connection.disconnect();
872 /* Save state before deleting the session, as that causes some
873 windows to be destroyed before their visible state can be
876 save_ardour_state ();
879 // _session->set_deletion_in_progress ();
880 _session->set_clean ();
881 _session->remove_pending_capture_state ();
886 ArdourDialog::close_all_dialogs ();
892 ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
894 ArdourDialog window (_("Unsaved Session"));
895 Gtk::HBox dhbox; // the hbox for the image and text
896 Gtk::Label prompt_label;
897 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
901 assert (actions.size() >= 3);
903 window.add_button (actions[0], RESPONSE_REJECT);
904 window.add_button (actions[1], RESPONSE_APPLY);
905 window.add_button (actions[2], RESPONSE_ACCEPT);
907 window.set_default_response (RESPONSE_ACCEPT);
909 Gtk::Button noquit_button (msg);
910 noquit_button.set_name ("EditorGTKButton");
914 if (_session->snap_name() == _session->name()) {
915 prompt = string_compose(_("The session \"%1\"\nhas not been saved.\n\nAny changes made this time\nwill be lost unless you save it.\n\nWhat do you want to do?"),
916 _session->snap_name());
918 prompt = string_compose(_("The snapshot \"%1\"\nhas not been saved.\n\nAny changes made this time\nwill be lost unless you save it.\n\nWhat do you want to do?"),
919 _session->snap_name());
922 prompt_label.set_text (prompt);
923 prompt_label.set_name (X_("PrompterLabel"));
924 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
926 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
927 dhbox.set_homogeneous (false);
928 dhbox.pack_start (*dimage, false, false, 5);
929 dhbox.pack_start (prompt_label, true, false, 5);
930 window.get_vbox()->pack_start (dhbox);
932 window.set_name (_("Prompter"));
933 window.set_position (Gtk::WIN_POS_MOUSE);
934 window.set_modal (true);
935 window.set_resizable (false);
941 window.set_keep_above (true);
944 ResponseType r = (ResponseType) window.run();
949 case RESPONSE_ACCEPT: // save and get out of here
951 case RESPONSE_APPLY: // get out of here
961 ARDOUR_UI::every_second ()
964 update_buffer_load ();
965 update_disk_space ();
970 ARDOUR_UI::every_point_one_seconds ()
972 shuttle_box->update_speed_display ();
973 RapidScreenUpdate(); /* EMIT_SIGNAL */
978 ARDOUR_UI::every_point_zero_one_seconds ()
980 // august 2007: actual update frequency: 40Hz, not 100Hz
982 SuperRapidScreenUpdate(); /* EMIT_SIGNAL */
987 ARDOUR_UI::update_sample_rate (framecnt_t)
991 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
993 if (!engine->connected()) {
995 snprintf (buf, sizeof (buf), _("disconnected"));
999 framecnt_t rate = engine->frame_rate();
1001 if (fmod (rate, 1000.0) != 0.0) {
1002 snprintf (buf, sizeof (buf), _("JACK: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
1003 (float) rate/1000.0f,
1004 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
1006 snprintf (buf, sizeof (buf), _("JACK: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
1008 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
1012 sample_rate_label.set_markup (buf);
1016 ARDOUR_UI::update_format ()
1019 format_label.set_text ("");
1024 s << "File: <span foreground=\"green\">";
1026 switch (_session->config.get_native_file_header_format ()) {
1052 switch (_session->config.get_native_file_data_format ()) {
1066 format_label.set_markup (s.str ());
1070 ARDOUR_UI::update_cpu_load ()
1074 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1075 should also be changed.
1078 float const c = engine->get_cpu_load ();
1079 snprintf (buf, sizeof (buf), _("DSP: <span foreground=\"%s\">%5.1f%%</span>"), c >= 90 ? X_("red") : X_("green"), c);
1080 cpu_load_label.set_markup (buf);
1084 ARDOUR_UI::update_buffer_load ()
1088 uint32_t const playback = _session ? _session->playback_load () : 100;
1089 uint32_t const capture = _session ? _session->capture_load () : 100;
1091 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1092 should also be changed.
1098 _("Buffers: <span foreground=\"green\">p:</span><span foreground=\"%s\">%" PRIu32 "%%</span> "
1099 "<span foreground=\"green\">c:</span><span foreground=\"%s\">%" PRIu32 "%%</span>"),
1100 playback <= 5 ? X_("red") : X_("green"),
1102 capture <= 5 ? X_("red") : X_("green"),
1106 buffer_load_label.set_markup (buf);
1108 buffer_load_label.set_text ("");
1113 ARDOUR_UI::count_recenabled_streams (Route& route)
1115 Track* track = dynamic_cast<Track*>(&route);
1116 if (track && track->record_enabled()) {
1117 rec_enabled_streams += track->n_inputs().n_total();
1122 ARDOUR_UI::update_disk_space()
1124 if (_session == 0) {
1128 framecnt_t frames = _session->available_capture_duration();
1130 framecnt_t fr = _session->frame_rate();
1132 if (frames == max_framecnt) {
1133 snprintf (buf, sizeof (buf), _("Disk: <span foreground=\"green\">24hrs+</span>"));
1135 rec_enabled_streams = 0;
1136 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams);
1138 if (rec_enabled_streams) {
1139 frames /= rec_enabled_streams;
1146 hrs = frames / (fr * 3600);
1149 snprintf (buf, sizeof (buf), _("Disk: <span foreground=\"green\">>24 hrs</span>"));
1151 frames -= hrs * fr * 3600;
1152 mins = frames / (fr * 60);
1153 frames -= mins * fr * 60;
1156 bool const low = (hrs == 0 && mins <= 30);
1160 _("Disk: <span foreground=\"%s\">%02dh:%02dm:%02ds</span>"),
1161 low ? X_("red") : X_("green"),
1167 disk_space_label.set_markup (buf);
1169 // An attempt to make the disk space label flash red when space has run out.
1171 if (frames < fr * 60 * 5) {
1172 /* disk_space_box.style ("disk_space_label_empty"); */
1174 /* disk_space_box.style ("disk_space_label"); */
1180 ARDOUR_UI::update_wall_clock ()
1187 tm_now = localtime (&now);
1189 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1190 wall_clock_label.set_text (buf);
1196 ARDOUR_UI::session_menu (GdkEventButton */*ev*/)
1198 session_popup_menu->popup (0, 0);
1203 ARDOUR_UI::redisplay_recent_sessions ()
1205 std::vector<sys::path> session_directories;
1206 RecentSessionsSorter cmp;
1208 recent_session_display.set_model (Glib::RefPtr<TreeModel>(0));
1209 recent_session_model->clear ();
1211 ARDOUR::RecentSessions rs;
1212 ARDOUR::read_recent_sessions (rs);
1215 recent_session_display.set_model (recent_session_model);
1219 // sort them alphabetically
1220 sort (rs.begin(), rs.end(), cmp);
1222 for (ARDOUR::RecentSessions::iterator i = rs.begin(); i != rs.end(); ++i) {
1223 session_directories.push_back ((*i).second);
1226 for (vector<sys::path>::const_iterator i = session_directories.begin();
1227 i != session_directories.end(); ++i)
1229 std::vector<sys::path> state_file_paths;
1231 // now get available states for this session
1233 get_state_files_in_directory (*i, state_file_paths);
1235 vector<string*>* states;
1236 vector<const gchar*> item;
1237 string fullpath = (*i).to_string();
1239 /* remove any trailing / */
1241 if (fullpath[fullpath.length()-1] == '/') {
1242 fullpath = fullpath.substr (0, fullpath.length()-1);
1245 /* check whether session still exists */
1246 if (!Glib::file_test(fullpath.c_str(), Glib::FILE_TEST_EXISTS)) {
1247 /* session doesn't exist */
1248 cerr << "skipping non-existent session " << fullpath << endl;
1252 /* now get available states for this session */
1254 if ((states = Session::possible_states (fullpath)) == 0) {
1255 /* no state file? */
1259 std::vector<string> state_file_names(get_file_names_no_extension (state_file_paths));
1261 Gtk::TreeModel::Row row = *(recent_session_model->append());
1263 row[recent_session_columns.visible_name] = Glib::path_get_basename (fullpath);
1264 row[recent_session_columns.fullpath] = fullpath;
1266 if (state_file_names.size() > 1) {
1270 for (std::vector<std::string>::iterator i2 = state_file_names.begin();
1271 i2 != state_file_names.end(); ++i2)
1274 Gtk::TreeModel::Row child_row = *(recent_session_model->append (row.children()));
1276 child_row[recent_session_columns.visible_name] = *i2;
1277 child_row[recent_session_columns.fullpath] = fullpath;
1282 recent_session_display.set_model (recent_session_model);
1286 ARDOUR_UI::build_session_selector ()
1288 session_selector_window = new ArdourDialog (_("Recent Sessions"));
1290 Gtk::ScrolledWindow *scroller = manage (new Gtk::ScrolledWindow);
1292 session_selector_window->add_button (Stock::CANCEL, RESPONSE_CANCEL);
1293 session_selector_window->add_button (Stock::OPEN, RESPONSE_ACCEPT);
1294 session_selector_window->set_default_response (RESPONSE_ACCEPT);
1295 recent_session_model = TreeStore::create (recent_session_columns);
1296 recent_session_display.set_model (recent_session_model);
1297 recent_session_display.append_column (_("Recent Sessions"), recent_session_columns.visible_name);
1298 recent_session_display.set_headers_visible (false);
1299 recent_session_display.get_selection()->set_mode (SELECTION_BROWSE);
1300 recent_session_display.signal_row_activated().connect (sigc::mem_fun (*this, &ARDOUR_UI::recent_session_row_activated));
1302 scroller->add (recent_session_display);
1303 scroller->set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
1305 session_selector_window->set_name ("SessionSelectorWindow");
1306 session_selector_window->set_size_request (200, 400);
1307 session_selector_window->get_vbox()->pack_start (*scroller);
1309 recent_session_display.show();
1311 //session_selector_window->get_vbox()->show();
1315 ARDOUR_UI::recent_session_row_activated (const TreePath& /*path*/, TreeViewColumn* /*col*/)
1317 session_selector_window->response (RESPONSE_ACCEPT);
1321 ARDOUR_UI::open_recent_session ()
1323 bool can_return = (_session != 0);
1325 if (session_selector_window == 0) {
1326 build_session_selector ();
1329 redisplay_recent_sessions ();
1333 session_selector_window->set_position (WIN_POS_MOUSE);
1335 ResponseType r = (ResponseType) session_selector_window->run ();
1338 case RESPONSE_ACCEPT:
1342 session_selector_window->hide();
1349 if (recent_session_display.get_selection()->count_selected_rows() == 0) {
1353 session_selector_window->hide();
1355 Gtk::TreeModel::iterator i = recent_session_display.get_selection()->get_selected();
1357 if (i == recent_session_model->children().end()) {
1361 std::string path = (*i)[recent_session_columns.fullpath];
1362 std::string state = (*i)[recent_session_columns.visible_name];
1364 _session_is_new = false;
1366 if (load_session (path, state) == 0) {
1375 ARDOUR_UI::check_audioengine ()
1378 if (!engine->connected()) {
1379 MessageDialog msg (string_compose (
1380 _("%1 is not connected to JACK\n"
1381 "You cannot open or close sessions in this condition"),
1394 ARDOUR_UI::open_session ()
1396 if (!check_audioengine()) {
1401 /* popup selector window */
1403 if (open_session_selector == 0) {
1405 /* ardour sessions are folders */
1407 open_session_selector = new Gtk::FileChooserDialog (_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1408 open_session_selector->add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1409 open_session_selector->add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1410 open_session_selector->set_default_response(Gtk::RESPONSE_ACCEPT);
1412 FileFilter session_filter;
1413 session_filter.add_pattern ("*.ardour");
1414 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1415 open_session_selector->add_filter (session_filter);
1416 open_session_selector->set_filter (session_filter);
1419 int response = open_session_selector->run();
1420 open_session_selector->hide ();
1423 case RESPONSE_ACCEPT:
1426 open_session_selector->hide();
1430 open_session_selector->hide();
1431 string session_path = open_session_selector->get_filename();
1435 if (session_path.length() > 0) {
1436 if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1437 _session_is_new = isnew;
1438 load_session (path, name);
1445 ARDOUR_UI::session_add_midi_route (bool disk, RouteGroup* route_group, uint32_t how_many, string const & name_template)
1447 list<boost::shared_ptr<MidiTrack> > tracks;
1449 if (_session == 0) {
1450 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1457 tracks = _session->new_midi_track (ARDOUR::Normal, route_group, how_many, name_template);
1459 if (tracks.size() != how_many) {
1460 if (how_many == 1) {
1461 error << _("could not create a new midi track") << endmsg;
1463 error << string_compose (_("could not create %1 new midi tracks"), how_many) << endmsg;
1467 if ((route = _session->new_midi_route ()) == 0) {
1468 error << _("could not create new midi bus") << endmsg;
1474 MessageDialog msg (*editor,
1475 string_compose (_("There are insufficient JACK ports available\n\
1476 to create a new track or bus.\n\
1477 You should save %1, exit and\n\
1478 restart JACK with more ports."), PROGRAM_NAME));
1485 ARDOUR_UI::session_add_audio_route (
1487 int32_t input_channels,
1488 int32_t output_channels,
1489 ARDOUR::TrackMode mode,
1490 RouteGroup* route_group,
1492 string const & name_template
1495 list<boost::shared_ptr<AudioTrack> > tracks;
1498 if (_session == 0) {
1499 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1505 tracks = _session->new_audio_track (input_channels, output_channels, mode, route_group, how_many, name_template);
1507 if (tracks.size() != how_many) {
1508 if (how_many == 1) {
1509 error << _("could not create a new audio track") << endmsg;
1511 error << string_compose (_("could only create %1 of %2 new audio %3"),
1512 tracks.size(), how_many, (track ? _("tracks") : _("busses"))) << endmsg;
1518 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template);
1520 if (routes.size() != how_many) {
1521 if (how_many == 1) {
1522 error << _("could not create a new audio bus") << endmsg;
1524 error << string_compose (_("could not create %1 new audio busses"), how_many) << endmsg;
1531 MessageDialog msg (*editor,
1532 string_compose (_("There are insufficient JACK ports available\n\
1533 to create a new track or bus.\n\
1534 You should save %1, exit and\n\
1535 restart JACK with more ports."), PROGRAM_NAME));
1542 ARDOUR_UI::do_transport_locate (framepos_t new_position, bool with_roll)
1544 framecnt_t _preroll = 0;
1547 // XXX CONFIG_CHANGE FIX - requires AnyTime handling
1548 // _preroll = _session->convert_to_frames_at (new_position, Config->get_preroll());
1550 if (new_position > _preroll) {
1551 new_position -= _preroll;
1556 _session->request_locate (new_position, with_roll);
1561 ARDOUR_UI::transport_goto_start ()
1564 _session->goto_start();
1566 /* force displayed area in editor to start no matter
1567 what "follow playhead" setting is.
1571 editor->center_screen (_session->current_start_frame ());
1577 ARDOUR_UI::transport_goto_zero ()
1580 _session->request_locate (0);
1582 /* force displayed area in editor to start no matter
1583 what "follow playhead" setting is.
1587 editor->reset_x_origin (0);
1593 ARDOUR_UI::transport_goto_wallclock ()
1595 if (_session && editor) {
1602 localtime_r (&now, &tmnow);
1604 frames = tmnow.tm_hour * (60 * 60 * _session->frame_rate());
1605 frames += tmnow.tm_min * (60 * _session->frame_rate());
1606 frames += tmnow.tm_sec * _session->frame_rate();
1608 _session->request_locate (frames, _session->transport_rolling ());
1610 /* force displayed area in editor to start no matter
1611 what "follow playhead" setting is.
1615 editor->center_screen (frames);
1621 ARDOUR_UI::transport_goto_end ()
1624 framepos_t const frame = _session->current_end_frame();
1625 _session->request_locate (frame);
1627 /* force displayed area in editor to start no matter
1628 what "follow playhead" setting is.
1632 editor->center_screen (frame);
1638 ARDOUR_UI::transport_stop ()
1644 if (_session->is_auditioning()) {
1645 _session->cancel_audition ();
1649 _session->request_stop (false, true);
1653 ARDOUR_UI::transport_stop_and_forget_capture ()
1656 _session->request_stop (true, true);
1661 ARDOUR_UI::remove_last_capture()
1664 editor->remove_last_capture();
1669 ARDOUR_UI::transport_record (bool roll)
1673 switch (_session->record_status()) {
1674 case Session::Disabled:
1675 if (_session->ntracks() == 0) {
1676 MessageDialog msg (*editor, _("Please create one or more tracks before trying to record.\nYou can do this with the \"Add Track or Bus\" option in the Session menu."));
1680 _session->maybe_enable_record ();
1685 case Session::Recording:
1687 _session->request_stop();
1689 _session->disable_record (false, true);
1693 case Session::Enabled:
1694 _session->disable_record (false, true);
1697 //cerr << "ARDOUR_UI::transport_record () called roll = " << roll << " _session->record_status() = " << _session->record_status() << endl;
1701 ARDOUR_UI::transport_roll ()
1707 if (_session->is_auditioning()) {
1712 if (_session->config.get_external_sync()) {
1713 switch (_session->config.get_sync_source()) {
1717 /* transport controlled by the master */
1723 bool rolling = _session->transport_rolling();
1725 if (_session->get_play_loop()) {
1726 /* XXX it is not possible to just leave seamless loop and keep
1727 playing at present (nov 4th 2009)
1729 if (!Config->get_seamless_loop()) {
1730 _session->request_play_loop (false, true);
1732 } else if (_session->get_play_range () && !join_play_range_button.active_state()) {
1733 /* stop playing a range if we currently are */
1734 _session->request_play_range (0, true);
1737 if (join_play_range_button.active_state()) {
1738 _session->request_play_range (&editor->get_selection().time, true);
1742 _session->request_transport_speed (1.0f);
1747 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
1754 if (_session->is_auditioning()) {
1755 _session->cancel_audition ();
1759 if (_session->config.get_external_sync()) {
1760 switch (_session->config.get_sync_source()) {
1764 /* transport controlled by the master */
1769 bool rolling = _session->transport_rolling();
1770 bool affect_transport = true;
1772 if (rolling && roll_out_of_bounded_mode) {
1773 /* drop out of loop/range playback but leave transport rolling */
1774 if (_session->get_play_loop()) {
1775 if (Config->get_seamless_loop()) {
1776 /* the disk buffers contain copies of the loop - we can't
1777 just keep playing, so stop the transport. the user
1778 can restart as they wish.
1780 affect_transport = true;
1782 /* disk buffers are normal, so we can keep playing */
1783 affect_transport = false;
1785 _session->request_play_loop (false, true);
1786 } else if (_session->get_play_range ()) {
1787 affect_transport = false;
1788 _session->request_play_range (0, true);
1792 if (affect_transport) {
1794 _session->request_stop (with_abort, true);
1796 if (join_play_range_button.active_state()) {
1797 _session->request_play_range (&editor->get_selection().time, true);
1800 _session->request_transport_speed (1.0f);
1806 ARDOUR_UI::toggle_session_auto_loop ()
1812 if (_session->get_play_loop()) {
1814 if (_session->transport_rolling()) {
1816 Location * looploc = _session->locations()->auto_loop_location();
1819 _session->request_locate (looploc->start(), true);
1820 _session->request_play_loop (false);
1824 _session->request_play_loop (false);
1828 Location * looploc = _session->locations()->auto_loop_location();
1831 _session->request_play_loop (true);
1837 ARDOUR_UI::transport_play_selection ()
1843 editor->play_selection ();
1847 ARDOUR_UI::transport_rewind (int option)
1849 float current_transport_speed;
1852 current_transport_speed = _session->transport_speed();
1854 if (current_transport_speed >= 0.0f) {
1857 _session->request_transport_speed (-1.0f);
1860 _session->request_transport_speed (-4.0f);
1863 _session->request_transport_speed (-0.5f);
1868 _session->request_transport_speed (current_transport_speed * 1.5f);
1874 ARDOUR_UI::transport_forward (int option)
1876 float current_transport_speed;
1879 current_transport_speed = _session->transport_speed();
1881 if (current_transport_speed <= 0.0f) {
1884 _session->request_transport_speed (1.0f);
1887 _session->request_transport_speed (4.0f);
1890 _session->request_transport_speed (0.5f);
1895 _session->request_transport_speed (current_transport_speed * 1.5f);
1902 ARDOUR_UI::toggle_record_enable (uint32_t rid)
1904 if (_session == 0) {
1908 boost::shared_ptr<Route> r;
1910 if ((r = _session->route_by_remote_id (rid)) != 0) {
1914 if ((t = dynamic_cast<Track*>(r.get())) != 0) {
1915 t->set_record_enabled (!t->record_enabled(), this);
1918 if (_session == 0) {
1924 ARDOUR_UI::map_transport_state ()
1927 auto_loop_button.unset_active_state ();
1928 play_selection_button.unset_active_state ();
1929 roll_button.unset_active_state ();
1930 stop_button.set_active_state (Gtkmm2ext::Active);
1934 shuttle_box->map_transport_state ();
1936 float sp = _session->transport_speed();
1942 if (_session->get_play_range()) {
1944 play_selection_button.set_active_state (Gtkmm2ext::Active);
1945 roll_button.unset_active_state ();
1946 auto_loop_button.unset_active_state ();
1948 } else if (_session->get_play_loop ()) {
1950 auto_loop_button.set_active_state (Gtkmm2ext::Active);
1951 play_selection_button.unset_active_state ();
1952 roll_button.unset_active_state ();
1956 roll_button.set_active_state (Gtkmm2ext::Active);
1957 play_selection_button.unset_active_state ();
1958 auto_loop_button.unset_active_state ();
1961 if (join_play_range_button.active_state()) {
1962 /* light up both roll and play-selection if they are joined */
1963 roll_button.set_active_state (Gtkmm2ext::Active);
1964 play_selection_button.set_active_state (Gtkmm2ext::Active);
1967 stop_button.unset_active_state ();
1971 stop_button.set_active_state (Gtkmm2ext::Active);
1972 roll_button.unset_active_state ();
1973 play_selection_button.unset_active_state ();
1974 auto_loop_button.unset_active_state ();
1975 update_disk_space ();
1980 ARDOUR_UI::engine_stopped ()
1982 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
1983 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1984 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1988 ARDOUR_UI::engine_running ()
1990 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
1991 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, true);
1992 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, false);
1994 Glib::RefPtr<Action> action;
1995 const char* action_name = 0;
1997 switch (engine->frames_per_cycle()) {
1999 action_name = X_("JACKLatency32");
2002 action_name = X_("JACKLatency64");
2005 action_name = X_("JACKLatency128");
2008 action_name = X_("JACKLatency512");
2011 action_name = X_("JACKLatency1024");
2014 action_name = X_("JACKLatency2048");
2017 action_name = X_("JACKLatency4096");
2020 action_name = X_("JACKLatency8192");
2023 /* XXX can we do anything useful ? */
2029 action = ActionManager::get_action (X_("JACK"), action_name);
2032 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (action);
2033 ract->set_active ();
2039 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
2041 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
2042 /* we can't rely on the original string continuing to exist when we are called
2043 again in the GUI thread, so make a copy and note that we need to
2046 char *copy = strdup (reason);
2047 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
2051 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
2052 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
2054 update_sample_rate (0);
2058 /* if the reason is a non-empty string, it means that the backend was shutdown
2059 rather than just Ardour.
2062 if (strlen (reason)) {
2063 msgstr = string_compose (_("The audio backend (JACK) was shutdown because:\n\n%1"), reason);
2065 msgstr = string_compose (_("\
2066 JACK has either been shutdown or it\n\
2067 disconnected %1 because %1\n\
2068 was not fast enough. Try to restart\n\
2069 JACK, reconnect and save the session."), PROGRAM_NAME);
2072 MessageDialog msg (*editor, msgstr);
2077 free ((char*) reason);
2082 ARDOUR_UI::do_engine_start ()
2090 error << _("Unable to start the session running")
2100 ARDOUR_UI::setup_theme ()
2102 theme_manager->setup_theme();
2106 ARDOUR_UI::update_clocks ()
2108 if (!editor || !editor->dragging_playhead()) {
2109 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position()); /* EMIT_SIGNAL */
2114 ARDOUR_UI::start_clocking ()
2116 clock_signal_connection = RapidScreenUpdate.connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2120 ARDOUR_UI::stop_clocking ()
2122 clock_signal_connection.disconnect ();
2126 ARDOUR_UI::toggle_clocking ()
2129 if (clock_button.get_active()) {
2138 ARDOUR_UI::_blink (void *arg)
2141 ((ARDOUR_UI *) arg)->blink ();
2148 Blink (blink_on = !blink_on); /* EMIT_SIGNAL */
2152 ARDOUR_UI::start_blinking ()
2154 /* Start the blink signal. Everybody with a blinking widget
2155 uses Blink to drive the widget's state.
2158 if (blink_timeout_tag < 0) {
2160 blink_timeout_tag = g_timeout_add (240, _blink, this);
2165 ARDOUR_UI::stop_blinking ()
2167 if (blink_timeout_tag >= 0) {
2168 g_source_remove (blink_timeout_tag);
2169 blink_timeout_tag = -1;
2174 /** Ask the user for the name of a new shapshot and then take it.
2178 ARDOUR_UI::snapshot_session (bool switch_to_it)
2180 ArdourPrompter prompter (true);
2183 prompter.set_name ("Prompter");
2184 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2185 prompter.set_title (_("Take Snapshot"));
2186 prompter.set_prompt (_("Name of new snapshot"));
2188 if (!switch_to_it) {
2191 struct tm local_time;
2194 localtime_r (&n, &local_time);
2195 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2196 prompter.set_initial_text (timebuf);
2200 switch (prompter.run()) {
2201 case RESPONSE_ACCEPT:
2203 prompter.get_result (snapname);
2205 bool do_save = (snapname.length() != 0);
2208 if (snapname.find ('/') != string::npos) {
2209 MessageDialog msg (_("To ensure compatibility with various systems\n"
2210 "snapshot names may not contain a '/' character"));
2214 if (snapname.find ('\\') != string::npos) {
2215 MessageDialog msg (_("To ensure compatibility with various systems\n"
2216 "snapshot names may not contain a '\\' character"));
2220 if (snapname.find (':') != string::npos) {
2221 MessageDialog msg (_("To ensure compatibility with various systems\n"
2222 "snapshot names may not contain a ':' character"));
2228 vector<sys::path> p;
2229 get_state_files_in_directory (_session->session_directory().root_path(), p);
2230 vector<string> n = get_file_names_no_extension (p);
2231 if (find (n.begin(), n.end(), snapname) != n.end()) {
2233 ArdourDialog confirm (_("Confirm Snapshot Overwrite"), true);
2234 Label m (_("A snapshot already exists with that name. Do you want to overwrite it?"));
2235 confirm.get_vbox()->pack_start (m, true, true);
2236 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2237 confirm.add_button (_("Overwrite"), Gtk::RESPONSE_ACCEPT);
2238 confirm.show_all ();
2239 switch (confirm.run()) {
2240 case RESPONSE_CANCEL:
2246 save_state (snapname, switch_to_it);
2256 /** Ask the user for the name of a new shapshot and then take it.
2260 ARDOUR_UI::rename_session ()
2266 ArdourPrompter prompter (true);
2269 prompter.set_name ("Prompter");
2270 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2271 prompter.set_title (_("Rename Session"));
2272 prompter.set_prompt (_("New session name"));
2275 switch (prompter.run()) {
2276 case RESPONSE_ACCEPT:
2278 prompter.get_result (name);
2280 bool do_rename = (name.length() != 0);
2283 if (name.find ('/') != string::npos) {
2284 MessageDialog msg (_("To ensure compatibility with various systems\n"
2285 "session names may not contain a '/' character"));
2289 if (name.find ('\\') != string::npos) {
2290 MessageDialog msg (_("To ensure compatibility with various systems\n"
2291 "session names may not contain a '\\' character"));
2296 switch (_session->rename (name)) {
2298 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
2299 msg.set_position (WIN_POS_MOUSE);
2307 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
2308 msg.set_position (WIN_POS_MOUSE);
2324 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2326 XMLNode* node = new XMLNode (X_("UI"));
2328 for (list<WindowProxyBase*>::iterator i = _window_proxies.begin(); i != _window_proxies.end(); ++i) {
2329 if (!(*i)->rc_configured()) {
2330 node->add_child_nocopy (*((*i)->get_state ()));
2334 node->add_child_nocopy (gui_object_state->get_state());
2336 _session->add_extra_xml (*node);
2338 save_state_canfail (name, switch_to_it);
2342 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2347 if (name.length() == 0) {
2348 name = _session->snap_name();
2351 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2356 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2361 ARDOUR_UI::primary_clock_value_changed ()
2364 _session->request_locate (primary_clock->current_time ());
2369 ARDOUR_UI::big_clock_value_changed ()
2372 _session->request_locate (big_clock->current_time ());
2377 ARDOUR_UI::secondary_clock_value_changed ()
2380 _session->request_locate (secondary_clock->current_time ());
2385 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2387 if (_session == 0) {
2391 if (_session->step_editing()) {
2395 Session::RecordState const r = _session->record_status ();
2396 bool const h = _session->have_rec_enabled_track ();
2398 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2400 rec_button.set_active_state (Active);
2402 rec_button.set_active_state (Mid);
2404 } else if (r == Session::Recording && h) {
2405 rec_button.set_active_state (Mid);
2407 rec_button.unset_active_state ();
2412 ARDOUR_UI::save_template ()
2414 ArdourPrompter prompter (true);
2417 if (!check_audioengine()) {
2421 prompter.set_name (X_("Prompter"));
2422 prompter.set_title (_("Save Template"));
2423 prompter.set_prompt (_("Name for template:"));
2424 prompter.set_initial_text(_session->name() + _("-template"));
2425 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2427 switch (prompter.run()) {
2428 case RESPONSE_ACCEPT:
2429 prompter.get_result (name);
2431 if (name.length()) {
2432 _session->save_template (name);
2442 ARDOUR_UI::edit_metadata ()
2444 SessionMetadataEditor dialog;
2445 dialog.set_session (_session);
2446 editor->ensure_float (dialog);
2451 ARDOUR_UI::import_metadata ()
2453 SessionMetadataImporter dialog;
2454 dialog.set_session (_session);
2455 editor->ensure_float (dialog);
2460 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
2462 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2464 MessageDialog msg (str,
2466 Gtk::MESSAGE_WARNING,
2467 Gtk::BUTTONS_YES_NO,
2471 msg.set_name (X_("OpenExistingDialog"));
2472 msg.set_title (_("Open Existing Session"));
2473 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
2474 msg.set_position (Gtk::WIN_POS_MOUSE);
2477 switch (msg.run()) {
2486 ARDOUR_UI::build_session_from_nsd (const std::string& session_path, const std::string& session_name)
2488 BusProfile bus_profile;
2490 if (Profile->get_sae()) {
2492 bus_profile.master_out_channels = 2;
2493 bus_profile.input_ac = AutoConnectPhysical;
2494 bus_profile.output_ac = AutoConnectMaster;
2495 bus_profile.requested_physical_in = 0; // use all available
2496 bus_profile.requested_physical_out = 0; // use all available
2500 /* get settings from advanced section of NSD */
2502 if (_startup->create_master_bus()) {
2503 bus_profile.master_out_channels = (uint32_t) _startup->master_channel_count();
2505 bus_profile.master_out_channels = 0;
2508 if (_startup->connect_inputs()) {
2509 bus_profile.input_ac = AutoConnectPhysical;
2511 bus_profile.input_ac = AutoConnectOption (0);
2514 /// @todo some minor tweaks.
2516 bus_profile.output_ac = AutoConnectOption (0);
2518 if (_startup->connect_outputs ()) {
2519 if (_startup->connect_outs_to_master()) {
2520 bus_profile.output_ac = AutoConnectMaster;
2521 } else if (_startup->connect_outs_to_physical()) {
2522 bus_profile.output_ac = AutoConnectPhysical;
2526 bus_profile.requested_physical_in = (uint32_t) _startup->input_limit_count();
2527 bus_profile.requested_physical_out = (uint32_t) _startup->output_limit_count();
2530 if (build_session (session_path, session_name, bus_profile)) {
2538 ARDOUR_UI::idle_load (const std::string& path)
2541 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2542 /* /path/to/foo => /path/to/foo, foo */
2543 load_session (path, basename_nosuffix (path));
2545 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2546 load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2550 ARDOUR_COMMAND_LINE::session_name = path;
2553 * new_session_dialog doens't exist in A3
2554 * Try to remove all references to it to
2555 * see if it will compile. NOTE: this will
2556 * likely cause a runtime issue is my somewhat
2560 //if (new_session_dialog) {
2563 /* make it break out of Dialog::run() and
2567 //new_session_dialog->response (1);
2573 ARDOUR_UI::end_loading_messages ()
2579 ARDOUR_UI::loading_message (const std::string& /*msg*/)
2582 // splash->message (msg);
2586 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
2588 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
2590 string session_name;
2591 string session_path;
2592 string template_name;
2594 bool likely_new = false;
2596 if (!load_template.empty()) {
2597 should_be_new = true;
2598 template_name = load_template;
2603 if (!should_be_new && !ARDOUR_COMMAND_LINE::session_name.empty()) {
2605 /* if they named a specific statefile, use it, otherwise they are
2606 just giving a session folder, and we want to use it as is
2607 to find the session.
2610 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
2612 if (suffix != string::npos) {
2613 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
2614 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
2615 session_name = Glib::path_get_basename (session_name);
2617 session_path = ARDOUR_COMMAND_LINE::session_name;
2618 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
2623 bool const apply = run_startup (should_be_new, load_template);
2626 if (quit_on_cancel) {
2633 /* if we run the startup dialog again, offer more than just "new session" */
2635 should_be_new = false;
2637 session_name = _startup->session_name (likely_new);
2639 string::size_type suffix = session_name.find (statefile_suffix);
2641 if (suffix != string::npos) {
2642 session_name = session_name.substr (0, suffix);
2645 /* this shouldn't happen, but we catch it just in case it does */
2647 if (session_name.empty()) {
2651 if (_startup->use_session_template()) {
2652 template_name = _startup->session_template_name();
2653 _session_is_new = true;
2656 if (session_name[0] == G_DIR_SEPARATOR ||
2657 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
2658 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)) {
2660 /* absolute path or cwd-relative path specified for session name: infer session folder
2661 from what was given.
2664 session_path = Glib::path_get_dirname (session_name);
2665 session_name = Glib::path_get_basename (session_name);
2669 session_path = _startup->session_folder();
2671 if (session_name.find ('/') != string::npos) {
2672 MessageDialog msg (*_startup,
2673 _("To ensure compatibility with various systems\n"
2674 "session names may not contain a '/' character"));
2676 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2680 if (session_name.find ('\\') != string::npos) {
2681 MessageDialog msg (*_startup,
2682 _("To ensure compatibility with various systems\n"
2683 "session names may not contain a '\\' character"));
2685 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2691 if (create_engine ()) {
2695 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
2699 std::string existing = Glib::build_filename (session_path, session_name);
2701 if (!ask_about_loading_existing_session (existing)) {
2702 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2707 _session_is_new = false;
2712 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
2714 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2718 if (session_name.find ('/') != std::string::npos) {
2719 MessageDialog msg (*_startup,
2720 _("To ensure compatibility with various systems\n"
2721 "session names may not contain a '/' character"));
2723 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2727 if (session_name.find ('\\') != std::string::npos) {
2728 MessageDialog msg (*_startup,
2729 _("To ensure compatibility with various systems\n"
2730 "session names may not contain a '\\' character"));
2732 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2736 _session_is_new = true;
2739 if (likely_new && template_name.empty()) {
2741 ret = build_session_from_nsd (session_path, session_name);
2745 ret = load_session (session_path, session_name, template_name);
2748 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
2752 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
2753 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
2763 ARDOUR_UI::close_session()
2765 if (!check_audioengine()) {
2769 if (unload_session (true)) {
2773 ARDOUR_COMMAND_LINE::session_name = "";
2775 if (get_session_parameters (true, false)) {
2779 goto_editor_window ();
2782 /** @param snap_name Snapshot name (without .ardour suffix).
2783 * @return -2 if the load failed because we are not connected to the AudioEngine.
2786 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
2788 Session *new_session;
2792 session_loaded = false;
2794 if (!check_audioengine()) {
2798 unload_status = unload_session ();
2800 if (unload_status < 0) {
2802 } else if (unload_status > 0) {
2807 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
2810 new_session = new Session (*engine, path, snap_name, 0, mix_template);
2813 /* this one is special */
2815 catch (AudioEngine::PortRegistrationFailure& err) {
2817 MessageDialog msg (err.what(),
2820 Gtk::BUTTONS_CLOSE);
2822 msg.set_title (_("Port Registration Error"));
2823 msg.set_secondary_text (_("Click the Close button to try again."));
2824 msg.set_position (Gtk::WIN_POS_CENTER);
2828 int response = msg.run ();
2833 case RESPONSE_CANCEL:
2843 MessageDialog msg (string_compose(
2844 _("Session \"%1 (snapshot %2)\" did not load successfully"),
2850 msg.set_title (_("Loading Error"));
2851 msg.set_secondary_text (_("Click the Refresh button to try again."));
2852 msg.add_button (Stock::REFRESH, 1);
2853 msg.set_position (Gtk::WIN_POS_CENTER);
2857 int response = msg.run ();
2872 list<string> const u = new_session->unknown_processors ();
2874 MissingPluginDialog d (_session, u);
2879 /* Now the session been created, add the transport controls */
2880 new_session->add_controllable(roll_controllable);
2881 new_session->add_controllable(stop_controllable);
2882 new_session->add_controllable(goto_start_controllable);
2883 new_session->add_controllable(goto_end_controllable);
2884 new_session->add_controllable(auto_loop_controllable);
2885 new_session->add_controllable(play_selection_controllable);
2886 new_session->add_controllable(rec_controllable);
2888 set_session (new_session);
2890 session_loaded = true;
2892 goto_editor_window ();
2895 _session->set_clean ();
2906 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
2908 Session *new_session;
2911 if (!check_audioengine()) {
2915 session_loaded = false;
2917 x = unload_session ();
2925 _session_is_new = true;
2928 new_session = new Session (*engine, path, snap_name, &bus_profile);
2933 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
2939 /* Give the new session the default GUI state, if such things exist */
2942 n = Config->instant_xml (X_("Editor"));
2944 new_session->add_instant_xml (*n, false);
2946 n = Config->instant_xml (X_("Mixer"));
2948 new_session->add_instant_xml (*n, false);
2951 /* Put the playhead at 0 and scroll fully left */
2952 n = new_session->instant_xml (X_("Editor"));
2954 n->add_property (X_("playhead"), X_("0"));
2955 n->add_property (X_("left-frame"), X_("0"));
2958 set_session (new_session);
2960 session_loaded = true;
2962 new_session->save_state(new_session->name());
2968 ARDOUR_UI::launch_chat ()
2971 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
2973 open_uri("http://webchat.freenode.net/?channels=ardour");
2978 ARDOUR_UI::show_about ()
2982 about->signal_response().connect(sigc::mem_fun (*this, &ARDOUR_UI::about_signal_response) );
2985 about->set_transient_for(*editor);
2990 ARDOUR_UI::launch_manual ()
2992 PBD::open_uri("http://ardour.org/flossmanual");
2996 ARDOUR_UI::launch_reference ()
2998 PBD::open_uri("http://ardour.org/refmanual");
3002 ARDOUR_UI::hide_about ()
3005 about->get_window()->set_cursor ();
3011 ARDOUR_UI::about_signal_response (int /*response*/)
3017 ARDOUR_UI::show_splash ()
3021 splash = new Splash;
3029 splash->queue_draw ();
3030 splash->get_window()->process_updates (true);
3035 ARDOUR_UI::hide_splash ()
3043 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title,
3044 const string& plural_msg, const string& singular_msg)
3048 removed = rep.paths.size();
3051 MessageDialog msgd (*editor,
3052 _("No files were ready for clean-up"),
3055 (Gtk::ButtonsType)(Gtk::BUTTONS_OK) );
3056 msgd.set_title (_("Clean-up"));
3057 msgd.set_secondary_text (_("If this seems suprising, \n\
3058 check for any existing snapshots.\n\
3059 These may still include regions that\n\
3060 require some unused files to continue to exist."));
3066 ArdourDialog results (_("Clean-up"), true, false);
3068 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
3069 CleanupResultsModelColumns() {
3073 Gtk::TreeModelColumn<std::string> visible_name;
3074 Gtk::TreeModelColumn<std::string> fullpath;
3078 CleanupResultsModelColumns results_columns;
3079 Glib::RefPtr<Gtk::ListStore> results_model;
3080 Gtk::TreeView results_display;
3082 results_model = ListStore::create (results_columns);
3083 results_display.set_model (results_model);
3084 results_display.append_column (list_title, results_columns.visible_name);
3086 results_display.set_name ("CleanupResultsList");
3087 results_display.set_headers_visible (true);
3088 results_display.set_headers_clickable (false);
3089 results_display.set_reorderable (false);
3091 Gtk::ScrolledWindow list_scroller;
3094 Gtk::HBox dhbox; // the hbox for the image and text
3095 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
3096 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
3098 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
3100 const string dead_directory = _session->session_directory().dead_path().to_string();
3103 %1 - number of files removed
3104 %2 - location of "dead"
3105 %3 - size of files affected
3106 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
3109 const char* bprefix;
3110 double space_adjusted = 0;
3112 if (rep.space < 1000) {
3114 space_adjusted = rep.space;
3115 } else if (rep.space < 1000000) {
3116 bprefix = X_("kilo");
3117 space_adjusted = truncf((float)rep.space / 1000.0);
3118 } else if (rep.space < 1000000 * 1000) {
3119 bprefix = X_("mega");
3120 space_adjusted = truncf((float)rep.space / (1000.0 * 1000.0));
3122 bprefix = X_("giga");
3123 space_adjusted = truncf((float)rep.space / (1000.0 * 1000 * 1000.0));
3127 txt.set_text (string_compose (plural_msg, removed, dead_directory, space_adjusted, bprefix));
3129 txt.set_text (string_compose (singular_msg, removed, dead_directory, space_adjusted, bprefix));
3132 dhbox.pack_start (*dimage, true, false, 5);
3133 dhbox.pack_start (txt, true, false, 5);
3135 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
3136 TreeModel::Row row = *(results_model->append());
3137 row[results_columns.visible_name] = *i;
3138 row[results_columns.fullpath] = *i;
3141 list_scroller.add (results_display);
3142 list_scroller.set_size_request (-1, 150);
3143 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
3145 dvbox.pack_start (dhbox, true, false, 5);
3146 dvbox.pack_start (list_scroller, true, false, 5);
3147 ddhbox.pack_start (dvbox, true, false, 5);
3149 results.get_vbox()->pack_start (ddhbox, true, false, 5);
3150 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
3151 results.set_default_response (RESPONSE_CLOSE);
3152 results.set_position (Gtk::WIN_POS_MOUSE);
3154 results_display.show();
3155 list_scroller.show();
3162 //results.get_vbox()->show();
3163 results.set_resizable (false);
3170 ARDOUR_UI::cleanup ()
3172 if (_session == 0) {
3173 /* shouldn't happen: menu item is insensitive */
3178 MessageDialog checker (_("Are you sure you want to clean-up?"),
3180 Gtk::MESSAGE_QUESTION,
3181 (Gtk::ButtonsType)(Gtk::BUTTONS_NONE));
3183 checker.set_title (_("Clean-up"));
3185 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
3186 ALL undo/redo information will be lost if you clean-up.\n\
3187 Clean-up will move all unused files to a \"dead\" location."));
3189 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3190 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
3191 checker.set_default_response (RESPONSE_CANCEL);
3193 checker.set_name (_("CleanupDialog"));
3194 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3195 checker.set_position (Gtk::WIN_POS_MOUSE);
3197 switch (checker.run()) {
3198 case RESPONSE_ACCEPT:
3204 ARDOUR::CleanupReport rep;
3206 editor->prepare_for_cleanup ();
3208 /* do not allow flush until a session is reloaded */
3210 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3212 act->set_sensitive (false);
3215 if (_session->cleanup_sources (rep)) {
3216 editor->finish_cleanup ();
3220 editor->finish_cleanup ();
3223 display_cleanup_results (rep,
3226 The following %1 files were not in use and \n\
3227 have been moved to:\n\n\
3229 After a restart of Ardour,\n\n\
3230 Session -> Clean-up -> Flush Wastebasket\n\n\
3231 will release an additional\n\
3232 %3 %4bytes of disk space.\n"),
3234 The following file was not in use and \n\
3235 has been moved to:\n \
3237 After a restart of Ardour,\n\n\
3238 Session -> Clean-up -> Flush Wastebasket\n\n\
3239 will release an additional\n\
3240 %3 %4bytes of disk space.\n"
3246 ARDOUR_UI::flush_trash ()
3248 if (_session == 0) {
3249 /* shouldn't happen: menu item is insensitive */
3253 ARDOUR::CleanupReport rep;
3255 if (_session->cleanup_trash_sources (rep)) {
3259 display_cleanup_results (rep,
3261 _("The following %1 files were deleted from\n\
3263 releasing %3 %4bytes of disk space"),
3264 _("The following file was deleted from\n\
3266 releasing %3 %4bytes of disk space"));
3270 ARDOUR_UI::add_route (Gtk::Window* float_window)
3278 if (add_route_dialog == 0) {
3279 add_route_dialog = new AddRouteDialog (_session);
3281 add_route_dialog->set_transient_for (*float_window);
3285 if (add_route_dialog->is_visible()) {
3286 /* we're already doing this */
3290 ResponseType r = (ResponseType) add_route_dialog->run ();
3292 add_route_dialog->hide();
3295 case RESPONSE_ACCEPT:
3302 if ((count = add_route_dialog->count()) <= 0) {
3306 string template_path = add_route_dialog->track_template();
3308 if (!template_path.empty()) {
3309 _session->new_route_from_template (count, template_path);
3313 uint32_t input_chan = add_route_dialog->channels ();
3314 uint32_t output_chan;
3315 string name_template = add_route_dialog->name_template ();
3316 bool track = add_route_dialog->track ();
3317 RouteGroup* route_group = add_route_dialog->route_group ();
3319 AutoConnectOption oac = Config->get_output_auto_connect();
3321 if (oac & AutoConnectMaster) {
3322 output_chan = (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan);
3324 output_chan = input_chan;
3327 /* XXX do something with name template */
3329 if (add_route_dialog->type() == ARDOUR::DataType::MIDI) {
3331 session_add_midi_track (route_group, count, name_template);
3333 MessageDialog msg (*editor,
3334 _("Sorry, MIDI Busses are not supported at this time."));
3336 //session_add_midi_bus();
3340 session_add_audio_track (input_chan, output_chan, add_route_dialog->mode(), route_group, count, name_template);
3342 session_add_audio_bus (input_chan, output_chan, route_group, count, name_template);
3348 ARDOUR_UI::mixer_settings () const
3353 node = _session->instant_xml(X_("Mixer"));
3355 node = Config->instant_xml(X_("Mixer"));
3359 node = new XMLNode (X_("Mixer"));
3366 ARDOUR_UI::editor_settings () const
3371 node = _session->instant_xml(X_("Editor"));
3373 node = Config->instant_xml(X_("Editor"));
3377 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
3378 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
3383 node = new XMLNode (X_("Editor"));
3390 ARDOUR_UI::keyboard_settings () const
3394 node = Config->extra_xml(X_("Keyboard"));
3397 node = new XMLNode (X_("Keyboard"));
3404 ARDOUR_UI::create_xrun_marker (framepos_t where)
3406 editor->mouse_add_new_marker (where, false, true);
3410 ARDOUR_UI::halt_on_xrun_message ()
3412 MessageDialog msg (*editor,
3413 _("Recording was stopped because your system could not keep up."));
3418 ARDOUR_UI::xrun_handler (framepos_t where)
3424 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
3426 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
3427 create_xrun_marker(where);
3430 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
3431 halt_on_xrun_message ();
3436 ARDOUR_UI::disk_overrun_handler ()
3438 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
3440 if (!have_disk_speed_dialog_displayed) {
3441 have_disk_speed_dialog_displayed = true;
3442 MessageDialog* msg = new MessageDialog (*editor, string_compose (_("\
3443 The disk system on your computer\n\
3444 was not able to keep up with %1.\n\
3446 Specifically, it failed to write data to disk\n\
3447 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
3448 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3454 ARDOUR_UI::disk_underrun_handler ()
3456 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
3458 if (!have_disk_speed_dialog_displayed) {
3459 have_disk_speed_dialog_displayed = true;
3460 MessageDialog* msg = new MessageDialog (
3461 *editor, string_compose (_("The disk system on your computer\n\
3462 was not able to keep up with %1.\n\
3464 Specifically, it failed to read data from disk\n\
3465 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
3466 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3472 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
3474 have_disk_speed_dialog_displayed = false;
3479 ARDOUR_UI::session_dialog (std::string msg)
3481 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
3486 d = new MessageDialog (*editor, msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3488 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3497 ARDOUR_UI::pending_state_dialog ()
3499 HBox* hbox = new HBox();
3500 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3501 ArdourDialog dialog (_("Crash Recovery"), true);
3503 This session appears to have been in\n\
3504 middle of recording when ardour or\n\
3505 the computer was shutdown.\n\
3507 Ardour can recover any captured audio for\n\
3508 you, or it can ignore it. Please decide\n\
3509 what you would like to do.\n"));
3510 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3511 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3512 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3513 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3514 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
3515 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
3516 dialog.set_default_response (RESPONSE_ACCEPT);
3517 dialog.set_position (WIN_POS_CENTER);
3522 switch (dialog.run ()) {
3523 case RESPONSE_ACCEPT:
3531 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
3533 HBox* hbox = new HBox();
3534 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3535 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
3536 Label message (string_compose (_("\
3537 This session was created with a sample rate of %1 Hz\n\
3539 The audioengine is currently running at %2 Hz\n"), desired, actual));
3541 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3542 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3543 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3544 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3545 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
3546 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
3547 dialog.set_default_response (RESPONSE_ACCEPT);
3548 dialog.set_position (WIN_POS_CENTER);
3553 switch (dialog.run ()) {
3554 case RESPONSE_ACCEPT:
3563 ARDOUR_UI::disconnect_from_jack ()
3566 if( engine->disconnect_from_jack ()) {
3567 MessageDialog msg (*editor, _("Could not disconnect from JACK"));
3571 update_sample_rate (0);
3576 ARDOUR_UI::reconnect_to_jack ()
3579 if (engine->reconnect_to_jack ()) {
3580 MessageDialog msg (*editor, _("Could not reconnect to JACK"));
3584 update_sample_rate (0);
3589 ARDOUR_UI::use_config ()
3591 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
3593 set_transport_controllable_state (*node);
3598 ARDOUR_UI::update_transport_clocks (framepos_t pos)
3600 if (Config->get_primary_clock_delta_edit_cursor()) {
3601 primary_clock->set (pos, false, editor->get_preferred_edit_position(), 1);
3603 primary_clock->set (pos, 0, true);
3606 if (Config->get_secondary_clock_delta_edit_cursor()) {
3607 secondary_clock->set (pos, false, editor->get_preferred_edit_position(), 2);
3609 secondary_clock->set (pos);
3612 if (big_clock_window->get()) {
3613 big_clock->set (pos);
3619 ARDOUR_UI::step_edit_status_change (bool yn)
3621 // XXX should really store pre-step edit status of things
3622 // we make insensitive
3625 rec_button.set_active_state (Mid);
3626 rec_button.set_sensitive (false);
3628 rec_button.unset_active_state ();;
3629 rec_button.set_sensitive (true);
3634 ARDOUR_UI::record_state_changed ()
3636 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
3638 if (!_session || !big_clock_window->get()) {
3639 /* why bother - the clock isn't visible */
3643 Session::RecordState const r = _session->record_status ();
3644 bool const h = _session->have_rec_enabled_track ();
3646 if (r == Session::Recording && h) {
3647 big_clock->set_widget_name ("BigClockRecording");
3649 big_clock->set_widget_name ("BigClockNonRecording");
3654 ARDOUR_UI::first_idle ()
3657 _session->allow_auto_play (true);
3661 editor->first_idle();
3664 Keyboard::set_can_save_keybindings (true);
3669 ARDOUR_UI::store_clock_modes ()
3671 XMLNode* node = new XMLNode(X_("ClockModes"));
3673 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
3674 XMLNode* child = new XMLNode (X_("Clock"));
3676 child->add_property (X_("name"), (*x)->name());
3677 child->add_property (X_("mode"), enum_2_string ((*x)->mode()));
3678 child->add_property (X_("on"), ((*x)->off() ? X_("no") : X_("yes")));
3680 node->add_child_nocopy (*child);
3683 _session->add_extra_xml (*node);
3684 _session->set_dirty ();
3687 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
3688 : Controllable (name), ui (u), type(tp)
3694 ARDOUR_UI::TransportControllable::set_value (double val)
3697 /* do nothing: these are radio-style actions */
3701 const char *action = 0;
3705 action = X_("Roll");
3708 action = X_("Stop");
3711 action = X_("Goto Start");
3714 action = X_("Goto End");
3717 action = X_("Loop");
3720 action = X_("Play Selection");
3723 action = X_("Record");
3733 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
3741 ARDOUR_UI::TransportControllable::get_value (void) const
3768 ARDOUR_UI::setup_profile ()
3770 if (gdk_screen_width() < 1200) {
3771 Profile->set_small_screen ();
3775 if (getenv ("ARDOUR_SAE")) {
3776 Profile->set_sae ();
3777 Profile->set_single_package ();
3782 ARDOUR_UI::toggle_translations ()
3784 using namespace Glib;
3786 RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("EnableTranslation"));
3788 RefPtr<ToggleAction> ract = RefPtr<ToggleAction>::cast_dynamic (act);
3791 string i18n_killer = ARDOUR::translation_kill_path();
3793 bool already_enabled = !ARDOUR::translations_are_disabled ();
3795 if (ract->get_active ()) {
3796 /* we don't care about errors */
3797 int fd = ::open (i18n_killer.c_str(), O_RDONLY|O_CREAT, 0644);
3800 /* we don't care about errors */
3801 unlink (i18n_killer.c_str());
3804 if (already_enabled != ract->get_active()) {
3805 MessageDialog win (already_enabled ? _("Translations disabled") : _("Translations enabled"),
3807 Gtk::MESSAGE_WARNING,
3809 win.set_secondary_text (string_compose (_("You must restart %1 for this to take effect."), PROGRAM_NAME));
3810 win.set_position (Gtk::WIN_POS_CENTER);
3818 /** Add a window proxy to our list, so that its state will be saved.
3819 * This call also causes the window to be created and opened if its
3820 * state was saved as `visible'.
3823 ARDOUR_UI::add_window_proxy (WindowProxyBase* p)
3825 _window_proxies.push_back (p);
3829 /** Remove a window proxy from our list. Must be called if a WindowProxy
3830 * is deleted, to prevent hanging pointers.
3833 ARDOUR_UI::remove_window_proxy (WindowProxyBase* p)
3835 _window_proxies.remove (p);
3839 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
3841 MissingFileDialog dialog (s, str, type);
3846 int result = dialog.run ();
3853 return 1; // quit entire session load
3856 result = dialog.get_action ();
3862 ARDOUR_UI::ambiguous_file (std::string file, std::string /*path*/, std::vector<std::string> hits)
3864 AmbiguousFileDialog dialog (file, hits);
3870 return dialog.get_which ();
3873 /** Allocate our thread-local buffers */
3875 ARDOUR_UI::get_process_buffers ()
3877 _process_thread->get_buffers ();
3880 /** Drop our thread-local buffers */
3882 ARDOUR_UI::drop_process_buffers ()
3884 _process_thread->drop_buffers ();
3888 ARDOUR_UI::feedback_detected ()
3890 _feedback_exists = true;
3894 ARDOUR_UI::successful_graph_sort ()
3896 _feedback_exists = false;
3900 ARDOUR_UI::midi_panic ()
3903 _session->midi_panic();