2 Copyright (C) 1999-2007 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include "gtk2ardour-config.h"
37 #include <sys/resource.h>
39 #include <gtkmm/messagedialog.h>
40 #include <gtkmm/accelmap.h>
42 #include "pbd/error.h"
43 #include "pbd/basename.h"
44 #include "pbd/compose.h"
45 #include "pbd/failed_constructor.h"
46 #include "pbd/enumwriter.h"
47 #include "pbd/memento_command.h"
48 #include "pbd/openuri.h"
49 #include "pbd/file_utils.h"
51 #include "gtkmm2ext/application.h"
52 #include "gtkmm2ext/bindings.h"
53 #include "gtkmm2ext/gtk_ui.h"
54 #include "gtkmm2ext/utils.h"
55 #include "gtkmm2ext/click_box.h"
56 #include "gtkmm2ext/fastmeter.h"
57 #include "gtkmm2ext/popup.h"
58 #include "gtkmm2ext/window_title.h"
60 #include "midi++/manager.h"
62 #include "ardour/ardour.h"
63 #include "ardour/callback.h"
64 #include "ardour/profile.h"
65 #include "ardour/plugin_manager.h"
66 #include "ardour/session_directory.h"
67 #include "ardour/session_route.h"
68 #include "ardour/session_state_utils.h"
69 #include "ardour/session_utils.h"
70 #include "ardour/port.h"
71 #include "ardour/audioengine.h"
72 #include "ardour/playlist.h"
73 #include "ardour/utils.h"
74 #include "ardour/audio_diskstream.h"
75 #include "ardour/audiofilesource.h"
76 #include "ardour/recent_sessions.h"
77 #include "ardour/port.h"
78 #include "ardour/audio_track.h"
79 #include "ardour/midi_track.h"
80 #include "ardour/filesystem_paths.h"
81 #include "ardour/filename_extensions.h"
82 #include "ardour/process_thread.h"
84 typedef uint64_t microseconds_t;
88 #include "add_route_dialog.h"
89 #include "ambiguous_file_dialog.h"
90 #include "ardour_ui.h"
91 #include "audio_clock.h"
92 #include "bundle_manager.h"
93 #include "engine_dialog.h"
94 #include "gain_meter.h"
95 #include "global_port_matrix.h"
96 #include "gui_object.h"
97 #include "gui_thread.h"
99 #include "location_ui.h"
100 #include "missing_file_dialog.h"
101 #include "missing_plugin_dialog.h"
102 #include "mixer_ui.h"
104 #include "processor_box.h"
105 #include "prompter.h"
106 #include "public_editor.h"
107 #include "route_time_axis.h"
108 #include "session_metadata_dialog.h"
109 #include "shuttle_control.h"
110 #include "speaker_dialog.h"
113 #include "theme_manager.h"
114 #include "time_axis_view_item.h"
116 #include "window_proxy.h"
120 using namespace ARDOUR;
122 using namespace Gtkmm2ext;
125 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
126 UIConfiguration *ARDOUR_UI::ui_config = 0;
128 sigc::signal<void,bool> ARDOUR_UI::Blink;
129 sigc::signal<void> ARDOUR_UI::RapidScreenUpdate;
130 sigc::signal<void> ARDOUR_UI::SuperRapidScreenUpdate;
131 sigc::signal<void, framepos_t, bool, framepos_t> ARDOUR_UI::Clock;
133 bool could_be_a_valid_path (const string& path);
135 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[])
137 : Gtkmm2ext::UI (PROGRAM_NAME, argcp, argvp)
139 , gui_object_state (new GUIObjectState)
140 , primary_clock (new AudioClock (X_("primary"), false, X_("transport"), true, true, false, true))
141 , secondary_clock (new AudioClock (X_("secondary"), false, X_("secondary"), true, true, false, true))
145 , big_clock (new AudioClock (X_("bigclock"), false, "big", true, true, false, false))
149 , roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll))
150 , stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop))
151 , goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart))
152 , goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd))
153 , auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop))
154 , play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection))
155 , rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable))
157 , auto_return_button (ArdourButton::led_default_elements)
158 , auto_play_button (ArdourButton::led_default_elements)
159 , auto_input_button (ArdourButton::led_default_elements)
161 , auditioning_alert_button (_("audition"))
162 , solo_alert_button (_("solo"))
163 , feedback_alert_button (_("feedback"))
165 , error_log_button (_("Errors"))
167 , _status_bar_visibility (X_("status-bar"))
168 , _feedback_exists (false)
171 using namespace Gtk::Menu_Helpers;
177 // _auto_display_errors = false;
179 * This was commented out as it wasn't defined
180 * in A3 IIRC. If this is not needed it should
181 * be completely removed.
189 if (theArdourUI == 0) {
193 ui_config = new UIConfiguration();
194 theme_manager = new ThemeManager();
202 _session_is_new = false;
203 big_clock_window = 0;
204 big_clock_height = 0;
205 big_clock_resize_in_progress = false;
206 session_selector_window = 0;
207 last_key_press_time = 0;
208 add_route_dialog = 0;
211 rc_option_editor = 0;
212 session_option_editor = 0;
214 open_session_selector = 0;
215 have_configure_timeout = false;
216 have_disk_speed_dialog_displayed = false;
217 session_loaded = false;
218 ignore_dual_punch = false;
219 original_big_clock_width = -1;
220 original_big_clock_height = -1;
221 original_big_clock_font_size = 0;
223 roll_button.set_elements (ArdourButton::Element (ArdourButton::Body|ArdourButton::Text));
224 play_selection_button.set_elements (ArdourButton::Element (ArdourButton::Body|ArdourButton::Text));
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::startup ()
656 Application* app = Application::instance ();
658 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
659 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::idle_load));
662 call_the_mothership (VERSIONSTRING);
667 if (get_session_parameters (true, ARDOUR_COMMAND_LINE::new_session, ARDOUR_COMMAND_LINE::load_template)) {
673 goto_editor_window ();
675 /* Add the window proxies here; their addition may cause windows to be opened, and we want them
676 to be opened on top of the editor window that goto_editor_window() just opened.
678 add_window_proxy (location_ui);
679 add_window_proxy (big_clock_window);
680 for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) {
681 add_window_proxy (_global_port_matrix[*i]);
684 /* We have to do this here since goto_editor_window() ends up calling show_all() on the
685 * editor window, and we may want stuff to be hidden.
687 _status_bar_visibility.update ();
689 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
693 ARDOUR_UI::no_memory_warning ()
695 XMLNode node (X_("no-memory-warning"));
696 Config->add_instant_xml (node);
700 ARDOUR_UI::check_memory_locking ()
703 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
707 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
709 if (engine->is_realtime() && memory_warning_node == 0) {
711 struct rlimit limits;
713 long pages, page_size;
715 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0) {
718 ram = (int64_t) pages * (int64_t) page_size;
721 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
725 if (limits.rlim_cur != RLIM_INFINITY) {
727 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
731 _("WARNING: Your system has a limit for maximum amount of locked memory. "
732 "This might cause %1 to run out of memory before your system "
733 "runs out of memory. \n\n"
734 "You can view the memory limit with 'ulimit -l', "
735 "and it is normally controlled by /etc/security/limits.conf"),
736 PROGRAM_NAME).c_str());
738 VBox* vbox = msg.get_vbox();
740 CheckButton cb (_("Do not show this window again"));
742 cb.signal_toggled().connect (sigc::mem_fun (*this, &ARDOUR_UI::no_memory_warning));
744 hbox.pack_start (cb, true, false);
745 vbox->pack_start (hbox);
750 pop_back_splash (msg);
752 editor->ensure_float (msg);
762 ARDOUR_UI::queue_finish ()
764 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
768 ARDOUR_UI::idle_finish ()
771 return false; /* do not call again */
780 if (_session->transport_rolling() && (++tries < 8)) {
781 _session->request_stop (false, true);
785 if (_session->dirty()) {
786 vector<string> actions;
787 actions.push_back (_("Don't quit"));
788 actions.push_back (_("Just quit"));
789 actions.push_back (_("Save and quit"));
790 switch (ask_about_saving_session(actions)) {
795 /* use the default name */
796 if (save_state_canfail ("")) {
797 /* failed - don't quit */
798 MessageDialog msg (*editor,
800 Ardour was unable to save your session.\n\n\
801 If you still wish to quit, please use the\n\n\
802 \"Just quit\" option."));
803 pop_back_splash(msg);
813 second_connection.disconnect ();
814 point_one_second_connection.disconnect ();
815 point_oh_five_second_connection.disconnect ();
816 point_zero_one_second_connection.disconnect();
819 /* Save state before deleting the session, as that causes some
820 windows to be destroyed before their visible state can be
823 save_ardour_state ();
826 // _session->set_deletion_in_progress ();
827 _session->set_clean ();
828 _session->remove_pending_capture_state ();
833 ArdourDialog::close_all_dialogs ();
839 ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
841 ArdourDialog window (_("Unsaved Session"));
842 Gtk::HBox dhbox; // the hbox for the image and text
843 Gtk::Label prompt_label;
844 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
848 assert (actions.size() >= 3);
850 window.add_button (actions[0], RESPONSE_REJECT);
851 window.add_button (actions[1], RESPONSE_APPLY);
852 window.add_button (actions[2], RESPONSE_ACCEPT);
854 window.set_default_response (RESPONSE_ACCEPT);
856 Gtk::Button noquit_button (msg);
857 noquit_button.set_name ("EditorGTKButton");
861 if (_session->snap_name() == _session->name()) {
862 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?"),
863 _session->snap_name());
865 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?"),
866 _session->snap_name());
869 prompt_label.set_text (prompt);
870 prompt_label.set_name (X_("PrompterLabel"));
871 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
873 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
874 dhbox.set_homogeneous (false);
875 dhbox.pack_start (*dimage, false, false, 5);
876 dhbox.pack_start (prompt_label, true, false, 5);
877 window.get_vbox()->pack_start (dhbox);
879 window.set_name (_("Prompter"));
880 window.set_position (Gtk::WIN_POS_MOUSE);
881 window.set_modal (true);
882 window.set_resizable (false);
888 window.set_keep_above (true);
891 ResponseType r = (ResponseType) window.run();
896 case RESPONSE_ACCEPT: // save and get out of here
898 case RESPONSE_APPLY: // get out of here
908 ARDOUR_UI::every_second ()
911 update_buffer_load ();
912 update_disk_space ();
917 ARDOUR_UI::every_point_one_seconds ()
919 shuttle_box->update_speed_display ();
920 RapidScreenUpdate(); /* EMIT_SIGNAL */
925 ARDOUR_UI::every_point_zero_one_seconds ()
927 // august 2007: actual update frequency: 40Hz, not 100Hz
929 SuperRapidScreenUpdate(); /* EMIT_SIGNAL */
934 ARDOUR_UI::update_sample_rate (framecnt_t)
938 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
940 if (!engine->connected()) {
942 snprintf (buf, sizeof (buf), _("disconnected"));
946 framecnt_t rate = engine->frame_rate();
948 if (fmod (rate, 1000.0) != 0.0) {
949 snprintf (buf, sizeof (buf), _("JACK: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
950 (float) rate/1000.0f,
951 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
953 snprintf (buf, sizeof (buf), _("JACK: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
955 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
959 sample_rate_label.set_markup (buf);
963 ARDOUR_UI::update_format ()
966 format_label.set_text ("");
971 s << _("File:") << X_(" <span foreground=\"green\">");
973 switch (_session->config.get_native_file_header_format ()) {
999 switch (_session->config.get_native_file_data_format ()) {
1013 format_label.set_markup (s.str ());
1017 ARDOUR_UI::update_cpu_load ()
1021 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1022 should also be changed.
1025 float const c = engine->get_cpu_load ();
1026 snprintf (buf, sizeof (buf), _("DSP: <span foreground=\"%s\">%5.1f%%</span>"), c >= 90 ? X_("red") : X_("green"), c);
1027 cpu_load_label.set_markup (buf);
1031 ARDOUR_UI::update_buffer_load ()
1035 uint32_t const playback = _session ? _session->playback_load () : 100;
1036 uint32_t const capture = _session ? _session->capture_load () : 100;
1038 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1039 should also be changed.
1045 _("Buffers: <span foreground=\"green\">p:</span><span foreground=\"%s\">%" PRIu32 "%%</span> "
1046 "<span foreground=\"green\">c:</span><span foreground=\"%s\">%" PRIu32 "%%</span>"),
1047 playback <= 5 ? X_("red") : X_("green"),
1049 capture <= 5 ? X_("red") : X_("green"),
1053 buffer_load_label.set_markup (buf);
1055 buffer_load_label.set_text ("");
1060 ARDOUR_UI::count_recenabled_streams (Route& route)
1062 Track* track = dynamic_cast<Track*>(&route);
1063 if (track && track->record_enabled()) {
1064 rec_enabled_streams += track->n_inputs().n_total();
1069 ARDOUR_UI::update_disk_space()
1071 if (_session == 0) {
1075 framecnt_t frames = _session->available_capture_duration();
1077 framecnt_t fr = _session->frame_rate();
1079 if (frames == max_framecnt) {
1080 snprintf (buf, sizeof (buf), _("Disk: <span foreground=\"green\">24hrs+</span>"));
1082 rec_enabled_streams = 0;
1083 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams);
1085 if (rec_enabled_streams) {
1086 frames /= rec_enabled_streams;
1093 hrs = frames / (fr * 3600);
1096 snprintf (buf, sizeof (buf), _("Disk: <span foreground=\"green\">>24 hrs</span>"));
1098 frames -= hrs * fr * 3600;
1099 mins = frames / (fr * 60);
1100 frames -= mins * fr * 60;
1103 bool const low = (hrs == 0 && mins <= 30);
1107 _("Disk: <span foreground=\"%s\">%02dh:%02dm:%02ds</span>"),
1108 low ? X_("red") : X_("green"),
1114 disk_space_label.set_markup (buf);
1116 // An attempt to make the disk space label flash red when space has run out.
1118 if (frames < fr * 60 * 5) {
1119 /* disk_space_box.style ("disk_space_label_empty"); */
1121 /* disk_space_box.style ("disk_space_label"); */
1127 ARDOUR_UI::update_wall_clock ()
1134 tm_now = localtime (&now);
1136 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1137 wall_clock_label.set_text (buf);
1143 ARDOUR_UI::redisplay_recent_sessions ()
1145 std::vector<sys::path> session_directories;
1146 RecentSessionsSorter cmp;
1148 recent_session_display.set_model (Glib::RefPtr<TreeModel>(0));
1149 recent_session_model->clear ();
1151 ARDOUR::RecentSessions rs;
1152 ARDOUR::read_recent_sessions (rs);
1155 recent_session_display.set_model (recent_session_model);
1159 // sort them alphabetically
1160 sort (rs.begin(), rs.end(), cmp);
1162 for (ARDOUR::RecentSessions::iterator i = rs.begin(); i != rs.end(); ++i) {
1163 session_directories.push_back ((*i).second);
1166 for (vector<sys::path>::const_iterator i = session_directories.begin();
1167 i != session_directories.end(); ++i)
1169 std::vector<sys::path> state_file_paths;
1171 // now get available states for this session
1173 get_state_files_in_directory (*i, state_file_paths);
1175 vector<string*>* states;
1176 vector<const gchar*> item;
1177 string fullpath = (*i).to_string();
1179 /* remove any trailing / */
1181 if (fullpath[fullpath.length()-1] == '/') {
1182 fullpath = fullpath.substr (0, fullpath.length()-1);
1185 /* check whether session still exists */
1186 if (!Glib::file_test(fullpath.c_str(), Glib::FILE_TEST_EXISTS)) {
1187 /* session doesn't exist */
1188 cerr << "skipping non-existent session " << fullpath << endl;
1192 /* now get available states for this session */
1194 if ((states = Session::possible_states (fullpath)) == 0) {
1195 /* no state file? */
1199 std::vector<string> state_file_names(get_file_names_no_extension (state_file_paths));
1201 Gtk::TreeModel::Row row = *(recent_session_model->append());
1203 row[recent_session_columns.visible_name] = Glib::path_get_basename (fullpath);
1204 row[recent_session_columns.fullpath] = fullpath;
1206 if (state_file_names.size() > 1) {
1210 for (std::vector<std::string>::iterator i2 = state_file_names.begin();
1211 i2 != state_file_names.end(); ++i2)
1214 Gtk::TreeModel::Row child_row = *(recent_session_model->append (row.children()));
1216 child_row[recent_session_columns.visible_name] = *i2;
1217 child_row[recent_session_columns.fullpath] = fullpath;
1222 recent_session_display.set_tooltip_column(1); // recent_session_columns.fullpath
1223 recent_session_display.set_model (recent_session_model);
1227 ARDOUR_UI::build_session_selector ()
1229 session_selector_window = new ArdourDialog (_("Recent Sessions"));
1231 Gtk::ScrolledWindow *scroller = manage (new Gtk::ScrolledWindow);
1233 session_selector_window->add_button (Stock::CANCEL, RESPONSE_CANCEL);
1234 session_selector_window->add_button (Stock::OPEN, RESPONSE_ACCEPT);
1235 session_selector_window->set_default_response (RESPONSE_ACCEPT);
1236 recent_session_model = TreeStore::create (recent_session_columns);
1237 recent_session_display.set_model (recent_session_model);
1238 recent_session_display.append_column (_("Recent Sessions"), recent_session_columns.visible_name);
1239 recent_session_display.set_headers_visible (false);
1240 recent_session_display.get_selection()->set_mode (SELECTION_BROWSE);
1241 recent_session_display.signal_row_activated().connect (sigc::mem_fun (*this, &ARDOUR_UI::recent_session_row_activated));
1243 scroller->add (recent_session_display);
1244 scroller->set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
1246 session_selector_window->set_name ("SessionSelectorWindow");
1247 session_selector_window->set_size_request (200, 400);
1248 session_selector_window->get_vbox()->pack_start (*scroller);
1250 recent_session_display.show();
1252 //session_selector_window->get_vbox()->show();
1256 ARDOUR_UI::recent_session_row_activated (const TreePath& /*path*/, TreeViewColumn* /*col*/)
1258 session_selector_window->response (RESPONSE_ACCEPT);
1262 ARDOUR_UI::open_recent_session ()
1264 bool can_return = (_session != 0);
1266 if (session_selector_window == 0) {
1267 build_session_selector ();
1270 redisplay_recent_sessions ();
1274 session_selector_window->set_position (WIN_POS_MOUSE);
1276 ResponseType r = (ResponseType) session_selector_window->run ();
1279 case RESPONSE_ACCEPT:
1283 session_selector_window->hide();
1290 if (recent_session_display.get_selection()->count_selected_rows() == 0) {
1294 session_selector_window->hide();
1296 Gtk::TreeModel::iterator i = recent_session_display.get_selection()->get_selected();
1298 if (i == recent_session_model->children().end()) {
1302 std::string path = (*i)[recent_session_columns.fullpath];
1303 std::string state = (*i)[recent_session_columns.visible_name];
1305 _session_is_new = false;
1307 if (load_session (path, state) == 0) {
1316 ARDOUR_UI::check_audioengine ()
1319 if (!engine->connected()) {
1320 MessageDialog msg (string_compose (
1321 _("%1 is not connected to JACK\n"
1322 "You cannot open or close sessions in this condition"),
1324 pop_back_splash (msg);
1335 ARDOUR_UI::open_session ()
1337 if (!check_audioengine()) {
1342 /* popup selector window */
1344 if (open_session_selector == 0) {
1346 /* ardour sessions are folders */
1348 open_session_selector = new Gtk::FileChooserDialog (_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1349 open_session_selector->add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1350 open_session_selector->add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1351 open_session_selector->set_default_response(Gtk::RESPONSE_ACCEPT);
1354 string session_parent_dir = Glib::path_get_dirname(_session->path());
1355 string::size_type last_dir_sep = session_parent_dir.rfind(G_DIR_SEPARATOR);
1356 session_parent_dir = session_parent_dir.substr(0, last_dir_sep);
1357 open_session_selector->set_current_folder(session_parent_dir);
1359 open_session_selector->set_current_folder(Config->get_default_session_parent_dir());
1362 open_session_selector->add_shortcut_folder (Config->get_default_session_parent_dir());
1364 FileFilter session_filter;
1365 session_filter.add_pattern ("*.ardour");
1366 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1367 open_session_selector->add_filter (session_filter);
1368 open_session_selector->set_filter (session_filter);
1371 int response = open_session_selector->run();
1372 open_session_selector->hide ();
1375 case RESPONSE_ACCEPT:
1378 open_session_selector->hide();
1382 open_session_selector->hide();
1383 string session_path = open_session_selector->get_filename();
1387 if (session_path.length() > 0) {
1388 if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1389 _session_is_new = isnew;
1390 load_session (path, name);
1397 ARDOUR_UI::session_add_midi_route (bool disk, RouteGroup* route_group, uint32_t how_many, const string& name_template, PluginInfoPtr instrument)
1399 list<boost::shared_ptr<MidiTrack> > tracks;
1401 if (_session == 0) {
1402 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1409 tracks = _session->new_midi_track (instrument, ARDOUR::Normal, route_group, how_many, name_template);
1411 if (tracks.size() != how_many) {
1412 if (how_many == 1) {
1413 error << _("could not create a new midi track") << endmsg;
1415 error << string_compose (_("could not create %1 new midi tracks"), how_many) << endmsg;
1420 if ((route = _session->new_midi_route ()) == 0) {
1421 error << _("could not create new midi bus") << endmsg;
1427 MessageDialog msg (*editor,
1428 string_compose (_("There are insufficient JACK ports available\n\
1429 to create a new track or bus.\n\
1430 You should save %1, exit and\n\
1431 restart JACK with more ports."), PROGRAM_NAME));
1438 ARDOUR_UI::session_add_audio_route (
1440 int32_t input_channels,
1441 int32_t output_channels,
1442 ARDOUR::TrackMode mode,
1443 RouteGroup* route_group,
1445 string const & name_template
1448 list<boost::shared_ptr<AudioTrack> > tracks;
1451 if (_session == 0) {
1452 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1458 tracks = _session->new_audio_track (input_channels, output_channels, mode, route_group, how_many, name_template);
1460 if (tracks.size() != how_many) {
1461 if (how_many == 1) {
1462 error << _("could not create a new audio track") << endmsg;
1464 error << string_compose (_("could only create %1 of %2 new audio %3"),
1465 tracks.size(), how_many, (track ? _("tracks") : _("busses"))) << endmsg;
1471 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template);
1473 if (routes.size() != how_many) {
1474 if (how_many == 1) {
1475 error << _("could not create a new audio bus") << endmsg;
1477 error << string_compose (_("could not create %1 new audio busses"), how_many) << endmsg;
1484 MessageDialog msg (*editor,
1485 string_compose (_("There are insufficient JACK ports available\n\
1486 to create a new track or bus.\n\
1487 You should save %1, exit and\n\
1488 restart JACK with more ports."), PROGRAM_NAME));
1489 pop_back_splash (msg);
1495 ARDOUR_UI::transport_goto_start ()
1498 _session->goto_start();
1500 /* force displayed area in editor to start no matter
1501 what "follow playhead" setting is.
1505 editor->center_screen (_session->current_start_frame ());
1511 ARDOUR_UI::transport_goto_zero ()
1514 _session->request_locate (0);
1516 /* force displayed area in editor to start no matter
1517 what "follow playhead" setting is.
1521 editor->reset_x_origin (0);
1527 ARDOUR_UI::transport_goto_wallclock ()
1529 if (_session && editor) {
1536 localtime_r (&now, &tmnow);
1538 frames = tmnow.tm_hour * (60 * 60 * _session->frame_rate());
1539 frames += tmnow.tm_min * (60 * _session->frame_rate());
1540 frames += tmnow.tm_sec * _session->frame_rate();
1542 _session->request_locate (frames, _session->transport_rolling ());
1544 /* force displayed area in editor to start no matter
1545 what "follow playhead" setting is.
1549 editor->center_screen (frames);
1555 ARDOUR_UI::transport_goto_end ()
1558 framepos_t const frame = _session->current_end_frame();
1559 _session->request_locate (frame);
1561 /* force displayed area in editor to start no matter
1562 what "follow playhead" setting is.
1566 editor->center_screen (frame);
1572 ARDOUR_UI::transport_stop ()
1578 if (_session->is_auditioning()) {
1579 _session->cancel_audition ();
1583 _session->request_stop (false, true);
1587 ARDOUR_UI::transport_record (bool roll)
1591 switch (_session->record_status()) {
1592 case Session::Disabled:
1593 if (_session->ntracks() == 0) {
1594 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."));
1598 _session->maybe_enable_record ();
1603 case Session::Recording:
1605 _session->request_stop();
1607 _session->disable_record (false, true);
1611 case Session::Enabled:
1612 _session->disable_record (false, true);
1615 //cerr << "ARDOUR_UI::transport_record () called roll = " << roll << " _session->record_status() = " << _session->record_status() << endl;
1619 ARDOUR_UI::transport_roll ()
1625 if (_session->is_auditioning()) {
1630 if (_session->config.get_external_sync()) {
1631 switch (_session->config.get_sync_source()) {
1635 /* transport controlled by the master */
1641 bool rolling = _session->transport_rolling();
1643 if (_session->get_play_loop()) {
1644 /* XXX it is not possible to just leave seamless loop and keep
1645 playing at present (nov 4th 2009)
1647 if (!Config->get_seamless_loop()) {
1648 _session->request_play_loop (false, true);
1650 } else if (_session->get_play_range () && !Config->get_always_play_range()) {
1651 /* stop playing a range if we currently are */
1652 _session->request_play_range (0, true);
1655 if (Config->get_always_play_range()) {
1656 _session->request_play_range (&editor->get_selection().time, true);
1660 _session->request_transport_speed (1.0f);
1665 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
1672 if (_session->is_auditioning()) {
1673 _session->cancel_audition ();
1677 if (_session->config.get_external_sync()) {
1678 switch (_session->config.get_sync_source()) {
1682 /* transport controlled by the master */
1687 bool rolling = _session->transport_rolling();
1688 bool affect_transport = true;
1690 if (rolling && roll_out_of_bounded_mode) {
1691 /* drop out of loop/range playback but leave transport rolling */
1692 if (_session->get_play_loop()) {
1693 if (Config->get_seamless_loop()) {
1694 /* the disk buffers contain copies of the loop - we can't
1695 just keep playing, so stop the transport. the user
1696 can restart as they wish.
1698 affect_transport = true;
1700 /* disk buffers are normal, so we can keep playing */
1701 affect_transport = false;
1703 _session->request_play_loop (false, true);
1704 } else if (_session->get_play_range ()) {
1705 affect_transport = false;
1706 _session->request_play_range (0, true);
1710 if (affect_transport) {
1712 _session->request_stop (with_abort, true);
1714 if (Config->get_always_play_range ()) {
1715 _session->request_play_range (&editor->get_selection().time, true);
1718 _session->request_transport_speed (1.0f);
1724 ARDOUR_UI::toggle_session_auto_loop ()
1726 Location * looploc = _session->locations()->auto_loop_location();
1728 if (!_session || !looploc) {
1732 if (_session->get_play_loop()) {
1734 if (_session->transport_rolling()) {
1736 _session->request_locate (looploc->start(), true);
1737 _session->request_play_loop (false);
1740 _session->request_play_loop (false);
1743 _session->request_play_loop (true);
1746 //show the loop markers
1747 looploc->set_hidden (false, this);
1751 ARDOUR_UI::transport_play_selection ()
1757 editor->play_selection ();
1761 ARDOUR_UI::transport_rewind (int option)
1763 float current_transport_speed;
1766 current_transport_speed = _session->transport_speed();
1768 if (current_transport_speed >= 0.0f) {
1771 _session->request_transport_speed (-1.0f);
1774 _session->request_transport_speed (-4.0f);
1777 _session->request_transport_speed (-0.5f);
1782 _session->request_transport_speed (current_transport_speed * 1.5f);
1788 ARDOUR_UI::transport_forward (int option)
1790 float current_transport_speed;
1793 current_transport_speed = _session->transport_speed();
1795 if (current_transport_speed <= 0.0f) {
1798 _session->request_transport_speed (1.0f);
1801 _session->request_transport_speed (4.0f);
1804 _session->request_transport_speed (0.5f);
1809 _session->request_transport_speed (current_transport_speed * 1.5f);
1816 ARDOUR_UI::toggle_record_enable (uint32_t rid)
1818 if (_session == 0) {
1822 boost::shared_ptr<Route> r;
1824 if ((r = _session->route_by_remote_id (rid)) != 0) {
1828 if ((t = dynamic_cast<Track*>(r.get())) != 0) {
1829 t->set_record_enabled (!t->record_enabled(), this);
1832 if (_session == 0) {
1838 ARDOUR_UI::map_transport_state ()
1841 auto_loop_button.unset_active_state ();
1842 play_selection_button.unset_active_state ();
1843 roll_button.unset_active_state ();
1844 stop_button.set_active_state (Gtkmm2ext::ExplicitActive);
1848 shuttle_box->map_transport_state ();
1850 float sp = _session->transport_speed();
1856 if (_session->get_play_range()) {
1858 play_selection_button.set_active_state (Gtkmm2ext::ExplicitActive);
1859 roll_button.unset_active_state ();
1860 auto_loop_button.unset_active_state ();
1862 } else if (_session->get_play_loop ()) {
1864 auto_loop_button.set_active (true);
1865 play_selection_button.set_active (false);
1866 roll_button.set_active (false);
1870 roll_button.set_active (true);
1871 play_selection_button.set_active (false);
1872 auto_loop_button.set_active (false);
1875 if (Config->get_always_play_range()) {
1876 /* light up both roll and play-selection if they are joined */
1877 roll_button.set_active (true);
1878 play_selection_button.set_active (true);
1881 stop_button.set_active (false);
1885 stop_button.set_active (true);
1886 roll_button.set_active (false);
1887 play_selection_button.set_active (false);
1888 auto_loop_button.set_active (false);
1889 update_disk_space ();
1894 ARDOUR_UI::engine_stopped ()
1896 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
1897 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1898 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1902 ARDOUR_UI::engine_running ()
1904 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
1905 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, true);
1906 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, false);
1908 Glib::RefPtr<Action> action;
1909 const char* action_name = 0;
1911 switch (engine->frames_per_cycle()) {
1913 action_name = X_("JACKLatency32");
1916 action_name = X_("JACKLatency64");
1919 action_name = X_("JACKLatency128");
1922 action_name = X_("JACKLatency512");
1925 action_name = X_("JACKLatency1024");
1928 action_name = X_("JACKLatency2048");
1931 action_name = X_("JACKLatency4096");
1934 action_name = X_("JACKLatency8192");
1937 /* XXX can we do anything useful ? */
1943 action = ActionManager::get_action (X_("JACK"), action_name);
1946 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (action);
1947 ract->set_active ();
1953 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
1955 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
1956 /* we can't rely on the original string continuing to exist when we are called
1957 again in the GUI thread, so make a copy and note that we need to
1960 char *copy = strdup (reason);
1961 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
1965 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1966 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1968 update_sample_rate (0);
1972 /* if the reason is a non-empty string, it means that the backend was shutdown
1973 rather than just Ardour.
1976 if (strlen (reason)) {
1977 msgstr = string_compose (_("The audio backend (JACK) was shutdown because:\n\n%1"), reason);
1979 msgstr = string_compose (_("\
1980 JACK has either been shutdown or it\n\
1981 disconnected %1 because %1\n\
1982 was not fast enough. Try to restart\n\
1983 JACK, reconnect and save the session."), PROGRAM_NAME);
1986 MessageDialog msg (*editor, msgstr);
1987 pop_back_splash (msg);
1991 free ((char*) reason);
1996 ARDOUR_UI::do_engine_start ()
2004 error << _("Unable to start the session running")
2014 ARDOUR_UI::update_clocks ()
2016 if (!editor || !editor->dragging_playhead()) {
2017 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position()); /* EMIT_SIGNAL */
2022 ARDOUR_UI::start_clocking ()
2024 clock_signal_connection = RapidScreenUpdate.connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2028 ARDOUR_UI::stop_clocking ()
2030 clock_signal_connection.disconnect ();
2034 ARDOUR_UI::_blink (void *arg)
2037 ((ARDOUR_UI *) arg)->blink ();
2044 Blink (blink_on = !blink_on); /* EMIT_SIGNAL */
2048 ARDOUR_UI::start_blinking ()
2050 /* Start the blink signal. Everybody with a blinking widget
2051 uses Blink to drive the widget's state.
2054 if (blink_timeout_tag < 0) {
2056 blink_timeout_tag = g_timeout_add (240, _blink, this);
2061 ARDOUR_UI::stop_blinking ()
2063 if (blink_timeout_tag >= 0) {
2064 g_source_remove (blink_timeout_tag);
2065 blink_timeout_tag = -1;
2070 /** Ask the user for the name of a new snapshot and then take it.
2074 ARDOUR_UI::snapshot_session (bool switch_to_it)
2076 ArdourPrompter prompter (true);
2079 prompter.set_name ("Prompter");
2080 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2081 prompter.set_title (_("Take Snapshot"));
2082 prompter.set_prompt (_("Name of new snapshot"));
2084 if (!switch_to_it) {
2087 struct tm local_time;
2090 localtime_r (&n, &local_time);
2091 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2092 prompter.set_initial_text (timebuf);
2096 switch (prompter.run()) {
2097 case RESPONSE_ACCEPT:
2099 prompter.get_result (snapname);
2101 bool do_save = (snapname.length() != 0);
2104 char illegal = Session::session_name_is_legal(snapname);
2106 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2107 "snapshot names may not contain a '%1' character"), illegal));
2113 vector<sys::path> p;
2114 get_state_files_in_directory (_session->session_directory().root_path(), p);
2115 vector<string> n = get_file_names_no_extension (p);
2116 if (find (n.begin(), n.end(), snapname) != n.end()) {
2118 ArdourDialog confirm (_("Confirm Snapshot Overwrite"), true);
2119 Label m (_("A snapshot already exists with that name. Do you want to overwrite it?"));
2120 confirm.get_vbox()->pack_start (m, true, true);
2121 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2122 confirm.add_button (_("Overwrite"), Gtk::RESPONSE_ACCEPT);
2123 confirm.show_all ();
2124 switch (confirm.run()) {
2125 case RESPONSE_CANCEL:
2131 save_state (snapname, switch_to_it);
2141 /** Ask the user for a new session name and then rename the session to it.
2145 ARDOUR_UI::rename_session ()
2151 ArdourPrompter prompter (true);
2154 prompter.set_name ("Prompter");
2155 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2156 prompter.set_title (_("Rename Session"));
2157 prompter.set_prompt (_("New session name"));
2160 switch (prompter.run()) {
2161 case RESPONSE_ACCEPT:
2163 prompter.get_result (name);
2165 bool do_rename = (name.length() != 0);
2168 char illegal = Session::session_name_is_legal (name);
2171 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2172 "session names may not contain a '%1' character"), illegal));
2177 switch (_session->rename (name)) {
2179 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
2180 msg.set_position (WIN_POS_MOUSE);
2188 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
2189 msg.set_position (WIN_POS_MOUSE);
2205 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2207 XMLNode* node = new XMLNode (X_("UI"));
2209 for (list<WindowProxyBase*>::iterator i = _window_proxies.begin(); i != _window_proxies.end(); ++i) {
2210 if (!(*i)->rc_configured()) {
2211 node->add_child_nocopy (*((*i)->get_state ()));
2215 node->add_child_nocopy (gui_object_state->get_state());
2217 _session->add_extra_xml (*node);
2219 save_state_canfail (name, switch_to_it);
2223 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2228 if (name.length() == 0) {
2229 name = _session->snap_name();
2232 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2237 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2242 ARDOUR_UI::primary_clock_value_changed ()
2245 _session->request_locate (primary_clock->current_time ());
2250 ARDOUR_UI::big_clock_value_changed ()
2253 _session->request_locate (big_clock->current_time ());
2258 ARDOUR_UI::secondary_clock_value_changed ()
2261 _session->request_locate (secondary_clock->current_time ());
2266 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2268 if (_session == 0) {
2272 if (_session->step_editing()) {
2276 Session::RecordState const r = _session->record_status ();
2277 bool const h = _session->have_rec_enabled_track ();
2279 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2281 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2283 rec_button.set_active_state (Gtkmm2ext::ImplicitActive);
2285 } else if (r == Session::Recording && h) {
2286 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2288 rec_button.unset_active_state ();
2293 ARDOUR_UI::save_template ()
2295 ArdourPrompter prompter (true);
2298 if (!check_audioengine()) {
2302 prompter.set_name (X_("Prompter"));
2303 prompter.set_title (_("Save Template"));
2304 prompter.set_prompt (_("Name for template:"));
2305 prompter.set_initial_text(_session->name() + _("-template"));
2306 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2308 switch (prompter.run()) {
2309 case RESPONSE_ACCEPT:
2310 prompter.get_result (name);
2312 if (name.length()) {
2313 _session->save_template (name);
2323 ARDOUR_UI::edit_metadata ()
2325 SessionMetadataEditor dialog;
2326 dialog.set_session (_session);
2327 editor->ensure_float (dialog);
2332 ARDOUR_UI::import_metadata ()
2334 SessionMetadataImporter dialog;
2335 dialog.set_session (_session);
2336 editor->ensure_float (dialog);
2341 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
2343 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2345 MessageDialog msg (str,
2347 Gtk::MESSAGE_WARNING,
2348 Gtk::BUTTONS_YES_NO,
2352 msg.set_name (X_("OpenExistingDialog"));
2353 msg.set_title (_("Open Existing Session"));
2354 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
2355 msg.set_position (Gtk::WIN_POS_MOUSE);
2356 pop_back_splash (msg);
2358 switch (msg.run()) {
2367 ARDOUR_UI::build_session_from_nsd (const std::string& session_path, const std::string& session_name)
2369 BusProfile bus_profile;
2371 if (Profile->get_sae()) {
2373 bus_profile.master_out_channels = 2;
2374 bus_profile.input_ac = AutoConnectPhysical;
2375 bus_profile.output_ac = AutoConnectMaster;
2376 bus_profile.requested_physical_in = 0; // use all available
2377 bus_profile.requested_physical_out = 0; // use all available
2381 /* get settings from advanced section of NSD */
2383 if (_startup->create_master_bus()) {
2384 bus_profile.master_out_channels = (uint32_t) _startup->master_channel_count();
2386 bus_profile.master_out_channels = 0;
2389 if (_startup->connect_inputs()) {
2390 bus_profile.input_ac = AutoConnectPhysical;
2392 bus_profile.input_ac = AutoConnectOption (0);
2395 bus_profile.output_ac = AutoConnectOption (0);
2397 if (_startup->connect_outputs ()) {
2398 if (_startup->connect_outs_to_master()) {
2399 bus_profile.output_ac = AutoConnectMaster;
2400 } else if (_startup->connect_outs_to_physical()) {
2401 bus_profile.output_ac = AutoConnectPhysical;
2405 bus_profile.requested_physical_in = (uint32_t) _startup->input_limit_count();
2406 bus_profile.requested_physical_out = (uint32_t) _startup->output_limit_count();
2409 if (build_session (session_path, session_name, bus_profile)) {
2417 ARDOUR_UI::idle_load (const std::string& path)
2420 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2421 /* /path/to/foo => /path/to/foo, foo */
2422 load_session (path, basename_nosuffix (path));
2424 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2425 load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2429 ARDOUR_COMMAND_LINE::session_name = path;
2432 * new_session_dialog doens't exist in A3
2433 * Try to remove all references to it to
2434 * see if it will compile. NOTE: this will
2435 * likely cause a runtime issue is my somewhat
2439 //if (new_session_dialog) {
2442 /* make it break out of Dialog::run() and
2446 //new_session_dialog->response (1);
2452 ARDOUR_UI::loading_message (const std::string& msg)
2454 if (ARDOUR_COMMAND_LINE::no_splash) {
2460 splash->message (msg);
2465 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
2467 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
2469 string session_name;
2470 string session_path;
2471 string template_name;
2473 bool likely_new = false;
2475 if (!load_template.empty()) {
2476 should_be_new = true;
2477 template_name = load_template;
2482 if (!should_be_new && !ARDOUR_COMMAND_LINE::session_name.empty()) {
2484 /* if they named a specific statefile, use it, otherwise they are
2485 just giving a session folder, and we want to use it as is
2486 to find the session.
2489 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
2491 if (suffix != string::npos) {
2492 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
2493 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
2494 session_name = Glib::path_get_basename (session_name);
2496 session_path = ARDOUR_COMMAND_LINE::session_name;
2497 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
2502 bool const apply = run_startup (should_be_new, load_template);
2505 if (quit_on_cancel) {
2512 /* if we run the startup dialog again, offer more than just "new session" */
2514 should_be_new = false;
2516 session_name = _startup->session_name (likely_new);
2518 string::size_type suffix = session_name.find (statefile_suffix);
2520 if (suffix != string::npos) {
2521 session_name = session_name.substr (0, suffix);
2524 /* this shouldn't happen, but we catch it just in case it does */
2526 if (session_name.empty()) {
2530 if (_startup->use_session_template()) {
2531 template_name = _startup->session_template_name();
2532 _session_is_new = true;
2535 if (session_name[0] == G_DIR_SEPARATOR ||
2536 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
2537 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)) {
2539 /* absolute path or cwd-relative path specified for session name: infer session folder
2540 from what was given.
2543 session_path = Glib::path_get_dirname (session_name);
2544 session_name = Glib::path_get_basename (session_name);
2548 session_path = _startup->session_folder();
2550 char illegal = Session::session_name_is_legal (session_name);
2553 MessageDialog msg (*_startup,
2554 string_compose (_("To ensure compatibility with various systems\n"
2555 "session names may not contain a '%1' character"),
2558 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2564 if (create_engine ()) {
2568 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
2572 std::string existing = Glib::build_filename (session_path, session_name);
2574 if (!ask_about_loading_existing_session (existing)) {
2575 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2580 _session_is_new = false;
2586 pop_back_splash (*_startup);
2591 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
2593 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2597 char illegal = Session::session_name_is_legal(session_name);
2599 pop_back_splash (*_startup);
2600 MessageDialog msg (*_startup, string_compose(_("To ensure compatibility with various systems\n"
2601 "session names may not contain a '%1' character"), illegal));
2603 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2607 _session_is_new = true;
2610 if (likely_new && template_name.empty()) {
2612 ret = build_session_from_nsd (session_path, session_name);
2616 ret = load_session (session_path, session_name, template_name);
2619 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
2623 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
2624 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
2634 ARDOUR_UI::close_session()
2636 if (!check_audioengine()) {
2640 if (unload_session (true)) {
2644 ARDOUR_COMMAND_LINE::session_name = "";
2646 if (get_session_parameters (true, false)) {
2650 goto_editor_window ();
2653 /** @param snap_name Snapshot name (without .ardour suffix).
2654 * @return -2 if the load failed because we are not connected to the AudioEngine.
2657 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
2659 Session *new_session;
2663 session_loaded = false;
2665 if (!check_audioengine()) {
2669 unload_status = unload_session ();
2671 if (unload_status < 0) {
2673 } else if (unload_status > 0) {
2678 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
2681 new_session = new Session (*engine, path, snap_name, 0, mix_template);
2684 /* this one is special */
2686 catch (AudioEngine::PortRegistrationFailure& err) {
2688 MessageDialog msg (err.what(),
2691 Gtk::BUTTONS_CLOSE);
2693 msg.set_title (_("Port Registration Error"));
2694 msg.set_secondary_text (_("Click the Close button to try again."));
2695 msg.set_position (Gtk::WIN_POS_CENTER);
2696 pop_back_splash (msg);
2699 int response = msg.run ();
2704 case RESPONSE_CANCEL:
2714 MessageDialog msg (string_compose(
2715 _("Session \"%1 (snapshot %2)\" did not load successfully"),
2721 msg.set_title (_("Loading Error"));
2722 msg.set_secondary_text (_("Click the Refresh button to try again."));
2723 msg.add_button (Stock::REFRESH, 1);
2724 msg.set_position (Gtk::WIN_POS_CENTER);
2725 pop_back_splash (msg);
2728 int response = msg.run ();
2743 list<string> const u = new_session->unknown_processors ();
2745 MissingPluginDialog d (_session, u);
2750 /* Now the session been created, add the transport controls */
2751 new_session->add_controllable(roll_controllable);
2752 new_session->add_controllable(stop_controllable);
2753 new_session->add_controllable(goto_start_controllable);
2754 new_session->add_controllable(goto_end_controllable);
2755 new_session->add_controllable(auto_loop_controllable);
2756 new_session->add_controllable(play_selection_controllable);
2757 new_session->add_controllable(rec_controllable);
2759 set_session (new_session);
2761 session_loaded = true;
2763 goto_editor_window ();
2766 _session->set_clean ();
2777 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
2779 Session *new_session;
2782 if (!check_audioengine()) {
2786 session_loaded = false;
2788 x = unload_session ();
2796 _session_is_new = true;
2799 new_session = new Session (*engine, path, snap_name, &bus_profile);
2804 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
2805 pop_back_splash (msg);
2810 /* Give the new session the default GUI state, if such things exist */
2813 n = Config->instant_xml (X_("Editor"));
2815 new_session->add_instant_xml (*n, false);
2817 n = Config->instant_xml (X_("Mixer"));
2819 new_session->add_instant_xml (*n, false);
2822 /* Put the playhead at 0 and scroll fully left */
2823 n = new_session->instant_xml (X_("Editor"));
2825 n->add_property (X_("playhead"), X_("0"));
2826 n->add_property (X_("left-frame"), X_("0"));
2829 set_session (new_session);
2831 session_loaded = true;
2833 new_session->save_state(new_session->name());
2839 ARDOUR_UI::launch_chat ()
2842 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
2844 open_uri("http://webchat.freenode.net/?channels=ardour");
2849 ARDOUR_UI::show_about ()
2853 about->signal_response().connect(sigc::mem_fun (*this, &ARDOUR_UI::about_signal_response) );
2856 about->set_transient_for(*editor);
2861 ARDOUR_UI::launch_manual ()
2863 PBD::open_uri("http://ardour.org/flossmanual");
2867 ARDOUR_UI::launch_reference ()
2869 PBD::open_uri("http://ardour.org/refmanual");
2873 ARDOUR_UI::hide_about ()
2876 about->get_window()->set_cursor ();
2882 ARDOUR_UI::about_signal_response (int /*response*/)
2888 ARDOUR_UI::show_splash ()
2892 splash = new Splash;
2894 cerr << "Splash could not be created\n";
2900 splash->pop_front ();
2901 splash->queue_draw ();
2902 splash->get_window()->process_updates (true);
2907 ARDOUR_UI::hide_splash ()
2915 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title,
2916 const string& plural_msg, const string& singular_msg)
2920 removed = rep.paths.size();
2923 MessageDialog msgd (*editor,
2924 _("No files were ready for clean-up"),
2928 msgd.set_title (_("Clean-up"));
2929 msgd.set_secondary_text (_("If this seems suprising, \n\
2930 check for any existing snapshots.\n\
2931 These may still include regions that\n\
2932 require some unused files to continue to exist."));
2938 ArdourDialog results (_("Clean-up"), true, false);
2940 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
2941 CleanupResultsModelColumns() {
2945 Gtk::TreeModelColumn<std::string> visible_name;
2946 Gtk::TreeModelColumn<std::string> fullpath;
2950 CleanupResultsModelColumns results_columns;
2951 Glib::RefPtr<Gtk::ListStore> results_model;
2952 Gtk::TreeView results_display;
2954 results_model = ListStore::create (results_columns);
2955 results_display.set_model (results_model);
2956 results_display.append_column (list_title, results_columns.visible_name);
2958 results_display.set_name ("CleanupResultsList");
2959 results_display.set_headers_visible (true);
2960 results_display.set_headers_clickable (false);
2961 results_display.set_reorderable (false);
2963 Gtk::ScrolledWindow list_scroller;
2966 Gtk::HBox dhbox; // the hbox for the image and text
2967 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
2968 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
2970 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
2972 const string dead_directory = _session->session_directory().dead_path().to_string();
2975 %1 - number of files removed
2976 %2 - location of "dead"
2977 %3 - size of files affected
2978 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
2981 const char* bprefix;
2982 double space_adjusted = 0;
2984 if (rep.space < 1000) {
2986 space_adjusted = rep.space;
2987 } else if (rep.space < 1000000) {
2988 bprefix = X_("kilo");
2989 space_adjusted = truncf((float)rep.space / 1000.0);
2990 } else if (rep.space < 1000000 * 1000) {
2991 bprefix = X_("mega");
2992 space_adjusted = truncf((float)rep.space / (1000.0 * 1000.0));
2994 bprefix = X_("giga");
2995 space_adjusted = truncf((float)rep.space / (1000.0 * 1000 * 1000.0));
2999 txt.set_text (string_compose (plural_msg, removed, dead_directory, space_adjusted, bprefix, PROGRAM_NAME));
3001 txt.set_text (string_compose (singular_msg, removed, dead_directory, space_adjusted, bprefix, PROGRAM_NAME));
3004 dhbox.pack_start (*dimage, true, false, 5);
3005 dhbox.pack_start (txt, true, false, 5);
3007 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
3008 TreeModel::Row row = *(results_model->append());
3009 row[results_columns.visible_name] = *i;
3010 row[results_columns.fullpath] = *i;
3013 list_scroller.add (results_display);
3014 list_scroller.set_size_request (-1, 150);
3015 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
3017 dvbox.pack_start (dhbox, true, false, 5);
3018 dvbox.pack_start (list_scroller, true, false, 5);
3019 ddhbox.pack_start (dvbox, true, false, 5);
3021 results.get_vbox()->pack_start (ddhbox, true, false, 5);
3022 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
3023 results.set_default_response (RESPONSE_CLOSE);
3024 results.set_position (Gtk::WIN_POS_MOUSE);
3026 results_display.show();
3027 list_scroller.show();
3034 //results.get_vbox()->show();
3035 results.set_resizable (false);
3042 ARDOUR_UI::cleanup ()
3044 if (_session == 0) {
3045 /* shouldn't happen: menu item is insensitive */
3050 MessageDialog checker (_("Are you sure you want to clean-up?"),
3052 Gtk::MESSAGE_QUESTION,
3055 checker.set_title (_("Clean-up"));
3057 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
3058 ALL undo/redo information will be lost if you clean-up.\n\
3059 Clean-up will move all unused files to a \"dead\" location."));
3061 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3062 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
3063 checker.set_default_response (RESPONSE_CANCEL);
3065 checker.set_name (_("CleanupDialog"));
3066 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3067 checker.set_position (Gtk::WIN_POS_MOUSE);
3069 switch (checker.run()) {
3070 case RESPONSE_ACCEPT:
3076 ARDOUR::CleanupReport rep;
3078 editor->prepare_for_cleanup ();
3080 /* do not allow flush until a session is reloaded */
3082 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3084 act->set_sensitive (false);
3087 if (_session->cleanup_sources (rep)) {
3088 editor->finish_cleanup ();
3092 editor->finish_cleanup ();
3095 display_cleanup_results (rep,
3098 The following %1 files were not in use and \n\
3099 have been moved to:\n\n\
3101 After a restart of %5,\n\n\
3102 Session -> Clean-up -> Flush Wastebasket\n\n\
3103 will release an additional\n\
3104 %3 %4bytes of disk space.\n"),
3106 The following file was not in use and \n\
3107 has been moved to:\n \
3109 After a restart of %5,\n\n\
3110 Session -> Clean-up -> Flush Wastebasket\n\n\
3111 will release an additional\n\
3112 %3 %4bytes of disk space.\n"
3118 ARDOUR_UI::flush_trash ()
3120 if (_session == 0) {
3121 /* shouldn't happen: menu item is insensitive */
3125 ARDOUR::CleanupReport rep;
3127 if (_session->cleanup_trash_sources (rep)) {
3131 display_cleanup_results (rep,
3133 _("The following %1 files were deleted from\n\
3135 releasing %3 %4bytes of disk space"),
3136 _("The following file was deleted from\n\
3138 releasing %3 %4bytes of disk space"));
3142 ARDOUR_UI::add_route (Gtk::Window* float_window)
3150 if (add_route_dialog == 0) {
3151 add_route_dialog = new AddRouteDialog (_session);
3152 add_route_dialog->set_position (WIN_POS_MOUSE);
3154 add_route_dialog->set_transient_for (*float_window);
3158 if (add_route_dialog->is_visible()) {
3159 /* we're already doing this */
3163 ResponseType r = (ResponseType) add_route_dialog->run ();
3165 add_route_dialog->hide();
3168 case RESPONSE_ACCEPT:
3175 if ((count = add_route_dialog->count()) <= 0) {
3179 string template_path = add_route_dialog->track_template();
3181 if (!template_path.empty()) {
3182 _session->new_route_from_template (count, template_path);
3186 uint32_t input_chan = add_route_dialog->channels ();
3187 uint32_t output_chan;
3188 string name_template = add_route_dialog->name_template ();
3189 PluginInfoPtr instrument = add_route_dialog->requested_instrument ();
3190 RouteGroup* route_group = add_route_dialog->route_group ();
3192 AutoConnectOption oac = Config->get_output_auto_connect();
3194 if (oac & AutoConnectMaster) {
3195 output_chan = (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan);
3197 output_chan = input_chan;
3200 /* XXX do something with name template */
3202 if (add_route_dialog->midi_tracks_wanted()) {
3203 session_add_midi_track (route_group, count, name_template, instrument);
3204 } else if (add_route_dialog->audio_tracks_wanted()) {
3205 session_add_audio_track (input_chan, output_chan, add_route_dialog->mode(), route_group, count, name_template);
3207 session_add_audio_bus (input_chan, output_chan, route_group, count, name_template);
3212 ARDOUR_UI::mixer_settings () const
3217 node = _session->instant_xml(X_("Mixer"));
3219 node = Config->instant_xml(X_("Mixer"));
3223 node = new XMLNode (X_("Mixer"));
3230 ARDOUR_UI::editor_settings () const
3235 node = _session->instant_xml(X_("Editor"));
3237 node = Config->instant_xml(X_("Editor"));
3241 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
3242 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
3247 node = new XMLNode (X_("Editor"));
3254 ARDOUR_UI::keyboard_settings () const
3258 node = Config->extra_xml(X_("Keyboard"));
3261 node = new XMLNode (X_("Keyboard"));
3268 ARDOUR_UI::create_xrun_marker (framepos_t where)
3270 editor->mouse_add_new_marker (where, false, true);
3274 ARDOUR_UI::halt_on_xrun_message ()
3276 MessageDialog msg (*editor,
3277 _("Recording was stopped because your system could not keep up."));
3282 ARDOUR_UI::xrun_handler (framepos_t where)
3288 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
3290 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
3291 create_xrun_marker(where);
3294 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
3295 halt_on_xrun_message ();
3300 ARDOUR_UI::disk_overrun_handler ()
3302 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
3304 if (!have_disk_speed_dialog_displayed) {
3305 have_disk_speed_dialog_displayed = true;
3306 MessageDialog* msg = new MessageDialog (*editor, string_compose (_("\
3307 The disk system on your computer\n\
3308 was not able to keep up with %1.\n\
3310 Specifically, it failed to write data to disk\n\
3311 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
3312 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3318 ARDOUR_UI::disk_underrun_handler ()
3320 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
3322 if (!have_disk_speed_dialog_displayed) {
3323 have_disk_speed_dialog_displayed = true;
3324 MessageDialog* msg = new MessageDialog (
3325 *editor, string_compose (_("The disk system on your computer\n\
3326 was not able to keep up with %1.\n\
3328 Specifically, it failed to read data from disk\n\
3329 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
3330 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3336 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
3338 have_disk_speed_dialog_displayed = false;
3343 ARDOUR_UI::session_dialog (std::string msg)
3345 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
3350 d = new MessageDialog (*editor, msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3352 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3361 ARDOUR_UI::pending_state_dialog ()
3363 HBox* hbox = new HBox();
3364 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3365 ArdourDialog dialog (_("Crash Recovery"), true);
3367 This session appears to have been in\n\
3368 middle of recording when ardour or\n\
3369 the computer was shutdown.\n\
3371 Ardour can recover any captured audio for\n\
3372 you, or it can ignore it. Please decide\n\
3373 what you would like to do.\n"));
3374 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3375 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3376 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3377 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3378 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
3379 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
3380 dialog.set_default_response (RESPONSE_ACCEPT);
3381 dialog.set_position (WIN_POS_CENTER);
3386 switch (dialog.run ()) {
3387 case RESPONSE_ACCEPT:
3395 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
3397 HBox* hbox = new HBox();
3398 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3399 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
3400 Label message (string_compose (_("\
3401 This session was created with a sample rate of %1 Hz\n\
3403 The audioengine is currently running at %2 Hz\n"), desired, actual));
3405 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3406 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3407 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3408 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3409 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
3410 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
3411 dialog.set_default_response (RESPONSE_ACCEPT);
3412 dialog.set_position (WIN_POS_CENTER);
3417 switch (dialog.run ()) {
3418 case RESPONSE_ACCEPT:
3427 ARDOUR_UI::disconnect_from_jack ()
3430 if( engine->disconnect_from_jack ()) {
3431 MessageDialog msg (*editor, _("Could not disconnect from JACK"));
3435 update_sample_rate (0);
3440 ARDOUR_UI::reconnect_to_jack ()
3443 if (engine->reconnect_to_jack ()) {
3444 MessageDialog msg (*editor, _("Could not reconnect to JACK"));
3448 update_sample_rate (0);
3453 ARDOUR_UI::use_config ()
3455 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
3457 set_transport_controllable_state (*node);
3462 ARDOUR_UI::update_transport_clocks (framepos_t pos)
3464 if (Config->get_primary_clock_delta_edit_cursor()) {
3465 primary_clock->set (pos, false, editor->get_preferred_edit_position());
3467 primary_clock->set (pos);
3470 if (Config->get_secondary_clock_delta_edit_cursor()) {
3471 secondary_clock->set (pos, false, editor->get_preferred_edit_position());
3473 secondary_clock->set (pos);
3476 if (big_clock_window->get()) {
3477 big_clock->set (pos);
3483 ARDOUR_UI::step_edit_status_change (bool yn)
3485 // XXX should really store pre-step edit status of things
3486 // we make insensitive
3489 rec_button.set_active_state (Gtkmm2ext::ImplicitActive);
3490 rec_button.set_sensitive (false);
3492 rec_button.unset_active_state ();;
3493 rec_button.set_sensitive (true);
3498 ARDOUR_UI::record_state_changed ()
3500 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
3502 if (!_session || !big_clock_window->get()) {
3503 /* why bother - the clock isn't visible */
3507 if (_session->record_status () == Session::Recording && _session->have_rec_enabled_track ()) {
3508 big_clock->set_active (true);
3510 big_clock->set_active (false);
3515 ARDOUR_UI::first_idle ()
3518 _session->allow_auto_play (true);
3522 editor->first_idle();
3525 Keyboard::set_can_save_keybindings (true);
3530 ARDOUR_UI::store_clock_modes ()
3532 XMLNode* node = new XMLNode(X_("ClockModes"));
3534 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
3535 XMLNode* child = new XMLNode (X_("Clock"));
3537 child->add_property (X_("name"), (*x)->name());
3538 child->add_property (X_("mode"), enum_2_string ((*x)->mode()));
3539 child->add_property (X_("on"), ((*x)->off() ? X_("no") : X_("yes")));
3541 node->add_child_nocopy (*child);
3544 _session->add_extra_xml (*node);
3545 _session->set_dirty ();
3548 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
3549 : Controllable (name), ui (u), type(tp)
3555 ARDOUR_UI::TransportControllable::set_value (double val)
3558 /* do nothing: these are radio-style actions */
3562 const char *action = 0;
3566 action = X_("Roll");
3569 action = X_("Stop");
3572 action = X_("Goto Start");
3575 action = X_("Goto End");
3578 action = X_("Loop");
3581 action = X_("Play Selection");
3584 action = X_("Record");
3594 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
3602 ARDOUR_UI::TransportControllable::get_value (void) const
3629 ARDOUR_UI::setup_profile ()
3631 if (gdk_screen_width() < 1200 || getenv ("ARDOUR_NARROW_SCREEN")) {
3632 Profile->set_small_screen ();
3636 if (getenv ("ARDOUR_SAE")) {
3637 Profile->set_sae ();
3638 Profile->set_single_package ();
3643 ARDOUR_UI::toggle_translations ()
3645 using namespace Glib;
3647 RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("EnableTranslation"));
3649 RefPtr<ToggleAction> ract = RefPtr<ToggleAction>::cast_dynamic (act);
3652 string i18n_killer = ARDOUR::translation_kill_path();
3654 bool already_enabled = !ARDOUR::translations_are_disabled ();
3656 if (ract->get_active ()) {
3657 /* we don't care about errors */
3658 int fd = ::open (i18n_killer.c_str(), O_RDONLY|O_CREAT, 0644);
3661 /* we don't care about errors */
3662 unlink (i18n_killer.c_str());
3665 if (already_enabled != ract->get_active()) {
3666 MessageDialog win (already_enabled ? _("Translations disabled") : _("Translations enabled"),
3668 Gtk::MESSAGE_WARNING,
3670 win.set_secondary_text (string_compose (_("You must restart %1 for this to take effect."), PROGRAM_NAME));
3671 win.set_position (Gtk::WIN_POS_CENTER);
3679 /** Add a window proxy to our list, so that its state will be saved.
3680 * This call also causes the window to be created and opened if its
3681 * state was saved as `visible'.
3684 ARDOUR_UI::add_window_proxy (WindowProxyBase* p)
3686 _window_proxies.push_back (p);
3690 /** Remove a window proxy from our list. Must be called if a WindowProxy
3691 * is deleted, to prevent hanging pointers.
3694 ARDOUR_UI::remove_window_proxy (WindowProxyBase* p)
3696 _window_proxies.remove (p);
3700 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
3702 MissingFileDialog dialog (s, str, type);
3707 int result = dialog.run ();
3714 return 1; // quit entire session load
3717 result = dialog.get_action ();
3723 ARDOUR_UI::ambiguous_file (std::string file, std::string /*path*/, std::vector<std::string> hits)
3725 AmbiguousFileDialog dialog (file, hits);
3731 return dialog.get_which ();
3734 /** Allocate our thread-local buffers */
3736 ARDOUR_UI::get_process_buffers ()
3738 _process_thread->get_buffers ();
3741 /** Drop our thread-local buffers */
3743 ARDOUR_UI::drop_process_buffers ()
3745 _process_thread->drop_buffers ();
3749 ARDOUR_UI::feedback_detected ()
3751 _feedback_exists = true;
3755 ARDOUR_UI::successful_graph_sort ()
3757 _feedback_exists = false;
3761 ARDOUR_UI::midi_panic ()
3764 _session->midi_panic();