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 , transport_joiner (play_selection_button, roll_button)
159 , auto_return_button (ArdourButton::led_default_elements)
160 , auto_play_button (ArdourButton::led_default_elements)
161 , auto_input_button (ArdourButton::led_default_elements)
163 , auditioning_alert_button (_("audition"))
164 , solo_alert_button (_("solo"))
165 , feedback_alert_button (_("feedback"))
167 , error_log_button (_("Errors"))
169 , _status_bar_visibility (X_("status-bar"))
170 , _feedback_exists (false)
173 using namespace Gtk::Menu_Helpers;
179 // _auto_display_errors = false;
181 * This was commented out as it wasn't defined
182 * in A3 IIRC. If this is not needed it should
183 * be completely removed.
191 if (theArdourUI == 0) {
195 ui_config = new UIConfiguration();
196 theme_manager = new ThemeManager();
204 _session_is_new = false;
205 big_clock_window = 0;
206 big_clock_height = 0;
207 big_clock_resize_in_progress = false;
208 session_selector_window = 0;
209 last_key_press_time = 0;
210 _will_create_new_session_automatically = false;
211 add_route_dialog = 0;
214 rc_option_editor = 0;
215 session_option_editor = 0;
217 open_session_selector = 0;
218 have_configure_timeout = false;
219 have_disk_speed_dialog_displayed = false;
220 session_loaded = false;
221 ignore_dual_punch = false;
222 original_big_clock_width = -1;
223 original_big_clock_height = -1;
224 original_big_clock_font_size = 0;
226 roll_button.set_controllable (roll_controllable);
227 stop_button.set_controllable (stop_controllable);
228 goto_start_button.set_controllable (goto_start_controllable);
229 goto_end_button.set_controllable (goto_end_controllable);
230 auto_loop_button.set_controllable (auto_loop_controllable);
231 play_selection_button.set_controllable (play_selection_controllable);
232 rec_button.set_controllable (rec_controllable);
234 roll_button.set_name ("transport button");
235 stop_button.set_name ("transport button");
236 goto_start_button.set_name ("transport button");
237 goto_end_button.set_name ("transport button");
238 auto_loop_button.set_name ("transport button");
239 play_selection_button.set_name ("transport button");
240 rec_button.set_name ("transport recenable button");
241 midi_panic_button.set_name ("transport button");
243 goto_start_button.set_tweaks (ArdourButton::ShowClick);
244 goto_end_button.set_tweaks (ArdourButton::ShowClick);
245 midi_panic_button.set_tweaks (ArdourButton::ShowClick);
247 last_configure_time= 0;
250 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
251 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
253 /* handle dialog requests */
255 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
257 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
259 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
261 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
263 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
265 /* handle requests to quit (coming from JACK session) */
267 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::finish, this), gui_context ());
269 /* tell the user about feedback */
271 ARDOUR::Session::FeedbackDetected.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::feedback_detected, this), gui_context ());
272 ARDOUR::Session::SuccessfulGraphSort.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::successful_graph_sort, this), gui_context ());
274 /* handle requests to deal with missing files */
276 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
278 /* and ambiguous files */
280 ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2, _3));
282 /* lets get this party started */
285 if (ARDOUR::init (ARDOUR_COMMAND_LINE::use_vst, ARDOUR_COMMAND_LINE::try_hw_optimization)) {
286 throw failed_constructor ();
289 setup_gtk_ardour_enums ();
292 GainMeter::setup_slider_pix ();
293 RouteTimeAxisView::setup_slider_pix ();
294 ProcessorEntry::setup_slider_pix ();
295 SessionEvent::create_per_thread_pool ("GUI", 512);
297 } catch (failed_constructor& err) {
298 error << string_compose (_("could not initialize %1."), PROGRAM_NAME) << endmsg;
303 /* we like keyboards */
305 keyboard = new ArdourKeyboard(*this);
307 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
309 keyboard->set_state (*node, Stateful::loading_state_version);
312 /* we don't like certain modifiers */
313 Bindings::set_ignored_state (GDK_LOCK_MASK|GDK_MOD2_MASK|GDK_MOD3_MASK);
317 TimeAxisViewItem::set_constant_heights ();
319 /* The following must happen after ARDOUR::init() so that Config is set up */
321 location_ui = new ActionWindowProxy<LocationUIWindow> (X_("locations"), Config->extra_xml (X_("UI")), X_("ToggleLocations"));
322 big_clock_window = new ActionWindowProxy<Gtk::Window> (X_("bigclock"), Config->extra_xml (X_("UI")), X_("ToggleBigClock"));
323 speaker_config_window = new ActionWindowProxy<SpeakerDialog> (X_("speakerconf"), Config->extra_xml (X_("UI")), X_("toggle-speaker-config"));
325 for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) {
326 _global_port_matrix[*i] = new ActionWindowProxy<GlobalPortMatrixWindow> (
327 string_compose ("GlobalPortMatrix-%1", (*i).to_string()),
328 Config->extra_xml (X_("UI")),
329 string_compose ("toggle-%1-connection-manager", (*i).to_string())
335 SpeakerDialog* s = new SpeakerDialog ();
336 s->signal_unmap().connect (sigc::bind (sigc::ptr_fun (&ActionManager::uncheck_toggleaction), X_("<Actions>/Common/toggle-speaker-config")));
337 speaker_config_window->set (s);
339 starting.connect (sigc::mem_fun(*this, &ARDOUR_UI::startup));
340 stopping.connect (sigc::mem_fun(*this, &ARDOUR_UI::shutdown));
342 _process_thread = new ProcessThread ();
343 _process_thread->init ();
345 DPIReset.connect (sigc::mem_fun (*this, &ARDOUR_UI::resize_text_widgets));
348 /** @return true if a session was chosen and `apply' clicked, otherwise false if `cancel' was clicked */
350 ARDOUR_UI::run_startup (bool should_be_new, string load_template)
353 _startup = new ArdourStartup ();
355 XMLNode* audio_setup = Config->extra_xml ("AudioSetup");
357 if (audio_setup && _startup->engine_control()) {
358 _startup->engine_control()->set_state (*audio_setup);
361 _startup->set_new_only (should_be_new);
362 if (!load_template.empty()) {
363 _startup->set_load_template( load_template );
365 _startup->present ();
371 switch (_startup->response()) {
380 ARDOUR_UI::create_engine ()
382 // this gets called every time by new_session()
388 loading_message (_("Starting audio engine"));
391 engine = new ARDOUR::AudioEngine (ARDOUR_COMMAND_LINE::jack_client_name, ARDOUR_COMMAND_LINE::jack_session_uuid);
398 engine->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
399 engine->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
400 engine->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
402 engine->Halted.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
404 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
412 ARDOUR_UI::post_engine ()
414 /* Things to be done once we create the AudioEngine
417 ARDOUR::init_post_engine ();
419 /* load up the UI manager */
421 ActionManager::init ();
425 if (setup_windows ()) {
426 throw failed_constructor ();
429 /* Do this after setup_windows (), as that's when the _status_bar_visibility is created */
430 XMLNode* n = Config->extra_xml (X_("UI"));
432 _status_bar_visibility.set_state (*n);
435 check_memory_locking();
437 /* this is the first point at which all the keybindings are available */
439 if (ARDOUR_COMMAND_LINE::show_key_actions) {
440 vector<string> names;
441 vector<string> paths;
442 vector<string> tooltips;
444 vector<AccelKey> bindings;
446 ActionManager::get_all_actions (names, paths, tooltips, keys, bindings);
448 vector<string>::iterator n;
449 vector<string>::iterator k;
450 for (n = names.begin(), k = keys.begin(); n != names.end(); ++n, ++k) {
451 cerr << "Action: " << (*n) << " bound to " << (*k) << endl;
457 blink_timeout_tag = -1;
459 /* this being a GUI and all, we want peakfiles */
461 AudioFileSource::set_build_peakfiles (true);
462 AudioFileSource::set_build_missing_peakfiles (true);
464 /* set default clock modes */
466 if (Profile->get_sae()) {
467 primary_clock->set_mode (AudioClock::BBT);
468 secondary_clock->set_mode (AudioClock::MinSec);
470 primary_clock->set_mode (AudioClock::Timecode);
471 secondary_clock->set_mode (AudioClock::BBT);
474 /* start the time-of-day-clock */
477 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
478 update_wall_clock ();
479 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 60000);
482 update_disk_space ();
484 update_sample_rate (engine->frame_rate());
486 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
487 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
488 Config->map_parameters (pc);
490 /* now start and maybe save state */
492 if (do_engine_start () == 0) {
493 if (_session && _session_is_new) {
494 /* we need to retain initial visual
495 settings for a new session
497 _session->save_state ("");
502 ARDOUR_UI::~ARDOUR_UI ()
507 delete add_route_dialog;
511 ARDOUR_UI::pop_back_splash (Gtk::Window& win)
513 if (Splash::instance()) {
514 Splash::instance()->pop_back_for (win);
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);
699 pop_back_splash (win);
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);
803 pop_back_splash (msg);
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."));
856 pop_back_splash(msg);
866 second_connection.disconnect ();
867 point_one_second_connection.disconnect ();
868 point_oh_five_second_connection.disconnect ();
869 point_zero_one_second_connection.disconnect();
872 /* Save state before deleting the session, as that causes some
873 windows to be destroyed before their visible state can be
876 save_ardour_state ();
879 // _session->set_deletion_in_progress ();
880 _session->set_clean ();
881 _session->remove_pending_capture_state ();
886 ArdourDialog::close_all_dialogs ();
892 ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
894 ArdourDialog window (_("Unsaved Session"));
895 Gtk::HBox dhbox; // the hbox for the image and text
896 Gtk::Label prompt_label;
897 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
901 assert (actions.size() >= 3);
903 window.add_button (actions[0], RESPONSE_REJECT);
904 window.add_button (actions[1], RESPONSE_APPLY);
905 window.add_button (actions[2], RESPONSE_ACCEPT);
907 window.set_default_response (RESPONSE_ACCEPT);
909 Gtk::Button noquit_button (msg);
910 noquit_button.set_name ("EditorGTKButton");
914 if (_session->snap_name() == _session->name()) {
915 prompt = string_compose(_("The session \"%1\"\nhas not been saved.\n\nAny changes made this time\nwill be lost unless you save it.\n\nWhat do you want to do?"),
916 _session->snap_name());
918 prompt = string_compose(_("The snapshot \"%1\"\nhas not been saved.\n\nAny changes made this time\nwill be lost unless you save it.\n\nWhat do you want to do?"),
919 _session->snap_name());
922 prompt_label.set_text (prompt);
923 prompt_label.set_name (X_("PrompterLabel"));
924 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
926 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
927 dhbox.set_homogeneous (false);
928 dhbox.pack_start (*dimage, false, false, 5);
929 dhbox.pack_start (prompt_label, true, false, 5);
930 window.get_vbox()->pack_start (dhbox);
932 window.set_name (_("Prompter"));
933 window.set_position (Gtk::WIN_POS_MOUSE);
934 window.set_modal (true);
935 window.set_resizable (false);
941 window.set_keep_above (true);
944 ResponseType r = (ResponseType) window.run();
949 case RESPONSE_ACCEPT: // save and get out of here
951 case RESPONSE_APPLY: // get out of here
961 ARDOUR_UI::every_second ()
964 update_buffer_load ();
965 update_disk_space ();
970 ARDOUR_UI::every_point_one_seconds ()
972 shuttle_box->update_speed_display ();
973 RapidScreenUpdate(); /* EMIT_SIGNAL */
978 ARDOUR_UI::every_point_zero_one_seconds ()
980 // august 2007: actual update frequency: 40Hz, not 100Hz
982 SuperRapidScreenUpdate(); /* EMIT_SIGNAL */
987 ARDOUR_UI::update_sample_rate (framecnt_t)
991 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
993 if (!engine->connected()) {
995 snprintf (buf, sizeof (buf), _("disconnected"));
999 framecnt_t rate = engine->frame_rate();
1001 if (fmod (rate, 1000.0) != 0.0) {
1002 snprintf (buf, sizeof (buf), _("JACK: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
1003 (float) rate/1000.0f,
1004 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
1006 snprintf (buf, sizeof (buf), _("JACK: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
1008 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
1012 sample_rate_label.set_markup (buf);
1016 ARDOUR_UI::update_format ()
1019 format_label.set_text ("");
1024 s << _("File:") << X_(" <span foreground=\"green\">");
1026 switch (_session->config.get_native_file_header_format ()) {
1052 switch (_session->config.get_native_file_data_format ()) {
1066 format_label.set_markup (s.str ());
1070 ARDOUR_UI::update_cpu_load ()
1074 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1075 should also be changed.
1078 float const c = engine->get_cpu_load ();
1079 snprintf (buf, sizeof (buf), _("DSP: <span foreground=\"%s\">%5.1f%%</span>"), c >= 90 ? X_("red") : X_("green"), c);
1080 cpu_load_label.set_markup (buf);
1084 ARDOUR_UI::update_buffer_load ()
1088 uint32_t const playback = _session ? _session->playback_load () : 100;
1089 uint32_t const capture = _session ? _session->capture_load () : 100;
1091 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1092 should also be changed.
1098 _("Buffers: <span foreground=\"green\">p:</span><span foreground=\"%s\">%" PRIu32 "%%</span> "
1099 "<span foreground=\"green\">c:</span><span foreground=\"%s\">%" PRIu32 "%%</span>"),
1100 playback <= 5 ? X_("red") : X_("green"),
1102 capture <= 5 ? X_("red") : X_("green"),
1106 buffer_load_label.set_markup (buf);
1108 buffer_load_label.set_text ("");
1113 ARDOUR_UI::count_recenabled_streams (Route& route)
1115 Track* track = dynamic_cast<Track*>(&route);
1116 if (track && track->record_enabled()) {
1117 rec_enabled_streams += track->n_inputs().n_total();
1122 ARDOUR_UI::update_disk_space()
1124 if (_session == 0) {
1128 framecnt_t frames = _session->available_capture_duration();
1130 framecnt_t fr = _session->frame_rate();
1132 if (frames == max_framecnt) {
1133 snprintf (buf, sizeof (buf), _("Disk: <span foreground=\"green\">24hrs+</span>"));
1135 rec_enabled_streams = 0;
1136 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams);
1138 if (rec_enabled_streams) {
1139 frames /= rec_enabled_streams;
1146 hrs = frames / (fr * 3600);
1149 snprintf (buf, sizeof (buf), _("Disk: <span foreground=\"green\">>24 hrs</span>"));
1151 frames -= hrs * fr * 3600;
1152 mins = frames / (fr * 60);
1153 frames -= mins * fr * 60;
1156 bool const low = (hrs == 0 && mins <= 30);
1160 _("Disk: <span foreground=\"%s\">%02dh:%02dm:%02ds</span>"),
1161 low ? X_("red") : X_("green"),
1167 disk_space_label.set_markup (buf);
1169 // An attempt to make the disk space label flash red when space has run out.
1171 if (frames < fr * 60 * 5) {
1172 /* disk_space_box.style ("disk_space_label_empty"); */
1174 /* disk_space_box.style ("disk_space_label"); */
1180 ARDOUR_UI::update_wall_clock ()
1187 tm_now = localtime (&now);
1189 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1190 wall_clock_label.set_text (buf);
1196 ARDOUR_UI::session_menu (GdkEventButton */*ev*/)
1198 session_popup_menu->popup (0, 0);
1203 ARDOUR_UI::redisplay_recent_sessions ()
1205 std::vector<sys::path> session_directories;
1206 RecentSessionsSorter cmp;
1208 recent_session_display.set_model (Glib::RefPtr<TreeModel>(0));
1209 recent_session_model->clear ();
1211 ARDOUR::RecentSessions rs;
1212 ARDOUR::read_recent_sessions (rs);
1215 recent_session_display.set_model (recent_session_model);
1219 // sort them alphabetically
1220 sort (rs.begin(), rs.end(), cmp);
1222 for (ARDOUR::RecentSessions::iterator i = rs.begin(); i != rs.end(); ++i) {
1223 session_directories.push_back ((*i).second);
1226 for (vector<sys::path>::const_iterator i = session_directories.begin();
1227 i != session_directories.end(); ++i)
1229 std::vector<sys::path> state_file_paths;
1231 // now get available states for this session
1233 get_state_files_in_directory (*i, state_file_paths);
1235 vector<string*>* states;
1236 vector<const gchar*> item;
1237 string fullpath = (*i).to_string();
1239 /* remove any trailing / */
1241 if (fullpath[fullpath.length()-1] == '/') {
1242 fullpath = fullpath.substr (0, fullpath.length()-1);
1245 /* check whether session still exists */
1246 if (!Glib::file_test(fullpath.c_str(), Glib::FILE_TEST_EXISTS)) {
1247 /* session doesn't exist */
1248 cerr << "skipping non-existent session " << fullpath << endl;
1252 /* now get available states for this session */
1254 if ((states = Session::possible_states (fullpath)) == 0) {
1255 /* no state file? */
1259 std::vector<string> state_file_names(get_file_names_no_extension (state_file_paths));
1261 Gtk::TreeModel::Row row = *(recent_session_model->append());
1263 row[recent_session_columns.visible_name] = Glib::path_get_basename (fullpath);
1264 row[recent_session_columns.fullpath] = fullpath;
1266 if (state_file_names.size() > 1) {
1270 for (std::vector<std::string>::iterator i2 = state_file_names.begin();
1271 i2 != state_file_names.end(); ++i2)
1274 Gtk::TreeModel::Row child_row = *(recent_session_model->append (row.children()));
1276 child_row[recent_session_columns.visible_name] = *i2;
1277 child_row[recent_session_columns.fullpath] = fullpath;
1282 recent_session_display.set_model (recent_session_model);
1286 ARDOUR_UI::build_session_selector ()
1288 session_selector_window = new ArdourDialog (_("Recent Sessions"));
1290 Gtk::ScrolledWindow *scroller = manage (new Gtk::ScrolledWindow);
1292 session_selector_window->add_button (Stock::CANCEL, RESPONSE_CANCEL);
1293 session_selector_window->add_button (Stock::OPEN, RESPONSE_ACCEPT);
1294 session_selector_window->set_default_response (RESPONSE_ACCEPT);
1295 recent_session_model = TreeStore::create (recent_session_columns);
1296 recent_session_display.set_model (recent_session_model);
1297 recent_session_display.append_column (_("Recent Sessions"), recent_session_columns.visible_name);
1298 recent_session_display.set_headers_visible (false);
1299 recent_session_display.get_selection()->set_mode (SELECTION_BROWSE);
1300 recent_session_display.signal_row_activated().connect (sigc::mem_fun (*this, &ARDOUR_UI::recent_session_row_activated));
1302 scroller->add (recent_session_display);
1303 scroller->set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
1305 session_selector_window->set_name ("SessionSelectorWindow");
1306 session_selector_window->set_size_request (200, 400);
1307 session_selector_window->get_vbox()->pack_start (*scroller);
1309 recent_session_display.show();
1311 //session_selector_window->get_vbox()->show();
1315 ARDOUR_UI::recent_session_row_activated (const TreePath& /*path*/, TreeViewColumn* /*col*/)
1317 session_selector_window->response (RESPONSE_ACCEPT);
1321 ARDOUR_UI::open_recent_session ()
1323 bool can_return = (_session != 0);
1325 if (session_selector_window == 0) {
1326 build_session_selector ();
1329 redisplay_recent_sessions ();
1333 session_selector_window->set_position (WIN_POS_MOUSE);
1335 ResponseType r = (ResponseType) session_selector_window->run ();
1338 case RESPONSE_ACCEPT:
1342 session_selector_window->hide();
1349 if (recent_session_display.get_selection()->count_selected_rows() == 0) {
1353 session_selector_window->hide();
1355 Gtk::TreeModel::iterator i = recent_session_display.get_selection()->get_selected();
1357 if (i == recent_session_model->children().end()) {
1361 std::string path = (*i)[recent_session_columns.fullpath];
1362 std::string state = (*i)[recent_session_columns.visible_name];
1364 _session_is_new = false;
1366 if (load_session (path, state) == 0) {
1375 ARDOUR_UI::check_audioengine ()
1378 if (!engine->connected()) {
1379 MessageDialog msg (string_compose (
1380 _("%1 is not connected to JACK\n"
1381 "You cannot open or close sessions in this condition"),
1383 pop_back_splash (msg);
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, const string& name_template, PluginInfoPtr instrument)
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 (instrument, 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;
1468 if ((route = _session->new_midi_route ()) == 0) {
1469 error << _("could not create new midi bus") << endmsg;
1475 MessageDialog msg (*editor,
1476 string_compose (_("There are insufficient JACK ports available\n\
1477 to create a new track or bus.\n\
1478 You should save %1, exit and\n\
1479 restart JACK with more ports."), PROGRAM_NAME));
1486 ARDOUR_UI::session_add_audio_route (
1488 int32_t input_channels,
1489 int32_t output_channels,
1490 ARDOUR::TrackMode mode,
1491 RouteGroup* route_group,
1493 string const & name_template
1496 list<boost::shared_ptr<AudioTrack> > tracks;
1499 if (_session == 0) {
1500 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1506 tracks = _session->new_audio_track (input_channels, output_channels, mode, route_group, how_many, name_template);
1508 if (tracks.size() != how_many) {
1509 if (how_many == 1) {
1510 error << _("could not create a new audio track") << endmsg;
1512 error << string_compose (_("could only create %1 of %2 new audio %3"),
1513 tracks.size(), how_many, (track ? _("tracks") : _("busses"))) << endmsg;
1519 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template);
1521 if (routes.size() != how_many) {
1522 if (how_many == 1) {
1523 error << _("could not create a new audio bus") << endmsg;
1525 error << string_compose (_("could not create %1 new audio busses"), how_many) << endmsg;
1532 MessageDialog msg (*editor,
1533 string_compose (_("There are insufficient JACK ports available\n\
1534 to create a new track or bus.\n\
1535 You should save %1, exit and\n\
1536 restart JACK with more ports."), PROGRAM_NAME));
1537 pop_back_splash (msg);
1543 ARDOUR_UI::do_transport_locate (framepos_t new_position, bool with_roll)
1545 framecnt_t _preroll = 0;
1548 // XXX CONFIG_CHANGE FIX - requires AnyTime handling
1549 // _preroll = _session->convert_to_frames_at (new_position, Config->get_preroll());
1551 if (new_position > _preroll) {
1552 new_position -= _preroll;
1557 _session->request_locate (new_position, with_roll);
1562 ARDOUR_UI::transport_goto_start ()
1565 _session->goto_start();
1567 /* force displayed area in editor to start no matter
1568 what "follow playhead" setting is.
1572 editor->center_screen (_session->current_start_frame ());
1578 ARDOUR_UI::transport_goto_zero ()
1581 _session->request_locate (0);
1583 /* force displayed area in editor to start no matter
1584 what "follow playhead" setting is.
1588 editor->reset_x_origin (0);
1594 ARDOUR_UI::transport_goto_wallclock ()
1596 if (_session && editor) {
1603 localtime_r (&now, &tmnow);
1605 frames = tmnow.tm_hour * (60 * 60 * _session->frame_rate());
1606 frames += tmnow.tm_min * (60 * _session->frame_rate());
1607 frames += tmnow.tm_sec * _session->frame_rate();
1609 _session->request_locate (frames, _session->transport_rolling ());
1611 /* force displayed area in editor to start no matter
1612 what "follow playhead" setting is.
1616 editor->center_screen (frames);
1622 ARDOUR_UI::transport_goto_end ()
1625 framepos_t const frame = _session->current_end_frame();
1626 _session->request_locate (frame);
1628 /* force displayed area in editor to start no matter
1629 what "follow playhead" setting is.
1633 editor->center_screen (frame);
1639 ARDOUR_UI::transport_stop ()
1645 if (_session->is_auditioning()) {
1646 _session->cancel_audition ();
1650 _session->request_stop (false, true);
1654 ARDOUR_UI::transport_stop_and_forget_capture ()
1657 _session->request_stop (true, true);
1662 ARDOUR_UI::remove_last_capture()
1665 editor->remove_last_capture();
1670 ARDOUR_UI::transport_record (bool roll)
1674 switch (_session->record_status()) {
1675 case Session::Disabled:
1676 if (_session->ntracks() == 0) {
1677 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."));
1681 _session->maybe_enable_record ();
1686 case Session::Recording:
1688 _session->request_stop();
1690 _session->disable_record (false, true);
1694 case Session::Enabled:
1695 _session->disable_record (false, true);
1698 //cerr << "ARDOUR_UI::transport_record () called roll = " << roll << " _session->record_status() = " << _session->record_status() << endl;
1702 ARDOUR_UI::transport_roll ()
1708 if (_session->is_auditioning()) {
1713 if (_session->config.get_external_sync()) {
1714 switch (_session->config.get_sync_source()) {
1718 /* transport controlled by the master */
1724 bool rolling = _session->transport_rolling();
1726 if (_session->get_play_loop()) {
1727 /* XXX it is not possible to just leave seamless loop and keep
1728 playing at present (nov 4th 2009)
1730 if (!Config->get_seamless_loop()) {
1731 _session->request_play_loop (false, true);
1733 } else if (_session->get_play_range () && !Config->get_always_play_range()) {
1734 /* stop playing a range if we currently are */
1735 _session->request_play_range (0, true);
1738 if (Config->get_always_play_range()) {
1739 _session->request_play_range (&editor->get_selection().time, true);
1743 _session->request_transport_speed (1.0f);
1748 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
1755 if (_session->is_auditioning()) {
1756 _session->cancel_audition ();
1760 if (_session->config.get_external_sync()) {
1761 switch (_session->config.get_sync_source()) {
1765 /* transport controlled by the master */
1770 bool rolling = _session->transport_rolling();
1771 bool affect_transport = true;
1773 if (rolling && roll_out_of_bounded_mode) {
1774 /* drop out of loop/range playback but leave transport rolling */
1775 if (_session->get_play_loop()) {
1776 if (Config->get_seamless_loop()) {
1777 /* the disk buffers contain copies of the loop - we can't
1778 just keep playing, so stop the transport. the user
1779 can restart as they wish.
1781 affect_transport = true;
1783 /* disk buffers are normal, so we can keep playing */
1784 affect_transport = false;
1786 _session->request_play_loop (false, true);
1787 } else if (_session->get_play_range ()) {
1788 affect_transport = false;
1789 _session->request_play_range (0, true);
1793 if (affect_transport) {
1795 _session->request_stop (with_abort, true);
1797 if (Config->get_always_play_range ()) {
1798 _session->request_play_range (&editor->get_selection().time, true);
1801 _session->request_transport_speed (1.0f);
1807 ARDOUR_UI::toggle_session_auto_loop ()
1813 if (_session->get_play_loop()) {
1815 if (_session->transport_rolling()) {
1817 Location * looploc = _session->locations()->auto_loop_location();
1820 _session->request_locate (looploc->start(), true);
1821 _session->request_play_loop (false);
1825 _session->request_play_loop (false);
1829 Location * looploc = _session->locations()->auto_loop_location();
1832 _session->request_play_loop (true);
1838 ARDOUR_UI::transport_play_selection ()
1844 editor->play_selection ();
1848 ARDOUR_UI::transport_rewind (int option)
1850 float current_transport_speed;
1853 current_transport_speed = _session->transport_speed();
1855 if (current_transport_speed >= 0.0f) {
1858 _session->request_transport_speed (-1.0f);
1861 _session->request_transport_speed (-4.0f);
1864 _session->request_transport_speed (-0.5f);
1869 _session->request_transport_speed (current_transport_speed * 1.5f);
1875 ARDOUR_UI::transport_forward (int option)
1877 float current_transport_speed;
1880 current_transport_speed = _session->transport_speed();
1882 if (current_transport_speed <= 0.0f) {
1885 _session->request_transport_speed (1.0f);
1888 _session->request_transport_speed (4.0f);
1891 _session->request_transport_speed (0.5f);
1896 _session->request_transport_speed (current_transport_speed * 1.5f);
1903 ARDOUR_UI::toggle_record_enable (uint32_t rid)
1905 if (_session == 0) {
1909 boost::shared_ptr<Route> r;
1911 if ((r = _session->route_by_remote_id (rid)) != 0) {
1915 if ((t = dynamic_cast<Track*>(r.get())) != 0) {
1916 t->set_record_enabled (!t->record_enabled(), this);
1919 if (_session == 0) {
1925 ARDOUR_UI::map_transport_state ()
1928 auto_loop_button.unset_active_state ();
1929 play_selection_button.unset_active_state ();
1930 roll_button.unset_active_state ();
1931 stop_button.set_active_state (Gtkmm2ext::Active);
1935 shuttle_box->map_transport_state ();
1937 float sp = _session->transport_speed();
1943 if (_session->get_play_range()) {
1945 play_selection_button.set_active_state (Gtkmm2ext::Active);
1946 roll_button.unset_active_state ();
1947 auto_loop_button.unset_active_state ();
1949 } else if (_session->get_play_loop ()) {
1951 auto_loop_button.set_active_state (Gtkmm2ext::Active);
1952 play_selection_button.unset_active_state ();
1953 roll_button.unset_active_state ();
1957 roll_button.set_active_state (Gtkmm2ext::Active);
1958 play_selection_button.unset_active_state ();
1959 auto_loop_button.unset_active_state ();
1962 if (Config->get_always_play_range()) {
1963 /* light up both roll and play-selection if they are joined */
1964 roll_button.set_active_state (Gtkmm2ext::Active);
1965 play_selection_button.set_active_state (Gtkmm2ext::Active);
1968 stop_button.unset_active_state ();
1972 stop_button.set_active_state (Gtkmm2ext::Active);
1973 roll_button.unset_active_state ();
1974 play_selection_button.unset_active_state ();
1975 auto_loop_button.unset_active_state ();
1976 update_disk_space ();
1981 ARDOUR_UI::engine_stopped ()
1983 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
1984 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1985 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1989 ARDOUR_UI::engine_running ()
1991 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
1992 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, true);
1993 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, false);
1995 Glib::RefPtr<Action> action;
1996 const char* action_name = 0;
1998 switch (engine->frames_per_cycle()) {
2000 action_name = X_("JACKLatency32");
2003 action_name = X_("JACKLatency64");
2006 action_name = X_("JACKLatency128");
2009 action_name = X_("JACKLatency512");
2012 action_name = X_("JACKLatency1024");
2015 action_name = X_("JACKLatency2048");
2018 action_name = X_("JACKLatency4096");
2021 action_name = X_("JACKLatency8192");
2024 /* XXX can we do anything useful ? */
2030 action = ActionManager::get_action (X_("JACK"), action_name);
2033 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (action);
2034 ract->set_active ();
2040 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
2042 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
2043 /* we can't rely on the original string continuing to exist when we are called
2044 again in the GUI thread, so make a copy and note that we need to
2047 char *copy = strdup (reason);
2048 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
2052 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
2053 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
2055 update_sample_rate (0);
2059 /* if the reason is a non-empty string, it means that the backend was shutdown
2060 rather than just Ardour.
2063 if (strlen (reason)) {
2064 msgstr = string_compose (_("The audio backend (JACK) was shutdown because:\n\n%1"), reason);
2066 msgstr = string_compose (_("\
2067 JACK has either been shutdown or it\n\
2068 disconnected %1 because %1\n\
2069 was not fast enough. Try to restart\n\
2070 JACK, reconnect and save the session."), PROGRAM_NAME);
2073 MessageDialog msg (*editor, msgstr);
2074 pop_back_splash (msg);
2078 free ((char*) reason);
2083 ARDOUR_UI::do_engine_start ()
2091 error << _("Unable to start the session running")
2101 ARDOUR_UI::setup_theme ()
2103 theme_manager->setup_theme();
2107 ARDOUR_UI::update_clocks ()
2109 if (!editor || !editor->dragging_playhead()) {
2110 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position()); /* EMIT_SIGNAL */
2115 ARDOUR_UI::start_clocking ()
2117 clock_signal_connection = RapidScreenUpdate.connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2121 ARDOUR_UI::stop_clocking ()
2123 clock_signal_connection.disconnect ();
2127 ARDOUR_UI::toggle_clocking ()
2130 if (clock_button.get_active()) {
2139 ARDOUR_UI::_blink (void *arg)
2142 ((ARDOUR_UI *) arg)->blink ();
2149 Blink (blink_on = !blink_on); /* EMIT_SIGNAL */
2153 ARDOUR_UI::start_blinking ()
2155 /* Start the blink signal. Everybody with a blinking widget
2156 uses Blink to drive the widget's state.
2159 if (blink_timeout_tag < 0) {
2161 blink_timeout_tag = g_timeout_add (240, _blink, this);
2166 ARDOUR_UI::stop_blinking ()
2168 if (blink_timeout_tag >= 0) {
2169 g_source_remove (blink_timeout_tag);
2170 blink_timeout_tag = -1;
2175 /** Ask the user for the name of a new snapshot and then take it.
2179 ARDOUR_UI::snapshot_session (bool switch_to_it)
2181 ArdourPrompter prompter (true);
2184 prompter.set_name ("Prompter");
2185 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2186 prompter.set_title (_("Take Snapshot"));
2187 prompter.set_prompt (_("Name of new snapshot"));
2189 if (!switch_to_it) {
2192 struct tm local_time;
2195 localtime_r (&n, &local_time);
2196 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2197 prompter.set_initial_text (timebuf);
2201 switch (prompter.run()) {
2202 case RESPONSE_ACCEPT:
2204 prompter.get_result (snapname);
2206 bool do_save = (snapname.length() != 0);
2209 char illegal = Session::session_name_is_legal(snapname);
2211 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2212 "snapshot names may not contain a '%1' character"), illegal));
2218 vector<sys::path> p;
2219 get_state_files_in_directory (_session->session_directory().root_path(), p);
2220 vector<string> n = get_file_names_no_extension (p);
2221 if (find (n.begin(), n.end(), snapname) != n.end()) {
2223 ArdourDialog confirm (_("Confirm Snapshot Overwrite"), true);
2224 Label m (_("A snapshot already exists with that name. Do you want to overwrite it?"));
2225 confirm.get_vbox()->pack_start (m, true, true);
2226 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2227 confirm.add_button (_("Overwrite"), Gtk::RESPONSE_ACCEPT);
2228 confirm.show_all ();
2229 switch (confirm.run()) {
2230 case RESPONSE_CANCEL:
2236 save_state (snapname, switch_to_it);
2246 /** Ask the user for a new session name and then rename the session to it.
2250 ARDOUR_UI::rename_session ()
2256 ArdourPrompter prompter (true);
2259 prompter.set_name ("Prompter");
2260 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2261 prompter.set_title (_("Rename Session"));
2262 prompter.set_prompt (_("New session name"));
2265 switch (prompter.run()) {
2266 case RESPONSE_ACCEPT:
2268 prompter.get_result (name);
2270 bool do_rename = (name.length() != 0);
2273 char illegal = Session::session_name_is_legal (name);
2276 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2277 "session names may not contain a '%1' character"), illegal));
2282 switch (_session->rename (name)) {
2284 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
2285 msg.set_position (WIN_POS_MOUSE);
2293 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
2294 msg.set_position (WIN_POS_MOUSE);
2310 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2312 XMLNode* node = new XMLNode (X_("UI"));
2314 for (list<WindowProxyBase*>::iterator i = _window_proxies.begin(); i != _window_proxies.end(); ++i) {
2315 if (!(*i)->rc_configured()) {
2316 node->add_child_nocopy (*((*i)->get_state ()));
2320 node->add_child_nocopy (gui_object_state->get_state());
2322 _session->add_extra_xml (*node);
2324 save_state_canfail (name, switch_to_it);
2328 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2333 if (name.length() == 0) {
2334 name = _session->snap_name();
2337 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2342 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2347 ARDOUR_UI::primary_clock_value_changed ()
2350 _session->request_locate (primary_clock->current_time ());
2355 ARDOUR_UI::big_clock_value_changed ()
2358 _session->request_locate (big_clock->current_time ());
2363 ARDOUR_UI::secondary_clock_value_changed ()
2366 _session->request_locate (secondary_clock->current_time ());
2371 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2373 if (_session == 0) {
2377 if (_session->step_editing()) {
2381 Session::RecordState const r = _session->record_status ();
2382 bool const h = _session->have_rec_enabled_track ();
2384 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2386 rec_button.set_active_state (Active);
2388 rec_button.set_active_state (Mid);
2390 } else if (r == Session::Recording && h) {
2391 rec_button.set_active_state (Mid);
2393 rec_button.unset_active_state ();
2398 ARDOUR_UI::save_template ()
2400 ArdourPrompter prompter (true);
2403 if (!check_audioengine()) {
2407 prompter.set_name (X_("Prompter"));
2408 prompter.set_title (_("Save Template"));
2409 prompter.set_prompt (_("Name for template:"));
2410 prompter.set_initial_text(_session->name() + _("-template"));
2411 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2413 switch (prompter.run()) {
2414 case RESPONSE_ACCEPT:
2415 prompter.get_result (name);
2417 if (name.length()) {
2418 _session->save_template (name);
2428 ARDOUR_UI::edit_metadata ()
2430 SessionMetadataEditor dialog;
2431 dialog.set_session (_session);
2432 editor->ensure_float (dialog);
2437 ARDOUR_UI::import_metadata ()
2439 SessionMetadataImporter dialog;
2440 dialog.set_session (_session);
2441 editor->ensure_float (dialog);
2446 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
2448 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2450 MessageDialog msg (str,
2452 Gtk::MESSAGE_WARNING,
2453 Gtk::BUTTONS_YES_NO,
2457 msg.set_name (X_("OpenExistingDialog"));
2458 msg.set_title (_("Open Existing Session"));
2459 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
2460 msg.set_position (Gtk::WIN_POS_MOUSE);
2461 pop_back_splash (msg);
2463 switch (msg.run()) {
2472 ARDOUR_UI::build_session_from_nsd (const std::string& session_path, const std::string& session_name)
2474 BusProfile bus_profile;
2476 if (Profile->get_sae()) {
2478 bus_profile.master_out_channels = 2;
2479 bus_profile.input_ac = AutoConnectPhysical;
2480 bus_profile.output_ac = AutoConnectMaster;
2481 bus_profile.requested_physical_in = 0; // use all available
2482 bus_profile.requested_physical_out = 0; // use all available
2486 /* get settings from advanced section of NSD */
2488 if (_startup->create_master_bus()) {
2489 bus_profile.master_out_channels = (uint32_t) _startup->master_channel_count();
2491 bus_profile.master_out_channels = 0;
2494 if (_startup->connect_inputs()) {
2495 bus_profile.input_ac = AutoConnectPhysical;
2497 bus_profile.input_ac = AutoConnectOption (0);
2500 bus_profile.output_ac = AutoConnectOption (0);
2502 if (_startup->connect_outputs ()) {
2503 if (_startup->connect_outs_to_master()) {
2504 bus_profile.output_ac = AutoConnectMaster;
2505 } else if (_startup->connect_outs_to_physical()) {
2506 bus_profile.output_ac = AutoConnectPhysical;
2510 bus_profile.requested_physical_in = (uint32_t) _startup->input_limit_count();
2511 bus_profile.requested_physical_out = (uint32_t) _startup->output_limit_count();
2514 if (build_session (session_path, session_name, bus_profile)) {
2522 ARDOUR_UI::idle_load (const std::string& path)
2525 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2526 /* /path/to/foo => /path/to/foo, foo */
2527 load_session (path, basename_nosuffix (path));
2529 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2530 load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2534 ARDOUR_COMMAND_LINE::session_name = path;
2537 * new_session_dialog doens't exist in A3
2538 * Try to remove all references to it to
2539 * see if it will compile. NOTE: this will
2540 * likely cause a runtime issue is my somewhat
2544 //if (new_session_dialog) {
2547 /* make it break out of Dialog::run() and
2551 //new_session_dialog->response (1);
2557 ARDOUR_UI::end_loading_messages ()
2563 ARDOUR_UI::loading_message (const std::string& msg)
2565 if (ARDOUR_COMMAND_LINE::no_splash) {
2571 splash->message (msg);
2576 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
2578 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
2580 string session_name;
2581 string session_path;
2582 string template_name;
2584 bool likely_new = false;
2586 if (!load_template.empty()) {
2587 should_be_new = true;
2588 template_name = load_template;
2593 if (!should_be_new && !ARDOUR_COMMAND_LINE::session_name.empty()) {
2595 /* if they named a specific statefile, use it, otherwise they are
2596 just giving a session folder, and we want to use it as is
2597 to find the session.
2600 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
2602 if (suffix != string::npos) {
2603 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
2604 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
2605 session_name = Glib::path_get_basename (session_name);
2607 session_path = ARDOUR_COMMAND_LINE::session_name;
2608 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
2613 bool const apply = run_startup (should_be_new, load_template);
2616 if (quit_on_cancel) {
2623 /* if we run the startup dialog again, offer more than just "new session" */
2625 should_be_new = false;
2627 session_name = _startup->session_name (likely_new);
2629 string::size_type suffix = session_name.find (statefile_suffix);
2631 if (suffix != string::npos) {
2632 session_name = session_name.substr (0, suffix);
2635 /* this shouldn't happen, but we catch it just in case it does */
2637 if (session_name.empty()) {
2641 if (_startup->use_session_template()) {
2642 template_name = _startup->session_template_name();
2643 _session_is_new = true;
2646 if (session_name[0] == G_DIR_SEPARATOR ||
2647 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
2648 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)) {
2650 /* absolute path or cwd-relative path specified for session name: infer session folder
2651 from what was given.
2654 session_path = Glib::path_get_dirname (session_name);
2655 session_name = Glib::path_get_basename (session_name);
2659 session_path = _startup->session_folder();
2661 char illegal = Session::session_name_is_legal (session_name);
2664 MessageDialog msg (*_startup,
2665 string_compose (_("To ensure compatibility with various systems\n"
2666 "session names may not contain a '%1' character"),
2669 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2675 if (create_engine ()) {
2679 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
2683 std::string existing = Glib::build_filename (session_path, session_name);
2685 if (!ask_about_loading_existing_session (existing)) {
2686 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2691 _session_is_new = false;
2696 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
2698 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2702 if (session_name.find ('/') != std::string::npos) {
2703 MessageDialog msg (*_startup,
2704 _("To ensure compatibility with various systems\n"
2705 "session names may not contain a '/' character"));
2707 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2711 if (session_name.find ('\\') != std::string::npos) {
2712 MessageDialog msg (*_startup,
2713 _("To ensure compatibility with various systems\n"
2714 "session names may not contain a '\\' character"));
2716 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2720 _session_is_new = true;
2723 if (likely_new && template_name.empty()) {
2725 ret = build_session_from_nsd (session_path, session_name);
2729 ret = load_session (session_path, session_name, template_name);
2732 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
2736 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
2737 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
2747 ARDOUR_UI::close_session()
2749 if (!check_audioengine()) {
2753 if (unload_session (true)) {
2757 ARDOUR_COMMAND_LINE::session_name = "";
2759 if (get_session_parameters (true, false)) {
2763 goto_editor_window ();
2766 /** @param snap_name Snapshot name (without .ardour suffix).
2767 * @return -2 if the load failed because we are not connected to the AudioEngine.
2770 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
2772 Session *new_session;
2776 session_loaded = false;
2778 if (!check_audioengine()) {
2782 unload_status = unload_session ();
2784 if (unload_status < 0) {
2786 } else if (unload_status > 0) {
2791 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
2794 new_session = new Session (*engine, path, snap_name, 0, mix_template);
2797 /* this one is special */
2799 catch (AudioEngine::PortRegistrationFailure& err) {
2801 MessageDialog msg (err.what(),
2804 Gtk::BUTTONS_CLOSE);
2806 msg.set_title (_("Port Registration Error"));
2807 msg.set_secondary_text (_("Click the Close button to try again."));
2808 msg.set_position (Gtk::WIN_POS_CENTER);
2809 pop_back_splash (msg);
2812 int response = msg.run ();
2817 case RESPONSE_CANCEL:
2827 MessageDialog msg (string_compose(
2828 _("Session \"%1 (snapshot %2)\" did not load successfully"),
2834 msg.set_title (_("Loading Error"));
2835 msg.set_secondary_text (_("Click the Refresh button to try again."));
2836 msg.add_button (Stock::REFRESH, 1);
2837 msg.set_position (Gtk::WIN_POS_CENTER);
2838 pop_back_splash (msg);
2841 int response = msg.run ();
2856 list<string> const u = new_session->unknown_processors ();
2858 MissingPluginDialog d (_session, u);
2863 /* Now the session been created, add the transport controls */
2864 new_session->add_controllable(roll_controllable);
2865 new_session->add_controllable(stop_controllable);
2866 new_session->add_controllable(goto_start_controllable);
2867 new_session->add_controllable(goto_end_controllable);
2868 new_session->add_controllable(auto_loop_controllable);
2869 new_session->add_controllable(play_selection_controllable);
2870 new_session->add_controllable(rec_controllable);
2872 set_session (new_session);
2874 session_loaded = true;
2876 goto_editor_window ();
2879 _session->set_clean ();
2890 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
2892 Session *new_session;
2895 if (!check_audioengine()) {
2899 session_loaded = false;
2901 x = unload_session ();
2909 _session_is_new = true;
2912 new_session = new Session (*engine, path, snap_name, &bus_profile);
2917 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
2918 pop_back_splash (msg);
2923 /* Give the new session the default GUI state, if such things exist */
2926 n = Config->instant_xml (X_("Editor"));
2928 new_session->add_instant_xml (*n, false);
2930 n = Config->instant_xml (X_("Mixer"));
2932 new_session->add_instant_xml (*n, false);
2935 /* Put the playhead at 0 and scroll fully left */
2936 n = new_session->instant_xml (X_("Editor"));
2938 n->add_property (X_("playhead"), X_("0"));
2939 n->add_property (X_("left-frame"), X_("0"));
2942 set_session (new_session);
2944 session_loaded = true;
2946 new_session->save_state(new_session->name());
2952 ARDOUR_UI::launch_chat ()
2955 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
2957 open_uri("http://webchat.freenode.net/?channels=ardour");
2962 ARDOUR_UI::show_about ()
2966 about->signal_response().connect(sigc::mem_fun (*this, &ARDOUR_UI::about_signal_response) );
2969 about->set_transient_for(*editor);
2974 ARDOUR_UI::launch_manual ()
2976 PBD::open_uri("http://ardour.org/flossmanual");
2980 ARDOUR_UI::launch_reference ()
2982 PBD::open_uri("http://ardour.org/refmanual");
2986 ARDOUR_UI::hide_about ()
2989 about->get_window()->set_cursor ();
2995 ARDOUR_UI::about_signal_response (int /*response*/)
3001 ARDOUR_UI::show_splash ()
3005 splash = new Splash;
3007 cerr << "Splash could not be created\n";
3013 splash->pop_front ();
3014 splash->queue_draw ();
3015 splash->get_window()->process_updates (true);
3020 ARDOUR_UI::hide_splash ()
3028 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title,
3029 const string& plural_msg, const string& singular_msg)
3033 removed = rep.paths.size();
3036 MessageDialog msgd (*editor,
3037 _("No files were ready for clean-up"),
3041 msgd.set_title (_("Clean-up"));
3042 msgd.set_secondary_text (_("If this seems suprising, \n\
3043 check for any existing snapshots.\n\
3044 These may still include regions that\n\
3045 require some unused files to continue to exist."));
3051 ArdourDialog results (_("Clean-up"), true, false);
3053 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
3054 CleanupResultsModelColumns() {
3058 Gtk::TreeModelColumn<std::string> visible_name;
3059 Gtk::TreeModelColumn<std::string> fullpath;
3063 CleanupResultsModelColumns results_columns;
3064 Glib::RefPtr<Gtk::ListStore> results_model;
3065 Gtk::TreeView results_display;
3067 results_model = ListStore::create (results_columns);
3068 results_display.set_model (results_model);
3069 results_display.append_column (list_title, results_columns.visible_name);
3071 results_display.set_name ("CleanupResultsList");
3072 results_display.set_headers_visible (true);
3073 results_display.set_headers_clickable (false);
3074 results_display.set_reorderable (false);
3076 Gtk::ScrolledWindow list_scroller;
3079 Gtk::HBox dhbox; // the hbox for the image and text
3080 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
3081 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
3083 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
3085 const string dead_directory = _session->session_directory().dead_path().to_string();
3088 %1 - number of files removed
3089 %2 - location of "dead"
3090 %3 - size of files affected
3091 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
3094 const char* bprefix;
3095 double space_adjusted = 0;
3097 if (rep.space < 1000) {
3099 space_adjusted = rep.space;
3100 } else if (rep.space < 1000000) {
3101 bprefix = X_("kilo");
3102 space_adjusted = truncf((float)rep.space / 1000.0);
3103 } else if (rep.space < 1000000 * 1000) {
3104 bprefix = X_("mega");
3105 space_adjusted = truncf((float)rep.space / (1000.0 * 1000.0));
3107 bprefix = X_("giga");
3108 space_adjusted = truncf((float)rep.space / (1000.0 * 1000 * 1000.0));
3112 txt.set_text (string_compose (plural_msg, removed, dead_directory, space_adjusted, bprefix));
3114 txt.set_text (string_compose (singular_msg, removed, dead_directory, space_adjusted, bprefix));
3117 dhbox.pack_start (*dimage, true, false, 5);
3118 dhbox.pack_start (txt, true, false, 5);
3120 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
3121 TreeModel::Row row = *(results_model->append());
3122 row[results_columns.visible_name] = *i;
3123 row[results_columns.fullpath] = *i;
3126 list_scroller.add (results_display);
3127 list_scroller.set_size_request (-1, 150);
3128 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
3130 dvbox.pack_start (dhbox, true, false, 5);
3131 dvbox.pack_start (list_scroller, true, false, 5);
3132 ddhbox.pack_start (dvbox, true, false, 5);
3134 results.get_vbox()->pack_start (ddhbox, true, false, 5);
3135 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
3136 results.set_default_response (RESPONSE_CLOSE);
3137 results.set_position (Gtk::WIN_POS_MOUSE);
3139 results_display.show();
3140 list_scroller.show();
3147 //results.get_vbox()->show();
3148 results.set_resizable (false);
3155 ARDOUR_UI::cleanup ()
3157 if (_session == 0) {
3158 /* shouldn't happen: menu item is insensitive */
3163 MessageDialog checker (_("Are you sure you want to clean-up?"),
3165 Gtk::MESSAGE_QUESTION,
3168 checker.set_title (_("Clean-up"));
3170 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
3171 ALL undo/redo information will be lost if you clean-up.\n\
3172 Clean-up will move all unused files to a \"dead\" location."));
3174 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3175 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
3176 checker.set_default_response (RESPONSE_CANCEL);
3178 checker.set_name (_("CleanupDialog"));
3179 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3180 checker.set_position (Gtk::WIN_POS_MOUSE);
3182 switch (checker.run()) {
3183 case RESPONSE_ACCEPT:
3189 ARDOUR::CleanupReport rep;
3191 editor->prepare_for_cleanup ();
3193 /* do not allow flush until a session is reloaded */
3195 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3197 act->set_sensitive (false);
3200 if (_session->cleanup_sources (rep)) {
3201 editor->finish_cleanup ();
3205 editor->finish_cleanup ();
3208 display_cleanup_results (rep,
3211 The following %1 files were not in use and \n\
3212 have been moved to:\n\n\
3214 After a restart of Ardour,\n\n\
3215 Session -> Clean-up -> Flush Wastebasket\n\n\
3216 will release an additional\n\
3217 %3 %4bytes of disk space.\n"),
3219 The following file was not in use and \n\
3220 has been moved to:\n \
3222 After a restart of Ardour,\n\n\
3223 Session -> Clean-up -> Flush Wastebasket\n\n\
3224 will release an additional\n\
3225 %3 %4bytes of disk space.\n"
3231 ARDOUR_UI::flush_trash ()
3233 if (_session == 0) {
3234 /* shouldn't happen: menu item is insensitive */
3238 ARDOUR::CleanupReport rep;
3240 if (_session->cleanup_trash_sources (rep)) {
3244 display_cleanup_results (rep,
3246 _("The following %1 files were deleted from\n\
3248 releasing %3 %4bytes of disk space"),
3249 _("The following file was deleted from\n\
3251 releasing %3 %4bytes of disk space"));
3255 ARDOUR_UI::add_route (Gtk::Window* float_window)
3263 if (add_route_dialog == 0) {
3264 add_route_dialog = new AddRouteDialog (_session);
3265 add_route_dialog->set_position (WIN_POS_MOUSE);
3267 add_route_dialog->set_transient_for (*float_window);
3271 if (add_route_dialog->is_visible()) {
3272 /* we're already doing this */
3276 ResponseType r = (ResponseType) add_route_dialog->run ();
3278 add_route_dialog->hide();
3281 case RESPONSE_ACCEPT:
3288 if ((count = add_route_dialog->count()) <= 0) {
3292 string template_path = add_route_dialog->track_template();
3294 if (!template_path.empty()) {
3295 _session->new_route_from_template (count, template_path);
3299 uint32_t input_chan = add_route_dialog->channels ();
3300 uint32_t output_chan;
3301 string name_template = add_route_dialog->name_template ();
3302 PluginInfoPtr instrument = add_route_dialog->requested_instrument ();
3303 RouteGroup* route_group = add_route_dialog->route_group ();
3305 AutoConnectOption oac = Config->get_output_auto_connect();
3307 if (oac & AutoConnectMaster) {
3308 output_chan = (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan);
3310 output_chan = input_chan;
3313 /* XXX do something with name template */
3315 if (add_route_dialog->midi_tracks_wanted()) {
3316 session_add_midi_track (route_group, count, name_template, instrument);
3317 } else if (add_route_dialog->audio_tracks_wanted()) {
3318 session_add_audio_track (input_chan, output_chan, add_route_dialog->mode(), route_group, count, name_template);
3320 session_add_audio_bus (input_chan, output_chan, route_group, count, name_template);
3325 ARDOUR_UI::mixer_settings () const
3330 node = _session->instant_xml(X_("Mixer"));
3332 node = Config->instant_xml(X_("Mixer"));
3336 node = new XMLNode (X_("Mixer"));
3343 ARDOUR_UI::editor_settings () const
3348 node = _session->instant_xml(X_("Editor"));
3350 node = Config->instant_xml(X_("Editor"));
3354 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
3355 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
3360 node = new XMLNode (X_("Editor"));
3367 ARDOUR_UI::keyboard_settings () const
3371 node = Config->extra_xml(X_("Keyboard"));
3374 node = new XMLNode (X_("Keyboard"));
3381 ARDOUR_UI::create_xrun_marker (framepos_t where)
3383 editor->mouse_add_new_marker (where, false, true);
3387 ARDOUR_UI::halt_on_xrun_message ()
3389 MessageDialog msg (*editor,
3390 _("Recording was stopped because your system could not keep up."));
3395 ARDOUR_UI::xrun_handler (framepos_t where)
3401 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
3403 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
3404 create_xrun_marker(where);
3407 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
3408 halt_on_xrun_message ();
3413 ARDOUR_UI::disk_overrun_handler ()
3415 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
3417 if (!have_disk_speed_dialog_displayed) {
3418 have_disk_speed_dialog_displayed = true;
3419 MessageDialog* msg = new MessageDialog (*editor, string_compose (_("\
3420 The disk system on your computer\n\
3421 was not able to keep up with %1.\n\
3423 Specifically, it failed to write data to disk\n\
3424 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
3425 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3431 ARDOUR_UI::disk_underrun_handler ()
3433 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
3435 if (!have_disk_speed_dialog_displayed) {
3436 have_disk_speed_dialog_displayed = true;
3437 MessageDialog* msg = new MessageDialog (
3438 *editor, string_compose (_("The disk system on your computer\n\
3439 was not able to keep up with %1.\n\
3441 Specifically, it failed to read data from disk\n\
3442 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
3443 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3449 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
3451 have_disk_speed_dialog_displayed = false;
3456 ARDOUR_UI::session_dialog (std::string msg)
3458 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
3463 d = new MessageDialog (*editor, msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3465 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3474 ARDOUR_UI::pending_state_dialog ()
3476 HBox* hbox = new HBox();
3477 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3478 ArdourDialog dialog (_("Crash Recovery"), true);
3480 This session appears to have been in\n\
3481 middle of recording when ardour or\n\
3482 the computer was shutdown.\n\
3484 Ardour can recover any captured audio for\n\
3485 you, or it can ignore it. Please decide\n\
3486 what you would like to do.\n"));
3487 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3488 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3489 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3490 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3491 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
3492 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
3493 dialog.set_default_response (RESPONSE_ACCEPT);
3494 dialog.set_position (WIN_POS_CENTER);
3499 switch (dialog.run ()) {
3500 case RESPONSE_ACCEPT:
3508 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
3510 HBox* hbox = new HBox();
3511 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3512 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
3513 Label message (string_compose (_("\
3514 This session was created with a sample rate of %1 Hz\n\
3516 The audioengine is currently running at %2 Hz\n"), desired, actual));
3518 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3519 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3520 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3521 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3522 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
3523 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
3524 dialog.set_default_response (RESPONSE_ACCEPT);
3525 dialog.set_position (WIN_POS_CENTER);
3530 switch (dialog.run ()) {
3531 case RESPONSE_ACCEPT:
3540 ARDOUR_UI::disconnect_from_jack ()
3543 if( engine->disconnect_from_jack ()) {
3544 MessageDialog msg (*editor, _("Could not disconnect from JACK"));
3548 update_sample_rate (0);
3553 ARDOUR_UI::reconnect_to_jack ()
3556 if (engine->reconnect_to_jack ()) {
3557 MessageDialog msg (*editor, _("Could not reconnect to JACK"));
3561 update_sample_rate (0);
3566 ARDOUR_UI::use_config ()
3568 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
3570 set_transport_controllable_state (*node);
3575 ARDOUR_UI::update_transport_clocks (framepos_t pos)
3577 if (Config->get_primary_clock_delta_edit_cursor()) {
3578 primary_clock->set (pos, false, editor->get_preferred_edit_position());
3580 primary_clock->set (pos);
3583 if (Config->get_secondary_clock_delta_edit_cursor()) {
3584 secondary_clock->set (pos, false, editor->get_preferred_edit_position());
3586 secondary_clock->set (pos);
3589 if (big_clock_window->get()) {
3590 big_clock->set (pos);
3596 ARDOUR_UI::step_edit_status_change (bool yn)
3598 // XXX should really store pre-step edit status of things
3599 // we make insensitive
3602 rec_button.set_active_state (Mid);
3603 rec_button.set_sensitive (false);
3605 rec_button.unset_active_state ();;
3606 rec_button.set_sensitive (true);
3611 ARDOUR_UI::record_state_changed ()
3613 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
3615 if (!_session || !big_clock_window->get()) {
3616 /* why bother - the clock isn't visible */
3620 if (_session->record_status () == Session::Recording && _session->have_rec_enabled_track ()) {
3621 big_clock->set_active (true);
3623 big_clock->set_active (false);
3628 ARDOUR_UI::first_idle ()
3631 _session->allow_auto_play (true);
3635 editor->first_idle();
3638 Keyboard::set_can_save_keybindings (true);
3643 ARDOUR_UI::store_clock_modes ()
3645 XMLNode* node = new XMLNode(X_("ClockModes"));
3647 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
3648 XMLNode* child = new XMLNode (X_("Clock"));
3650 child->add_property (X_("name"), (*x)->name());
3651 child->add_property (X_("mode"), enum_2_string ((*x)->mode()));
3652 child->add_property (X_("on"), ((*x)->off() ? X_("no") : X_("yes")));
3654 node->add_child_nocopy (*child);
3657 _session->add_extra_xml (*node);
3658 _session->set_dirty ();
3661 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
3662 : Controllable (name), ui (u), type(tp)
3668 ARDOUR_UI::TransportControllable::set_value (double val)
3671 /* do nothing: these are radio-style actions */
3675 const char *action = 0;
3679 action = X_("Roll");
3682 action = X_("Stop");
3685 action = X_("Goto Start");
3688 action = X_("Goto End");
3691 action = X_("Loop");
3694 action = X_("Play Selection");
3697 action = X_("Record");
3707 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
3715 ARDOUR_UI::TransportControllable::get_value (void) const
3742 ARDOUR_UI::setup_profile ()
3744 if (gdk_screen_width() < 1200) {
3745 Profile->set_small_screen ();
3749 if (getenv ("ARDOUR_SAE")) {
3750 Profile->set_sae ();
3751 Profile->set_single_package ();
3756 ARDOUR_UI::toggle_translations ()
3758 using namespace Glib;
3760 RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("EnableTranslation"));
3762 RefPtr<ToggleAction> ract = RefPtr<ToggleAction>::cast_dynamic (act);
3765 string i18n_killer = ARDOUR::translation_kill_path();
3767 bool already_enabled = !ARDOUR::translations_are_disabled ();
3769 if (ract->get_active ()) {
3770 /* we don't care about errors */
3771 int fd = ::open (i18n_killer.c_str(), O_RDONLY|O_CREAT, 0644);
3774 /* we don't care about errors */
3775 unlink (i18n_killer.c_str());
3778 if (already_enabled != ract->get_active()) {
3779 MessageDialog win (already_enabled ? _("Translations disabled") : _("Translations enabled"),
3781 Gtk::MESSAGE_WARNING,
3783 win.set_secondary_text (string_compose (_("You must restart %1 for this to take effect."), PROGRAM_NAME));
3784 win.set_position (Gtk::WIN_POS_CENTER);
3792 /** Add a window proxy to our list, so that its state will be saved.
3793 * This call also causes the window to be created and opened if its
3794 * state was saved as `visible'.
3797 ARDOUR_UI::add_window_proxy (WindowProxyBase* p)
3799 _window_proxies.push_back (p);
3803 /** Remove a window proxy from our list. Must be called if a WindowProxy
3804 * is deleted, to prevent hanging pointers.
3807 ARDOUR_UI::remove_window_proxy (WindowProxyBase* p)
3809 _window_proxies.remove (p);
3813 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
3815 MissingFileDialog dialog (s, str, type);
3820 int result = dialog.run ();
3827 return 1; // quit entire session load
3830 result = dialog.get_action ();
3836 ARDOUR_UI::ambiguous_file (std::string file, std::string /*path*/, std::vector<std::string> hits)
3838 AmbiguousFileDialog dialog (file, hits);
3844 return dialog.get_which ();
3847 /** Allocate our thread-local buffers */
3849 ARDOUR_UI::get_process_buffers ()
3851 _process_thread->get_buffers ();
3854 /** Drop our thread-local buffers */
3856 ARDOUR_UI::drop_process_buffers ()
3858 _process_thread->drop_buffers ();
3862 ARDOUR_UI::feedback_detected ()
3864 _feedback_exists = true;
3868 ARDOUR_UI::successful_graph_sort ()
3870 _feedback_exists = false;
3874 ARDOUR_UI::midi_panic ()
3877 _session->midi_panic();