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_model (recent_session_model);
1226 ARDOUR_UI::build_session_selector ()
1228 session_selector_window = new ArdourDialog (_("Recent Sessions"));
1230 Gtk::ScrolledWindow *scroller = manage (new Gtk::ScrolledWindow);
1232 session_selector_window->add_button (Stock::CANCEL, RESPONSE_CANCEL);
1233 session_selector_window->add_button (Stock::OPEN, RESPONSE_ACCEPT);
1234 session_selector_window->set_default_response (RESPONSE_ACCEPT);
1235 recent_session_model = TreeStore::create (recent_session_columns);
1236 recent_session_display.set_model (recent_session_model);
1237 recent_session_display.append_column (_("Recent Sessions"), recent_session_columns.visible_name);
1238 recent_session_display.set_headers_visible (false);
1239 recent_session_display.get_selection()->set_mode (SELECTION_BROWSE);
1240 recent_session_display.signal_row_activated().connect (sigc::mem_fun (*this, &ARDOUR_UI::recent_session_row_activated));
1242 scroller->add (recent_session_display);
1243 scroller->set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
1245 session_selector_window->set_name ("SessionSelectorWindow");
1246 session_selector_window->set_size_request (200, 400);
1247 session_selector_window->get_vbox()->pack_start (*scroller);
1249 recent_session_display.show();
1251 //session_selector_window->get_vbox()->show();
1255 ARDOUR_UI::recent_session_row_activated (const TreePath& /*path*/, TreeViewColumn* /*col*/)
1257 session_selector_window->response (RESPONSE_ACCEPT);
1261 ARDOUR_UI::open_recent_session ()
1263 bool can_return = (_session != 0);
1265 if (session_selector_window == 0) {
1266 build_session_selector ();
1269 redisplay_recent_sessions ();
1273 session_selector_window->set_position (WIN_POS_MOUSE);
1275 ResponseType r = (ResponseType) session_selector_window->run ();
1278 case RESPONSE_ACCEPT:
1282 session_selector_window->hide();
1289 if (recent_session_display.get_selection()->count_selected_rows() == 0) {
1293 session_selector_window->hide();
1295 Gtk::TreeModel::iterator i = recent_session_display.get_selection()->get_selected();
1297 if (i == recent_session_model->children().end()) {
1301 std::string path = (*i)[recent_session_columns.fullpath];
1302 std::string state = (*i)[recent_session_columns.visible_name];
1304 _session_is_new = false;
1306 if (load_session (path, state) == 0) {
1315 ARDOUR_UI::check_audioengine ()
1318 if (!engine->connected()) {
1319 MessageDialog msg (string_compose (
1320 _("%1 is not connected to JACK\n"
1321 "You cannot open or close sessions in this condition"),
1323 pop_back_splash (msg);
1334 ARDOUR_UI::open_session ()
1336 if (!check_audioengine()) {
1341 /* popup selector window */
1343 if (open_session_selector == 0) {
1345 /* ardour sessions are folders */
1347 open_session_selector = new Gtk::FileChooserDialog (_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1348 open_session_selector->add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1349 open_session_selector->add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1350 open_session_selector->set_default_response(Gtk::RESPONSE_ACCEPT);
1352 FileFilter session_filter;
1353 session_filter.add_pattern ("*.ardour");
1354 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1355 open_session_selector->add_filter (session_filter);
1356 open_session_selector->set_filter (session_filter);
1359 int response = open_session_selector->run();
1360 open_session_selector->hide ();
1363 case RESPONSE_ACCEPT:
1366 open_session_selector->hide();
1370 open_session_selector->hide();
1371 string session_path = open_session_selector->get_filename();
1375 if (session_path.length() > 0) {
1376 if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1377 _session_is_new = isnew;
1378 load_session (path, name);
1385 ARDOUR_UI::session_add_midi_route (bool disk, RouteGroup* route_group, uint32_t how_many, const string& name_template, PluginInfoPtr instrument)
1387 list<boost::shared_ptr<MidiTrack> > tracks;
1389 if (_session == 0) {
1390 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1397 tracks = _session->new_midi_track (instrument, ARDOUR::Normal, route_group, how_many, name_template);
1399 if (tracks.size() != how_many) {
1400 if (how_many == 1) {
1401 error << _("could not create a new midi track") << endmsg;
1403 error << string_compose (_("could not create %1 new midi tracks"), how_many) << endmsg;
1408 if ((route = _session->new_midi_route ()) == 0) {
1409 error << _("could not create new midi bus") << endmsg;
1415 MessageDialog msg (*editor,
1416 string_compose (_("There are insufficient JACK ports available\n\
1417 to create a new track or bus.\n\
1418 You should save %1, exit and\n\
1419 restart JACK with more ports."), PROGRAM_NAME));
1426 ARDOUR_UI::session_add_audio_route (
1428 int32_t input_channels,
1429 int32_t output_channels,
1430 ARDOUR::TrackMode mode,
1431 RouteGroup* route_group,
1433 string const & name_template
1436 list<boost::shared_ptr<AudioTrack> > tracks;
1439 if (_session == 0) {
1440 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1446 tracks = _session->new_audio_track (input_channels, output_channels, mode, route_group, how_many, name_template);
1448 if (tracks.size() != how_many) {
1449 if (how_many == 1) {
1450 error << _("could not create a new audio track") << endmsg;
1452 error << string_compose (_("could only create %1 of %2 new audio %3"),
1453 tracks.size(), how_many, (track ? _("tracks") : _("busses"))) << endmsg;
1459 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template);
1461 if (routes.size() != how_many) {
1462 if (how_many == 1) {
1463 error << _("could not create a new audio bus") << endmsg;
1465 error << string_compose (_("could not create %1 new audio busses"), how_many) << endmsg;
1472 MessageDialog msg (*editor,
1473 string_compose (_("There are insufficient JACK ports available\n\
1474 to create a new track or bus.\n\
1475 You should save %1, exit and\n\
1476 restart JACK with more ports."), PROGRAM_NAME));
1477 pop_back_splash (msg);
1483 ARDOUR_UI::transport_goto_start ()
1486 _session->goto_start();
1488 /* force displayed area in editor to start no matter
1489 what "follow playhead" setting is.
1493 editor->center_screen (_session->current_start_frame ());
1499 ARDOUR_UI::transport_goto_zero ()
1502 _session->request_locate (0);
1504 /* force displayed area in editor to start no matter
1505 what "follow playhead" setting is.
1509 editor->reset_x_origin (0);
1515 ARDOUR_UI::transport_goto_wallclock ()
1517 if (_session && editor) {
1524 localtime_r (&now, &tmnow);
1526 frames = tmnow.tm_hour * (60 * 60 * _session->frame_rate());
1527 frames += tmnow.tm_min * (60 * _session->frame_rate());
1528 frames += tmnow.tm_sec * _session->frame_rate();
1530 _session->request_locate (frames, _session->transport_rolling ());
1532 /* force displayed area in editor to start no matter
1533 what "follow playhead" setting is.
1537 editor->center_screen (frames);
1543 ARDOUR_UI::transport_goto_end ()
1546 framepos_t const frame = _session->current_end_frame();
1547 _session->request_locate (frame);
1549 /* force displayed area in editor to start no matter
1550 what "follow playhead" setting is.
1554 editor->center_screen (frame);
1560 ARDOUR_UI::transport_stop ()
1566 if (_session->is_auditioning()) {
1567 _session->cancel_audition ();
1571 _session->request_stop (false, true);
1575 ARDOUR_UI::remove_last_capture()
1578 editor->remove_last_capture();
1583 ARDOUR_UI::transport_record (bool roll)
1587 switch (_session->record_status()) {
1588 case Session::Disabled:
1589 if (_session->ntracks() == 0) {
1590 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."));
1594 _session->maybe_enable_record ();
1599 case Session::Recording:
1601 _session->request_stop();
1603 _session->disable_record (false, true);
1607 case Session::Enabled:
1608 _session->disable_record (false, true);
1611 //cerr << "ARDOUR_UI::transport_record () called roll = " << roll << " _session->record_status() = " << _session->record_status() << endl;
1615 ARDOUR_UI::transport_roll ()
1621 if (_session->is_auditioning()) {
1626 if (_session->config.get_external_sync()) {
1627 switch (_session->config.get_sync_source()) {
1631 /* transport controlled by the master */
1637 bool rolling = _session->transport_rolling();
1639 if (_session->get_play_loop()) {
1640 /* XXX it is not possible to just leave seamless loop and keep
1641 playing at present (nov 4th 2009)
1643 if (!Config->get_seamless_loop()) {
1644 _session->request_play_loop (false, true);
1646 } else if (_session->get_play_range () && !Config->get_always_play_range()) {
1647 /* stop playing a range if we currently are */
1648 _session->request_play_range (0, true);
1651 if (Config->get_always_play_range()) {
1652 _session->request_play_range (&editor->get_selection().time, true);
1656 _session->request_transport_speed (1.0f);
1661 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
1668 if (_session->is_auditioning()) {
1669 _session->cancel_audition ();
1673 if (_session->config.get_external_sync()) {
1674 switch (_session->config.get_sync_source()) {
1678 /* transport controlled by the master */
1683 bool rolling = _session->transport_rolling();
1684 bool affect_transport = true;
1686 if (rolling && roll_out_of_bounded_mode) {
1687 /* drop out of loop/range playback but leave transport rolling */
1688 if (_session->get_play_loop()) {
1689 if (Config->get_seamless_loop()) {
1690 /* the disk buffers contain copies of the loop - we can't
1691 just keep playing, so stop the transport. the user
1692 can restart as they wish.
1694 affect_transport = true;
1696 /* disk buffers are normal, so we can keep playing */
1697 affect_transport = false;
1699 _session->request_play_loop (false, true);
1700 } else if (_session->get_play_range ()) {
1701 affect_transport = false;
1702 _session->request_play_range (0, true);
1706 if (affect_transport) {
1708 _session->request_stop (with_abort, true);
1710 if (Config->get_always_play_range ()) {
1711 _session->request_play_range (&editor->get_selection().time, true);
1714 _session->request_transport_speed (1.0f);
1720 ARDOUR_UI::toggle_session_auto_loop ()
1722 Location * looploc = _session->locations()->auto_loop_location();
1724 if (!_session || !looploc) {
1728 if (_session->get_play_loop()) {
1730 if (_session->transport_rolling()) {
1732 _session->request_locate (looploc->start(), true);
1733 _session->request_play_loop (false);
1736 _session->request_play_loop (false);
1739 _session->request_play_loop (true);
1742 //show the loop markers
1743 looploc->set_hidden (false, this);
1747 ARDOUR_UI::transport_play_selection ()
1753 editor->play_selection ();
1757 ARDOUR_UI::transport_rewind (int option)
1759 float current_transport_speed;
1762 current_transport_speed = _session->transport_speed();
1764 if (current_transport_speed >= 0.0f) {
1767 _session->request_transport_speed (-1.0f);
1770 _session->request_transport_speed (-4.0f);
1773 _session->request_transport_speed (-0.5f);
1778 _session->request_transport_speed (current_transport_speed * 1.5f);
1784 ARDOUR_UI::transport_forward (int option)
1786 float current_transport_speed;
1789 current_transport_speed = _session->transport_speed();
1791 if (current_transport_speed <= 0.0f) {
1794 _session->request_transport_speed (1.0f);
1797 _session->request_transport_speed (4.0f);
1800 _session->request_transport_speed (0.5f);
1805 _session->request_transport_speed (current_transport_speed * 1.5f);
1812 ARDOUR_UI::toggle_record_enable (uint32_t rid)
1814 if (_session == 0) {
1818 boost::shared_ptr<Route> r;
1820 if ((r = _session->route_by_remote_id (rid)) != 0) {
1824 if ((t = dynamic_cast<Track*>(r.get())) != 0) {
1825 t->set_record_enabled (!t->record_enabled(), this);
1828 if (_session == 0) {
1834 ARDOUR_UI::map_transport_state ()
1837 auto_loop_button.unset_active_state ();
1838 play_selection_button.unset_active_state ();
1839 roll_button.unset_active_state ();
1840 stop_button.set_active_state (Gtkmm2ext::ExplicitActive);
1844 shuttle_box->map_transport_state ();
1846 float sp = _session->transport_speed();
1852 if (_session->get_play_range()) {
1854 play_selection_button.set_active_state (Gtkmm2ext::ExplicitActive);
1855 roll_button.unset_active_state ();
1856 auto_loop_button.unset_active_state ();
1858 } else if (_session->get_play_loop ()) {
1860 auto_loop_button.set_active (true);
1861 play_selection_button.set_active (false);
1862 roll_button.set_active (false);
1866 roll_button.set_active (true);
1867 play_selection_button.set_active (false);
1868 auto_loop_button.set_active (false);
1871 if (Config->get_always_play_range()) {
1872 /* light up both roll and play-selection if they are joined */
1873 roll_button.set_active (true);
1874 play_selection_button.set_active (true);
1877 stop_button.set_active (false);
1881 stop_button.set_active (true);
1882 roll_button.set_active (false);
1883 play_selection_button.set_active (false);
1884 auto_loop_button.set_active (false);
1885 update_disk_space ();
1890 ARDOUR_UI::engine_stopped ()
1892 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
1893 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1894 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1898 ARDOUR_UI::engine_running ()
1900 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
1901 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, true);
1902 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, false);
1904 Glib::RefPtr<Action> action;
1905 const char* action_name = 0;
1907 switch (engine->frames_per_cycle()) {
1909 action_name = X_("JACKLatency32");
1912 action_name = X_("JACKLatency64");
1915 action_name = X_("JACKLatency128");
1918 action_name = X_("JACKLatency512");
1921 action_name = X_("JACKLatency1024");
1924 action_name = X_("JACKLatency2048");
1927 action_name = X_("JACKLatency4096");
1930 action_name = X_("JACKLatency8192");
1933 /* XXX can we do anything useful ? */
1939 action = ActionManager::get_action (X_("JACK"), action_name);
1942 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (action);
1943 ract->set_active ();
1949 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
1951 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
1952 /* we can't rely on the original string continuing to exist when we are called
1953 again in the GUI thread, so make a copy and note that we need to
1956 char *copy = strdup (reason);
1957 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
1961 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1962 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1964 update_sample_rate (0);
1968 /* if the reason is a non-empty string, it means that the backend was shutdown
1969 rather than just Ardour.
1972 if (strlen (reason)) {
1973 msgstr = string_compose (_("The audio backend (JACK) was shutdown because:\n\n%1"), reason);
1975 msgstr = string_compose (_("\
1976 JACK has either been shutdown or it\n\
1977 disconnected %1 because %1\n\
1978 was not fast enough. Try to restart\n\
1979 JACK, reconnect and save the session."), PROGRAM_NAME);
1982 MessageDialog msg (*editor, msgstr);
1983 pop_back_splash (msg);
1987 free ((char*) reason);
1992 ARDOUR_UI::do_engine_start ()
2000 error << _("Unable to start the session running")
2010 ARDOUR_UI::update_clocks ()
2012 if (!editor || !editor->dragging_playhead()) {
2013 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position()); /* EMIT_SIGNAL */
2018 ARDOUR_UI::start_clocking ()
2020 clock_signal_connection = RapidScreenUpdate.connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2024 ARDOUR_UI::stop_clocking ()
2026 clock_signal_connection.disconnect ();
2030 ARDOUR_UI::_blink (void *arg)
2033 ((ARDOUR_UI *) arg)->blink ();
2040 Blink (blink_on = !blink_on); /* EMIT_SIGNAL */
2044 ARDOUR_UI::start_blinking ()
2046 /* Start the blink signal. Everybody with a blinking widget
2047 uses Blink to drive the widget's state.
2050 if (blink_timeout_tag < 0) {
2052 blink_timeout_tag = g_timeout_add (240, _blink, this);
2057 ARDOUR_UI::stop_blinking ()
2059 if (blink_timeout_tag >= 0) {
2060 g_source_remove (blink_timeout_tag);
2061 blink_timeout_tag = -1;
2066 /** Ask the user for the name of a new snapshot and then take it.
2070 ARDOUR_UI::snapshot_session (bool switch_to_it)
2072 ArdourPrompter prompter (true);
2075 prompter.set_name ("Prompter");
2076 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2077 prompter.set_title (_("Take Snapshot"));
2078 prompter.set_prompt (_("Name of new snapshot"));
2080 if (!switch_to_it) {
2083 struct tm local_time;
2086 localtime_r (&n, &local_time);
2087 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2088 prompter.set_initial_text (timebuf);
2092 switch (prompter.run()) {
2093 case RESPONSE_ACCEPT:
2095 prompter.get_result (snapname);
2097 bool do_save = (snapname.length() != 0);
2100 char illegal = Session::session_name_is_legal(snapname);
2102 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2103 "snapshot names may not contain a '%1' character"), illegal));
2109 vector<sys::path> p;
2110 get_state_files_in_directory (_session->session_directory().root_path(), p);
2111 vector<string> n = get_file_names_no_extension (p);
2112 if (find (n.begin(), n.end(), snapname) != n.end()) {
2114 ArdourDialog confirm (_("Confirm Snapshot Overwrite"), true);
2115 Label m (_("A snapshot already exists with that name. Do you want to overwrite it?"));
2116 confirm.get_vbox()->pack_start (m, true, true);
2117 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2118 confirm.add_button (_("Overwrite"), Gtk::RESPONSE_ACCEPT);
2119 confirm.show_all ();
2120 switch (confirm.run()) {
2121 case RESPONSE_CANCEL:
2127 save_state (snapname, switch_to_it);
2137 /** Ask the user for a new session name and then rename the session to it.
2141 ARDOUR_UI::rename_session ()
2147 ArdourPrompter prompter (true);
2150 prompter.set_name ("Prompter");
2151 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2152 prompter.set_title (_("Rename Session"));
2153 prompter.set_prompt (_("New session name"));
2156 switch (prompter.run()) {
2157 case RESPONSE_ACCEPT:
2159 prompter.get_result (name);
2161 bool do_rename = (name.length() != 0);
2164 char illegal = Session::session_name_is_legal (name);
2167 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2168 "session names may not contain a '%1' character"), illegal));
2173 switch (_session->rename (name)) {
2175 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
2176 msg.set_position (WIN_POS_MOUSE);
2184 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
2185 msg.set_position (WIN_POS_MOUSE);
2201 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2203 XMLNode* node = new XMLNode (X_("UI"));
2205 for (list<WindowProxyBase*>::iterator i = _window_proxies.begin(); i != _window_proxies.end(); ++i) {
2206 if (!(*i)->rc_configured()) {
2207 node->add_child_nocopy (*((*i)->get_state ()));
2211 node->add_child_nocopy (gui_object_state->get_state());
2213 _session->add_extra_xml (*node);
2215 save_state_canfail (name, switch_to_it);
2219 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2224 if (name.length() == 0) {
2225 name = _session->snap_name();
2228 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2233 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2238 ARDOUR_UI::primary_clock_value_changed ()
2241 _session->request_locate (primary_clock->current_time ());
2246 ARDOUR_UI::big_clock_value_changed ()
2249 _session->request_locate (big_clock->current_time ());
2254 ARDOUR_UI::secondary_clock_value_changed ()
2257 _session->request_locate (secondary_clock->current_time ());
2262 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2264 if (_session == 0) {
2268 if (_session->step_editing()) {
2272 Session::RecordState const r = _session->record_status ();
2273 bool const h = _session->have_rec_enabled_track ();
2275 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2277 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2279 rec_button.set_active_state (Gtkmm2ext::ImplicitActive);
2281 } else if (r == Session::Recording && h) {
2282 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2284 rec_button.unset_active_state ();
2289 ARDOUR_UI::save_template ()
2291 ArdourPrompter prompter (true);
2294 if (!check_audioengine()) {
2298 prompter.set_name (X_("Prompter"));
2299 prompter.set_title (_("Save Template"));
2300 prompter.set_prompt (_("Name for template:"));
2301 prompter.set_initial_text(_session->name() + _("-template"));
2302 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2304 switch (prompter.run()) {
2305 case RESPONSE_ACCEPT:
2306 prompter.get_result (name);
2308 if (name.length()) {
2309 _session->save_template (name);
2319 ARDOUR_UI::edit_metadata ()
2321 SessionMetadataEditor dialog;
2322 dialog.set_session (_session);
2323 editor->ensure_float (dialog);
2328 ARDOUR_UI::import_metadata ()
2330 SessionMetadataImporter dialog;
2331 dialog.set_session (_session);
2332 editor->ensure_float (dialog);
2337 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
2339 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2341 MessageDialog msg (str,
2343 Gtk::MESSAGE_WARNING,
2344 Gtk::BUTTONS_YES_NO,
2348 msg.set_name (X_("OpenExistingDialog"));
2349 msg.set_title (_("Open Existing Session"));
2350 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
2351 msg.set_position (Gtk::WIN_POS_MOUSE);
2352 pop_back_splash (msg);
2354 switch (msg.run()) {
2363 ARDOUR_UI::build_session_from_nsd (const std::string& session_path, const std::string& session_name)
2365 BusProfile bus_profile;
2367 if (Profile->get_sae()) {
2369 bus_profile.master_out_channels = 2;
2370 bus_profile.input_ac = AutoConnectPhysical;
2371 bus_profile.output_ac = AutoConnectMaster;
2372 bus_profile.requested_physical_in = 0; // use all available
2373 bus_profile.requested_physical_out = 0; // use all available
2377 /* get settings from advanced section of NSD */
2379 if (_startup->create_master_bus()) {
2380 bus_profile.master_out_channels = (uint32_t) _startup->master_channel_count();
2382 bus_profile.master_out_channels = 0;
2385 if (_startup->connect_inputs()) {
2386 bus_profile.input_ac = AutoConnectPhysical;
2388 bus_profile.input_ac = AutoConnectOption (0);
2391 bus_profile.output_ac = AutoConnectOption (0);
2393 if (_startup->connect_outputs ()) {
2394 if (_startup->connect_outs_to_master()) {
2395 bus_profile.output_ac = AutoConnectMaster;
2396 } else if (_startup->connect_outs_to_physical()) {
2397 bus_profile.output_ac = AutoConnectPhysical;
2401 bus_profile.requested_physical_in = (uint32_t) _startup->input_limit_count();
2402 bus_profile.requested_physical_out = (uint32_t) _startup->output_limit_count();
2405 if (build_session (session_path, session_name, bus_profile)) {
2413 ARDOUR_UI::idle_load (const std::string& path)
2416 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2417 /* /path/to/foo => /path/to/foo, foo */
2418 load_session (path, basename_nosuffix (path));
2420 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2421 load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2425 ARDOUR_COMMAND_LINE::session_name = path;
2428 * new_session_dialog doens't exist in A3
2429 * Try to remove all references to it to
2430 * see if it will compile. NOTE: this will
2431 * likely cause a runtime issue is my somewhat
2435 //if (new_session_dialog) {
2438 /* make it break out of Dialog::run() and
2442 //new_session_dialog->response (1);
2448 ARDOUR_UI::loading_message (const std::string& msg)
2450 if (ARDOUR_COMMAND_LINE::no_splash) {
2456 splash->message (msg);
2461 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
2463 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
2465 string session_name;
2466 string session_path;
2467 string template_name;
2469 bool likely_new = false;
2471 if (!load_template.empty()) {
2472 should_be_new = true;
2473 template_name = load_template;
2478 if (!should_be_new && !ARDOUR_COMMAND_LINE::session_name.empty()) {
2480 /* if they named a specific statefile, use it, otherwise they are
2481 just giving a session folder, and we want to use it as is
2482 to find the session.
2485 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
2487 if (suffix != string::npos) {
2488 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
2489 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
2490 session_name = Glib::path_get_basename (session_name);
2492 session_path = ARDOUR_COMMAND_LINE::session_name;
2493 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
2498 bool const apply = run_startup (should_be_new, load_template);
2501 if (quit_on_cancel) {
2508 /* if we run the startup dialog again, offer more than just "new session" */
2510 should_be_new = false;
2512 session_name = _startup->session_name (likely_new);
2514 string::size_type suffix = session_name.find (statefile_suffix);
2516 if (suffix != string::npos) {
2517 session_name = session_name.substr (0, suffix);
2520 /* this shouldn't happen, but we catch it just in case it does */
2522 if (session_name.empty()) {
2526 if (_startup->use_session_template()) {
2527 template_name = _startup->session_template_name();
2528 _session_is_new = true;
2531 if (session_name[0] == G_DIR_SEPARATOR ||
2532 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
2533 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)) {
2535 /* absolute path or cwd-relative path specified for session name: infer session folder
2536 from what was given.
2539 session_path = Glib::path_get_dirname (session_name);
2540 session_name = Glib::path_get_basename (session_name);
2544 session_path = _startup->session_folder();
2546 char illegal = Session::session_name_is_legal (session_name);
2549 MessageDialog msg (*_startup,
2550 string_compose (_("To ensure compatibility with various systems\n"
2551 "session names may not contain a '%1' character"),
2554 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2560 if (create_engine ()) {
2564 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
2568 std::string existing = Glib::build_filename (session_path, session_name);
2570 if (!ask_about_loading_existing_session (existing)) {
2571 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2576 _session_is_new = false;
2581 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
2583 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2587 if (session_name.find ('/') != std::string::npos) {
2588 MessageDialog msg (*_startup,
2589 _("To ensure compatibility with various systems\n"
2590 "session names may not contain a '/' character"));
2592 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2596 if (session_name.find ('\\') != std::string::npos) {
2597 MessageDialog msg (*_startup,
2598 _("To ensure compatibility with various systems\n"
2599 "session names may not contain a '\\' character"));
2601 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2605 _session_is_new = true;
2608 if (likely_new && template_name.empty()) {
2610 ret = build_session_from_nsd (session_path, session_name);
2614 ret = load_session (session_path, session_name, template_name);
2617 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
2621 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
2622 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
2632 ARDOUR_UI::close_session()
2634 if (!check_audioengine()) {
2638 if (unload_session (true)) {
2642 ARDOUR_COMMAND_LINE::session_name = "";
2644 if (get_session_parameters (true, false)) {
2648 goto_editor_window ();
2651 /** @param snap_name Snapshot name (without .ardour suffix).
2652 * @return -2 if the load failed because we are not connected to the AudioEngine.
2655 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
2657 Session *new_session;
2661 session_loaded = false;
2663 if (!check_audioengine()) {
2667 unload_status = unload_session ();
2669 if (unload_status < 0) {
2671 } else if (unload_status > 0) {
2676 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
2679 new_session = new Session (*engine, path, snap_name, 0, mix_template);
2682 /* this one is special */
2684 catch (AudioEngine::PortRegistrationFailure& err) {
2686 MessageDialog msg (err.what(),
2689 Gtk::BUTTONS_CLOSE);
2691 msg.set_title (_("Port Registration Error"));
2692 msg.set_secondary_text (_("Click the Close button to try again."));
2693 msg.set_position (Gtk::WIN_POS_CENTER);
2694 pop_back_splash (msg);
2697 int response = msg.run ();
2702 case RESPONSE_CANCEL:
2712 MessageDialog msg (string_compose(
2713 _("Session \"%1 (snapshot %2)\" did not load successfully"),
2719 msg.set_title (_("Loading Error"));
2720 msg.set_secondary_text (_("Click the Refresh button to try again."));
2721 msg.add_button (Stock::REFRESH, 1);
2722 msg.set_position (Gtk::WIN_POS_CENTER);
2723 pop_back_splash (msg);
2726 int response = msg.run ();
2741 list<string> const u = new_session->unknown_processors ();
2743 MissingPluginDialog d (_session, u);
2748 /* Now the session been created, add the transport controls */
2749 new_session->add_controllable(roll_controllable);
2750 new_session->add_controllable(stop_controllable);
2751 new_session->add_controllable(goto_start_controllable);
2752 new_session->add_controllable(goto_end_controllable);
2753 new_session->add_controllable(auto_loop_controllable);
2754 new_session->add_controllable(play_selection_controllable);
2755 new_session->add_controllable(rec_controllable);
2757 set_session (new_session);
2759 session_loaded = true;
2761 goto_editor_window ();
2764 _session->set_clean ();
2775 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
2777 Session *new_session;
2780 if (!check_audioengine()) {
2784 session_loaded = false;
2786 x = unload_session ();
2794 _session_is_new = true;
2797 new_session = new Session (*engine, path, snap_name, &bus_profile);
2802 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
2803 pop_back_splash (msg);
2808 /* Give the new session the default GUI state, if such things exist */
2811 n = Config->instant_xml (X_("Editor"));
2813 new_session->add_instant_xml (*n, false);
2815 n = Config->instant_xml (X_("Mixer"));
2817 new_session->add_instant_xml (*n, false);
2820 /* Put the playhead at 0 and scroll fully left */
2821 n = new_session->instant_xml (X_("Editor"));
2823 n->add_property (X_("playhead"), X_("0"));
2824 n->add_property (X_("left-frame"), X_("0"));
2827 set_session (new_session);
2829 session_loaded = true;
2831 new_session->save_state(new_session->name());
2837 ARDOUR_UI::launch_chat ()
2840 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
2842 open_uri("http://webchat.freenode.net/?channels=ardour");
2847 ARDOUR_UI::show_about ()
2851 about->signal_response().connect(sigc::mem_fun (*this, &ARDOUR_UI::about_signal_response) );
2854 about->set_transient_for(*editor);
2859 ARDOUR_UI::launch_manual ()
2861 PBD::open_uri("http://ardour.org/flossmanual");
2865 ARDOUR_UI::launch_reference ()
2867 PBD::open_uri("http://ardour.org/refmanual");
2871 ARDOUR_UI::hide_about ()
2874 about->get_window()->set_cursor ();
2880 ARDOUR_UI::about_signal_response (int /*response*/)
2886 ARDOUR_UI::show_splash ()
2890 splash = new Splash;
2892 cerr << "Splash could not be created\n";
2898 splash->pop_front ();
2899 splash->queue_draw ();
2900 splash->get_window()->process_updates (true);
2905 ARDOUR_UI::hide_splash ()
2913 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title,
2914 const string& plural_msg, const string& singular_msg)
2918 removed = rep.paths.size();
2921 MessageDialog msgd (*editor,
2922 _("No files were ready for clean-up"),
2926 msgd.set_title (_("Clean-up"));
2927 msgd.set_secondary_text (_("If this seems suprising, \n\
2928 check for any existing snapshots.\n\
2929 These may still include regions that\n\
2930 require some unused files to continue to exist."));
2936 ArdourDialog results (_("Clean-up"), true, false);
2938 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
2939 CleanupResultsModelColumns() {
2943 Gtk::TreeModelColumn<std::string> visible_name;
2944 Gtk::TreeModelColumn<std::string> fullpath;
2948 CleanupResultsModelColumns results_columns;
2949 Glib::RefPtr<Gtk::ListStore> results_model;
2950 Gtk::TreeView results_display;
2952 results_model = ListStore::create (results_columns);
2953 results_display.set_model (results_model);
2954 results_display.append_column (list_title, results_columns.visible_name);
2956 results_display.set_name ("CleanupResultsList");
2957 results_display.set_headers_visible (true);
2958 results_display.set_headers_clickable (false);
2959 results_display.set_reorderable (false);
2961 Gtk::ScrolledWindow list_scroller;
2964 Gtk::HBox dhbox; // the hbox for the image and text
2965 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
2966 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
2968 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
2970 const string dead_directory = _session->session_directory().dead_path().to_string();
2973 %1 - number of files removed
2974 %2 - location of "dead"
2975 %3 - size of files affected
2976 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
2979 const char* bprefix;
2980 double space_adjusted = 0;
2982 if (rep.space < 1000) {
2984 space_adjusted = rep.space;
2985 } else if (rep.space < 1000000) {
2986 bprefix = X_("kilo");
2987 space_adjusted = truncf((float)rep.space / 1000.0);
2988 } else if (rep.space < 1000000 * 1000) {
2989 bprefix = X_("mega");
2990 space_adjusted = truncf((float)rep.space / (1000.0 * 1000.0));
2992 bprefix = X_("giga");
2993 space_adjusted = truncf((float)rep.space / (1000.0 * 1000 * 1000.0));
2997 txt.set_text (string_compose (plural_msg, removed, dead_directory, space_adjusted, bprefix, PROGRAM_NAME));
2999 txt.set_text (string_compose (singular_msg, removed, dead_directory, space_adjusted, bprefix, PROGRAM_NAME));
3002 dhbox.pack_start (*dimage, true, false, 5);
3003 dhbox.pack_start (txt, true, false, 5);
3005 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
3006 TreeModel::Row row = *(results_model->append());
3007 row[results_columns.visible_name] = *i;
3008 row[results_columns.fullpath] = *i;
3011 list_scroller.add (results_display);
3012 list_scroller.set_size_request (-1, 150);
3013 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
3015 dvbox.pack_start (dhbox, true, false, 5);
3016 dvbox.pack_start (list_scroller, true, false, 5);
3017 ddhbox.pack_start (dvbox, true, false, 5);
3019 results.get_vbox()->pack_start (ddhbox, true, false, 5);
3020 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
3021 results.set_default_response (RESPONSE_CLOSE);
3022 results.set_position (Gtk::WIN_POS_MOUSE);
3024 results_display.show();
3025 list_scroller.show();
3032 //results.get_vbox()->show();
3033 results.set_resizable (false);
3040 ARDOUR_UI::cleanup ()
3042 if (_session == 0) {
3043 /* shouldn't happen: menu item is insensitive */
3048 MessageDialog checker (_("Are you sure you want to clean-up?"),
3050 Gtk::MESSAGE_QUESTION,
3053 checker.set_title (_("Clean-up"));
3055 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
3056 ALL undo/redo information will be lost if you clean-up.\n\
3057 Clean-up will move all unused files to a \"dead\" location."));
3059 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3060 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
3061 checker.set_default_response (RESPONSE_CANCEL);
3063 checker.set_name (_("CleanupDialog"));
3064 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3065 checker.set_position (Gtk::WIN_POS_MOUSE);
3067 switch (checker.run()) {
3068 case RESPONSE_ACCEPT:
3074 ARDOUR::CleanupReport rep;
3076 editor->prepare_for_cleanup ();
3078 /* do not allow flush until a session is reloaded */
3080 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3082 act->set_sensitive (false);
3085 if (_session->cleanup_sources (rep)) {
3086 editor->finish_cleanup ();
3090 editor->finish_cleanup ();
3093 display_cleanup_results (rep,
3096 The following %1 files were not in use and \n\
3097 have been moved to:\n\n\
3099 After a restart of %5,\n\n\
3100 Session -> Clean-up -> Flush Wastebasket\n\n\
3101 will release an additional\n\
3102 %3 %4bytes of disk space.\n"),
3104 The following file was not in use and \n\
3105 has been moved to:\n \
3107 After a restart of %5,\n\n\
3108 Session -> Clean-up -> Flush Wastebasket\n\n\
3109 will release an additional\n\
3110 %3 %4bytes of disk space.\n"
3116 ARDOUR_UI::flush_trash ()
3118 if (_session == 0) {
3119 /* shouldn't happen: menu item is insensitive */
3123 ARDOUR::CleanupReport rep;
3125 if (_session->cleanup_trash_sources (rep)) {
3129 display_cleanup_results (rep,
3131 _("The following %1 files were deleted from\n\
3133 releasing %3 %4bytes of disk space"),
3134 _("The following file was deleted from\n\
3136 releasing %3 %4bytes of disk space"));
3140 ARDOUR_UI::add_route (Gtk::Window* float_window)
3148 if (add_route_dialog == 0) {
3149 add_route_dialog = new AddRouteDialog (_session);
3150 add_route_dialog->set_position (WIN_POS_MOUSE);
3152 add_route_dialog->set_transient_for (*float_window);
3156 if (add_route_dialog->is_visible()) {
3157 /* we're already doing this */
3161 ResponseType r = (ResponseType) add_route_dialog->run ();
3163 add_route_dialog->hide();
3166 case RESPONSE_ACCEPT:
3173 if ((count = add_route_dialog->count()) <= 0) {
3177 string template_path = add_route_dialog->track_template();
3179 if (!template_path.empty()) {
3180 _session->new_route_from_template (count, template_path);
3184 uint32_t input_chan = add_route_dialog->channels ();
3185 uint32_t output_chan;
3186 string name_template = add_route_dialog->name_template ();
3187 PluginInfoPtr instrument = add_route_dialog->requested_instrument ();
3188 RouteGroup* route_group = add_route_dialog->route_group ();
3190 AutoConnectOption oac = Config->get_output_auto_connect();
3192 if (oac & AutoConnectMaster) {
3193 output_chan = (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan);
3195 output_chan = input_chan;
3198 /* XXX do something with name template */
3200 if (add_route_dialog->midi_tracks_wanted()) {
3201 session_add_midi_track (route_group, count, name_template, instrument);
3202 } else if (add_route_dialog->audio_tracks_wanted()) {
3203 session_add_audio_track (input_chan, output_chan, add_route_dialog->mode(), route_group, count, name_template);
3205 session_add_audio_bus (input_chan, output_chan, route_group, count, name_template);
3210 ARDOUR_UI::mixer_settings () const
3215 node = _session->instant_xml(X_("Mixer"));
3217 node = Config->instant_xml(X_("Mixer"));
3221 node = new XMLNode (X_("Mixer"));
3228 ARDOUR_UI::editor_settings () const
3233 node = _session->instant_xml(X_("Editor"));
3235 node = Config->instant_xml(X_("Editor"));
3239 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
3240 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
3245 node = new XMLNode (X_("Editor"));
3252 ARDOUR_UI::keyboard_settings () const
3256 node = Config->extra_xml(X_("Keyboard"));
3259 node = new XMLNode (X_("Keyboard"));
3266 ARDOUR_UI::create_xrun_marker (framepos_t where)
3268 editor->mouse_add_new_marker (where, false, true);
3272 ARDOUR_UI::halt_on_xrun_message ()
3274 MessageDialog msg (*editor,
3275 _("Recording was stopped because your system could not keep up."));
3280 ARDOUR_UI::xrun_handler (framepos_t where)
3286 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
3288 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
3289 create_xrun_marker(where);
3292 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
3293 halt_on_xrun_message ();
3298 ARDOUR_UI::disk_overrun_handler ()
3300 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
3302 if (!have_disk_speed_dialog_displayed) {
3303 have_disk_speed_dialog_displayed = true;
3304 MessageDialog* msg = new MessageDialog (*editor, string_compose (_("\
3305 The disk system on your computer\n\
3306 was not able to keep up with %1.\n\
3308 Specifically, it failed to write data to disk\n\
3309 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
3310 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3316 ARDOUR_UI::disk_underrun_handler ()
3318 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
3320 if (!have_disk_speed_dialog_displayed) {
3321 have_disk_speed_dialog_displayed = true;
3322 MessageDialog* msg = new MessageDialog (
3323 *editor, string_compose (_("The disk system on your computer\n\
3324 was not able to keep up with %1.\n\
3326 Specifically, it failed to read data from disk\n\
3327 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
3328 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3334 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
3336 have_disk_speed_dialog_displayed = false;
3341 ARDOUR_UI::session_dialog (std::string msg)
3343 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
3348 d = new MessageDialog (*editor, msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3350 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3359 ARDOUR_UI::pending_state_dialog ()
3361 HBox* hbox = new HBox();
3362 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3363 ArdourDialog dialog (_("Crash Recovery"), true);
3365 This session appears to have been in\n\
3366 middle of recording when ardour or\n\
3367 the computer was shutdown.\n\
3369 Ardour can recover any captured audio for\n\
3370 you, or it can ignore it. Please decide\n\
3371 what you would like to do.\n"));
3372 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3373 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3374 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3375 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3376 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
3377 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
3378 dialog.set_default_response (RESPONSE_ACCEPT);
3379 dialog.set_position (WIN_POS_CENTER);
3384 switch (dialog.run ()) {
3385 case RESPONSE_ACCEPT:
3393 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
3395 HBox* hbox = new HBox();
3396 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3397 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
3398 Label message (string_compose (_("\
3399 This session was created with a sample rate of %1 Hz\n\
3401 The audioengine is currently running at %2 Hz\n"), desired, actual));
3403 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3404 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3405 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3406 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3407 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
3408 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
3409 dialog.set_default_response (RESPONSE_ACCEPT);
3410 dialog.set_position (WIN_POS_CENTER);
3415 switch (dialog.run ()) {
3416 case RESPONSE_ACCEPT:
3425 ARDOUR_UI::disconnect_from_jack ()
3428 if( engine->disconnect_from_jack ()) {
3429 MessageDialog msg (*editor, _("Could not disconnect from JACK"));
3433 update_sample_rate (0);
3438 ARDOUR_UI::reconnect_to_jack ()
3441 if (engine->reconnect_to_jack ()) {
3442 MessageDialog msg (*editor, _("Could not reconnect to JACK"));
3446 update_sample_rate (0);
3451 ARDOUR_UI::use_config ()
3453 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
3455 set_transport_controllable_state (*node);
3460 ARDOUR_UI::update_transport_clocks (framepos_t pos)
3462 if (Config->get_primary_clock_delta_edit_cursor()) {
3463 primary_clock->set (pos, false, editor->get_preferred_edit_position());
3465 primary_clock->set (pos);
3468 if (Config->get_secondary_clock_delta_edit_cursor()) {
3469 secondary_clock->set (pos, false, editor->get_preferred_edit_position());
3471 secondary_clock->set (pos);
3474 if (big_clock_window->get()) {
3475 big_clock->set (pos);
3481 ARDOUR_UI::step_edit_status_change (bool yn)
3483 // XXX should really store pre-step edit status of things
3484 // we make insensitive
3487 rec_button.set_active_state (Gtkmm2ext::ImplicitActive);
3488 rec_button.set_sensitive (false);
3490 rec_button.unset_active_state ();;
3491 rec_button.set_sensitive (true);
3496 ARDOUR_UI::record_state_changed ()
3498 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
3500 if (!_session || !big_clock_window->get()) {
3501 /* why bother - the clock isn't visible */
3505 if (_session->record_status () == Session::Recording && _session->have_rec_enabled_track ()) {
3506 big_clock->set_active (true);
3508 big_clock->set_active (false);
3513 ARDOUR_UI::first_idle ()
3516 _session->allow_auto_play (true);
3520 editor->first_idle();
3523 Keyboard::set_can_save_keybindings (true);
3528 ARDOUR_UI::store_clock_modes ()
3530 XMLNode* node = new XMLNode(X_("ClockModes"));
3532 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
3533 XMLNode* child = new XMLNode (X_("Clock"));
3535 child->add_property (X_("name"), (*x)->name());
3536 child->add_property (X_("mode"), enum_2_string ((*x)->mode()));
3537 child->add_property (X_("on"), ((*x)->off() ? X_("no") : X_("yes")));
3539 node->add_child_nocopy (*child);
3542 _session->add_extra_xml (*node);
3543 _session->set_dirty ();
3546 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
3547 : Controllable (name), ui (u), type(tp)
3553 ARDOUR_UI::TransportControllable::set_value (double val)
3556 /* do nothing: these are radio-style actions */
3560 const char *action = 0;
3564 action = X_("Roll");
3567 action = X_("Stop");
3570 action = X_("Goto Start");
3573 action = X_("Goto End");
3576 action = X_("Loop");
3579 action = X_("Play Selection");
3582 action = X_("Record");
3592 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
3600 ARDOUR_UI::TransportControllable::get_value (void) const
3627 ARDOUR_UI::setup_profile ()
3629 if (gdk_screen_width() < 1200) {
3630 Profile->set_small_screen ();
3634 if (getenv ("ARDOUR_SAE")) {
3635 Profile->set_sae ();
3636 Profile->set_single_package ();
3641 ARDOUR_UI::toggle_translations ()
3643 using namespace Glib;
3645 RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("EnableTranslation"));
3647 RefPtr<ToggleAction> ract = RefPtr<ToggleAction>::cast_dynamic (act);
3650 string i18n_killer = ARDOUR::translation_kill_path();
3652 bool already_enabled = !ARDOUR::translations_are_disabled ();
3654 if (ract->get_active ()) {
3655 /* we don't care about errors */
3656 int fd = ::open (i18n_killer.c_str(), O_RDONLY|O_CREAT, 0644);
3659 /* we don't care about errors */
3660 unlink (i18n_killer.c_str());
3663 if (already_enabled != ract->get_active()) {
3664 MessageDialog win (already_enabled ? _("Translations disabled") : _("Translations enabled"),
3666 Gtk::MESSAGE_WARNING,
3668 win.set_secondary_text (string_compose (_("You must restart %1 for this to take effect."), PROGRAM_NAME));
3669 win.set_position (Gtk::WIN_POS_CENTER);
3677 /** Add a window proxy to our list, so that its state will be saved.
3678 * This call also causes the window to be created and opened if its
3679 * state was saved as `visible'.
3682 ARDOUR_UI::add_window_proxy (WindowProxyBase* p)
3684 _window_proxies.push_back (p);
3688 /** Remove a window proxy from our list. Must be called if a WindowProxy
3689 * is deleted, to prevent hanging pointers.
3692 ARDOUR_UI::remove_window_proxy (WindowProxyBase* p)
3694 _window_proxies.remove (p);
3698 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
3700 MissingFileDialog dialog (s, str, type);
3705 int result = dialog.run ();
3712 return 1; // quit entire session load
3715 result = dialog.get_action ();
3721 ARDOUR_UI::ambiguous_file (std::string file, std::string /*path*/, std::vector<std::string> hits)
3723 AmbiguousFileDialog dialog (file, hits);
3729 return dialog.get_which ();
3732 /** Allocate our thread-local buffers */
3734 ARDOUR_UI::get_process_buffers ()
3736 _process_thread->get_buffers ();
3739 /** Drop our thread-local buffers */
3741 ARDOUR_UI::drop_process_buffers ()
3743 _process_thread->drop_buffers ();
3747 ARDOUR_UI::feedback_detected ()
3749 _feedback_exists = true;
3753 ARDOUR_UI::successful_graph_sort ()
3755 _feedback_exists = false;
3759 ARDOUR_UI::midi_panic ()
3762 _session->midi_panic();