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 (_("Auto Return"))
157 , auto_play_button (_("Auto Play"))
158 , auto_input_button (_("Auto Input"))
159 // , click_button (_("Click"))
160 , time_master_button (_("time\nmaster"))
162 , auditioning_alert_button (_("AUDITION"))
163 , solo_alert_button (_("SOLO"))
165 , error_log_button (_("Errors"))
167 , _status_bar_visibility (X_("status-bar"))
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");
240 roll_button.set_tweaks (ArdourButton::ShowHover);
241 stop_button.set_tweaks (ArdourButton::ShowHover);
242 auto_loop_button.set_tweaks (ArdourButton::ShowHover);
243 play_selection_button.set_tweaks (ArdourButton::ShowHover);
244 rec_button.set_tweaks (ArdourButton::ShowHover);
245 join_play_range_button.set_tweaks (ArdourButton::ShowHover);
247 goto_start_button.set_tweaks (ArdourButton::Tweaks(ArdourButton::ShowClick|ArdourButton::ShowHover));
248 goto_end_button.set_tweaks (ArdourButton::Tweaks(ArdourButton::ShowClick|ArdourButton::ShowHover));
250 last_configure_time= 0;
253 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
254 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
256 /* handle dialog requests */
258 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
260 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
262 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
264 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
266 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
268 /* handle requests to quit (coming from JACK session) */
270 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::finish, 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);
1141 frames -= hrs * fr * 3600;
1142 mins = frames / (fr * 60);
1143 frames -= mins * fr * 60;
1146 bool const low = (hrs == 0 && mins <= 30);
1150 _("Disk: <span foreground=\"%s\">%02dh:%02dm:%02ds</span>"),
1151 low ? X_("red") : X_("green"),
1156 disk_space_label.set_markup (buf);
1158 // An attempt to make the disk space label flash red when space has run out.
1160 if (frames < fr * 60 * 5) {
1161 /* disk_space_box.style ("disk_space_label_empty"); */
1163 /* disk_space_box.style ("disk_space_label"); */
1169 ARDOUR_UI::update_wall_clock ()
1176 tm_now = localtime (&now);
1178 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1179 wall_clock_label.set_text (buf);
1185 ARDOUR_UI::session_menu (GdkEventButton */*ev*/)
1187 session_popup_menu->popup (0, 0);
1192 ARDOUR_UI::redisplay_recent_sessions ()
1194 std::vector<sys::path> session_directories;
1195 RecentSessionsSorter cmp;
1197 recent_session_display.set_model (Glib::RefPtr<TreeModel>(0));
1198 recent_session_model->clear ();
1200 ARDOUR::RecentSessions rs;
1201 ARDOUR::read_recent_sessions (rs);
1204 recent_session_display.set_model (recent_session_model);
1208 // sort them alphabetically
1209 sort (rs.begin(), rs.end(), cmp);
1211 for (ARDOUR::RecentSessions::iterator i = rs.begin(); i != rs.end(); ++i) {
1212 session_directories.push_back ((*i).second);
1215 for (vector<sys::path>::const_iterator i = session_directories.begin();
1216 i != session_directories.end(); ++i)
1218 std::vector<sys::path> state_file_paths;
1220 // now get available states for this session
1222 get_state_files_in_directory (*i, state_file_paths);
1224 vector<string*>* states;
1225 vector<const gchar*> item;
1226 string fullpath = (*i).to_string();
1228 /* remove any trailing / */
1230 if (fullpath[fullpath.length()-1] == '/') {
1231 fullpath = fullpath.substr (0, fullpath.length()-1);
1234 /* check whether session still exists */
1235 if (!Glib::file_test(fullpath.c_str(), Glib::FILE_TEST_EXISTS)) {
1236 /* session doesn't exist */
1237 cerr << "skipping non-existent session " << fullpath << endl;
1241 /* now get available states for this session */
1243 if ((states = Session::possible_states (fullpath)) == 0) {
1244 /* no state file? */
1248 std::vector<string> state_file_names(get_file_names_no_extension (state_file_paths));
1250 Gtk::TreeModel::Row row = *(recent_session_model->append());
1252 row[recent_session_columns.visible_name] = Glib::path_get_basename (fullpath);
1253 row[recent_session_columns.fullpath] = fullpath;
1255 if (state_file_names.size() > 1) {
1259 for (std::vector<std::string>::iterator i2 = state_file_names.begin();
1260 i2 != state_file_names.end(); ++i2)
1263 Gtk::TreeModel::Row child_row = *(recent_session_model->append (row.children()));
1265 child_row[recent_session_columns.visible_name] = *i2;
1266 child_row[recent_session_columns.fullpath] = fullpath;
1271 recent_session_display.set_model (recent_session_model);
1275 ARDOUR_UI::build_session_selector ()
1277 session_selector_window = new ArdourDialog (_("Recent Sessions"));
1279 Gtk::ScrolledWindow *scroller = manage (new Gtk::ScrolledWindow);
1281 session_selector_window->add_button (Stock::CANCEL, RESPONSE_CANCEL);
1282 session_selector_window->add_button (Stock::OPEN, RESPONSE_ACCEPT);
1283 session_selector_window->set_default_response (RESPONSE_ACCEPT);
1284 recent_session_model = TreeStore::create (recent_session_columns);
1285 recent_session_display.set_model (recent_session_model);
1286 recent_session_display.append_column (_("Recent Sessions"), recent_session_columns.visible_name);
1287 recent_session_display.set_headers_visible (false);
1288 recent_session_display.get_selection()->set_mode (SELECTION_BROWSE);
1289 recent_session_display.signal_row_activated().connect (sigc::mem_fun (*this, &ARDOUR_UI::recent_session_row_activated));
1291 scroller->add (recent_session_display);
1292 scroller->set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
1294 session_selector_window->set_name ("SessionSelectorWindow");
1295 session_selector_window->set_size_request (200, 400);
1296 session_selector_window->get_vbox()->pack_start (*scroller);
1298 recent_session_display.show();
1300 //session_selector_window->get_vbox()->show();
1304 ARDOUR_UI::recent_session_row_activated (const TreePath& /*path*/, TreeViewColumn* /*col*/)
1306 session_selector_window->response (RESPONSE_ACCEPT);
1310 ARDOUR_UI::open_recent_session ()
1312 bool can_return = (_session != 0);
1314 if (session_selector_window == 0) {
1315 build_session_selector ();
1318 redisplay_recent_sessions ();
1322 session_selector_window->set_position (WIN_POS_MOUSE);
1324 ResponseType r = (ResponseType) session_selector_window->run ();
1327 case RESPONSE_ACCEPT:
1331 session_selector_window->hide();
1338 if (recent_session_display.get_selection()->count_selected_rows() == 0) {
1342 session_selector_window->hide();
1344 Gtk::TreeModel::iterator i = recent_session_display.get_selection()->get_selected();
1346 if (i == recent_session_model->children().end()) {
1350 std::string path = (*i)[recent_session_columns.fullpath];
1351 std::string state = (*i)[recent_session_columns.visible_name];
1353 _session_is_new = false;
1355 if (load_session (path, state) == 0) {
1364 ARDOUR_UI::check_audioengine ()
1367 if (!engine->connected()) {
1368 MessageDialog msg (string_compose (
1369 _("%1 is not connected to JACK\n"
1370 "You cannot open or close sessions in this condition"),
1383 ARDOUR_UI::open_session ()
1385 if (!check_audioengine()) {
1390 /* popup selector window */
1392 if (open_session_selector == 0) {
1394 /* ardour sessions are folders */
1396 open_session_selector = new Gtk::FileChooserDialog (_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1397 open_session_selector->add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1398 open_session_selector->add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1399 open_session_selector->set_default_response(Gtk::RESPONSE_ACCEPT);
1401 FileFilter session_filter;
1402 session_filter.add_pattern ("*.ardour");
1403 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1404 open_session_selector->add_filter (session_filter);
1405 open_session_selector->set_filter (session_filter);
1408 int response = open_session_selector->run();
1409 open_session_selector->hide ();
1412 case RESPONSE_ACCEPT:
1415 open_session_selector->hide();
1419 open_session_selector->hide();
1420 string session_path = open_session_selector->get_filename();
1424 if (session_path.length() > 0) {
1425 if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1426 _session_is_new = isnew;
1427 load_session (path, name);
1434 ARDOUR_UI::session_add_midi_route (bool disk, RouteGroup* route_group, uint32_t how_many, string const & name_template)
1436 list<boost::shared_ptr<MidiTrack> > tracks;
1438 if (_session == 0) {
1439 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1446 tracks = _session->new_midi_track (ARDOUR::Normal, route_group, how_many, name_template);
1448 if (tracks.size() != how_many) {
1449 if (how_many == 1) {
1450 error << _("could not create a new midi track") << endmsg;
1452 error << string_compose (_("could not create %1 new midi tracks"), how_many) << endmsg;
1456 if ((route = _session->new_midi_route ()) == 0) {
1457 error << _("could not create new midi bus") << endmsg;
1463 MessageDialog msg (*editor,
1464 string_compose (_("There are insufficient JACK ports available\n\
1465 to create a new track or bus.\n\
1466 You should save %1, exit and\n\
1467 restart JACK with more ports."), PROGRAM_NAME));
1474 ARDOUR_UI::session_add_audio_route (
1476 int32_t input_channels,
1477 int32_t output_channels,
1478 ARDOUR::TrackMode mode,
1479 RouteGroup* route_group,
1481 string const & name_template
1484 list<boost::shared_ptr<AudioTrack> > tracks;
1487 if (_session == 0) {
1488 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1494 tracks = _session->new_audio_track (input_channels, output_channels, mode, route_group, how_many, name_template);
1496 if (tracks.size() != how_many) {
1497 if (how_many == 1) {
1498 error << _("could not create a new audio track") << endmsg;
1500 error << string_compose (_("could only create %1 of %2 new audio %3"),
1501 tracks.size(), how_many, (track ? _("tracks") : _("busses"))) << endmsg;
1507 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template);
1509 if (routes.size() != how_many) {
1510 if (how_many == 1) {
1511 error << _("could not create a new audio bus") << endmsg;
1513 error << string_compose (_("could not create %1 new audio busses"), how_many) << endmsg;
1520 MessageDialog msg (*editor,
1521 string_compose (_("There are insufficient JACK ports available\n\
1522 to create a new track or bus.\n\
1523 You should save %1, exit and\n\
1524 restart JACK with more ports."), PROGRAM_NAME));
1531 ARDOUR_UI::do_transport_locate (framepos_t new_position, bool with_roll)
1533 framecnt_t _preroll = 0;
1536 // XXX CONFIG_CHANGE FIX - requires AnyTime handling
1537 // _preroll = _session->convert_to_frames_at (new_position, Config->get_preroll());
1539 if (new_position > _preroll) {
1540 new_position -= _preroll;
1545 _session->request_locate (new_position, with_roll);
1550 ARDOUR_UI::transport_goto_start ()
1553 _session->goto_start();
1555 /* force displayed area in editor to start no matter
1556 what "follow playhead" setting is.
1560 editor->center_screen (_session->current_start_frame ());
1566 ARDOUR_UI::transport_goto_zero ()
1569 _session->request_locate (0);
1571 /* force displayed area in editor to start no matter
1572 what "follow playhead" setting is.
1576 editor->reset_x_origin (0);
1582 ARDOUR_UI::transport_goto_wallclock ()
1584 if (_session && editor) {
1591 localtime_r (&now, &tmnow);
1593 frames = tmnow.tm_hour * (60 * 60 * _session->frame_rate());
1594 frames += tmnow.tm_min * (60 * _session->frame_rate());
1595 frames += tmnow.tm_sec * _session->frame_rate();
1597 _session->request_locate (frames, _session->transport_rolling ());
1599 /* force displayed area in editor to start no matter
1600 what "follow playhead" setting is.
1604 editor->center_screen (frames);
1610 ARDOUR_UI::transport_goto_end ()
1613 framepos_t const frame = _session->current_end_frame();
1614 _session->request_locate (frame);
1616 /* force displayed area in editor to start no matter
1617 what "follow playhead" setting is.
1621 editor->center_screen (frame);
1627 ARDOUR_UI::transport_stop ()
1633 if (_session->is_auditioning()) {
1634 _session->cancel_audition ();
1638 _session->request_stop (false, true);
1642 ARDOUR_UI::transport_stop_and_forget_capture ()
1645 _session->request_stop (true, true);
1650 ARDOUR_UI::remove_last_capture()
1653 editor->remove_last_capture();
1658 ARDOUR_UI::transport_record (bool roll)
1662 switch (_session->record_status()) {
1663 case Session::Disabled:
1664 if (_session->ntracks() == 0) {
1665 MessageDialog msg (*editor, _("Please create 1 or more track\nbefore trying to record.\nCheck the Session menu."));
1669 _session->maybe_enable_record ();
1674 case Session::Recording:
1676 _session->request_stop();
1678 _session->disable_record (false, true);
1682 case Session::Enabled:
1683 _session->disable_record (false, true);
1686 //cerr << "ARDOUR_UI::transport_record () called roll = " << roll << " _session->record_status() = " << _session->record_status() << endl;
1690 ARDOUR_UI::transport_roll ()
1696 if (_session->is_auditioning()) {
1701 if (_session->config.get_external_sync()) {
1702 switch (_session->config.get_sync_source()) {
1706 /* transport controlled by the master */
1712 bool rolling = _session->transport_rolling();
1714 if (_session->get_play_loop()) {
1715 /* XXX it is not possible to just leave seamless loop and keep
1716 playing at present (nov 4th 2009)
1718 if (!Config->get_seamless_loop()) {
1719 _session->request_play_loop (false, true);
1721 } else if (_session->get_play_range () && !join_play_range_button.active_state()) {
1722 /* stop playing a range if we currently are */
1723 _session->request_play_range (0, true);
1726 if (join_play_range_button.active_state()) {
1727 _session->request_play_range (&editor->get_selection().time, true);
1731 _session->request_transport_speed (1.0f);
1736 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
1743 if (_session->is_auditioning()) {
1744 _session->cancel_audition ();
1748 if (_session->config.get_external_sync()) {
1749 switch (_session->config.get_sync_source()) {
1753 /* transport controlled by the master */
1758 bool rolling = _session->transport_rolling();
1759 bool affect_transport = true;
1761 if (rolling && roll_out_of_bounded_mode) {
1762 /* drop out of loop/range playback but leave transport rolling */
1763 if (_session->get_play_loop()) {
1764 if (Config->get_seamless_loop()) {
1765 /* the disk buffers contain copies of the loop - we can't
1766 just keep playing, so stop the transport. the user
1767 can restart as they wish.
1769 affect_transport = true;
1771 /* disk buffers are normal, so we can keep playing */
1772 affect_transport = false;
1774 _session->request_play_loop (false, true);
1775 } else if (_session->get_play_range ()) {
1776 affect_transport = false;
1777 _session->request_play_range (0, true);
1781 if (affect_transport) {
1783 _session->request_stop (with_abort, true);
1785 if (join_play_range_button.active_state()) {
1786 _session->request_play_range (&editor->get_selection().time, true);
1789 _session->request_transport_speed (1.0f);
1795 ARDOUR_UI::toggle_session_auto_loop ()
1801 if (_session->get_play_loop()) {
1803 if (_session->transport_rolling()) {
1805 Location * looploc = _session->locations()->auto_loop_location();
1808 _session->request_locate (looploc->start(), true);
1809 _session->request_play_loop (false);
1813 _session->request_play_loop (false);
1817 Location * looploc = _session->locations()->auto_loop_location();
1820 _session->request_play_loop (true);
1826 ARDOUR_UI::transport_play_selection ()
1832 editor->play_selection ();
1836 ARDOUR_UI::transport_rewind (int option)
1838 float current_transport_speed;
1841 current_transport_speed = _session->transport_speed();
1843 if (current_transport_speed >= 0.0f) {
1846 _session->request_transport_speed (-1.0f);
1849 _session->request_transport_speed (-4.0f);
1852 _session->request_transport_speed (-0.5f);
1857 _session->request_transport_speed (current_transport_speed * 1.5f);
1863 ARDOUR_UI::transport_forward (int option)
1865 float current_transport_speed;
1868 current_transport_speed = _session->transport_speed();
1870 if (current_transport_speed <= 0.0f) {
1873 _session->request_transport_speed (1.0f);
1876 _session->request_transport_speed (4.0f);
1879 _session->request_transport_speed (0.5f);
1884 _session->request_transport_speed (current_transport_speed * 1.5f);
1891 ARDOUR_UI::toggle_record_enable (uint32_t rid)
1893 if (_session == 0) {
1897 boost::shared_ptr<Route> r;
1899 if ((r = _session->route_by_remote_id (rid)) != 0) {
1903 if ((t = dynamic_cast<Track*>(r.get())) != 0) {
1904 t->set_record_enabled (!t->record_enabled(), this);
1907 if (_session == 0) {
1913 ARDOUR_UI::map_transport_state ()
1916 auto_loop_button.unset_active_state ();
1917 play_selection_button.unset_active_state ();
1918 roll_button.unset_active_state ();
1919 stop_button.set_active_state (Gtkmm2ext::Active);
1923 shuttle_box->map_transport_state ();
1925 float sp = _session->transport_speed();
1931 if (_session->get_play_range()) {
1933 play_selection_button.set_active_state (Gtkmm2ext::Active);
1934 roll_button.unset_active_state ();
1935 auto_loop_button.unset_active_state ();
1937 } else if (_session->get_play_loop ()) {
1939 auto_loop_button.set_active_state (Gtkmm2ext::Active);
1940 play_selection_button.unset_active_state ();
1941 roll_button.unset_active_state ();
1945 roll_button.set_active_state (Gtkmm2ext::Active);
1946 play_selection_button.unset_active_state ();
1947 auto_loop_button.unset_active_state ();
1950 if (join_play_range_button.active_state()) {
1951 /* light up both roll and play-selection if they are joined */
1952 roll_button.set_active_state (Gtkmm2ext::Active);
1953 play_selection_button.set_active_state (Gtkmm2ext::Active);
1956 stop_button.unset_active_state ();
1960 stop_button.set_active_state (Gtkmm2ext::Active);
1961 roll_button.unset_active_state ();
1962 play_selection_button.unset_active_state ();
1963 auto_loop_button.unset_active_state ();
1964 update_disk_space ();
1969 ARDOUR_UI::engine_stopped ()
1971 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
1972 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1973 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1977 ARDOUR_UI::engine_running ()
1979 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
1980 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, true);
1981 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, false);
1983 Glib::RefPtr<Action> action;
1984 const char* action_name = 0;
1986 switch (engine->frames_per_cycle()) {
1988 action_name = X_("JACKLatency32");
1991 action_name = X_("JACKLatency64");
1994 action_name = X_("JACKLatency128");
1997 action_name = X_("JACKLatency512");
2000 action_name = X_("JACKLatency1024");
2003 action_name = X_("JACKLatency2048");
2006 action_name = X_("JACKLatency4096");
2009 action_name = X_("JACKLatency8192");
2012 /* XXX can we do anything useful ? */
2018 action = ActionManager::get_action (X_("JACK"), action_name);
2021 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (action);
2022 ract->set_active ();
2028 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
2030 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
2031 /* we can't rely on the original string continuing to exist when we are called
2032 again in the GUI thread, so make a copy and note that we need to
2035 char *copy = strdup (reason);
2036 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
2040 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
2041 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
2043 update_sample_rate (0);
2047 /* if the reason is a non-empty string, it means that the backend was shutdown
2048 rather than just Ardour.
2051 if (strlen (reason)) {
2052 msgstr = string_compose (_("The audio backend (JACK) was shutdown because:\n\n%1"), reason);
2054 msgstr = string_compose (_("\
2055 JACK has either been shutdown or it\n\
2056 disconnected %1 because %1\n\
2057 was not fast enough. Try to restart\n\
2058 JACK, reconnect and save the session."), PROGRAM_NAME);
2061 MessageDialog msg (*editor, msgstr);
2066 free ((char*) reason);
2071 ARDOUR_UI::do_engine_start ()
2079 error << _("Unable to start the session running")
2089 ARDOUR_UI::setup_theme ()
2091 theme_manager->setup_theme();
2095 ARDOUR_UI::update_clocks ()
2097 if (!editor || !editor->dragging_playhead()) {
2098 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position()); /* EMIT_SIGNAL */
2103 ARDOUR_UI::start_clocking ()
2105 clock_signal_connection = RapidScreenUpdate.connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2109 ARDOUR_UI::stop_clocking ()
2111 clock_signal_connection.disconnect ();
2115 ARDOUR_UI::toggle_clocking ()
2118 if (clock_button.get_active()) {
2127 ARDOUR_UI::_blink (void *arg)
2130 ((ARDOUR_UI *) arg)->blink ();
2137 Blink (blink_on = !blink_on); /* EMIT_SIGNAL */
2141 ARDOUR_UI::start_blinking ()
2143 /* Start the blink signal. Everybody with a blinking widget
2144 uses Blink to drive the widget's state.
2147 if (blink_timeout_tag < 0) {
2149 blink_timeout_tag = g_timeout_add (240, _blink, this);
2154 ARDOUR_UI::stop_blinking ()
2156 if (blink_timeout_tag >= 0) {
2157 g_source_remove (blink_timeout_tag);
2158 blink_timeout_tag = -1;
2163 /** Ask the user for the name of a new shapshot and then take it.
2167 ARDOUR_UI::snapshot_session (bool switch_to_it)
2169 ArdourPrompter prompter (true);
2172 prompter.set_name ("Prompter");
2173 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2174 prompter.set_title (_("Take Snapshot"));
2175 prompter.set_prompt (_("Name of new snapshot"));
2177 if (!switch_to_it) {
2180 struct tm local_time;
2183 localtime_r (&n, &local_time);
2184 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2185 prompter.set_initial_text (timebuf);
2189 switch (prompter.run()) {
2190 case RESPONSE_ACCEPT:
2192 prompter.get_result (snapname);
2194 bool do_save = (snapname.length() != 0);
2197 if (snapname.find ('/') != string::npos) {
2198 MessageDialog msg (_("To ensure compatibility with various systems\n"
2199 "snapshot names may not contain a '/' character"));
2203 if (snapname.find ('\\') != string::npos) {
2204 MessageDialog msg (_("To ensure compatibility with various systems\n"
2205 "snapshot names may not contain a '\\' character"));
2209 if (snapname.find (':') != string::npos) {
2210 MessageDialog msg (_("To ensure compatibility with various systems\n"
2211 "snapshot names may not contain a ':' character"));
2217 vector<sys::path> p;
2218 get_state_files_in_directory (_session->session_directory().root_path(), p);
2219 vector<string> n = get_file_names_no_extension (p);
2220 if (find (n.begin(), n.end(), snapname) != n.end()) {
2222 ArdourDialog confirm (_("Confirm Snapshot Overwrite"), true);
2223 Label m (_("A snapshot already exists with that name. Do you want to overwrite it?"));
2224 confirm.get_vbox()->pack_start (m, true, true);
2225 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2226 confirm.add_button (_("Overwrite"), Gtk::RESPONSE_ACCEPT);
2227 confirm.show_all ();
2228 switch (confirm.run()) {
2229 case RESPONSE_CANCEL:
2235 save_state (snapname, switch_to_it);
2245 /** Ask the user for the name of a new shapshot and then take it.
2249 ARDOUR_UI::rename_session ()
2255 ArdourPrompter prompter (true);
2258 prompter.set_name ("Prompter");
2259 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2260 prompter.set_title (_("Rename Session"));
2261 prompter.set_prompt (_("New session name"));
2264 switch (prompter.run()) {
2265 case RESPONSE_ACCEPT:
2267 prompter.get_result (name);
2269 bool do_rename = (name.length() != 0);
2272 if (name.find ('/') != string::npos) {
2273 MessageDialog msg (_("To ensure compatibility with various systems\n"
2274 "session names may not contain a '/' character"));
2278 if (name.find ('\\') != string::npos) {
2279 MessageDialog msg (_("To ensure compatibility with various systems\n"
2280 "session names may not contain a '\\' character"));
2285 switch (_session->rename (name)) {
2287 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
2288 msg.set_position (WIN_POS_MOUSE);
2296 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
2297 msg.set_position (WIN_POS_MOUSE);
2313 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2315 XMLNode* node = new XMLNode (X_("UI"));
2317 for (list<WindowProxyBase*>::iterator i = _window_proxies.begin(); i != _window_proxies.end(); ++i) {
2318 if (!(*i)->rc_configured()) {
2319 node->add_child_nocopy (*((*i)->get_state ()));
2323 node->add_child_nocopy (gui_object_state->get_state());
2325 _session->add_extra_xml (*node);
2327 save_state_canfail (name, switch_to_it);
2331 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2336 if (name.length() == 0) {
2337 name = _session->snap_name();
2340 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2345 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2350 ARDOUR_UI::primary_clock_value_changed ()
2353 _session->request_locate (primary_clock->current_time ());
2358 ARDOUR_UI::big_clock_value_changed ()
2361 _session->request_locate (big_clock->current_time ());
2366 ARDOUR_UI::secondary_clock_value_changed ()
2369 _session->request_locate (secondary_clock->current_time ());
2374 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2376 if (_session == 0) {
2380 if (_session->step_editing()) {
2384 Session::RecordState const r = _session->record_status ();
2385 bool const h = _session->have_rec_enabled_track ();
2387 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2389 rec_button.set_active_state (Active);
2391 rec_button.set_active_state (Mid);
2393 } else if (r == Session::Recording && h) {
2394 rec_button.set_active_state (Mid);
2396 rec_button.unset_active_state ();
2401 ARDOUR_UI::save_template ()
2403 ArdourPrompter prompter (true);
2406 if (!check_audioengine()) {
2410 prompter.set_name (X_("Prompter"));
2411 prompter.set_title (_("Save Template"));
2412 prompter.set_prompt (_("Name for template:"));
2413 prompter.set_initial_text(_session->name() + _("-template"));
2414 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2416 switch (prompter.run()) {
2417 case RESPONSE_ACCEPT:
2418 prompter.get_result (name);
2420 if (name.length()) {
2421 _session->save_template (name);
2431 ARDOUR_UI::edit_metadata ()
2433 SessionMetadataEditor dialog;
2434 dialog.set_session (_session);
2435 editor->ensure_float (dialog);
2440 ARDOUR_UI::import_metadata ()
2442 SessionMetadataImporter dialog;
2443 dialog.set_session (_session);
2444 editor->ensure_float (dialog);
2449 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
2451 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2453 MessageDialog msg (str,
2455 Gtk::MESSAGE_WARNING,
2456 Gtk::BUTTONS_YES_NO,
2460 msg.set_name (X_("OpenExistingDialog"));
2461 msg.set_title (_("Open Existing Session"));
2462 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
2463 msg.set_position (Gtk::WIN_POS_MOUSE);
2466 switch (msg.run()) {
2475 ARDOUR_UI::build_session_from_nsd (const std::string& session_path, const std::string& session_name)
2477 BusProfile bus_profile;
2479 if (Profile->get_sae()) {
2481 bus_profile.master_out_channels = 2;
2482 bus_profile.input_ac = AutoConnectPhysical;
2483 bus_profile.output_ac = AutoConnectMaster;
2484 bus_profile.requested_physical_in = 0; // use all available
2485 bus_profile.requested_physical_out = 0; // use all available
2489 /* get settings from advanced section of NSD */
2491 if (_startup->create_master_bus()) {
2492 bus_profile.master_out_channels = (uint32_t) _startup->master_channel_count();
2494 bus_profile.master_out_channels = 0;
2497 if (_startup->connect_inputs()) {
2498 bus_profile.input_ac = AutoConnectPhysical;
2500 bus_profile.input_ac = AutoConnectOption (0);
2503 /// @todo some minor tweaks.
2505 bus_profile.output_ac = AutoConnectOption (0);
2507 if (_startup->connect_outputs ()) {
2508 if (_startup->connect_outs_to_master()) {
2509 bus_profile.output_ac = AutoConnectMaster;
2510 } else if (_startup->connect_outs_to_physical()) {
2511 bus_profile.output_ac = AutoConnectPhysical;
2515 bus_profile.requested_physical_in = (uint32_t) _startup->input_limit_count();
2516 bus_profile.requested_physical_out = (uint32_t) _startup->output_limit_count();
2519 if (build_session (session_path, session_name, bus_profile)) {
2527 ARDOUR_UI::idle_load (const std::string& path)
2530 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2531 /* /path/to/foo => /path/to/foo, foo */
2532 load_session (path, basename_nosuffix (path));
2534 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2535 load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2539 ARDOUR_COMMAND_LINE::session_name = path;
2542 * new_session_dialog doens't exist in A3
2543 * Try to remove all references to it to
2544 * see if it will compile. NOTE: this will
2545 * likely cause a runtime issue is my somewhat
2549 //if (new_session_dialog) {
2552 /* make it break out of Dialog::run() and
2556 //new_session_dialog->response (1);
2562 ARDOUR_UI::end_loading_messages ()
2568 ARDOUR_UI::loading_message (const std::string& /*msg*/)
2571 // splash->message (msg);
2575 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
2577 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
2579 string session_name;
2580 string session_path;
2581 string template_name;
2583 bool likely_new = false;
2585 if (!load_template.empty()) {
2586 should_be_new = true;
2587 template_name = load_template;
2592 if (!should_be_new && !ARDOUR_COMMAND_LINE::session_name.empty()) {
2594 /* if they named a specific statefile, use it, otherwise they are
2595 just giving a session folder, and we want to use it as is
2596 to find the session.
2599 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
2601 if (suffix != string::npos) {
2602 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
2603 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
2604 session_name = Glib::path_get_basename (session_name);
2606 session_path = ARDOUR_COMMAND_LINE::session_name;
2607 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
2612 bool const apply = run_startup (should_be_new, load_template);
2615 if (quit_on_cancel) {
2622 /* if we run the startup dialog again, offer more than just "new session" */
2624 should_be_new = false;
2626 session_name = _startup->session_name (likely_new);
2628 string::size_type suffix = session_name.find (statefile_suffix);
2630 if (suffix != string::npos) {
2631 session_name = session_name.substr (0, suffix);
2634 /* this shouldn't happen, but we catch it just in case it does */
2636 if (session_name.empty()) {
2640 if (_startup->use_session_template()) {
2641 template_name = _startup->session_template_name();
2642 _session_is_new = true;
2645 if (session_name[0] == G_DIR_SEPARATOR ||
2646 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
2647 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)) {
2649 /* absolute path or cwd-relative path specified for session name: infer session folder
2650 from what was given.
2653 session_path = Glib::path_get_dirname (session_name);
2654 session_name = Glib::path_get_basename (session_name);
2658 session_path = _startup->session_folder();
2660 if (session_name.find ('/') != string::npos) {
2661 MessageDialog msg (*_startup,
2662 _("To ensure compatibility with various systems\n"
2663 "session names may not contain a '/' character"));
2665 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2669 if (session_name.find ('\\') != string::npos) {
2670 MessageDialog msg (*_startup,
2671 _("To ensure compatibility with various systems\n"
2672 "session names may not contain a '\\' character"));
2674 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2680 if (create_engine ()) {
2684 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
2688 std::string existing = Glib::build_filename (session_path, session_name);
2690 if (!ask_about_loading_existing_session (existing)) {
2691 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2696 _session_is_new = false;
2701 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
2703 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2707 if (session_name.find ('/') != std::string::npos) {
2708 MessageDialog msg (*_startup,
2709 _("To ensure compatibility with various systems\n"
2710 "session names may not contain a '/' character"));
2712 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2716 if (session_name.find ('\\') != std::string::npos) {
2717 MessageDialog msg (*_startup,
2718 _("To ensure compatibility with various systems\n"
2719 "session names may not contain a '\\' character"));
2721 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2725 _session_is_new = true;
2728 if (likely_new && template_name.empty()) {
2730 ret = build_session_from_nsd (session_path, session_name);
2734 ret = load_session (session_path, session_name, template_name);
2737 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
2741 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
2742 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
2752 ARDOUR_UI::close_session()
2754 if (!check_audioengine()) {
2758 if (unload_session (true)) {
2762 ARDOUR_COMMAND_LINE::session_name = "";
2764 if (get_session_parameters (true, false)) {
2768 goto_editor_window ();
2771 /** @param snap_name Snapshot name (without .ardour suffix).
2772 * @return -2 if the load failed because we are not connected to the AudioEngine.
2775 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
2777 Session *new_session;
2781 session_loaded = false;
2783 if (!check_audioengine()) {
2787 unload_status = unload_session ();
2789 if (unload_status < 0) {
2791 } else if (unload_status > 0) {
2796 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
2799 new_session = new Session (*engine, path, snap_name, 0, mix_template);
2802 /* this one is special */
2804 catch (AudioEngine::PortRegistrationFailure& err) {
2806 MessageDialog msg (err.what(),
2809 Gtk::BUTTONS_CLOSE);
2811 msg.set_title (_("Port Registration Error"));
2812 msg.set_secondary_text (_("Click the Close button to try again."));
2813 msg.set_position (Gtk::WIN_POS_CENTER);
2817 int response = msg.run ();
2822 case RESPONSE_CANCEL:
2832 MessageDialog msg (string_compose(
2833 _("Session \"%1 (snapshot %2)\" did not load successfully"),
2839 msg.set_title (_("Loading Error"));
2840 msg.set_secondary_text (_("Click the Refresh button to try again."));
2841 msg.add_button (Stock::REFRESH, 1);
2842 msg.set_position (Gtk::WIN_POS_CENTER);
2846 int response = msg.run ();
2861 list<string> const u = new_session->unknown_processors ();
2863 MissingPluginDialog d (_session, u);
2868 /* Now the session been created, add the transport controls */
2869 new_session->add_controllable(roll_controllable);
2870 new_session->add_controllable(stop_controllable);
2871 new_session->add_controllable(goto_start_controllable);
2872 new_session->add_controllable(goto_end_controllable);
2873 new_session->add_controllable(auto_loop_controllable);
2874 new_session->add_controllable(play_selection_controllable);
2875 new_session->add_controllable(rec_controllable);
2877 set_session (new_session);
2879 session_loaded = true;
2881 goto_editor_window ();
2884 _session->set_clean ();
2895 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
2897 Session *new_session;
2900 if (!check_audioengine()) {
2904 session_loaded = false;
2906 x = unload_session ();
2914 _session_is_new = true;
2917 new_session = new Session (*engine, path, snap_name, &bus_profile);
2922 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
2928 /* Give the new session the default GUI state, if such things exist */
2931 n = Config->instant_xml (X_("Editor"));
2933 new_session->add_instant_xml (*n, false);
2935 n = Config->instant_xml (X_("Mixer"));
2937 new_session->add_instant_xml (*n, false);
2940 /* Put the playhead at 0 and scroll fully left */
2941 n = new_session->instant_xml (X_("Editor"));
2943 n->add_property (X_("playhead"), X_("0"));
2944 n->add_property (X_("left-frame"), X_("0"));
2947 set_session (new_session);
2949 session_loaded = true;
2951 new_session->save_state(new_session->name());
2957 ARDOUR_UI::launch_chat ()
2960 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
2962 open_uri("http://webchat.freenode.net/?channels=ardour");
2967 ARDOUR_UI::show_about ()
2971 about->signal_response().connect(sigc::mem_fun (*this, &ARDOUR_UI::about_signal_response) );
2974 about->set_transient_for(*editor);
2979 ARDOUR_UI::launch_manual ()
2981 PBD::open_uri("http://ardour.org/flossmanual");
2985 ARDOUR_UI::launch_reference ()
2987 PBD::open_uri("http://ardour.org/refmanual");
2991 ARDOUR_UI::hide_about ()
2994 about->get_window()->set_cursor ();
3000 ARDOUR_UI::about_signal_response (int /*response*/)
3006 ARDOUR_UI::show_splash ()
3010 splash = new Splash;
3018 splash->queue_draw ();
3019 splash->get_window()->process_updates (true);
3024 ARDOUR_UI::hide_splash ()
3032 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title,
3033 const string& plural_msg, const string& singular_msg)
3037 removed = rep.paths.size();
3040 MessageDialog msgd (*editor,
3041 _("No files were ready for clean-up"),
3044 (Gtk::ButtonsType)(Gtk::BUTTONS_OK) );
3045 msgd.set_title (_("Clean-up"));
3046 msgd.set_secondary_text (_("If this seems suprising, \n\
3047 check for any existing snapshots.\n\
3048 These may still include regions that\n\
3049 require some unused files to continue to exist."));
3055 ArdourDialog results (_("Clean-up"), true, false);
3057 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
3058 CleanupResultsModelColumns() {
3062 Gtk::TreeModelColumn<std::string> visible_name;
3063 Gtk::TreeModelColumn<std::string> fullpath;
3067 CleanupResultsModelColumns results_columns;
3068 Glib::RefPtr<Gtk::ListStore> results_model;
3069 Gtk::TreeView results_display;
3071 results_model = ListStore::create (results_columns);
3072 results_display.set_model (results_model);
3073 results_display.append_column (list_title, results_columns.visible_name);
3075 results_display.set_name ("CleanupResultsList");
3076 results_display.set_headers_visible (true);
3077 results_display.set_headers_clickable (false);
3078 results_display.set_reorderable (false);
3080 Gtk::ScrolledWindow list_scroller;
3083 Gtk::HBox dhbox; // the hbox for the image and text
3084 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
3085 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
3087 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
3089 const string dead_directory = _session->session_directory().dead_path().to_string();
3092 %1 - number of files removed
3093 %2 - location of "dead"
3094 %3 - size of files affected
3095 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
3098 const char* bprefix;
3099 double space_adjusted = 0;
3101 if (rep.space < 1000) {
3103 space_adjusted = rep.space;
3104 } else if (rep.space < 1000000) {
3105 bprefix = X_("kilo");
3106 space_adjusted = truncf((float)rep.space / 1000.0);
3107 } else if (rep.space < 1000000 * 1000) {
3108 bprefix = X_("mega");
3109 space_adjusted = truncf((float)rep.space / (1000.0 * 1000.0));
3111 bprefix = X_("giga");
3112 space_adjusted = truncf((float)rep.space / (1000.0 * 1000 * 1000.0));
3116 txt.set_text (string_compose (plural_msg, removed, dead_directory, space_adjusted, bprefix));
3118 txt.set_text (string_compose (singular_msg, removed, dead_directory, space_adjusted, bprefix));
3121 dhbox.pack_start (*dimage, true, false, 5);
3122 dhbox.pack_start (txt, true, false, 5);
3124 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
3125 TreeModel::Row row = *(results_model->append());
3126 row[results_columns.visible_name] = *i;
3127 row[results_columns.fullpath] = *i;
3130 list_scroller.add (results_display);
3131 list_scroller.set_size_request (-1, 150);
3132 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
3134 dvbox.pack_start (dhbox, true, false, 5);
3135 dvbox.pack_start (list_scroller, true, false, 5);
3136 ddhbox.pack_start (dvbox, true, false, 5);
3138 results.get_vbox()->pack_start (ddhbox, true, false, 5);
3139 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
3140 results.set_default_response (RESPONSE_CLOSE);
3141 results.set_position (Gtk::WIN_POS_MOUSE);
3143 results_display.show();
3144 list_scroller.show();
3151 //results.get_vbox()->show();
3152 results.set_resizable (false);
3159 ARDOUR_UI::cleanup ()
3161 if (_session == 0) {
3162 /* shouldn't happen: menu item is insensitive */
3167 MessageDialog checker (_("Are you sure you want to clean-up?"),
3169 Gtk::MESSAGE_QUESTION,
3170 (Gtk::ButtonsType)(Gtk::BUTTONS_NONE));
3172 checker.set_title (_("Clean-up"));
3174 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
3175 ALL undo/redo information will be lost if you clean-up.\n\
3176 Clean-up will move all unused files to a \"dead\" location."));
3178 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3179 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
3180 checker.set_default_response (RESPONSE_CANCEL);
3182 checker.set_name (_("CleanupDialog"));
3183 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3184 checker.set_position (Gtk::WIN_POS_MOUSE);
3186 switch (checker.run()) {
3187 case RESPONSE_ACCEPT:
3193 ARDOUR::CleanupReport rep;
3195 editor->prepare_for_cleanup ();
3197 /* do not allow flush until a session is reloaded */
3199 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3201 act->set_sensitive (false);
3204 if (_session->cleanup_sources (rep)) {
3205 editor->finish_cleanup ();
3209 editor->finish_cleanup ();
3212 display_cleanup_results (rep,
3215 The following %1 files were not in use and \n\
3216 have been moved to:\n\n\
3218 After a restart of Ardour,\n\n\
3219 Session -> Clean-up -> Flush Wastebasket\n\n\
3220 will release an additional\n\
3221 %3 %4bytes of disk space.\n"),
3223 The following file was not in use and \n\
3224 has been moved to:\n \
3226 After a restart of Ardour,\n\n\
3227 Session -> Clean-up -> Flush Wastebasket\n\n\
3228 will release an additional\n\
3229 %3 %4bytes of disk space.\n"
3235 ARDOUR_UI::flush_trash ()
3237 if (_session == 0) {
3238 /* shouldn't happen: menu item is insensitive */
3242 ARDOUR::CleanupReport rep;
3244 if (_session->cleanup_trash_sources (rep)) {
3248 display_cleanup_results (rep,
3250 _("The following %1 files were deleted from\n\
3252 releasing %3 %4bytes of disk space"),
3253 _("The following file was deleted from\n\
3255 releasing %3 %4bytes of disk space"));
3259 ARDOUR_UI::add_route (Gtk::Window* float_window)
3267 if (add_route_dialog == 0) {
3268 add_route_dialog = new AddRouteDialog (_session);
3270 add_route_dialog->set_transient_for (*float_window);
3274 if (add_route_dialog->is_visible()) {
3275 /* we're already doing this */
3279 ResponseType r = (ResponseType) add_route_dialog->run ();
3281 add_route_dialog->hide();
3284 case RESPONSE_ACCEPT:
3291 if ((count = add_route_dialog->count()) <= 0) {
3295 string template_path = add_route_dialog->track_template();
3297 if (!template_path.empty()) {
3298 _session->new_route_from_template (count, template_path);
3302 uint32_t input_chan = add_route_dialog->channels ();
3303 uint32_t output_chan;
3304 string name_template = add_route_dialog->name_template ();
3305 bool track = add_route_dialog->track ();
3306 RouteGroup* route_group = add_route_dialog->route_group ();
3308 AutoConnectOption oac = Config->get_output_auto_connect();
3310 if (oac & AutoConnectMaster) {
3311 output_chan = (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan);
3313 output_chan = input_chan;
3316 /* XXX do something with name template */
3318 if (add_route_dialog->type() == ARDOUR::DataType::MIDI) {
3320 session_add_midi_track (route_group, count, name_template);
3322 MessageDialog msg (*editor,
3323 _("Sorry, MIDI Busses are not supported at this time."));
3325 //session_add_midi_bus();
3329 session_add_audio_track (input_chan, output_chan, add_route_dialog->mode(), route_group, count, name_template);
3331 session_add_audio_bus (input_chan, output_chan, route_group, count, name_template);
3337 ARDOUR_UI::mixer_settings () const
3342 node = _session->instant_xml(X_("Mixer"));
3344 node = Config->instant_xml(X_("Mixer"));
3348 node = new XMLNode (X_("Mixer"));
3355 ARDOUR_UI::editor_settings () const
3360 node = _session->instant_xml(X_("Editor"));
3362 node = Config->instant_xml(X_("Editor"));
3366 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
3367 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
3372 node = new XMLNode (X_("Editor"));
3379 ARDOUR_UI::keyboard_settings () const
3383 node = Config->extra_xml(X_("Keyboard"));
3386 node = new XMLNode (X_("Keyboard"));
3393 ARDOUR_UI::create_xrun_marker (framepos_t where)
3395 editor->mouse_add_new_marker (where, false, true);
3399 ARDOUR_UI::halt_on_xrun_message ()
3401 MessageDialog msg (*editor,
3402 _("Recording was stopped because your system could not keep up."));
3407 ARDOUR_UI::xrun_handler (framepos_t where)
3413 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
3415 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
3416 create_xrun_marker(where);
3419 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
3420 halt_on_xrun_message ();
3425 ARDOUR_UI::disk_overrun_handler ()
3427 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
3429 if (!have_disk_speed_dialog_displayed) {
3430 have_disk_speed_dialog_displayed = true;
3431 MessageDialog* msg = new MessageDialog (*editor, string_compose (_("\
3432 The disk system on your computer\n\
3433 was not able to keep up with %1.\n\
3435 Specifically, it failed to write data to disk\n\
3436 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
3437 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3443 ARDOUR_UI::disk_underrun_handler ()
3445 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
3447 if (!have_disk_speed_dialog_displayed) {
3448 have_disk_speed_dialog_displayed = true;
3449 MessageDialog* msg = new MessageDialog (
3450 *editor, string_compose (_("The disk system on your computer\n\
3451 was not able to keep up with %1.\n\
3453 Specifically, it failed to read data from disk\n\
3454 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
3455 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3461 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
3463 have_disk_speed_dialog_displayed = false;
3468 ARDOUR_UI::session_dialog (std::string msg)
3470 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
3475 d = new MessageDialog (*editor, msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3477 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3486 ARDOUR_UI::pending_state_dialog ()
3488 HBox* hbox = new HBox();
3489 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3490 ArdourDialog dialog (_("Crash Recovery"), true);
3492 This session appears to have been in\n\
3493 middle of recording when ardour or\n\
3494 the computer was shutdown.\n\
3496 Ardour can recover any captured audio for\n\
3497 you, or it can ignore it. Please decide\n\
3498 what you would like to do.\n"));
3499 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3500 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3501 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3502 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3503 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
3504 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
3505 dialog.set_default_response (RESPONSE_ACCEPT);
3506 dialog.set_position (WIN_POS_CENTER);
3511 switch (dialog.run ()) {
3512 case RESPONSE_ACCEPT:
3520 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
3522 HBox* hbox = new HBox();
3523 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3524 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
3525 Label message (string_compose (_("\
3526 This session was created with a sample rate of %1 Hz\n\
3528 The audioengine is currently running at %2 Hz\n"), desired, actual));
3530 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3531 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3532 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3533 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3534 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
3535 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
3536 dialog.set_default_response (RESPONSE_ACCEPT);
3537 dialog.set_position (WIN_POS_CENTER);
3542 switch (dialog.run ()) {
3543 case RESPONSE_ACCEPT:
3552 ARDOUR_UI::disconnect_from_jack ()
3555 if( engine->disconnect_from_jack ()) {
3556 MessageDialog msg (*editor, _("Could not disconnect from JACK"));
3560 update_sample_rate (0);
3565 ARDOUR_UI::reconnect_to_jack ()
3568 if (engine->reconnect_to_jack ()) {
3569 MessageDialog msg (*editor, _("Could not reconnect to JACK"));
3573 update_sample_rate (0);
3578 ARDOUR_UI::use_config ()
3580 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
3582 set_transport_controllable_state (*node);
3587 ARDOUR_UI::update_transport_clocks (framepos_t pos)
3589 if (Config->get_primary_clock_delta_edit_cursor()) {
3590 primary_clock->set (pos, false, editor->get_preferred_edit_position(), 1);
3592 primary_clock->set (pos, 0, true);
3595 if (Config->get_secondary_clock_delta_edit_cursor()) {
3596 secondary_clock->set (pos, false, editor->get_preferred_edit_position(), 2);
3598 secondary_clock->set (pos);
3601 if (big_clock_window->get()) {
3602 big_clock->set (pos);
3608 ARDOUR_UI::step_edit_status_change (bool yn)
3610 // XXX should really store pre-step edit status of things
3611 // we make insensitive
3614 rec_button.set_active_state (Mid);
3615 rec_button.set_sensitive (false);
3617 rec_button.unset_active_state ();;
3618 rec_button.set_sensitive (true);
3623 ARDOUR_UI::record_state_changed ()
3625 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
3627 if (!_session || !big_clock_window->get()) {
3628 /* why bother - the clock isn't visible */
3632 Session::RecordState const r = _session->record_status ();
3633 bool const h = _session->have_rec_enabled_track ();
3635 if (r == Session::Recording && h) {
3636 big_clock->set_widget_name ("BigClockRecording");
3638 big_clock->set_widget_name ("BigClockNonRecording");
3643 ARDOUR_UI::first_idle ()
3646 _session->allow_auto_play (true);
3650 editor->first_idle();
3653 Keyboard::set_can_save_keybindings (true);
3658 ARDOUR_UI::store_clock_modes ()
3660 XMLNode* node = new XMLNode(X_("ClockModes"));
3662 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
3663 XMLNode* child = new XMLNode (X_("Clock"));
3665 child->add_property (X_("name"), (*x)->name());
3666 child->add_property (X_("mode"), enum_2_string ((*x)->mode()));
3667 child->add_property (X_("on"), ((*x)->off() ? X_("no") : X_("yes")));
3669 node->add_child_nocopy (*child);
3672 _session->add_extra_xml (*node);
3673 _session->set_dirty ();
3676 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
3677 : Controllable (name), ui (u), type(tp)
3683 ARDOUR_UI::TransportControllable::set_value (double val)
3686 /* do nothing: these are radio-style actions */
3690 const char *action = 0;
3694 action = X_("Roll");
3697 action = X_("Stop");
3700 action = X_("Goto Start");
3703 action = X_("Goto End");
3706 action = X_("Loop");
3709 action = X_("Play Selection");
3712 action = X_("Record");
3722 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
3730 ARDOUR_UI::TransportControllable::get_value (void) const
3757 ARDOUR_UI::setup_profile ()
3759 if (gdk_screen_width() < 1200) {
3760 Profile->set_small_screen ();
3764 if (getenv ("ARDOUR_SAE")) {
3765 Profile->set_sae ();
3766 Profile->set_single_package ();
3771 ARDOUR_UI::toggle_translations ()
3773 using namespace Glib;
3775 RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("EnableTranslation"));
3777 RefPtr<ToggleAction> ract = RefPtr<ToggleAction>::cast_dynamic (act);
3780 string i18n_killer = ARDOUR::translation_kill_path();
3782 bool already_enabled = !ARDOUR::translations_are_disabled ();
3784 if (ract->get_active ()) {
3785 /* we don't care about errors */
3786 int fd = ::open (i18n_killer.c_str(), O_RDONLY|O_CREAT, 0644);
3789 /* we don't care about errors */
3790 unlink (i18n_killer.c_str());
3793 if (already_enabled != ract->get_active()) {
3794 MessageDialog win (already_enabled ? _("Translations disabled") : _("Translations enabled"),
3796 Gtk::MESSAGE_WARNING,
3798 win.set_secondary_text (string_compose (_("You must restart %1 for this to take effect."), PROGRAM_NAME));
3799 win.set_position (Gtk::WIN_POS_CENTER);
3807 /** Add a window proxy to our list, so that its state will be saved.
3808 * This call also causes the window to be created and opened if its
3809 * state was saved as `visible'.
3812 ARDOUR_UI::add_window_proxy (WindowProxyBase* p)
3814 _window_proxies.push_back (p);
3818 /** Remove a window proxy from our list. Must be called if a WindowProxy
3819 * is deleted, to prevent hanging pointers.
3822 ARDOUR_UI::remove_window_proxy (WindowProxyBase* p)
3824 _window_proxies.remove (p);
3828 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
3830 MissingFileDialog dialog (s, str, type);
3835 int result = dialog.run ();
3842 return 1; // quit entire session load
3845 result = dialog.get_action ();
3851 ARDOUR_UI::ambiguous_file (std::string file, std::string /*path*/, std::vector<std::string> hits)
3853 AmbiguousFileDialog dialog (file, hits);
3859 return dialog.get_which ();
3862 /** Allocate our thread-local buffers */
3864 ARDOUR_UI::get_process_buffers ()
3866 _process_thread->get_buffers ();
3869 /** Drop our thread-local buffers */
3871 ARDOUR_UI::drop_process_buffers ()
3873 _process_thread->drop_buffers ();