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/session_directory.h"
66 #include "ardour/session_route.h"
67 #include "ardour/session_state_utils.h"
68 #include "ardour/session_utils.h"
69 #include "ardour/port.h"
70 #include "ardour/audioengine.h"
71 #include "ardour/playlist.h"
72 #include "ardour/utils.h"
73 #include "ardour/audio_diskstream.h"
74 #include "ardour/audiofilesource.h"
75 #include "ardour/recent_sessions.h"
76 #include "ardour/port.h"
77 #include "ardour/audio_track.h"
78 #include "ardour/midi_track.h"
79 #include "ardour/filesystem_paths.h"
80 #include "ardour/filename_extensions.h"
81 #include "ardour/process_thread.h"
83 typedef uint64_t microseconds_t;
87 #include "add_route_dialog.h"
88 #include "ambiguous_file_dialog.h"
89 #include "ardour_ui.h"
90 #include "audio_clock.h"
91 #include "bundle_manager.h"
92 #include "engine_dialog.h"
93 #include "gain_meter.h"
94 #include "global_port_matrix.h"
95 #include "gui_object.h"
96 #include "gui_thread.h"
98 #include "location_ui.h"
99 #include "missing_file_dialog.h"
100 #include "missing_plugin_dialog.h"
101 #include "mixer_ui.h"
103 #include "processor_box.h"
104 #include "prompter.h"
105 #include "public_editor.h"
106 #include "route_time_axis.h"
107 #include "session_metadata_dialog.h"
108 #include "shuttle_control.h"
109 #include "speaker_dialog.h"
112 #include "theme_manager.h"
113 #include "time_axis_view_item.h"
115 #include "window_proxy.h"
119 using namespace ARDOUR;
121 using namespace Gtkmm2ext;
124 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
125 UIConfiguration *ARDOUR_UI::ui_config = 0;
127 sigc::signal<void,bool> ARDOUR_UI::Blink;
128 sigc::signal<void> ARDOUR_UI::RapidScreenUpdate;
129 sigc::signal<void> ARDOUR_UI::SuperRapidScreenUpdate;
130 sigc::signal<void, framepos_t, bool, framepos_t> ARDOUR_UI::Clock;
132 bool could_be_a_valid_path (const string& path);
134 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[])
136 : Gtkmm2ext::UI (PROGRAM_NAME, argcp, argvp)
138 , gui_object_state (new GUIObjectState)
139 , primary_clock (new AudioClock (X_("primary"), false, X_("TransportClockDisplay"), true, true, false, true))
140 , secondary_clock (new AudioClock (X_("secondary"), false, X_("SecondaryClockDisplay"), true, true, false, true))
144 , big_clock (new AudioClock (X_("bigclock"), false, "BigClockNonRecording", true, true, false, false))
148 , roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll))
149 , stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop))
150 , goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart))
151 , goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd))
152 , auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop))
153 , play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection))
154 , rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable))
156 , auto_return_button (ArdourButton::led_default_elements)
157 , auto_play_button (ArdourButton::led_default_elements)
158 , auto_input_button (ArdourButton::led_default_elements)
160 , auditioning_alert_button (_("audition"))
161 , solo_alert_button (_("solo"))
162 , feedback_alert_button (_("feedback"))
164 , error_log_button (_("Errors"))
166 , _status_bar_visibility (X_("status-bar"))
167 , _feedback_exists (false)
170 using namespace Gtk::Menu_Helpers;
176 // _auto_display_errors = false;
178 * This was commented out as it wasn't defined
179 * in A3 IIRC. If this is not needed it should
180 * be completely removed.
188 if (theArdourUI == 0) {
192 ui_config = new UIConfiguration();
193 theme_manager = new ThemeManager();
201 _session_is_new = false;
202 big_clock_window = 0;
203 big_clock_height = 0;
204 big_clock_resize_in_progress = false;
205 session_selector_window = 0;
206 last_key_press_time = 0;
207 _will_create_new_session_automatically = false;
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_controllable (roll_controllable);
224 stop_button.set_controllable (stop_controllable);
225 goto_start_button.set_controllable (goto_start_controllable);
226 goto_end_button.set_controllable (goto_end_controllable);
227 auto_loop_button.set_controllable (auto_loop_controllable);
228 play_selection_button.set_controllable (play_selection_controllable);
229 rec_button.set_controllable (rec_controllable);
231 roll_button.set_name ("transport button");
232 stop_button.set_name ("transport button");
233 goto_start_button.set_name ("transport button");
234 goto_end_button.set_name ("transport button");
235 auto_loop_button.set_name ("transport button");
236 play_selection_button.set_name ("transport button");
237 rec_button.set_name ("transport recenable button");
238 join_play_range_button.set_name ("transport button");
239 midi_panic_button.set_name ("transport button");
241 goto_start_button.set_tweaks (ArdourButton::ShowClick);
242 goto_end_button.set_tweaks (ArdourButton::ShowClick);
243 midi_panic_button.set_tweaks (ArdourButton::ShowClick);
245 last_configure_time= 0;
248 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
249 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
251 /* handle dialog requests */
253 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
255 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
257 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
259 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
261 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
263 /* handle requests to quit (coming from JACK session) */
265 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::finish, this), gui_context ());
267 /* tell the user about feedback */
269 ARDOUR::Session::FeedbackDetected.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::feedback_detected, this), gui_context ());
270 ARDOUR::Session::SuccessfulGraphSort.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::successful_graph_sort, this), gui_context ());
272 /* handle requests to deal with missing files */
274 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
276 /* and ambiguous files */
278 ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2, _3));
280 /* lets get this party started */
283 if (ARDOUR::init (ARDOUR_COMMAND_LINE::use_vst, ARDOUR_COMMAND_LINE::try_hw_optimization)) {
284 throw failed_constructor ();
287 setup_gtk_ardour_enums ();
290 GainMeter::setup_slider_pix ();
291 RouteTimeAxisView::setup_slider_pix ();
292 SendProcessorEntry::setup_slider_pix ();
293 SessionEvent::create_per_thread_pool ("GUI", 512);
295 } catch (failed_constructor& err) {
296 error << string_compose (_("could not initialize %1."), PROGRAM_NAME) << endmsg;
301 /* we like keyboards */
303 keyboard = new ArdourKeyboard(*this);
305 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
307 keyboard->set_state (*node, Stateful::loading_state_version);
310 /* we don't like certain modifiers */
311 Bindings::set_ignored_state (GDK_LOCK_MASK|GDK_MOD2_MASK|GDK_MOD3_MASK);
315 TimeAxisViewItem::set_constant_heights ();
317 /* The following must happen after ARDOUR::init() so that Config is set up */
319 location_ui = new ActionWindowProxy<LocationUIWindow> (X_("locations"), Config->extra_xml (X_("UI")), X_("ToggleLocations"));
320 big_clock_window = new ActionWindowProxy<Gtk::Window> (X_("bigclock"), Config->extra_xml (X_("UI")), X_("ToggleBigClock"));
321 speaker_config_window = new ActionWindowProxy<SpeakerDialog> (X_("speakerconf"), Config->extra_xml (X_("UI")), X_("toggle-speaker-config"));
323 for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) {
324 _global_port_matrix[*i] = new ActionWindowProxy<GlobalPortMatrixWindow> (
325 string_compose ("GlobalPortMatrix-%1", (*i).to_string()),
326 Config->extra_xml (X_("UI")),
327 string_compose ("toggle-%1-connection-manager", (*i).to_string())
333 SpeakerDialog* s = new SpeakerDialog ();
334 s->signal_unmap().connect (sigc::bind (sigc::ptr_fun (&ActionManager::uncheck_toggleaction), X_("<Actions>/Common/toggle-speaker-config")));
335 speaker_config_window->set (s);
337 starting.connect (sigc::mem_fun(*this, &ARDOUR_UI::startup));
338 stopping.connect (sigc::mem_fun(*this, &ARDOUR_UI::shutdown));
340 _process_thread = new ProcessThread ();
341 _process_thread->init ();
344 /** @return true if a session was chosen and `apply' clicked, otherwise false if `cancel' was clicked */
346 ARDOUR_UI::run_startup (bool should_be_new, string load_template)
349 _startup = new ArdourStartup ();
351 XMLNode* audio_setup = Config->extra_xml ("AudioSetup");
353 if (audio_setup && _startup->engine_control()) {
354 _startup->engine_control()->set_state (*audio_setup);
357 _startup->set_new_only (should_be_new);
358 if (!load_template.empty()) {
359 _startup->set_load_template( load_template );
361 _startup->present ();
367 switch (_startup->response()) {
376 ARDOUR_UI::create_engine ()
378 // this gets called every time by new_session()
384 loading_message (_("Starting audio engine"));
387 engine = new ARDOUR::AudioEngine (ARDOUR_COMMAND_LINE::jack_client_name, ARDOUR_COMMAND_LINE::jack_session_uuid);
394 engine->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
395 engine->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
396 engine->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
398 engine->Halted.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
400 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
408 ARDOUR_UI::post_engine ()
410 /* Things to be done once we create the AudioEngine
413 ARDOUR::init_post_engine ();
415 ActionManager::init ();
418 if (setup_windows ()) {
419 throw failed_constructor ();
422 /* Do this after setup_windows (), as that's when the _status_bar_visibility is created */
423 XMLNode* n = Config->extra_xml (X_("UI"));
425 _status_bar_visibility.set_state (*n);
428 check_memory_locking();
430 /* this is the first point at which all the keybindings are available */
432 if (ARDOUR_COMMAND_LINE::show_key_actions) {
433 vector<string> names;
434 vector<string> paths;
435 vector<string> tooltips;
437 vector<AccelKey> bindings;
439 ActionManager::get_all_actions (names, paths, tooltips, keys, bindings);
441 vector<string>::iterator n;
442 vector<string>::iterator k;
443 for (n = names.begin(), k = keys.begin(); n != names.end(); ++n, ++k) {
444 cerr << "Action: " << (*n) << " bound to " << (*k) << endl;
450 blink_timeout_tag = -1;
452 /* this being a GUI and all, we want peakfiles */
454 AudioFileSource::set_build_peakfiles (true);
455 AudioFileSource::set_build_missing_peakfiles (true);
457 /* set default clock modes */
459 if (Profile->get_sae()) {
460 primary_clock->set_mode (AudioClock::BBT);
461 secondary_clock->set_mode (AudioClock::MinSec);
463 primary_clock->set_mode (AudioClock::Timecode);
464 secondary_clock->set_mode (AudioClock::BBT);
467 /* start the time-of-day-clock */
470 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
471 update_wall_clock ();
472 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 60000);
475 update_disk_space ();
477 update_sample_rate (engine->frame_rate());
479 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
480 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
481 Config->map_parameters (pc);
483 /* now start and maybe save state */
485 if (do_engine_start () == 0) {
486 if (_session && _session_is_new) {
487 /* we need to retain initial visual
488 settings for a new session
490 _session->save_state ("");
495 ARDOUR_UI::~ARDOUR_UI ()
500 delete add_route_dialog;
504 ARDOUR_UI::pop_back_splash ()
506 if (Splash::instance()) {
507 // Splash::instance()->pop_back();
508 Splash::instance()->hide ();
513 ARDOUR_UI::configure_timeout ()
515 if (last_configure_time == 0) {
516 /* no configure events yet */
520 /* force a gap of 0.5 seconds since the last configure event
523 if (get_microseconds() - last_configure_time < 500000) {
526 have_configure_timeout = false;
527 cerr << "config event-driven save\n";
528 save_ardour_state ();
534 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
536 if (have_configure_timeout) {
537 last_configure_time = get_microseconds();
539 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
540 have_configure_timeout = true;
547 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
549 const XMLProperty* prop;
551 if ((prop = node.property ("roll")) != 0) {
552 roll_controllable->set_id (prop->value());
554 if ((prop = node.property ("stop")) != 0) {
555 stop_controllable->set_id (prop->value());
557 if ((prop = node.property ("goto-start")) != 0) {
558 goto_start_controllable->set_id (prop->value());
560 if ((prop = node.property ("goto-end")) != 0) {
561 goto_end_controllable->set_id (prop->value());
563 if ((prop = node.property ("auto-loop")) != 0) {
564 auto_loop_controllable->set_id (prop->value());
566 if ((prop = node.property ("play-selection")) != 0) {
567 play_selection_controllable->set_id (prop->value());
569 if ((prop = node.property ("rec")) != 0) {
570 rec_controllable->set_id (prop->value());
572 if ((prop = node.property ("shuttle")) != 0) {
573 shuttle_box->controllable()->set_id (prop->value());
579 ARDOUR_UI::get_transport_controllable_state ()
581 XMLNode* node = new XMLNode(X_("TransportControllables"));
584 roll_controllable->id().print (buf, sizeof (buf));
585 node->add_property (X_("roll"), buf);
586 stop_controllable->id().print (buf, sizeof (buf));
587 node->add_property (X_("stop"), buf);
588 goto_start_controllable->id().print (buf, sizeof (buf));
589 node->add_property (X_("goto_start"), buf);
590 goto_end_controllable->id().print (buf, sizeof (buf));
591 node->add_property (X_("goto_end"), buf);
592 auto_loop_controllable->id().print (buf, sizeof (buf));
593 node->add_property (X_("auto_loop"), buf);
594 play_selection_controllable->id().print (buf, sizeof (buf));
595 node->add_property (X_("play_selection"), buf);
596 rec_controllable->id().print (buf, sizeof (buf));
597 node->add_property (X_("rec"), buf);
598 shuttle_box->controllable()->id().print (buf, sizeof (buf));
599 node->add_property (X_("shuttle"), buf);
606 ARDOUR_UI::autosave_session ()
608 if (g_main_depth() > 1) {
609 /* inside a recursive main loop,
610 give up because we may not be able to
616 if (!Config->get_periodic_safety_backups()) {
621 _session->maybe_write_autosave();
628 ARDOUR_UI::update_autosave ()
630 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_autosave)
632 if (_session && _session->dirty()) {
633 if (_autosave_connection.connected()) {
634 _autosave_connection.disconnect();
637 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
638 Config->get_periodic_safety_backup_interval() * 1000);
641 if (_autosave_connection.connected()) {
642 _autosave_connection.disconnect();
648 ARDOUR_UI::backend_audio_error (bool we_set_params, Gtk::Window* toplevel)
652 title = string_compose (_("%1 could not start JACK"), PROGRAM_NAME);
654 title = string_compose (_("%1 could not connect to JACK."), PROGRAM_NAME);
657 MessageDialog win (title,
663 win.set_secondary_text(_("There are several possible reasons:\n\
665 1) You requested audio parameters that are not supported..\n\
666 2) JACK is running as another user.\n\
668 Please consider the possibilities, and perhaps try different parameters."));
670 win.set_secondary_text(_("There are several possible reasons:\n\
672 1) JACK is not running.\n\
673 2) JACK is running as another user, perhaps root.\n\
674 3) There is already another client called \"ardour\".\n\
676 Please consider the possibilities, and perhaps (re)start JACK."));
680 win.set_transient_for (*toplevel);
684 win.add_button (Stock::OK, RESPONSE_CLOSE);
686 win.add_button (Stock::QUIT, RESPONSE_CLOSE);
689 win.set_default_response (RESPONSE_CLOSE);
692 win.set_position (Gtk::WIN_POS_CENTER);
695 /* we just don't care about the result, but we want to block */
701 ARDOUR_UI::startup ()
703 Application* app = Application::instance ();
705 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
706 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::idle_load));
709 call_the_mothership (VERSIONSTRING);
714 if (get_session_parameters (true, ARDOUR_COMMAND_LINE::new_session, ARDOUR_COMMAND_LINE::load_template)) {
720 goto_editor_window ();
722 /* Add the window proxies here; their addition may cause windows to be opened, and we want them
723 to be opened on top of the editor window that goto_editor_window() just opened.
725 add_window_proxy (location_ui);
726 add_window_proxy (big_clock_window);
727 for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) {
728 add_window_proxy (_global_port_matrix[*i]);
731 /* We have to do this here since goto_editor_window() ends up calling show_all() on the
732 * editor window, and we may want stuff to be hidden.
734 _status_bar_visibility.update ();
736 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
740 ARDOUR_UI::no_memory_warning ()
742 XMLNode node (X_("no-memory-warning"));
743 Config->add_instant_xml (node);
747 ARDOUR_UI::check_memory_locking ()
750 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
754 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
756 if (engine->is_realtime() && memory_warning_node == 0) {
758 struct rlimit limits;
760 long pages, page_size;
762 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0) {
765 ram = (int64_t) pages * (int64_t) page_size;
768 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
772 if (limits.rlim_cur != RLIM_INFINITY) {
774 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
778 _("WARNING: Your system has a limit for maximum amount of locked memory. "
779 "This might cause %1 to run out of memory before your system "
780 "runs out of memory. \n\n"
781 "You can view the memory limit with 'ulimit -l', "
782 "and it is normally controlled by /etc/security/limits.conf"),
783 PROGRAM_NAME).c_str());
785 VBox* vbox = msg.get_vbox();
787 CheckButton cb (_("Do not show this window again"));
789 cb.signal_toggled().connect (sigc::mem_fun (*this, &ARDOUR_UI::no_memory_warning));
791 hbox.pack_start (cb, true, false);
792 vbox->pack_start (hbox);
799 editor->ensure_float (msg);
809 ARDOUR_UI::queue_finish ()
811 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
815 ARDOUR_UI::idle_finish ()
818 return false; /* do not call again */
827 if (_session->transport_rolling() && (++tries < 8)) {
828 _session->request_stop (false, true);
832 if (_session->dirty()) {
833 vector<string> actions;
834 actions.push_back (_("Don't quit"));
835 actions.push_back (_("Just quit"));
836 actions.push_back (_("Save and quit"));
837 switch (ask_about_saving_session(actions)) {
842 /* use the default name */
843 if (save_state_canfail ("")) {
844 /* failed - don't quit */
845 MessageDialog msg (*editor,
847 Ardour was unable to save your session.\n\n\
848 If you still wish to quit, please use the\n\n\
849 \"Just quit\" option."));
860 second_connection.disconnect ();
861 point_one_second_connection.disconnect ();
862 point_oh_five_second_connection.disconnect ();
863 point_zero_one_second_connection.disconnect();
866 /* Save state before deleting the session, as that causes some
867 windows to be destroyed before their visible state can be
870 save_ardour_state ();
873 // _session->set_deletion_in_progress ();
874 _session->set_clean ();
875 _session->remove_pending_capture_state ();
880 ArdourDialog::close_all_dialogs ();
886 ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
888 ArdourDialog window (_("Unsaved Session"));
889 Gtk::HBox dhbox; // the hbox for the image and text
890 Gtk::Label prompt_label;
891 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
895 assert (actions.size() >= 3);
897 window.add_button (actions[0], RESPONSE_REJECT);
898 window.add_button (actions[1], RESPONSE_APPLY);
899 window.add_button (actions[2], RESPONSE_ACCEPT);
901 window.set_default_response (RESPONSE_ACCEPT);
903 Gtk::Button noquit_button (msg);
904 noquit_button.set_name ("EditorGTKButton");
908 if (_session->snap_name() == _session->name()) {
909 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?"),
910 _session->snap_name());
912 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?"),
913 _session->snap_name());
916 prompt_label.set_text (prompt);
917 prompt_label.set_name (X_("PrompterLabel"));
918 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
920 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
921 dhbox.set_homogeneous (false);
922 dhbox.pack_start (*dimage, false, false, 5);
923 dhbox.pack_start (prompt_label, true, false, 5);
924 window.get_vbox()->pack_start (dhbox);
926 window.set_name (_("Prompter"));
927 window.set_position (Gtk::WIN_POS_MOUSE);
928 window.set_modal (true);
929 window.set_resizable (false);
935 window.set_keep_above (true);
938 ResponseType r = (ResponseType) window.run();
943 case RESPONSE_ACCEPT: // save and get out of here
945 case RESPONSE_APPLY: // get out of here
955 ARDOUR_UI::every_second ()
958 update_buffer_load ();
959 update_disk_space ();
964 ARDOUR_UI::every_point_one_seconds ()
966 shuttle_box->update_speed_display ();
967 RapidScreenUpdate(); /* EMIT_SIGNAL */
972 ARDOUR_UI::every_point_zero_one_seconds ()
974 // august 2007: actual update frequency: 40Hz, not 100Hz
976 SuperRapidScreenUpdate(); /* EMIT_SIGNAL */
981 ARDOUR_UI::update_sample_rate (framecnt_t)
985 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
987 if (!engine->connected()) {
989 snprintf (buf, sizeof (buf), _("disconnected"));
993 framecnt_t rate = engine->frame_rate();
995 if (fmod (rate, 1000.0) != 0.0) {
996 snprintf (buf, sizeof (buf), _("JACK: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
997 (float) rate/1000.0f,
998 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
1000 snprintf (buf, sizeof (buf), _("JACK: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
1002 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
1006 sample_rate_label.set_markup (buf);
1010 ARDOUR_UI::update_format ()
1013 format_label.set_text ("");
1018 s << "File: <span foreground=\"green\">";
1020 switch (_session->config.get_native_file_header_format ()) {
1046 switch (_session->config.get_native_file_data_format ()) {
1060 format_label.set_markup (s.str ());
1064 ARDOUR_UI::update_cpu_load ()
1068 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::build_menu_bar
1069 should also be changed.
1072 float const c = engine->get_cpu_load ();
1073 snprintf (buf, sizeof (buf), _("DSP: <span foreground=\"%s\">%5.1f%%</span>"), c >= 90 ? X_("red") : X_("green"), c);
1074 cpu_load_label.set_markup (buf);
1078 ARDOUR_UI::update_buffer_load ()
1082 uint32_t const playback = _session ? _session->playback_load () : 100;
1083 uint32_t const capture = _session ? _session->capture_load () : 100;
1085 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::build_menu_bar
1086 should also be changed.
1092 _("Buffers: <span foreground=\"green\">p:</span><span foreground=\"%s\">%" PRIu32 "%%</span> "
1093 "<span foreground=\"green\">c:</span><span foreground=\"%s\">%" PRIu32 "%%</span>"),
1094 playback <= 5 ? X_("red") : X_("green"),
1096 capture <= 5 ? X_("red") : X_("green"),
1100 buffer_load_label.set_markup (buf);
1102 buffer_load_label.set_text ("");
1107 ARDOUR_UI::count_recenabled_streams (Route& route)
1109 Track* track = dynamic_cast<Track*>(&route);
1110 if (track && track->record_enabled()) {
1111 rec_enabled_streams += track->n_inputs().n_total();
1116 ARDOUR_UI::update_disk_space()
1118 if (_session == 0) {
1122 framecnt_t frames = _session->available_capture_duration();
1124 framecnt_t fr = _session->frame_rate();
1126 if (frames == max_framecnt) {
1127 snprintf (buf, sizeof (buf), _("Disk: <span foreground=\"green\">24hrs+</span>"));
1129 rec_enabled_streams = 0;
1130 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams);
1132 if (rec_enabled_streams) {
1133 frames /= rec_enabled_streams;
1140 hrs = frames / (fr * 3600);
1143 snprintf (buf, sizeof (buf), _("Disk: <span foreground=\"green\">>24 hrs</span>"));
1145 frames -= hrs * fr * 3600;
1146 mins = frames / (fr * 60);
1147 frames -= mins * fr * 60;
1150 bool const low = (hrs == 0 && mins <= 30);
1154 _("Disk: <span foreground=\"%s\">%02dh:%02dm:%02ds</span>"),
1155 low ? X_("red") : X_("green"),
1161 disk_space_label.set_markup (buf);
1163 // An attempt to make the disk space label flash red when space has run out.
1165 if (frames < fr * 60 * 5) {
1166 /* disk_space_box.style ("disk_space_label_empty"); */
1168 /* disk_space_box.style ("disk_space_label"); */
1174 ARDOUR_UI::update_wall_clock ()
1181 tm_now = localtime (&now);
1183 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1184 wall_clock_label.set_text (buf);
1190 ARDOUR_UI::session_menu (GdkEventButton */*ev*/)
1192 session_popup_menu->popup (0, 0);
1197 ARDOUR_UI::redisplay_recent_sessions ()
1199 std::vector<sys::path> session_directories;
1200 RecentSessionsSorter cmp;
1202 recent_session_display.set_model (Glib::RefPtr<TreeModel>(0));
1203 recent_session_model->clear ();
1205 ARDOUR::RecentSessions rs;
1206 ARDOUR::read_recent_sessions (rs);
1209 recent_session_display.set_model (recent_session_model);
1213 // sort them alphabetically
1214 sort (rs.begin(), rs.end(), cmp);
1216 for (ARDOUR::RecentSessions::iterator i = rs.begin(); i != rs.end(); ++i) {
1217 session_directories.push_back ((*i).second);
1220 for (vector<sys::path>::const_iterator i = session_directories.begin();
1221 i != session_directories.end(); ++i)
1223 std::vector<sys::path> state_file_paths;
1225 // now get available states for this session
1227 get_state_files_in_directory (*i, state_file_paths);
1229 vector<string*>* states;
1230 vector<const gchar*> item;
1231 string fullpath = (*i).to_string();
1233 /* remove any trailing / */
1235 if (fullpath[fullpath.length()-1] == '/') {
1236 fullpath = fullpath.substr (0, fullpath.length()-1);
1239 /* check whether session still exists */
1240 if (!Glib::file_test(fullpath.c_str(), Glib::FILE_TEST_EXISTS)) {
1241 /* session doesn't exist */
1242 cerr << "skipping non-existent session " << fullpath << endl;
1246 /* now get available states for this session */
1248 if ((states = Session::possible_states (fullpath)) == 0) {
1249 /* no state file? */
1253 std::vector<string> state_file_names(get_file_names_no_extension (state_file_paths));
1255 Gtk::TreeModel::Row row = *(recent_session_model->append());
1257 row[recent_session_columns.visible_name] = Glib::path_get_basename (fullpath);
1258 row[recent_session_columns.fullpath] = fullpath;
1260 if (state_file_names.size() > 1) {
1264 for (std::vector<std::string>::iterator i2 = state_file_names.begin();
1265 i2 != state_file_names.end(); ++i2)
1268 Gtk::TreeModel::Row child_row = *(recent_session_model->append (row.children()));
1270 child_row[recent_session_columns.visible_name] = *i2;
1271 child_row[recent_session_columns.fullpath] = fullpath;
1276 recent_session_display.set_model (recent_session_model);
1280 ARDOUR_UI::build_session_selector ()
1282 session_selector_window = new ArdourDialog (_("Recent Sessions"));
1284 Gtk::ScrolledWindow *scroller = manage (new Gtk::ScrolledWindow);
1286 session_selector_window->add_button (Stock::CANCEL, RESPONSE_CANCEL);
1287 session_selector_window->add_button (Stock::OPEN, RESPONSE_ACCEPT);
1288 session_selector_window->set_default_response (RESPONSE_ACCEPT);
1289 recent_session_model = TreeStore::create (recent_session_columns);
1290 recent_session_display.set_model (recent_session_model);
1291 recent_session_display.append_column (_("Recent Sessions"), recent_session_columns.visible_name);
1292 recent_session_display.set_headers_visible (false);
1293 recent_session_display.get_selection()->set_mode (SELECTION_BROWSE);
1294 recent_session_display.signal_row_activated().connect (sigc::mem_fun (*this, &ARDOUR_UI::recent_session_row_activated));
1296 scroller->add (recent_session_display);
1297 scroller->set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
1299 session_selector_window->set_name ("SessionSelectorWindow");
1300 session_selector_window->set_size_request (200, 400);
1301 session_selector_window->get_vbox()->pack_start (*scroller);
1303 recent_session_display.show();
1305 //session_selector_window->get_vbox()->show();
1309 ARDOUR_UI::recent_session_row_activated (const TreePath& /*path*/, TreeViewColumn* /*col*/)
1311 session_selector_window->response (RESPONSE_ACCEPT);
1315 ARDOUR_UI::open_recent_session ()
1317 bool can_return = (_session != 0);
1319 if (session_selector_window == 0) {
1320 build_session_selector ();
1323 redisplay_recent_sessions ();
1327 session_selector_window->set_position (WIN_POS_MOUSE);
1329 ResponseType r = (ResponseType) session_selector_window->run ();
1332 case RESPONSE_ACCEPT:
1336 session_selector_window->hide();
1343 if (recent_session_display.get_selection()->count_selected_rows() == 0) {
1347 session_selector_window->hide();
1349 Gtk::TreeModel::iterator i = recent_session_display.get_selection()->get_selected();
1351 if (i == recent_session_model->children().end()) {
1355 std::string path = (*i)[recent_session_columns.fullpath];
1356 std::string state = (*i)[recent_session_columns.visible_name];
1358 _session_is_new = false;
1360 if (load_session (path, state) == 0) {
1369 ARDOUR_UI::check_audioengine ()
1372 if (!engine->connected()) {
1373 MessageDialog msg (string_compose (
1374 _("%1 is not connected to JACK\n"
1375 "You cannot open or close sessions in this condition"),
1388 ARDOUR_UI::open_session ()
1390 if (!check_audioengine()) {
1395 /* popup selector window */
1397 if (open_session_selector == 0) {
1399 /* ardour sessions are folders */
1401 open_session_selector = new Gtk::FileChooserDialog (_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1402 open_session_selector->add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1403 open_session_selector->add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1404 open_session_selector->set_default_response(Gtk::RESPONSE_ACCEPT);
1406 FileFilter session_filter;
1407 session_filter.add_pattern ("*.ardour");
1408 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1409 open_session_selector->add_filter (session_filter);
1410 open_session_selector->set_filter (session_filter);
1413 int response = open_session_selector->run();
1414 open_session_selector->hide ();
1417 case RESPONSE_ACCEPT:
1420 open_session_selector->hide();
1424 open_session_selector->hide();
1425 string session_path = open_session_selector->get_filename();
1429 if (session_path.length() > 0) {
1430 if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1431 _session_is_new = isnew;
1432 load_session (path, name);
1439 ARDOUR_UI::session_add_midi_route (bool disk, RouteGroup* route_group, uint32_t how_many, string const & name_template)
1441 list<boost::shared_ptr<MidiTrack> > tracks;
1443 if (_session == 0) {
1444 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1451 tracks = _session->new_midi_track (ARDOUR::Normal, route_group, how_many, name_template);
1453 if (tracks.size() != how_many) {
1454 if (how_many == 1) {
1455 error << _("could not create a new midi track") << endmsg;
1457 error << string_compose (_("could not create %1 new midi tracks"), how_many) << endmsg;
1461 if ((route = _session->new_midi_route ()) == 0) {
1462 error << _("could not create new midi bus") << endmsg;
1468 MessageDialog msg (*editor,
1469 string_compose (_("There are insufficient JACK ports available\n\
1470 to create a new track or bus.\n\
1471 You should save %1, exit and\n\
1472 restart JACK with more ports."), PROGRAM_NAME));
1479 ARDOUR_UI::session_add_audio_route (
1481 int32_t input_channels,
1482 int32_t output_channels,
1483 ARDOUR::TrackMode mode,
1484 RouteGroup* route_group,
1486 string const & name_template
1489 list<boost::shared_ptr<AudioTrack> > tracks;
1492 if (_session == 0) {
1493 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1499 tracks = _session->new_audio_track (input_channels, output_channels, mode, route_group, how_many, name_template);
1501 if (tracks.size() != how_many) {
1502 if (how_many == 1) {
1503 error << _("could not create a new audio track") << endmsg;
1505 error << string_compose (_("could only create %1 of %2 new audio %3"),
1506 tracks.size(), how_many, (track ? _("tracks") : _("busses"))) << endmsg;
1512 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template);
1514 if (routes.size() != how_many) {
1515 if (how_many == 1) {
1516 error << _("could not create a new audio bus") << endmsg;
1518 error << string_compose (_("could not create %1 new audio busses"), how_many) << endmsg;
1525 MessageDialog msg (*editor,
1526 string_compose (_("There are insufficient JACK ports available\n\
1527 to create a new track or bus.\n\
1528 You should save %1, exit and\n\
1529 restart JACK with more ports."), PROGRAM_NAME));
1536 ARDOUR_UI::do_transport_locate (framepos_t new_position, bool with_roll)
1538 framecnt_t _preroll = 0;
1541 // XXX CONFIG_CHANGE FIX - requires AnyTime handling
1542 // _preroll = _session->convert_to_frames_at (new_position, Config->get_preroll());
1544 if (new_position > _preroll) {
1545 new_position -= _preroll;
1550 _session->request_locate (new_position, with_roll);
1555 ARDOUR_UI::transport_goto_start ()
1558 _session->goto_start();
1560 /* force displayed area in editor to start no matter
1561 what "follow playhead" setting is.
1565 editor->center_screen (_session->current_start_frame ());
1571 ARDOUR_UI::transport_goto_zero ()
1574 _session->request_locate (0);
1576 /* force displayed area in editor to start no matter
1577 what "follow playhead" setting is.
1581 editor->reset_x_origin (0);
1587 ARDOUR_UI::transport_goto_wallclock ()
1589 if (_session && editor) {
1596 localtime_r (&now, &tmnow);
1598 frames = tmnow.tm_hour * (60 * 60 * _session->frame_rate());
1599 frames += tmnow.tm_min * (60 * _session->frame_rate());
1600 frames += tmnow.tm_sec * _session->frame_rate();
1602 _session->request_locate (frames, _session->transport_rolling ());
1604 /* force displayed area in editor to start no matter
1605 what "follow playhead" setting is.
1609 editor->center_screen (frames);
1615 ARDOUR_UI::transport_goto_end ()
1618 framepos_t const frame = _session->current_end_frame();
1619 _session->request_locate (frame);
1621 /* force displayed area in editor to start no matter
1622 what "follow playhead" setting is.
1626 editor->center_screen (frame);
1632 ARDOUR_UI::transport_stop ()
1638 if (_session->is_auditioning()) {
1639 _session->cancel_audition ();
1643 _session->request_stop (false, true);
1647 ARDOUR_UI::transport_stop_and_forget_capture ()
1650 _session->request_stop (true, true);
1655 ARDOUR_UI::remove_last_capture()
1658 editor->remove_last_capture();
1663 ARDOUR_UI::transport_record (bool roll)
1667 switch (_session->record_status()) {
1668 case Session::Disabled:
1669 if (_session->ntracks() == 0) {
1670 MessageDialog msg (*editor, _("Please create 1 or more track\nbefore trying to record.\nCheck the Session menu."));
1674 _session->maybe_enable_record ();
1679 case Session::Recording:
1681 _session->request_stop();
1683 _session->disable_record (false, true);
1687 case Session::Enabled:
1688 _session->disable_record (false, true);
1691 //cerr << "ARDOUR_UI::transport_record () called roll = " << roll << " _session->record_status() = " << _session->record_status() << endl;
1695 ARDOUR_UI::transport_roll ()
1701 if (_session->is_auditioning()) {
1706 if (_session->config.get_external_sync()) {
1707 switch (_session->config.get_sync_source()) {
1711 /* transport controlled by the master */
1717 bool rolling = _session->transport_rolling();
1719 if (_session->get_play_loop()) {
1720 /* XXX it is not possible to just leave seamless loop and keep
1721 playing at present (nov 4th 2009)
1723 if (!Config->get_seamless_loop()) {
1724 _session->request_play_loop (false, true);
1726 } else if (_session->get_play_range () && !join_play_range_button.active_state()) {
1727 /* stop playing a range if we currently are */
1728 _session->request_play_range (0, true);
1731 if (join_play_range_button.active_state()) {
1732 _session->request_play_range (&editor->get_selection().time, true);
1736 _session->request_transport_speed (1.0f);
1741 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
1748 if (_session->is_auditioning()) {
1749 _session->cancel_audition ();
1753 if (_session->config.get_external_sync()) {
1754 switch (_session->config.get_sync_source()) {
1758 /* transport controlled by the master */
1763 bool rolling = _session->transport_rolling();
1764 bool affect_transport = true;
1766 if (rolling && roll_out_of_bounded_mode) {
1767 /* drop out of loop/range playback but leave transport rolling */
1768 if (_session->get_play_loop()) {
1769 if (Config->get_seamless_loop()) {
1770 /* the disk buffers contain copies of the loop - we can't
1771 just keep playing, so stop the transport. the user
1772 can restart as they wish.
1774 affect_transport = true;
1776 /* disk buffers are normal, so we can keep playing */
1777 affect_transport = false;
1779 _session->request_play_loop (false, true);
1780 } else if (_session->get_play_range ()) {
1781 affect_transport = false;
1782 _session->request_play_range (0, true);
1786 if (affect_transport) {
1788 _session->request_stop (with_abort, true);
1790 if (join_play_range_button.active_state()) {
1791 _session->request_play_range (&editor->get_selection().time, true);
1794 _session->request_transport_speed (1.0f);
1800 ARDOUR_UI::toggle_session_auto_loop ()
1806 if (_session->get_play_loop()) {
1808 if (_session->transport_rolling()) {
1810 Location * looploc = _session->locations()->auto_loop_location();
1813 _session->request_locate (looploc->start(), true);
1814 _session->request_play_loop (false);
1818 _session->request_play_loop (false);
1822 Location * looploc = _session->locations()->auto_loop_location();
1825 _session->request_play_loop (true);
1831 ARDOUR_UI::transport_play_selection ()
1837 editor->play_selection ();
1841 ARDOUR_UI::transport_rewind (int option)
1843 float current_transport_speed;
1846 current_transport_speed = _session->transport_speed();
1848 if (current_transport_speed >= 0.0f) {
1851 _session->request_transport_speed (-1.0f);
1854 _session->request_transport_speed (-4.0f);
1857 _session->request_transport_speed (-0.5f);
1862 _session->request_transport_speed (current_transport_speed * 1.5f);
1868 ARDOUR_UI::transport_forward (int option)
1870 float current_transport_speed;
1873 current_transport_speed = _session->transport_speed();
1875 if (current_transport_speed <= 0.0f) {
1878 _session->request_transport_speed (1.0f);
1881 _session->request_transport_speed (4.0f);
1884 _session->request_transport_speed (0.5f);
1889 _session->request_transport_speed (current_transport_speed * 1.5f);
1896 ARDOUR_UI::toggle_record_enable (uint32_t rid)
1898 if (_session == 0) {
1902 boost::shared_ptr<Route> r;
1904 if ((r = _session->route_by_remote_id (rid)) != 0) {
1908 if ((t = dynamic_cast<Track*>(r.get())) != 0) {
1909 t->set_record_enabled (!t->record_enabled(), this);
1912 if (_session == 0) {
1918 ARDOUR_UI::map_transport_state ()
1921 auto_loop_button.unset_active_state ();
1922 play_selection_button.unset_active_state ();
1923 roll_button.unset_active_state ();
1924 stop_button.set_active_state (Gtkmm2ext::Active);
1928 shuttle_box->map_transport_state ();
1930 float sp = _session->transport_speed();
1936 if (_session->get_play_range()) {
1938 play_selection_button.set_active_state (Gtkmm2ext::Active);
1939 roll_button.unset_active_state ();
1940 auto_loop_button.unset_active_state ();
1942 } else if (_session->get_play_loop ()) {
1944 auto_loop_button.set_active_state (Gtkmm2ext::Active);
1945 play_selection_button.unset_active_state ();
1946 roll_button.unset_active_state ();
1950 roll_button.set_active_state (Gtkmm2ext::Active);
1951 play_selection_button.unset_active_state ();
1952 auto_loop_button.unset_active_state ();
1955 if (join_play_range_button.active_state()) {
1956 /* light up both roll and play-selection if they are joined */
1957 roll_button.set_active_state (Gtkmm2ext::Active);
1958 play_selection_button.set_active_state (Gtkmm2ext::Active);
1961 stop_button.unset_active_state ();
1965 stop_button.set_active_state (Gtkmm2ext::Active);
1966 roll_button.unset_active_state ();
1967 play_selection_button.unset_active_state ();
1968 auto_loop_button.unset_active_state ();
1969 update_disk_space ();
1974 ARDOUR_UI::engine_stopped ()
1976 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
1977 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1978 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1982 ARDOUR_UI::engine_running ()
1984 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
1985 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, true);
1986 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, false);
1988 Glib::RefPtr<Action> action;
1989 const char* action_name = 0;
1991 switch (engine->frames_per_cycle()) {
1993 action_name = X_("JACKLatency32");
1996 action_name = X_("JACKLatency64");
1999 action_name = X_("JACKLatency128");
2002 action_name = X_("JACKLatency512");
2005 action_name = X_("JACKLatency1024");
2008 action_name = X_("JACKLatency2048");
2011 action_name = X_("JACKLatency4096");
2014 action_name = X_("JACKLatency8192");
2017 /* XXX can we do anything useful ? */
2023 action = ActionManager::get_action (X_("JACK"), action_name);
2026 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (action);
2027 ract->set_active ();
2033 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
2035 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
2036 /* we can't rely on the original string continuing to exist when we are called
2037 again in the GUI thread, so make a copy and note that we need to
2040 char *copy = strdup (reason);
2041 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
2045 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
2046 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
2048 update_sample_rate (0);
2052 /* if the reason is a non-empty string, it means that the backend was shutdown
2053 rather than just Ardour.
2056 if (strlen (reason)) {
2057 msgstr = string_compose (_("The audio backend (JACK) was shutdown because:\n\n%1"), reason);
2059 msgstr = string_compose (_("\
2060 JACK has either been shutdown or it\n\
2061 disconnected %1 because %1\n\
2062 was not fast enough. Try to restart\n\
2063 JACK, reconnect and save the session."), PROGRAM_NAME);
2066 MessageDialog msg (*editor, msgstr);
2071 free ((char*) reason);
2076 ARDOUR_UI::do_engine_start ()
2084 error << _("Unable to start the session running")
2094 ARDOUR_UI::setup_theme ()
2096 theme_manager->setup_theme();
2100 ARDOUR_UI::update_clocks ()
2102 if (!editor || !editor->dragging_playhead()) {
2103 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position()); /* EMIT_SIGNAL */
2108 ARDOUR_UI::start_clocking ()
2110 clock_signal_connection = RapidScreenUpdate.connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2114 ARDOUR_UI::stop_clocking ()
2116 clock_signal_connection.disconnect ();
2120 ARDOUR_UI::toggle_clocking ()
2123 if (clock_button.get_active()) {
2132 ARDOUR_UI::_blink (void *arg)
2135 ((ARDOUR_UI *) arg)->blink ();
2142 Blink (blink_on = !blink_on); /* EMIT_SIGNAL */
2146 ARDOUR_UI::start_blinking ()
2148 /* Start the blink signal. Everybody with a blinking widget
2149 uses Blink to drive the widget's state.
2152 if (blink_timeout_tag < 0) {
2154 blink_timeout_tag = g_timeout_add (240, _blink, this);
2159 ARDOUR_UI::stop_blinking ()
2161 if (blink_timeout_tag >= 0) {
2162 g_source_remove (blink_timeout_tag);
2163 blink_timeout_tag = -1;
2168 /** Ask the user for the name of a new shapshot and then take it.
2172 ARDOUR_UI::snapshot_session (bool switch_to_it)
2174 ArdourPrompter prompter (true);
2177 prompter.set_name ("Prompter");
2178 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2179 prompter.set_title (_("Take Snapshot"));
2180 prompter.set_prompt (_("Name of new snapshot"));
2182 if (!switch_to_it) {
2185 struct tm local_time;
2188 localtime_r (&n, &local_time);
2189 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2190 prompter.set_initial_text (timebuf);
2194 switch (prompter.run()) {
2195 case RESPONSE_ACCEPT:
2197 prompter.get_result (snapname);
2199 bool do_save = (snapname.length() != 0);
2202 if (snapname.find ('/') != string::npos) {
2203 MessageDialog msg (_("To ensure compatibility with various systems\n"
2204 "snapshot names may not contain a '/' character"));
2208 if (snapname.find ('\\') != string::npos) {
2209 MessageDialog msg (_("To ensure compatibility with various systems\n"
2210 "snapshot names may not contain a '\\' character"));
2214 if (snapname.find (':') != string::npos) {
2215 MessageDialog msg (_("To ensure compatibility with various systems\n"
2216 "snapshot names may not contain a ':' character"));
2222 vector<sys::path> p;
2223 get_state_files_in_directory (_session->session_directory().root_path(), p);
2224 vector<string> n = get_file_names_no_extension (p);
2225 if (find (n.begin(), n.end(), snapname) != n.end()) {
2227 ArdourDialog confirm (_("Confirm Snapshot Overwrite"), true);
2228 Label m (_("A snapshot already exists with that name. Do you want to overwrite it?"));
2229 confirm.get_vbox()->pack_start (m, true, true);
2230 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2231 confirm.add_button (_("Overwrite"), Gtk::RESPONSE_ACCEPT);
2232 confirm.show_all ();
2233 switch (confirm.run()) {
2234 case RESPONSE_CANCEL:
2240 save_state (snapname, switch_to_it);
2250 /** Ask the user for the name of a new shapshot and then take it.
2254 ARDOUR_UI::rename_session ()
2260 ArdourPrompter prompter (true);
2263 prompter.set_name ("Prompter");
2264 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2265 prompter.set_title (_("Rename Session"));
2266 prompter.set_prompt (_("New session name"));
2269 switch (prompter.run()) {
2270 case RESPONSE_ACCEPT:
2272 prompter.get_result (name);
2274 bool do_rename = (name.length() != 0);
2277 if (name.find ('/') != string::npos) {
2278 MessageDialog msg (_("To ensure compatibility with various systems\n"
2279 "session names may not contain a '/' character"));
2283 if (name.find ('\\') != string::npos) {
2284 MessageDialog msg (_("To ensure compatibility with various systems\n"
2285 "session names may not contain a '\\' character"));
2290 switch (_session->rename (name)) {
2292 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
2293 msg.set_position (WIN_POS_MOUSE);
2301 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
2302 msg.set_position (WIN_POS_MOUSE);
2318 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2320 XMLNode* node = new XMLNode (X_("UI"));
2322 for (list<WindowProxyBase*>::iterator i = _window_proxies.begin(); i != _window_proxies.end(); ++i) {
2323 if (!(*i)->rc_configured()) {
2324 node->add_child_nocopy (*((*i)->get_state ()));
2328 node->add_child_nocopy (gui_object_state->get_state());
2330 _session->add_extra_xml (*node);
2332 save_state_canfail (name, switch_to_it);
2336 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2341 if (name.length() == 0) {
2342 name = _session->snap_name();
2345 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2350 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2355 ARDOUR_UI::primary_clock_value_changed ()
2358 _session->request_locate (primary_clock->current_time ());
2363 ARDOUR_UI::big_clock_value_changed ()
2366 _session->request_locate (big_clock->current_time ());
2371 ARDOUR_UI::secondary_clock_value_changed ()
2374 _session->request_locate (secondary_clock->current_time ());
2379 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2381 if (_session == 0) {
2385 if (_session->step_editing()) {
2389 Session::RecordState const r = _session->record_status ();
2390 bool const h = _session->have_rec_enabled_track ();
2392 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2394 rec_button.set_active_state (Active);
2396 rec_button.set_active_state (Mid);
2398 } else if (r == Session::Recording && h) {
2399 rec_button.set_active_state (Mid);
2401 rec_button.unset_active_state ();
2406 ARDOUR_UI::save_template ()
2408 ArdourPrompter prompter (true);
2411 if (!check_audioengine()) {
2415 prompter.set_name (X_("Prompter"));
2416 prompter.set_title (_("Save Template"));
2417 prompter.set_prompt (_("Name for template:"));
2418 prompter.set_initial_text(_session->name() + _("-template"));
2419 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2421 switch (prompter.run()) {
2422 case RESPONSE_ACCEPT:
2423 prompter.get_result (name);
2425 if (name.length()) {
2426 _session->save_template (name);
2436 ARDOUR_UI::edit_metadata ()
2438 SessionMetadataEditor dialog;
2439 dialog.set_session (_session);
2440 editor->ensure_float (dialog);
2445 ARDOUR_UI::import_metadata ()
2447 SessionMetadataImporter dialog;
2448 dialog.set_session (_session);
2449 editor->ensure_float (dialog);
2454 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
2456 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2458 MessageDialog msg (str,
2460 Gtk::MESSAGE_WARNING,
2461 Gtk::BUTTONS_YES_NO,
2465 msg.set_name (X_("OpenExistingDialog"));
2466 msg.set_title (_("Open Existing Session"));
2467 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
2468 msg.set_position (Gtk::WIN_POS_MOUSE);
2471 switch (msg.run()) {
2480 ARDOUR_UI::build_session_from_nsd (const std::string& session_path, const std::string& session_name)
2482 BusProfile bus_profile;
2484 if (Profile->get_sae()) {
2486 bus_profile.master_out_channels = 2;
2487 bus_profile.input_ac = AutoConnectPhysical;
2488 bus_profile.output_ac = AutoConnectMaster;
2489 bus_profile.requested_physical_in = 0; // use all available
2490 bus_profile.requested_physical_out = 0; // use all available
2494 /* get settings from advanced section of NSD */
2496 if (_startup->create_master_bus()) {
2497 bus_profile.master_out_channels = (uint32_t) _startup->master_channel_count();
2499 bus_profile.master_out_channels = 0;
2502 if (_startup->connect_inputs()) {
2503 bus_profile.input_ac = AutoConnectPhysical;
2505 bus_profile.input_ac = AutoConnectOption (0);
2508 /// @todo some minor tweaks.
2510 bus_profile.output_ac = AutoConnectOption (0);
2512 if (_startup->connect_outputs ()) {
2513 if (_startup->connect_outs_to_master()) {
2514 bus_profile.output_ac = AutoConnectMaster;
2515 } else if (_startup->connect_outs_to_physical()) {
2516 bus_profile.output_ac = AutoConnectPhysical;
2520 bus_profile.requested_physical_in = (uint32_t) _startup->input_limit_count();
2521 bus_profile.requested_physical_out = (uint32_t) _startup->output_limit_count();
2524 if (build_session (session_path, session_name, bus_profile)) {
2532 ARDOUR_UI::idle_load (const std::string& path)
2535 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2536 /* /path/to/foo => /path/to/foo, foo */
2537 load_session (path, basename_nosuffix (path));
2539 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2540 load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2544 ARDOUR_COMMAND_LINE::session_name = path;
2547 * new_session_dialog doens't exist in A3
2548 * Try to remove all references to it to
2549 * see if it will compile. NOTE: this will
2550 * likely cause a runtime issue is my somewhat
2554 //if (new_session_dialog) {
2557 /* make it break out of Dialog::run() and
2561 //new_session_dialog->response (1);
2567 ARDOUR_UI::end_loading_messages ()
2573 ARDOUR_UI::loading_message (const std::string& /*msg*/)
2576 // splash->message (msg);
2580 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
2582 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
2584 string session_name;
2585 string session_path;
2586 string template_name;
2588 bool likely_new = false;
2590 if (!load_template.empty()) {
2591 should_be_new = true;
2592 template_name = load_template;
2597 if (!should_be_new && !ARDOUR_COMMAND_LINE::session_name.empty()) {
2599 /* if they named a specific statefile, use it, otherwise they are
2600 just giving a session folder, and we want to use it as is
2601 to find the session.
2604 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
2606 if (suffix != string::npos) {
2607 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
2608 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
2609 session_name = Glib::path_get_basename (session_name);
2611 session_path = ARDOUR_COMMAND_LINE::session_name;
2612 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
2617 bool const apply = run_startup (should_be_new, load_template);
2620 if (quit_on_cancel) {
2627 /* if we run the startup dialog again, offer more than just "new session" */
2629 should_be_new = false;
2631 session_name = _startup->session_name (likely_new);
2633 string::size_type suffix = session_name.find (statefile_suffix);
2635 if (suffix != string::npos) {
2636 session_name = session_name.substr (0, suffix);
2639 /* this shouldn't happen, but we catch it just in case it does */
2641 if (session_name.empty()) {
2645 if (_startup->use_session_template()) {
2646 template_name = _startup->session_template_name();
2647 _session_is_new = true;
2650 if (session_name[0] == G_DIR_SEPARATOR ||
2651 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
2652 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)) {
2654 /* absolute path or cwd-relative path specified for session name: infer session folder
2655 from what was given.
2658 session_path = Glib::path_get_dirname (session_name);
2659 session_name = Glib::path_get_basename (session_name);
2663 session_path = _startup->session_folder();
2665 if (session_name.find ('/') != string::npos) {
2666 MessageDialog msg (*_startup,
2667 _("To ensure compatibility with various systems\n"
2668 "session names may not contain a '/' character"));
2670 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2674 if (session_name.find ('\\') != string::npos) {
2675 MessageDialog msg (*_startup,
2676 _("To ensure compatibility with various systems\n"
2677 "session names may not contain a '\\' character"));
2679 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2685 if (create_engine ()) {
2689 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
2693 std::string existing = Glib::build_filename (session_path, session_name);
2695 if (!ask_about_loading_existing_session (existing)) {
2696 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2701 _session_is_new = false;
2706 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
2708 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2712 if (session_name.find ('/') != std::string::npos) {
2713 MessageDialog msg (*_startup,
2714 _("To ensure compatibility with various systems\n"
2715 "session names may not contain a '/' character"));
2717 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2721 if (session_name.find ('\\') != std::string::npos) {
2722 MessageDialog msg (*_startup,
2723 _("To ensure compatibility with various systems\n"
2724 "session names may not contain a '\\' character"));
2726 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2730 _session_is_new = true;
2733 if (likely_new && template_name.empty()) {
2735 ret = build_session_from_nsd (session_path, session_name);
2739 ret = load_session (session_path, session_name, template_name);
2742 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
2746 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
2747 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
2757 ARDOUR_UI::close_session()
2759 if (!check_audioengine()) {
2763 if (unload_session (true)) {
2767 ARDOUR_COMMAND_LINE::session_name = "";
2769 if (get_session_parameters (true, false)) {
2773 goto_editor_window ();
2776 /** @param snap_name Snapshot name (without .ardour suffix).
2777 * @return -2 if the load failed because we are not connected to the AudioEngine.
2780 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
2782 Session *new_session;
2786 session_loaded = false;
2788 if (!check_audioengine()) {
2792 unload_status = unload_session ();
2794 if (unload_status < 0) {
2796 } else if (unload_status > 0) {
2801 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
2804 new_session = new Session (*engine, path, snap_name, 0, mix_template);
2807 /* this one is special */
2809 catch (AudioEngine::PortRegistrationFailure& err) {
2811 MessageDialog msg (err.what(),
2814 Gtk::BUTTONS_CLOSE);
2816 msg.set_title (_("Port Registration Error"));
2817 msg.set_secondary_text (_("Click the Close button to try again."));
2818 msg.set_position (Gtk::WIN_POS_CENTER);
2822 int response = msg.run ();
2827 case RESPONSE_CANCEL:
2837 MessageDialog msg (string_compose(
2838 _("Session \"%1 (snapshot %2)\" did not load successfully"),
2844 msg.set_title (_("Loading Error"));
2845 msg.set_secondary_text (_("Click the Refresh button to try again."));
2846 msg.add_button (Stock::REFRESH, 1);
2847 msg.set_position (Gtk::WIN_POS_CENTER);
2851 int response = msg.run ();
2866 list<string> const u = new_session->unknown_processors ();
2868 MissingPluginDialog d (_session, u);
2873 /* Now the session been created, add the transport controls */
2874 new_session->add_controllable(roll_controllable);
2875 new_session->add_controllable(stop_controllable);
2876 new_session->add_controllable(goto_start_controllable);
2877 new_session->add_controllable(goto_end_controllable);
2878 new_session->add_controllable(auto_loop_controllable);
2879 new_session->add_controllable(play_selection_controllable);
2880 new_session->add_controllable(rec_controllable);
2882 set_session (new_session);
2884 session_loaded = true;
2886 goto_editor_window ();
2889 _session->set_clean ();
2900 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
2902 Session *new_session;
2905 if (!check_audioengine()) {
2909 session_loaded = false;
2911 x = unload_session ();
2919 _session_is_new = true;
2922 new_session = new Session (*engine, path, snap_name, &bus_profile);
2927 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
2933 /* Give the new session the default GUI state, if such things exist */
2936 n = Config->instant_xml (X_("Editor"));
2938 new_session->add_instant_xml (*n, false);
2940 n = Config->instant_xml (X_("Mixer"));
2942 new_session->add_instant_xml (*n, false);
2945 /* Put the playhead at 0 and scroll fully left */
2946 n = new_session->instant_xml (X_("Editor"));
2948 n->add_property (X_("playhead"), X_("0"));
2949 n->add_property (X_("left-frame"), X_("0"));
2952 set_session (new_session);
2954 session_loaded = true;
2956 new_session->save_state(new_session->name());
2962 ARDOUR_UI::launch_chat ()
2965 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
2967 open_uri("http://webchat.freenode.net/?channels=ardour");
2972 ARDOUR_UI::show_about ()
2976 about->signal_response().connect(sigc::mem_fun (*this, &ARDOUR_UI::about_signal_response) );
2979 about->set_transient_for(*editor);
2984 ARDOUR_UI::launch_manual ()
2986 PBD::open_uri("http://ardour.org/flossmanual");
2990 ARDOUR_UI::launch_reference ()
2992 PBD::open_uri("http://ardour.org/refmanual");
2996 ARDOUR_UI::hide_about ()
2999 about->get_window()->set_cursor ();
3005 ARDOUR_UI::about_signal_response (int /*response*/)
3011 ARDOUR_UI::show_splash ()
3015 splash = new Splash;
3023 splash->queue_draw ();
3024 splash->get_window()->process_updates (true);
3029 ARDOUR_UI::hide_splash ()
3037 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title,
3038 const string& plural_msg, const string& singular_msg)
3042 removed = rep.paths.size();
3045 MessageDialog msgd (*editor,
3046 _("No files were ready for clean-up"),
3049 (Gtk::ButtonsType)(Gtk::BUTTONS_OK) );
3050 msgd.set_title (_("Clean-up"));
3051 msgd.set_secondary_text (_("If this seems suprising, \n\
3052 check for any existing snapshots.\n\
3053 These may still include regions that\n\
3054 require some unused files to continue to exist."));
3060 ArdourDialog results (_("Clean-up"), true, false);
3062 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
3063 CleanupResultsModelColumns() {
3067 Gtk::TreeModelColumn<std::string> visible_name;
3068 Gtk::TreeModelColumn<std::string> fullpath;
3072 CleanupResultsModelColumns results_columns;
3073 Glib::RefPtr<Gtk::ListStore> results_model;
3074 Gtk::TreeView results_display;
3076 results_model = ListStore::create (results_columns);
3077 results_display.set_model (results_model);
3078 results_display.append_column (list_title, results_columns.visible_name);
3080 results_display.set_name ("CleanupResultsList");
3081 results_display.set_headers_visible (true);
3082 results_display.set_headers_clickable (false);
3083 results_display.set_reorderable (false);
3085 Gtk::ScrolledWindow list_scroller;
3088 Gtk::HBox dhbox; // the hbox for the image and text
3089 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
3090 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
3092 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
3094 const string dead_directory = _session->session_directory().dead_path().to_string();
3097 %1 - number of files removed
3098 %2 - location of "dead"
3099 %3 - size of files affected
3100 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
3103 const char* bprefix;
3104 double space_adjusted = 0;
3106 if (rep.space < 1000) {
3108 space_adjusted = rep.space;
3109 } else if (rep.space < 1000000) {
3110 bprefix = X_("kilo");
3111 space_adjusted = truncf((float)rep.space / 1000.0);
3112 } else if (rep.space < 1000000 * 1000) {
3113 bprefix = X_("mega");
3114 space_adjusted = truncf((float)rep.space / (1000.0 * 1000.0));
3116 bprefix = X_("giga");
3117 space_adjusted = truncf((float)rep.space / (1000.0 * 1000 * 1000.0));
3121 txt.set_text (string_compose (plural_msg, removed, dead_directory, space_adjusted, bprefix));
3123 txt.set_text (string_compose (singular_msg, removed, dead_directory, space_adjusted, bprefix));
3126 dhbox.pack_start (*dimage, true, false, 5);
3127 dhbox.pack_start (txt, true, false, 5);
3129 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
3130 TreeModel::Row row = *(results_model->append());
3131 row[results_columns.visible_name] = *i;
3132 row[results_columns.fullpath] = *i;
3135 list_scroller.add (results_display);
3136 list_scroller.set_size_request (-1, 150);
3137 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
3139 dvbox.pack_start (dhbox, true, false, 5);
3140 dvbox.pack_start (list_scroller, true, false, 5);
3141 ddhbox.pack_start (dvbox, true, false, 5);
3143 results.get_vbox()->pack_start (ddhbox, true, false, 5);
3144 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
3145 results.set_default_response (RESPONSE_CLOSE);
3146 results.set_position (Gtk::WIN_POS_MOUSE);
3148 results_display.show();
3149 list_scroller.show();
3156 //results.get_vbox()->show();
3157 results.set_resizable (false);
3164 ARDOUR_UI::cleanup ()
3166 if (_session == 0) {
3167 /* shouldn't happen: menu item is insensitive */
3172 MessageDialog checker (_("Are you sure you want to clean-up?"),
3174 Gtk::MESSAGE_QUESTION,
3175 (Gtk::ButtonsType)(Gtk::BUTTONS_NONE));
3177 checker.set_title (_("Clean-up"));
3179 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
3180 ALL undo/redo information will be lost if you clean-up.\n\
3181 Clean-up will move all unused files to a \"dead\" location."));
3183 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3184 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
3185 checker.set_default_response (RESPONSE_CANCEL);
3187 checker.set_name (_("CleanupDialog"));
3188 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3189 checker.set_position (Gtk::WIN_POS_MOUSE);
3191 switch (checker.run()) {
3192 case RESPONSE_ACCEPT:
3198 ARDOUR::CleanupReport rep;
3200 editor->prepare_for_cleanup ();
3202 /* do not allow flush until a session is reloaded */
3204 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3206 act->set_sensitive (false);
3209 if (_session->cleanup_sources (rep)) {
3210 editor->finish_cleanup ();
3214 editor->finish_cleanup ();
3217 display_cleanup_results (rep,
3220 The following %1 files were not in use and \n\
3221 have been moved to:\n\n\
3223 After a restart of Ardour,\n\n\
3224 Session -> Clean-up -> Flush Wastebasket\n\n\
3225 will release an additional\n\
3226 %3 %4bytes of disk space.\n"),
3228 The following file was not in use and \n\
3229 has been moved to:\n \
3231 After a restart of Ardour,\n\n\
3232 Session -> Clean-up -> Flush Wastebasket\n\n\
3233 will release an additional\n\
3234 %3 %4bytes of disk space.\n"
3240 ARDOUR_UI::flush_trash ()
3242 if (_session == 0) {
3243 /* shouldn't happen: menu item is insensitive */
3247 ARDOUR::CleanupReport rep;
3249 if (_session->cleanup_trash_sources (rep)) {
3253 display_cleanup_results (rep,
3255 _("The following %1 files were deleted from\n\
3257 releasing %3 %4bytes of disk space"),
3258 _("The following file was deleted from\n\
3260 releasing %3 %4bytes of disk space"));
3264 ARDOUR_UI::add_route (Gtk::Window* float_window)
3272 if (add_route_dialog == 0) {
3273 add_route_dialog = new AddRouteDialog (_session);
3275 add_route_dialog->set_transient_for (*float_window);
3279 if (add_route_dialog->is_visible()) {
3280 /* we're already doing this */
3284 ResponseType r = (ResponseType) add_route_dialog->run ();
3286 add_route_dialog->hide();
3289 case RESPONSE_ACCEPT:
3296 if ((count = add_route_dialog->count()) <= 0) {
3300 string template_path = add_route_dialog->track_template();
3302 if (!template_path.empty()) {
3303 _session->new_route_from_template (count, template_path);
3307 uint32_t input_chan = add_route_dialog->channels ();
3308 uint32_t output_chan;
3309 string name_template = add_route_dialog->name_template ();
3310 bool track = add_route_dialog->track ();
3311 RouteGroup* route_group = add_route_dialog->route_group ();
3313 AutoConnectOption oac = Config->get_output_auto_connect();
3315 if (oac & AutoConnectMaster) {
3316 output_chan = (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan);
3318 output_chan = input_chan;
3321 /* XXX do something with name template */
3323 if (add_route_dialog->type() == ARDOUR::DataType::MIDI) {
3325 session_add_midi_track (route_group, count, name_template);
3327 MessageDialog msg (*editor,
3328 _("Sorry, MIDI Busses are not supported at this time."));
3330 //session_add_midi_bus();
3334 session_add_audio_track (input_chan, output_chan, add_route_dialog->mode(), route_group, count, name_template);
3336 session_add_audio_bus (input_chan, output_chan, route_group, count, name_template);
3342 ARDOUR_UI::mixer_settings () const
3347 node = _session->instant_xml(X_("Mixer"));
3349 node = Config->instant_xml(X_("Mixer"));
3353 node = new XMLNode (X_("Mixer"));
3360 ARDOUR_UI::editor_settings () const
3365 node = _session->instant_xml(X_("Editor"));
3367 node = Config->instant_xml(X_("Editor"));
3371 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
3372 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
3377 node = new XMLNode (X_("Editor"));
3384 ARDOUR_UI::keyboard_settings () const
3388 node = Config->extra_xml(X_("Keyboard"));
3391 node = new XMLNode (X_("Keyboard"));
3398 ARDOUR_UI::create_xrun_marker (framepos_t where)
3400 editor->mouse_add_new_marker (where, false, true);
3404 ARDOUR_UI::halt_on_xrun_message ()
3406 MessageDialog msg (*editor,
3407 _("Recording was stopped because your system could not keep up."));
3412 ARDOUR_UI::xrun_handler (framepos_t where)
3418 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
3420 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
3421 create_xrun_marker(where);
3424 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
3425 halt_on_xrun_message ();
3430 ARDOUR_UI::disk_overrun_handler ()
3432 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
3434 if (!have_disk_speed_dialog_displayed) {
3435 have_disk_speed_dialog_displayed = true;
3436 MessageDialog* msg = new MessageDialog (*editor, string_compose (_("\
3437 The disk system on your computer\n\
3438 was not able to keep up with %1.\n\
3440 Specifically, it failed to write data to disk\n\
3441 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
3442 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3448 ARDOUR_UI::disk_underrun_handler ()
3450 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
3452 if (!have_disk_speed_dialog_displayed) {
3453 have_disk_speed_dialog_displayed = true;
3454 MessageDialog* msg = new MessageDialog (
3455 *editor, string_compose (_("The disk system on your computer\n\
3456 was not able to keep up with %1.\n\
3458 Specifically, it failed to read data from disk\n\
3459 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
3460 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3466 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
3468 have_disk_speed_dialog_displayed = false;
3473 ARDOUR_UI::session_dialog (std::string msg)
3475 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
3480 d = new MessageDialog (*editor, msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3482 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3491 ARDOUR_UI::pending_state_dialog ()
3493 HBox* hbox = new HBox();
3494 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3495 ArdourDialog dialog (_("Crash Recovery"), true);
3497 This session appears to have been in\n\
3498 middle of recording when ardour or\n\
3499 the computer was shutdown.\n\
3501 Ardour can recover any captured audio for\n\
3502 you, or it can ignore it. Please decide\n\
3503 what you would like to do.\n"));
3504 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3505 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3506 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3507 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3508 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
3509 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
3510 dialog.set_default_response (RESPONSE_ACCEPT);
3511 dialog.set_position (WIN_POS_CENTER);
3516 switch (dialog.run ()) {
3517 case RESPONSE_ACCEPT:
3525 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
3527 HBox* hbox = new HBox();
3528 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3529 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
3530 Label message (string_compose (_("\
3531 This session was created with a sample rate of %1 Hz\n\
3533 The audioengine is currently running at %2 Hz\n"), desired, actual));
3535 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3536 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3537 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3538 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3539 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
3540 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
3541 dialog.set_default_response (RESPONSE_ACCEPT);
3542 dialog.set_position (WIN_POS_CENTER);
3547 switch (dialog.run ()) {
3548 case RESPONSE_ACCEPT:
3557 ARDOUR_UI::disconnect_from_jack ()
3560 if( engine->disconnect_from_jack ()) {
3561 MessageDialog msg (*editor, _("Could not disconnect from JACK"));
3565 update_sample_rate (0);
3570 ARDOUR_UI::reconnect_to_jack ()
3573 if (engine->reconnect_to_jack ()) {
3574 MessageDialog msg (*editor, _("Could not reconnect to JACK"));
3578 update_sample_rate (0);
3583 ARDOUR_UI::use_config ()
3585 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
3587 set_transport_controllable_state (*node);
3592 ARDOUR_UI::update_transport_clocks (framepos_t pos)
3594 if (Config->get_primary_clock_delta_edit_cursor()) {
3595 primary_clock->set (pos, false, editor->get_preferred_edit_position(), 1);
3597 primary_clock->set (pos, 0, true);
3600 if (Config->get_secondary_clock_delta_edit_cursor()) {
3601 secondary_clock->set (pos, false, editor->get_preferred_edit_position(), 2);
3603 secondary_clock->set (pos);
3606 if (big_clock_window->get()) {
3607 big_clock->set (pos);
3613 ARDOUR_UI::step_edit_status_change (bool yn)
3615 // XXX should really store pre-step edit status of things
3616 // we make insensitive
3619 rec_button.set_active_state (Mid);
3620 rec_button.set_sensitive (false);
3622 rec_button.unset_active_state ();;
3623 rec_button.set_sensitive (true);
3628 ARDOUR_UI::record_state_changed ()
3630 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
3632 if (!_session || !big_clock_window->get()) {
3633 /* why bother - the clock isn't visible */
3637 Session::RecordState const r = _session->record_status ();
3638 bool const h = _session->have_rec_enabled_track ();
3640 if (r == Session::Recording && h) {
3641 big_clock->set_widget_name ("BigClockRecording");
3643 big_clock->set_widget_name ("BigClockNonRecording");
3648 ARDOUR_UI::first_idle ()
3651 _session->allow_auto_play (true);
3655 editor->first_idle();
3658 Keyboard::set_can_save_keybindings (true);
3663 ARDOUR_UI::store_clock_modes ()
3665 XMLNode* node = new XMLNode(X_("ClockModes"));
3667 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
3668 XMLNode* child = new XMLNode (X_("Clock"));
3670 child->add_property (X_("name"), (*x)->name());
3671 child->add_property (X_("mode"), enum_2_string ((*x)->mode()));
3672 child->add_property (X_("on"), ((*x)->off() ? X_("no") : X_("yes")));
3674 node->add_child_nocopy (*child);
3677 _session->add_extra_xml (*node);
3678 _session->set_dirty ();
3681 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
3682 : Controllable (name), ui (u), type(tp)
3688 ARDOUR_UI::TransportControllable::set_value (double val)
3691 /* do nothing: these are radio-style actions */
3695 const char *action = 0;
3699 action = X_("Roll");
3702 action = X_("Stop");
3705 action = X_("Goto Start");
3708 action = X_("Goto End");
3711 action = X_("Loop");
3714 action = X_("Play Selection");
3717 action = X_("Record");
3727 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
3735 ARDOUR_UI::TransportControllable::get_value (void) const
3762 ARDOUR_UI::setup_profile ()
3764 if (gdk_screen_width() < 1200) {
3765 Profile->set_small_screen ();
3769 if (getenv ("ARDOUR_SAE")) {
3770 Profile->set_sae ();
3771 Profile->set_single_package ();
3776 ARDOUR_UI::toggle_translations ()
3778 using namespace Glib;
3780 RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("EnableTranslation"));
3782 RefPtr<ToggleAction> ract = RefPtr<ToggleAction>::cast_dynamic (act);
3785 string i18n_killer = ARDOUR::translation_kill_path();
3787 bool already_enabled = !ARDOUR::translations_are_disabled ();
3789 if (ract->get_active ()) {
3790 /* we don't care about errors */
3791 int fd = ::open (i18n_killer.c_str(), O_RDONLY|O_CREAT, 0644);
3794 /* we don't care about errors */
3795 unlink (i18n_killer.c_str());
3798 if (already_enabled != ract->get_active()) {
3799 MessageDialog win (already_enabled ? _("Translations disabled") : _("Translations enabled"),
3801 Gtk::MESSAGE_WARNING,
3803 win.set_secondary_text (string_compose (_("You must restart %1 for this to take effect."), PROGRAM_NAME));
3804 win.set_position (Gtk::WIN_POS_CENTER);
3812 /** Add a window proxy to our list, so that its state will be saved.
3813 * This call also causes the window to be created and opened if its
3814 * state was saved as `visible'.
3817 ARDOUR_UI::add_window_proxy (WindowProxyBase* p)
3819 _window_proxies.push_back (p);
3823 /** Remove a window proxy from our list. Must be called if a WindowProxy
3824 * is deleted, to prevent hanging pointers.
3827 ARDOUR_UI::remove_window_proxy (WindowProxyBase* p)
3829 _window_proxies.remove (p);
3833 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
3835 MissingFileDialog dialog (s, str, type);
3840 int result = dialog.run ();
3847 return 1; // quit entire session load
3850 result = dialog.get_action ();
3856 ARDOUR_UI::ambiguous_file (std::string file, std::string /*path*/, std::vector<std::string> hits)
3858 AmbiguousFileDialog dialog (file, hits);
3864 return dialog.get_which ();
3867 /** Allocate our thread-local buffers */
3869 ARDOUR_UI::get_process_buffers ()
3871 _process_thread->get_buffers ();
3874 /** Drop our thread-local buffers */
3876 ARDOUR_UI::drop_process_buffers ()
3878 _process_thread->drop_buffers ();
3882 ARDOUR_UI::feedback_detected ()
3884 _feedback_exists = true;
3888 ARDOUR_UI::successful_graph_sort ()
3890 _feedback_exists = false;
3894 ARDOUR_UI::midi_panic ()
3897 _session->midi_panic();