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"
82 typedef uint64_t microseconds_t;
86 #include "add_route_dialog.h"
87 #include "ambiguous_file_dialog.h"
88 #include "ardour_ui.h"
89 #include "audio_clock.h"
90 #include "bundle_manager.h"
91 #include "engine_dialog.h"
92 #include "gain_meter.h"
93 #include "global_port_matrix.h"
94 #include "gui_object.h"
95 #include "gui_thread.h"
97 #include "location_ui.h"
98 #include "missing_file_dialog.h"
99 #include "missing_plugin_dialog.h"
100 #include "mixer_ui.h"
102 #include "processor_box.h"
103 #include "prompter.h"
104 #include "public_editor.h"
105 #include "route_time_axis.h"
106 #include "session_metadata_dialog.h"
107 #include "shuttle_control.h"
108 #include "speaker_dialog.h"
111 #include "theme_manager.h"
112 #include "time_axis_view_item.h"
114 #include "window_proxy.h"
118 using namespace ARDOUR;
120 using namespace Gtkmm2ext;
123 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
124 UIConfiguration *ARDOUR_UI::ui_config = 0;
126 sigc::signal<void,bool> ARDOUR_UI::Blink;
127 sigc::signal<void> ARDOUR_UI::RapidScreenUpdate;
128 sigc::signal<void> ARDOUR_UI::SuperRapidScreenUpdate;
129 sigc::signal<void, framepos_t, bool, framepos_t> ARDOUR_UI::Clock;
131 bool could_be_a_valid_path (const string& path);
133 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[])
135 : Gtkmm2ext::UI (PROGRAM_NAME, argcp, argvp)
137 , gui_object_state (new GUIObjectState)
138 , primary_clock (new AudioClock (X_("primary"), false, X_("TransportClockDisplay"), true, true, false, true))
139 , secondary_clock (new AudioClock (X_("secondary"), false, X_("SecondaryClockDisplay"), true, true, false, true))
140 , preroll_clock (new AudioClock (X_("preroll"), false, X_("PreRollClock"), true, false, true))
141 , postroll_clock (new AudioClock (X_("postroll"), false, X_("PostRollClock"), true, false, true))
145 , preroll_button (_("pre\nroll"))
146 , postroll_button (_("post\nroll"))
150 , big_clock (new AudioClock (X_("bigclock"), false, "BigClockNonRecording", true, true, false, false))
154 , roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll))
155 , stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop))
156 , goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart))
157 , goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd))
158 , auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop))
159 , play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection))
160 , rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable))
162 , roll_button (roll_controllable)
163 , stop_button (stop_controllable)
164 , goto_start_button (goto_start_controllable)
165 , goto_end_button (goto_end_controllable)
166 , auto_loop_button (auto_loop_controllable)
167 , play_selection_button (play_selection_controllable)
168 , rec_button (rec_controllable)
170 , auto_return_button (_("Auto Return"))
171 , auto_play_button (_("Auto Play"))
172 , auto_input_button (_("Auto Input"))
173 // , click_button (_("Click"))
174 , time_master_button (_("time\nmaster"))
176 , auditioning_alert_button (_("AUDITION"))
177 , solo_alert_button (_("SOLO"))
179 , error_log_button (_("Errors"))
182 using namespace Gtk::Menu_Helpers;
188 // _auto_display_errors = false;
190 * This was commented out as it wasn't defined
191 * in A3 IIRC. If this is not needed it should
192 * be completely removed.
200 if (theArdourUI == 0) {
204 ui_config = new UIConfiguration();
205 theme_manager = new ThemeManager();
213 _session_is_new = false;
214 big_clock_window = 0;
215 big_clock_height = 0;
216 big_clock_resize_in_progress = false;
217 session_selector_window = 0;
218 last_key_press_time = 0;
219 _will_create_new_session_automatically = false;
220 add_route_dialog = 0;
223 rc_option_editor = 0;
224 session_option_editor = 0;
226 open_session_selector = 0;
227 have_configure_timeout = false;
228 have_disk_speed_dialog_displayed = false;
229 session_loaded = false;
230 ignore_dual_punch = false;
231 original_big_clock_width = -1;
232 original_big_clock_height = -1;
233 original_big_clock_font_size = 0;
235 roll_button.unset_flags (Gtk::CAN_FOCUS);
236 stop_button.unset_flags (Gtk::CAN_FOCUS);
237 goto_start_button.unset_flags (Gtk::CAN_FOCUS);
238 goto_end_button.unset_flags (Gtk::CAN_FOCUS);
239 auto_loop_button.unset_flags (Gtk::CAN_FOCUS);
240 play_selection_button.unset_flags (Gtk::CAN_FOCUS);
241 rec_button.unset_flags (Gtk::CAN_FOCUS);
242 join_play_range_button.unset_flags (Gtk::CAN_FOCUS);
243 last_configure_time= 0;
246 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
247 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
249 /* handle dialog requests */
251 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
253 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
255 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
257 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
259 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
261 /* handle requests to quit (coming from JACK session) */
263 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::finish, this), gui_context ());
265 /* handle requests to deal with missing files */
267 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
269 /* and ambiguous files */
271 ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2, _3));
273 /* lets get this party started */
276 if (ARDOUR::init (ARDOUR_COMMAND_LINE::use_vst, ARDOUR_COMMAND_LINE::try_hw_optimization)) {
277 throw failed_constructor ();
280 setup_gtk_ardour_enums ();
283 GainMeter::setup_slider_pix ();
284 RouteTimeAxisView::setup_slider_pix ();
285 SendProcessorEntry::setup_slider_pix ();
286 SessionEvent::create_per_thread_pool ("GUI", 512);
288 } catch (failed_constructor& err) {
289 error << string_compose (_("could not initialize %1."), PROGRAM_NAME) << endmsg;
294 /* we like keyboards */
296 keyboard = new ArdourKeyboard(*this);
298 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
300 keyboard->set_state (*node, Stateful::loading_state_version);
303 /* we don't like certain modifiers */
304 Bindings::set_ignored_state (GDK_LOCK_MASK|GDK_MOD2_MASK|GDK_MOD3_MASK);
308 TimeAxisViewItem::set_constant_heights ();
310 /* The following must happen after ARDOUR::init() so that Config is set up */
312 location_ui = new ActionWindowProxy<LocationUIWindow> (X_("locations"), Config->extra_xml (X_("UI")), X_("ToggleLocations"));
313 big_clock_window = new ActionWindowProxy<Gtk::Window> (X_("bigclock"), Config->extra_xml (X_("UI")), X_("ToggleBigClock"));
314 speaker_config_window = new ActionWindowProxy<SpeakerDialog> (X_("speakerconf"), Config->extra_xml (X_("UI")), X_("toggle-speaker-config"));
316 for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) {
317 _global_port_matrix[*i] = new ActionWindowProxy<GlobalPortMatrixWindow> (
318 string_compose ("GlobalPortMatrix-%1", (*i).to_string()),
319 Config->extra_xml (X_("UI")),
320 string_compose ("toggle-%1-connection-manager", (*i).to_string())
326 SpeakerDialog* s = new SpeakerDialog ();
327 s->signal_unmap().connect (sigc::bind (sigc::ptr_fun (&ActionManager::uncheck_toggleaction), X_("<Actions>/Common/toggle-speaker-config")));
328 speaker_config_window->set (s);
330 starting.connect (sigc::mem_fun(*this, &ARDOUR_UI::startup));
331 stopping.connect (sigc::mem_fun(*this, &ARDOUR_UI::shutdown));
334 /** @return true if a session was chosen and `apply' clicked, otherwise false if `cancel' was clicked */
336 ARDOUR_UI::run_startup (bool should_be_new, string load_template)
339 _startup = new ArdourStartup ();
341 XMLNode* audio_setup = Config->extra_xml ("AudioSetup");
343 if (audio_setup && _startup->engine_control()) {
344 _startup->engine_control()->set_state (*audio_setup);
347 _startup->set_new_only (should_be_new);
348 if (!load_template.empty()) {
349 _startup->set_load_template( load_template );
351 _startup->present ();
357 switch (_startup->response()) {
366 ARDOUR_UI::create_engine ()
368 // this gets called every time by new_session()
374 loading_message (_("Starting audio engine"));
377 engine = new ARDOUR::AudioEngine (ARDOUR_COMMAND_LINE::jack_client_name, ARDOUR_COMMAND_LINE::jack_session_uuid);
384 engine->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
385 engine->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
386 engine->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
388 engine->Halted.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
390 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
398 ARDOUR_UI::post_engine ()
400 /* Things to be done once we create the AudioEngine
403 ARDOUR::init_post_engine ();
405 ActionManager::init ();
408 if (setup_windows ()) {
409 throw failed_constructor ();
412 check_memory_locking();
414 /* this is the first point at which all the keybindings are available */
416 if (ARDOUR_COMMAND_LINE::show_key_actions) {
417 vector<string> names;
418 vector<string> paths;
419 vector<string> tooltips;
421 vector<AccelKey> bindings;
423 ActionManager::get_all_actions (names, paths, tooltips, keys, bindings);
425 vector<string>::iterator n;
426 vector<string>::iterator k;
427 for (n = names.begin(), k = keys.begin(); n != names.end(); ++n, ++k) {
428 cerr << "Action: " << (*n) << " bound to " << (*k) << endl;
434 blink_timeout_tag = -1;
436 /* this being a GUI and all, we want peakfiles */
438 AudioFileSource::set_build_peakfiles (true);
439 AudioFileSource::set_build_missing_peakfiles (true);
441 /* set default clock modes */
443 if (Profile->get_sae()) {
444 primary_clock->set_mode (AudioClock::BBT);
445 secondary_clock->set_mode (AudioClock::MinSec);
447 primary_clock->set_mode (AudioClock::Timecode);
448 secondary_clock->set_mode (AudioClock::BBT);
451 /* start the time-of-day-clock */
454 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
455 update_wall_clock ();
456 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 60000);
459 update_disk_space ();
461 update_sample_rate (engine->frame_rate());
463 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
464 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
465 Config->map_parameters (pc);
467 /* now start and maybe save state */
469 if (do_engine_start () == 0) {
470 if (_session && _session_is_new) {
471 /* we need to retain initial visual
472 settings for a new session
474 _session->save_state ("");
479 ARDOUR_UI::~ARDOUR_UI ()
484 delete add_route_dialog;
488 ARDOUR_UI::pop_back_splash ()
490 if (Splash::instance()) {
491 // Splash::instance()->pop_back();
492 Splash::instance()->hide ();
497 ARDOUR_UI::configure_timeout ()
499 if (last_configure_time == 0) {
500 /* no configure events yet */
504 /* force a gap of 0.5 seconds since the last configure event
507 if (get_microseconds() - last_configure_time < 500000) {
510 have_configure_timeout = false;
511 cerr << "config event-driven save\n";
512 save_ardour_state ();
518 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
520 if (have_configure_timeout) {
521 last_configure_time = get_microseconds();
523 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
524 have_configure_timeout = true;
531 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
533 const XMLProperty* prop;
535 if ((prop = node.property ("roll")) != 0) {
536 roll_controllable->set_id (prop->value());
538 if ((prop = node.property ("stop")) != 0) {
539 stop_controllable->set_id (prop->value());
541 if ((prop = node.property ("goto-start")) != 0) {
542 goto_start_controllable->set_id (prop->value());
544 if ((prop = node.property ("goto-end")) != 0) {
545 goto_end_controllable->set_id (prop->value());
547 if ((prop = node.property ("auto-loop")) != 0) {
548 auto_loop_controllable->set_id (prop->value());
550 if ((prop = node.property ("play-selection")) != 0) {
551 play_selection_controllable->set_id (prop->value());
553 if ((prop = node.property ("rec")) != 0) {
554 rec_controllable->set_id (prop->value());
556 if ((prop = node.property ("shuttle")) != 0) {
557 shuttle_box->controllable()->set_id (prop->value());
563 ARDOUR_UI::get_transport_controllable_state ()
565 XMLNode* node = new XMLNode(X_("TransportControllables"));
568 roll_controllable->id().print (buf, sizeof (buf));
569 node->add_property (X_("roll"), buf);
570 stop_controllable->id().print (buf, sizeof (buf));
571 node->add_property (X_("stop"), buf);
572 goto_start_controllable->id().print (buf, sizeof (buf));
573 node->add_property (X_("goto_start"), buf);
574 goto_end_controllable->id().print (buf, sizeof (buf));
575 node->add_property (X_("goto_end"), buf);
576 auto_loop_controllable->id().print (buf, sizeof (buf));
577 node->add_property (X_("auto_loop"), buf);
578 play_selection_controllable->id().print (buf, sizeof (buf));
579 node->add_property (X_("play_selection"), buf);
580 rec_controllable->id().print (buf, sizeof (buf));
581 node->add_property (X_("rec"), buf);
582 shuttle_box->controllable()->id().print (buf, sizeof (buf));
583 node->add_property (X_("shuttle"), buf);
590 ARDOUR_UI::autosave_session ()
592 if (g_main_depth() > 1) {
593 /* inside a recursive main loop,
594 give up because we may not be able to
600 if (!Config->get_periodic_safety_backups()) {
605 _session->maybe_write_autosave();
612 ARDOUR_UI::update_autosave ()
614 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_autosave)
616 if (_session && _session->dirty()) {
617 if (_autosave_connection.connected()) {
618 _autosave_connection.disconnect();
621 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
622 Config->get_periodic_safety_backup_interval() * 1000);
625 if (_autosave_connection.connected()) {
626 _autosave_connection.disconnect();
632 ARDOUR_UI::backend_audio_error (bool we_set_params, Gtk::Window* toplevel)
636 title = string_compose (_("%1 could not start JACK"), PROGRAM_NAME);
638 title = string_compose (_("%1 could not connect to JACK."), PROGRAM_NAME);
641 MessageDialog win (title,
647 win.set_secondary_text(_("There are several possible reasons:\n\
649 1) You requested audio parameters that are not supported..\n\
650 2) JACK is running as another user.\n\
652 Please consider the possibilities, and perhaps try different parameters."));
654 win.set_secondary_text(_("There are several possible reasons:\n\
656 1) JACK is not running.\n\
657 2) JACK is running as another user, perhaps root.\n\
658 3) There is already another client called \"ardour\".\n\
660 Please consider the possibilities, and perhaps (re)start JACK."));
664 win.set_transient_for (*toplevel);
668 win.add_button (Stock::OK, RESPONSE_CLOSE);
670 win.add_button (Stock::QUIT, RESPONSE_CLOSE);
673 win.set_default_response (RESPONSE_CLOSE);
676 win.set_position (Gtk::WIN_POS_CENTER);
679 /* we just don't care about the result, but we want to block */
685 ARDOUR_UI::startup ()
687 Application* app = Application::instance ();
689 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
690 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::idle_load));
693 call_the_mothership (VERSIONSTRING);
698 if (get_session_parameters (true, ARDOUR_COMMAND_LINE::new_session, ARDOUR_COMMAND_LINE::load_template)) {
704 goto_editor_window ();
706 /* Add the window proxies here; their addition may cause windows to be opened, and we want them
707 to be opened on top of the editor window that goto_editor_window() just opened.
709 add_window_proxy (location_ui);
710 add_window_proxy (big_clock_window);
711 for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) {
712 add_window_proxy (_global_port_matrix[*i]);
715 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
719 ARDOUR_UI::no_memory_warning ()
721 XMLNode node (X_("no-memory-warning"));
722 Config->add_instant_xml (node);
726 ARDOUR_UI::check_memory_locking ()
729 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
733 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
735 if (engine->is_realtime() && memory_warning_node == 0) {
737 struct rlimit limits;
739 long pages, page_size;
741 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0) {
744 ram = (int64_t) pages * (int64_t) page_size;
747 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
751 if (limits.rlim_cur != RLIM_INFINITY) {
753 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
757 _("WARNING: Your system has a limit for maximum amount of locked memory. "
758 "This might cause %1 to run out of memory before your system "
759 "runs out of memory. \n\n"
760 "You can view the memory limit with 'ulimit -l', "
761 "and it is normally controlled by /etc/security/limits.conf"),
762 PROGRAM_NAME).c_str());
764 VBox* vbox = msg.get_vbox();
766 CheckButton cb (_("Do not show this window again"));
768 cb.signal_toggled().connect (sigc::mem_fun (*this, &ARDOUR_UI::no_memory_warning));
770 hbox.pack_start (cb, true, false);
771 vbox->pack_start (hbox);
778 editor->ensure_float (msg);
788 ARDOUR_UI::queue_finish ()
790 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
794 ARDOUR_UI::idle_finish ()
797 return false; /* do not call again */
806 if (_session->transport_rolling() && (++tries < 8)) {
807 _session->request_stop (false, true);
811 if (_session->dirty()) {
812 vector<string> actions;
813 actions.push_back (_("Don't quit"));
814 actions.push_back (_("Just quit"));
815 actions.push_back (_("Save and quit"));
816 switch (ask_about_saving_session(actions)) {
821 /* use the default name */
822 if (save_state_canfail ("")) {
823 /* failed - don't quit */
824 MessageDialog msg (*editor,
826 Ardour was unable to save your session.\n\n\
827 If you still wish to quit, please use the\n\n\
828 \"Just quit\" option."));
839 second_connection.disconnect ();
840 point_one_second_connection.disconnect ();
841 point_oh_five_second_connection.disconnect ();
842 point_zero_one_second_connection.disconnect();
845 /* Save state before deleting the session, as that causes some
846 windows to be destroyed before their visible state can be
849 save_ardour_state ();
852 // _session->set_deletion_in_progress ();
853 _session->set_clean ();
854 _session->remove_pending_capture_state ();
859 ArdourDialog::close_all_dialogs ();
865 ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
867 ArdourDialog window (_("Unsaved Session"));
868 Gtk::HBox dhbox; // the hbox for the image and text
869 Gtk::Label prompt_label;
870 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
874 assert (actions.size() >= 3);
876 window.add_button (actions[0], RESPONSE_REJECT);
877 window.add_button (actions[1], RESPONSE_APPLY);
878 window.add_button (actions[2], RESPONSE_ACCEPT);
880 window.set_default_response (RESPONSE_ACCEPT);
882 Gtk::Button noquit_button (msg);
883 noquit_button.set_name ("EditorGTKButton");
887 if (_session->snap_name() == _session->name()) {
888 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?"),
889 _session->snap_name());
891 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?"),
892 _session->snap_name());
895 prompt_label.set_text (prompt);
896 prompt_label.set_name (X_("PrompterLabel"));
897 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
899 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
900 dhbox.set_homogeneous (false);
901 dhbox.pack_start (*dimage, false, false, 5);
902 dhbox.pack_start (prompt_label, true, false, 5);
903 window.get_vbox()->pack_start (dhbox);
905 window.set_name (_("Prompter"));
906 window.set_position (Gtk::WIN_POS_MOUSE);
907 window.set_modal (true);
908 window.set_resizable (false);
914 window.set_keep_above (true);
917 ResponseType r = (ResponseType) window.run();
922 case RESPONSE_ACCEPT: // save and get out of here
924 case RESPONSE_APPLY: // get out of here
934 ARDOUR_UI::every_second ()
937 update_buffer_load ();
938 update_disk_space ();
943 ARDOUR_UI::every_point_one_seconds ()
945 shuttle_box->update_speed_display ();
946 RapidScreenUpdate(); /* EMIT_SIGNAL */
951 ARDOUR_UI::every_point_zero_one_seconds ()
953 // august 2007: actual update frequency: 40Hz, not 100Hz
955 SuperRapidScreenUpdate(); /* EMIT_SIGNAL */
960 ARDOUR_UI::update_sample_rate (framecnt_t)
964 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
966 if (!engine->connected()) {
968 snprintf (buf, sizeof (buf), _("disconnected"));
972 framecnt_t rate = engine->frame_rate();
974 if (fmod (rate, 1000.0) != 0.0) {
975 snprintf (buf, sizeof (buf), _("JACK: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
976 (float) rate/1000.0f,
977 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
979 snprintf (buf, sizeof (buf), _("JACK: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
981 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
985 sample_rate_label.set_markup (buf);
989 ARDOUR_UI::update_format ()
992 format_label.set_text ("");
997 s << "File: <span foreground=\"green\">";
999 switch (_session->config.get_native_file_header_format ()) {
1025 switch (_session->config.get_native_file_data_format ()) {
1039 format_label.set_markup (s.str ());
1043 ARDOUR_UI::update_cpu_load ()
1047 float const c = engine->get_cpu_load ();
1048 snprintf (buf, sizeof (buf), _("DSP: <span foreground=\"%s\">%5.1f%%</span>"), c >= 90 ? X_("red") : X_("green"), c_);
1049 cpu_load_label.set_markup (buf);
1053 ARDOUR_UI::update_buffer_load ()
1057 uint32_t const playback = _session ? _session->playback_load () : 100;
1058 uint32_t const capture = _session ? _session->capture_load () : 100;
1063 _("Buffers: <span foreground=\"green\">p:</span><span foreground=\"%s\">%" PRIu32 "%%</span> "
1064 "<span foreground=\"green\">c:</span><span foreground=\"%s\">%" PRIu32 "%%</span>"),
1065 playback <= 5 ? X_("red") : X_("green"),
1067 capture <= 5 ? X_("red") : X_("green"),
1071 buffer_load_label.set_markup (buf);
1073 buffer_load_label.set_text ("");
1078 ARDOUR_UI::count_recenabled_streams (Route& route)
1080 Track* track = dynamic_cast<Track*>(&route);
1081 if (track && track->record_enabled()) {
1082 rec_enabled_streams += track->n_inputs().n_total();
1087 ARDOUR_UI::update_disk_space()
1089 if (_session == 0) {
1093 framecnt_t frames = _session->available_capture_duration();
1095 framecnt_t fr = _session->frame_rate();
1097 if (frames == max_framecnt) {
1098 snprintf (buf, sizeof (buf), _("Disk: <span foreground=\"green\">24hrs+</span>"));
1100 rec_enabled_streams = 0;
1101 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams);
1103 if (rec_enabled_streams) {
1104 frames /= rec_enabled_streams;
1111 hrs = frames / (fr * 3600);
1112 frames -= hrs * fr * 3600;
1113 mins = frames / (fr * 60);
1114 frames -= mins * fr * 60;
1117 bool const low = (hrs == 0 && mins <= 30);
1121 _("Disk: <span foreground=\"%s\">%02dh:%02dm:%02ds</span>"),
1122 low ? X_("red") : X_("green"),
1127 disk_space_label.set_markup (buf);
1129 // An attempt to make the disk space label flash red when space has run out.
1131 if (frames < fr * 60 * 5) {
1132 /* disk_space_box.style ("disk_space_label_empty"); */
1134 /* disk_space_box.style ("disk_space_label"); */
1140 ARDOUR_UI::update_wall_clock ()
1147 tm_now = localtime (&now);
1149 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1150 wall_clock_label.set_text (buf);
1156 ARDOUR_UI::session_menu (GdkEventButton */*ev*/)
1158 session_popup_menu->popup (0, 0);
1163 ARDOUR_UI::redisplay_recent_sessions ()
1165 std::vector<sys::path> session_directories;
1166 RecentSessionsSorter cmp;
1168 recent_session_display.set_model (Glib::RefPtr<TreeModel>(0));
1169 recent_session_model->clear ();
1171 ARDOUR::RecentSessions rs;
1172 ARDOUR::read_recent_sessions (rs);
1175 recent_session_display.set_model (recent_session_model);
1179 // sort them alphabetically
1180 sort (rs.begin(), rs.end(), cmp);
1182 for (ARDOUR::RecentSessions::iterator i = rs.begin(); i != rs.end(); ++i) {
1183 session_directories.push_back ((*i).second);
1186 for (vector<sys::path>::const_iterator i = session_directories.begin();
1187 i != session_directories.end(); ++i)
1189 std::vector<sys::path> state_file_paths;
1191 // now get available states for this session
1193 get_state_files_in_directory (*i, state_file_paths);
1195 vector<string*>* states;
1196 vector<const gchar*> item;
1197 string fullpath = (*i).to_string();
1199 /* remove any trailing / */
1201 if (fullpath[fullpath.length()-1] == '/') {
1202 fullpath = fullpath.substr (0, fullpath.length()-1);
1205 /* check whether session still exists */
1206 if (!Glib::file_test(fullpath.c_str(), Glib::FILE_TEST_EXISTS)) {
1207 /* session doesn't exist */
1208 cerr << "skipping non-existent session " << fullpath << endl;
1212 /* now get available states for this session */
1214 if ((states = Session::possible_states (fullpath)) == 0) {
1215 /* no state file? */
1219 std::vector<string> state_file_names(get_file_names_no_extension (state_file_paths));
1221 Gtk::TreeModel::Row row = *(recent_session_model->append());
1223 row[recent_session_columns.visible_name] = Glib::path_get_basename (fullpath);
1224 row[recent_session_columns.fullpath] = fullpath;
1226 if (state_file_names.size() > 1) {
1230 for (std::vector<std::string>::iterator i2 = state_file_names.begin();
1231 i2 != state_file_names.end(); ++i2)
1234 Gtk::TreeModel::Row child_row = *(recent_session_model->append (row.children()));
1236 child_row[recent_session_columns.visible_name] = *i2;
1237 child_row[recent_session_columns.fullpath] = fullpath;
1242 recent_session_display.set_model (recent_session_model);
1246 ARDOUR_UI::build_session_selector ()
1248 session_selector_window = new ArdourDialog (_("Recent Sessions"));
1250 Gtk::ScrolledWindow *scroller = manage (new Gtk::ScrolledWindow);
1252 session_selector_window->add_button (Stock::CANCEL, RESPONSE_CANCEL);
1253 session_selector_window->add_button (Stock::OPEN, RESPONSE_ACCEPT);
1254 session_selector_window->set_default_response (RESPONSE_ACCEPT);
1255 recent_session_model = TreeStore::create (recent_session_columns);
1256 recent_session_display.set_model (recent_session_model);
1257 recent_session_display.append_column (_("Recent Sessions"), recent_session_columns.visible_name);
1258 recent_session_display.set_headers_visible (false);
1259 recent_session_display.get_selection()->set_mode (SELECTION_BROWSE);
1260 recent_session_display.signal_row_activated().connect (sigc::mem_fun (*this, &ARDOUR_UI::recent_session_row_activated));
1262 scroller->add (recent_session_display);
1263 scroller->set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
1265 session_selector_window->set_name ("SessionSelectorWindow");
1266 session_selector_window->set_size_request (200, 400);
1267 session_selector_window->get_vbox()->pack_start (*scroller);
1269 recent_session_display.show();
1271 //session_selector_window->get_vbox()->show();
1275 ARDOUR_UI::recent_session_row_activated (const TreePath& /*path*/, TreeViewColumn* /*col*/)
1277 session_selector_window->response (RESPONSE_ACCEPT);
1281 ARDOUR_UI::open_recent_session ()
1283 bool can_return = (_session != 0);
1285 if (session_selector_window == 0) {
1286 build_session_selector ();
1289 redisplay_recent_sessions ();
1293 session_selector_window->set_position (WIN_POS_MOUSE);
1295 ResponseType r = (ResponseType) session_selector_window->run ();
1298 case RESPONSE_ACCEPT:
1302 session_selector_window->hide();
1309 if (recent_session_display.get_selection()->count_selected_rows() == 0) {
1313 session_selector_window->hide();
1315 Gtk::TreeModel::iterator i = recent_session_display.get_selection()->get_selected();
1317 if (i == recent_session_model->children().end()) {
1321 std::string path = (*i)[recent_session_columns.fullpath];
1322 std::string state = (*i)[recent_session_columns.visible_name];
1324 _session_is_new = false;
1326 if (load_session (path, state) == 0) {
1335 ARDOUR_UI::check_audioengine ()
1338 if (!engine->connected()) {
1339 MessageDialog msg (string_compose (
1340 _("%1 is not connected to JACK\n"
1341 "You cannot open or close sessions in this condition"),
1354 ARDOUR_UI::open_session ()
1356 if (!check_audioengine()) {
1361 /* popup selector window */
1363 if (open_session_selector == 0) {
1365 /* ardour sessions are folders */
1367 open_session_selector = new Gtk::FileChooserDialog (_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1368 open_session_selector->add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1369 open_session_selector->add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1370 open_session_selector->set_default_response(Gtk::RESPONSE_ACCEPT);
1372 FileFilter session_filter;
1373 session_filter.add_pattern ("*.ardour");
1374 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1375 open_session_selector->add_filter (session_filter);
1376 open_session_selector->set_filter (session_filter);
1379 int response = open_session_selector->run();
1380 open_session_selector->hide ();
1383 case RESPONSE_ACCEPT:
1386 open_session_selector->hide();
1390 open_session_selector->hide();
1391 string session_path = open_session_selector->get_filename();
1395 if (session_path.length() > 0) {
1396 if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1397 _session_is_new = isnew;
1398 load_session (path, name);
1405 ARDOUR_UI::session_add_midi_route (bool disk, RouteGroup* route_group, uint32_t how_many, string const & name_template)
1407 list<boost::shared_ptr<MidiTrack> > tracks;
1409 if (_session == 0) {
1410 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1417 tracks = _session->new_midi_track (ARDOUR::Normal, route_group, how_many, name_template);
1419 if (tracks.size() != how_many) {
1420 if (how_many == 1) {
1421 error << _("could not create a new midi track") << endmsg;
1423 error << string_compose (_("could not create %1 new midi tracks"), how_many) << endmsg;
1427 if ((route = _session->new_midi_route ()) == 0) {
1428 error << _("could not create new midi bus") << endmsg;
1434 MessageDialog msg (*editor,
1435 string_compose (_("There are insufficient JACK ports available\n\
1436 to create a new track or bus.\n\
1437 You should save %1, exit and\n\
1438 restart JACK with more ports."), PROGRAM_NAME));
1445 ARDOUR_UI::session_add_audio_route (
1447 int32_t input_channels,
1448 int32_t output_channels,
1449 ARDOUR::TrackMode mode,
1450 RouteGroup* route_group,
1452 string const & name_template
1455 list<boost::shared_ptr<AudioTrack> > tracks;
1458 if (_session == 0) {
1459 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1465 tracks = _session->new_audio_track (input_channels, output_channels, mode, route_group, how_many, name_template);
1467 if (tracks.size() != how_many) {
1468 if (how_many == 1) {
1469 error << _("could not create a new audio track") << endmsg;
1471 error << string_compose (_("could only create %1 of %2 new audio %3"),
1472 tracks.size(), how_many, (track ? _("tracks") : _("busses"))) << endmsg;
1478 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template);
1480 if (routes.size() != how_many) {
1481 if (how_many == 1) {
1482 error << _("could not create a new audio bus") << endmsg;
1484 error << string_compose (_("could not create %1 new audio busses"), how_many) << endmsg;
1491 MessageDialog msg (*editor,
1492 string_compose (_("There are insufficient JACK ports available\n\
1493 to create a new track or bus.\n\
1494 You should save %1, exit and\n\
1495 restart JACK with more ports."), PROGRAM_NAME));
1502 ARDOUR_UI::do_transport_locate (framepos_t new_position, bool with_roll)
1504 framecnt_t _preroll = 0;
1507 // XXX CONFIG_CHANGE FIX - requires AnyTime handling
1508 // _preroll = _session->convert_to_frames_at (new_position, Config->get_preroll());
1510 if (new_position > _preroll) {
1511 new_position -= _preroll;
1516 _session->request_locate (new_position, with_roll);
1521 ARDOUR_UI::transport_goto_start ()
1524 _session->goto_start();
1526 /* force displayed area in editor to start no matter
1527 what "follow playhead" setting is.
1531 editor->center_screen (_session->current_start_frame ());
1537 ARDOUR_UI::transport_goto_zero ()
1540 _session->request_locate (0);
1542 /* force displayed area in editor to start no matter
1543 what "follow playhead" setting is.
1547 editor->reset_x_origin (0);
1553 ARDOUR_UI::transport_goto_wallclock ()
1555 if (_session && editor) {
1562 localtime_r (&now, &tmnow);
1564 frames = tmnow.tm_hour * (60 * 60 * _session->frame_rate());
1565 frames += tmnow.tm_min * (60 * _session->frame_rate());
1566 frames += tmnow.tm_sec * _session->frame_rate();
1568 _session->request_locate (frames, _session->transport_rolling ());
1570 /* force displayed area in editor to start no matter
1571 what "follow playhead" setting is.
1575 editor->center_screen (frames);
1581 ARDOUR_UI::transport_goto_end ()
1584 framepos_t const frame = _session->current_end_frame();
1585 _session->request_locate (frame);
1587 /* force displayed area in editor to start no matter
1588 what "follow playhead" setting is.
1592 editor->center_screen (frame);
1598 ARDOUR_UI::transport_stop ()
1604 if (_session->is_auditioning()) {
1605 _session->cancel_audition ();
1609 _session->request_stop (false, true);
1613 ARDOUR_UI::transport_stop_and_forget_capture ()
1616 _session->request_stop (true, true);
1621 ARDOUR_UI::remove_last_capture()
1624 editor->remove_last_capture();
1629 ARDOUR_UI::transport_record (bool roll)
1633 switch (_session->record_status()) {
1634 case Session::Disabled:
1635 if (_session->ntracks() == 0) {
1636 MessageDialog msg (*editor, _("Please create 1 or more track\nbefore trying to record.\nCheck the Session menu."));
1640 _session->maybe_enable_record ();
1645 case Session::Recording:
1647 _session->request_stop();
1649 _session->disable_record (false, true);
1653 case Session::Enabled:
1654 _session->disable_record (false, true);
1657 //cerr << "ARDOUR_UI::transport_record () called roll = " << roll << " _session->record_status() = " << _session->record_status() << endl;
1661 ARDOUR_UI::transport_roll ()
1667 if (_session->is_auditioning()) {
1672 if (_session->config.get_external_sync()) {
1673 switch (_session->config.get_sync_source()) {
1677 /* transport controlled by the master */
1683 bool rolling = _session->transport_rolling();
1685 if (_session->get_play_loop()) {
1686 /* XXX it is not possible to just leave seamless loop and keep
1687 playing at present (nov 4th 2009)
1689 if (!Config->get_seamless_loop()) {
1690 _session->request_play_loop (false, true);
1692 } else if (_session->get_play_range () && !join_play_range_button.get_active()) {
1693 /* stop playing a range if we currently are */
1694 _session->request_play_range (0, true);
1697 if (join_play_range_button.get_active()) {
1698 _session->request_play_range (&editor->get_selection().time, true);
1702 _session->request_transport_speed (1.0f);
1707 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
1714 if (_session->is_auditioning()) {
1715 _session->cancel_audition ();
1719 if (_session->config.get_external_sync()) {
1720 switch (_session->config.get_sync_source()) {
1724 /* transport controlled by the master */
1729 bool rolling = _session->transport_rolling();
1730 bool affect_transport = true;
1732 if (rolling && roll_out_of_bounded_mode) {
1733 /* drop out of loop/range playback but leave transport rolling */
1734 if (_session->get_play_loop()) {
1735 if (Config->get_seamless_loop()) {
1736 /* the disk buffers contain copies of the loop - we can't
1737 just keep playing, so stop the transport. the user
1738 can restart as they wish.
1740 affect_transport = true;
1742 /* disk buffers are normal, so we can keep playing */
1743 affect_transport = false;
1745 _session->request_play_loop (false, true);
1746 } else if (_session->get_play_range ()) {
1747 affect_transport = false;
1748 _session->request_play_range (0, true);
1752 if (affect_transport) {
1754 _session->request_stop (with_abort, true);
1756 if (join_play_range_button.get_active()) {
1757 _session->request_play_range (&editor->get_selection().time, true);
1760 _session->request_transport_speed (1.0f);
1766 ARDOUR_UI::toggle_session_auto_loop ()
1772 if (_session->get_play_loop()) {
1774 if (_session->transport_rolling()) {
1776 Location * looploc = _session->locations()->auto_loop_location();
1779 _session->request_locate (looploc->start(), true);
1780 _session->request_play_loop (false);
1784 _session->request_play_loop (false);
1788 Location * looploc = _session->locations()->auto_loop_location();
1791 _session->request_play_loop (true);
1797 ARDOUR_UI::transport_play_selection ()
1803 editor->play_selection ();
1807 ARDOUR_UI::transport_rewind (int option)
1809 float current_transport_speed;
1812 current_transport_speed = _session->transport_speed();
1814 if (current_transport_speed >= 0.0f) {
1817 _session->request_transport_speed (-1.0f);
1820 _session->request_transport_speed (-4.0f);
1823 _session->request_transport_speed (-0.5f);
1828 _session->request_transport_speed (current_transport_speed * 1.5f);
1834 ARDOUR_UI::transport_forward (int option)
1836 float current_transport_speed;
1839 current_transport_speed = _session->transport_speed();
1841 if (current_transport_speed <= 0.0f) {
1844 _session->request_transport_speed (1.0f);
1847 _session->request_transport_speed (4.0f);
1850 _session->request_transport_speed (0.5f);
1855 _session->request_transport_speed (current_transport_speed * 1.5f);
1862 ARDOUR_UI::toggle_record_enable (uint32_t rid)
1864 if (_session == 0) {
1868 boost::shared_ptr<Route> r;
1870 if ((r = _session->route_by_remote_id (rid)) != 0) {
1874 if ((t = dynamic_cast<Track*>(r.get())) != 0) {
1875 t->set_record_enabled (!t->record_enabled(), this);
1878 if (_session == 0) {
1884 ARDOUR_UI::map_transport_state ()
1887 auto_loop_button.set_visual_state (0);
1888 play_selection_button.set_visual_state (0);
1889 roll_button.set_visual_state (0);
1890 stop_button.set_visual_state (1);
1894 shuttle_box->map_transport_state ();
1896 float sp = _session->transport_speed();
1902 if (_session->get_play_range()) {
1904 play_selection_button.set_visual_state (1);
1905 roll_button.set_visual_state (0);
1906 auto_loop_button.set_visual_state (0);
1908 } else if (_session->get_play_loop ()) {
1910 auto_loop_button.set_visual_state (1);
1911 play_selection_button.set_visual_state (0);
1912 roll_button.set_visual_state (0);
1916 roll_button.set_visual_state (1);
1917 play_selection_button.set_visual_state (0);
1918 auto_loop_button.set_visual_state (0);
1921 if (join_play_range_button.get_active()) {
1922 /* light up both roll and play-selection if they are joined */
1923 roll_button.set_visual_state (1);
1924 play_selection_button.set_visual_state (1);
1927 stop_button.set_visual_state (0);
1931 stop_button.set_visual_state (1);
1932 roll_button.set_visual_state (0);
1933 play_selection_button.set_visual_state (0);
1934 auto_loop_button.set_visual_state (0);
1935 update_disk_space ();
1940 ARDOUR_UI::engine_stopped ()
1942 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
1943 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1944 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1948 ARDOUR_UI::engine_running ()
1950 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
1951 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, true);
1952 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, false);
1954 Glib::RefPtr<Action> action;
1955 const char* action_name = 0;
1957 switch (engine->frames_per_cycle()) {
1959 action_name = X_("JACKLatency32");
1962 action_name = X_("JACKLatency64");
1965 action_name = X_("JACKLatency128");
1968 action_name = X_("JACKLatency512");
1971 action_name = X_("JACKLatency1024");
1974 action_name = X_("JACKLatency2048");
1977 action_name = X_("JACKLatency4096");
1980 action_name = X_("JACKLatency8192");
1983 /* XXX can we do anything useful ? */
1989 action = ActionManager::get_action (X_("JACK"), action_name);
1992 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (action);
1993 ract->set_active ();
1999 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
2001 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
2002 /* we can't rely on the original string continuing to exist when we are called
2003 again in the GUI thread, so make a copy and note that we need to
2006 char *copy = strdup (reason);
2007 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
2011 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
2012 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
2014 update_sample_rate (0);
2018 /* if the reason is a non-empty string, it means that the backend was shutdown
2019 rather than just Ardour.
2022 if (strlen (reason)) {
2023 msgstr = string_compose (_("The audio backend (JACK) was shutdown because:\n\n%1"), reason);
2025 msgstr = string_compose (_("\
2026 JACK has either been shutdown or it\n\
2027 disconnected %1 because %1\n\
2028 was not fast enough. Try to restart\n\
2029 JACK, reconnect and save the session."), PROGRAM_NAME);
2032 MessageDialog msg (*editor, msgstr);
2037 free ((char*) reason);
2042 ARDOUR_UI::do_engine_start ()
2050 error << _("Unable to start the session running")
2060 ARDOUR_UI::setup_theme ()
2062 theme_manager->setup_theme();
2066 ARDOUR_UI::update_clocks ()
2068 if (!editor || !editor->dragging_playhead()) {
2069 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position()); /* EMIT_SIGNAL */
2074 ARDOUR_UI::start_clocking ()
2076 clock_signal_connection = RapidScreenUpdate.connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2080 ARDOUR_UI::stop_clocking ()
2082 clock_signal_connection.disconnect ();
2086 ARDOUR_UI::toggle_clocking ()
2089 if (clock_button.get_active()) {
2098 ARDOUR_UI::_blink (void *arg)
2101 ((ARDOUR_UI *) arg)->blink ();
2108 Blink (blink_on = !blink_on); /* EMIT_SIGNAL */
2112 ARDOUR_UI::start_blinking ()
2114 /* Start the blink signal. Everybody with a blinking widget
2115 uses Blink to drive the widget's state.
2118 if (blink_timeout_tag < 0) {
2120 blink_timeout_tag = g_timeout_add (240, _blink, this);
2125 ARDOUR_UI::stop_blinking ()
2127 if (blink_timeout_tag >= 0) {
2128 g_source_remove (blink_timeout_tag);
2129 blink_timeout_tag = -1;
2134 /** Ask the user for the name of a new shapshot and then take it.
2138 ARDOUR_UI::snapshot_session (bool switch_to_it)
2140 ArdourPrompter prompter (true);
2143 prompter.set_name ("Prompter");
2144 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2145 prompter.set_title (_("Take Snapshot"));
2146 prompter.set_prompt (_("Name of new snapshot"));
2148 if (!switch_to_it) {
2151 struct tm local_time;
2154 localtime_r (&n, &local_time);
2155 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2156 prompter.set_initial_text (timebuf);
2160 switch (prompter.run()) {
2161 case RESPONSE_ACCEPT:
2163 prompter.get_result (snapname);
2165 bool do_save = (snapname.length() != 0);
2168 if (snapname.find ('/') != string::npos) {
2169 MessageDialog msg (_("To ensure compatibility with various systems\n"
2170 "snapshot names may not contain a '/' character"));
2174 if (snapname.find ('\\') != string::npos) {
2175 MessageDialog msg (_("To ensure compatibility with various systems\n"
2176 "snapshot names may not contain a '\\' character"));
2180 if (snapname.find (':') != string::npos) {
2181 MessageDialog msg (_("To ensure compatibility with various systems\n"
2182 "snapshot names may not contain a ':' character"));
2188 vector<sys::path> p;
2189 get_state_files_in_directory (_session->session_directory().root_path(), p);
2190 vector<string> n = get_file_names_no_extension (p);
2191 if (find (n.begin(), n.end(), snapname) != n.end()) {
2193 ArdourDialog confirm (_("Confirm Snapshot Overwrite"), true);
2194 Label m (_("A snapshot already exists with that name. Do you want to overwrite it?"));
2195 confirm.get_vbox()->pack_start (m, true, true);
2196 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2197 confirm.add_button (_("Overwrite"), Gtk::RESPONSE_ACCEPT);
2198 confirm.show_all ();
2199 switch (confirm.run()) {
2200 case RESPONSE_CANCEL:
2206 save_state (snapname, switch_to_it);
2216 /** Ask the user for the name of a new shapshot and then take it.
2220 ARDOUR_UI::rename_session ()
2226 ArdourPrompter prompter (true);
2229 prompter.set_name ("Prompter");
2230 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2231 prompter.set_title (_("Rename Session"));
2232 prompter.set_prompt (_("New session name"));
2235 switch (prompter.run()) {
2236 case RESPONSE_ACCEPT:
2238 prompter.get_result (name);
2240 bool do_rename = (name.length() != 0);
2243 if (name.find ('/') != string::npos) {
2244 MessageDialog msg (_("To ensure compatibility with various systems\n"
2245 "session names may not contain a '/' character"));
2249 if (name.find ('\\') != string::npos) {
2250 MessageDialog msg (_("To ensure compatibility with various systems\n"
2251 "session names may not contain a '\\' character"));
2256 switch (_session->rename (name)) {
2258 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
2259 msg.set_position (WIN_POS_MOUSE);
2267 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
2268 msg.set_position (WIN_POS_MOUSE);
2284 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2286 XMLNode* node = new XMLNode (X_("UI"));
2288 for (list<WindowProxyBase*>::iterator i = _window_proxies.begin(); i != _window_proxies.end(); ++i) {
2289 if (!(*i)->rc_configured()) {
2290 node->add_child_nocopy (*((*i)->get_state ()));
2294 node->add_child_nocopy (gui_object_state->get_state());
2296 _session->add_extra_xml (*node);
2298 save_state_canfail (name, switch_to_it);
2302 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2307 if (name.length() == 0) {
2308 name = _session->snap_name();
2311 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2316 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2321 ARDOUR_UI::primary_clock_value_changed ()
2324 _session->request_locate (primary_clock->current_time ());
2329 ARDOUR_UI::big_clock_value_changed ()
2332 _session->request_locate (big_clock->current_time ());
2337 ARDOUR_UI::secondary_clock_value_changed ()
2340 _session->request_locate (secondary_clock->current_time ());
2345 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2347 if (_session == 0) {
2351 if (_session->step_editing()) {
2355 Session::RecordState const r = _session->record_status ();
2356 bool const h = _session->have_rec_enabled_track ();
2358 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2360 rec_button.set_visual_state (2);
2362 rec_button.set_visual_state (0);
2364 } else if (r == Session::Recording && h) {
2365 rec_button.set_visual_state (1);
2367 rec_button.set_visual_state (0);
2372 ARDOUR_UI::save_template ()
2374 ArdourPrompter prompter (true);
2377 if (!check_audioengine()) {
2381 prompter.set_name (X_("Prompter"));
2382 prompter.set_title (_("Save Template"));
2383 prompter.set_prompt (_("Name for template:"));
2384 prompter.set_initial_text(_session->name() + _("-template"));
2385 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2387 switch (prompter.run()) {
2388 case RESPONSE_ACCEPT:
2389 prompter.get_result (name);
2391 if (name.length()) {
2392 _session->save_template (name);
2402 ARDOUR_UI::edit_metadata ()
2404 SessionMetadataEditor dialog;
2405 dialog.set_session (_session);
2406 editor->ensure_float (dialog);
2411 ARDOUR_UI::import_metadata ()
2413 SessionMetadataImporter dialog;
2414 dialog.set_session (_session);
2415 editor->ensure_float (dialog);
2420 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
2422 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2424 MessageDialog msg (str,
2426 Gtk::MESSAGE_WARNING,
2427 Gtk::BUTTONS_YES_NO,
2431 msg.set_name (X_("OpenExistingDialog"));
2432 msg.set_title (_("Open Existing Session"));
2433 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
2434 msg.set_position (Gtk::WIN_POS_MOUSE);
2437 switch (msg.run()) {
2446 ARDOUR_UI::build_session_from_nsd (const std::string& session_path, const std::string& session_name)
2448 BusProfile bus_profile;
2450 if (Profile->get_sae()) {
2452 bus_profile.master_out_channels = 2;
2453 bus_profile.input_ac = AutoConnectPhysical;
2454 bus_profile.output_ac = AutoConnectMaster;
2455 bus_profile.requested_physical_in = 0; // use all available
2456 bus_profile.requested_physical_out = 0; // use all available
2460 /* get settings from advanced section of NSD */
2462 if (_startup->create_master_bus()) {
2463 bus_profile.master_out_channels = (uint32_t) _startup->master_channel_count();
2465 bus_profile.master_out_channels = 0;
2468 if (_startup->connect_inputs()) {
2469 bus_profile.input_ac = AutoConnectPhysical;
2471 bus_profile.input_ac = AutoConnectOption (0);
2474 /// @todo some minor tweaks.
2476 bus_profile.output_ac = AutoConnectOption (0);
2478 if (_startup->connect_outputs ()) {
2479 if (_startup->connect_outs_to_master()) {
2480 bus_profile.output_ac = AutoConnectMaster;
2481 } else if (_startup->connect_outs_to_physical()) {
2482 bus_profile.output_ac = AutoConnectPhysical;
2486 bus_profile.requested_physical_in = (uint32_t) _startup->input_limit_count();
2487 bus_profile.requested_physical_out = (uint32_t) _startup->output_limit_count();
2490 if (build_session (session_path, session_name, bus_profile)) {
2498 ARDOUR_UI::idle_load (const std::string& path)
2501 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2502 /* /path/to/foo => /path/to/foo, foo */
2503 load_session (path, basename_nosuffix (path));
2505 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2506 load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2510 ARDOUR_COMMAND_LINE::session_name = path;
2513 * new_session_dialog doens't exist in A3
2514 * Try to remove all references to it to
2515 * see if it will compile. NOTE: this will
2516 * likely cause a runtime issue is my somewhat
2520 //if (new_session_dialog) {
2523 /* make it break out of Dialog::run() and
2527 //new_session_dialog->response (1);
2533 ARDOUR_UI::end_loading_messages ()
2539 ARDOUR_UI::loading_message (const std::string& /*msg*/)
2542 // splash->message (msg);
2546 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
2548 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
2550 string session_name;
2551 string session_path;
2552 string template_name;
2554 bool likely_new = false;
2556 if (!load_template.empty()) {
2557 should_be_new = true;
2558 template_name = load_template;
2563 if (!should_be_new && !ARDOUR_COMMAND_LINE::session_name.empty()) {
2565 /* if they named a specific statefile, use it, otherwise they are
2566 just giving a session folder, and we want to use it as is
2567 to find the session.
2570 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
2572 if (suffix != string::npos) {
2573 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
2574 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
2575 session_name = Glib::path_get_basename (session_name);
2577 session_path = ARDOUR_COMMAND_LINE::session_name;
2578 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
2583 bool const apply = run_startup (should_be_new, load_template);
2586 if (quit_on_cancel) {
2593 /* if we run the startup dialog again, offer more than just "new session" */
2595 should_be_new = false;
2597 session_name = _startup->session_name (likely_new);
2599 string::size_type suffix = session_name.find (statefile_suffix);
2601 if (suffix != string::npos) {
2602 session_name = session_name.substr (0, suffix);
2605 /* this shouldn't happen, but we catch it just in case it does */
2607 if (session_name.empty()) {
2611 if (_startup->use_session_template()) {
2612 template_name = _startup->session_template_name();
2613 _session_is_new = true;
2616 if (session_name[0] == G_DIR_SEPARATOR ||
2617 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
2618 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)) {
2620 /* absolute path or cwd-relative path specified for session name: infer session folder
2621 from what was given.
2624 session_path = Glib::path_get_dirname (session_name);
2625 session_name = Glib::path_get_basename (session_name);
2629 session_path = _startup->session_folder();
2631 if (session_name.find ('/') != string::npos) {
2632 MessageDialog msg (*_startup,
2633 _("To ensure compatibility with various systems\n"
2634 "session names may not contain a '/' character"));
2636 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2640 if (session_name.find ('\\') != string::npos) {
2641 MessageDialog msg (*_startup,
2642 _("To ensure compatibility with various systems\n"
2643 "session names may not contain a '\\' character"));
2645 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2651 if (create_engine ()) {
2655 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
2659 std::string existing = Glib::build_filename (session_path, session_name);
2661 if (!ask_about_loading_existing_session (existing)) {
2662 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2667 _session_is_new = false;
2672 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
2674 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2678 if (session_name.find ('/') != std::string::npos) {
2679 MessageDialog msg (*_startup,
2680 _("To ensure compatibility with various systems\n"
2681 "session names may not contain a '/' character"));
2683 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2687 if (session_name.find ('\\') != std::string::npos) {
2688 MessageDialog msg (*_startup,
2689 _("To ensure compatibility with various systems\n"
2690 "session names may not contain a '\\' character"));
2692 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2696 _session_is_new = true;
2699 if (likely_new && template_name.empty()) {
2701 ret = build_session_from_nsd (session_path, session_name);
2705 ret = load_session (session_path, session_name, template_name);
2708 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
2712 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
2713 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
2723 ARDOUR_UI::close_session()
2725 if (!check_audioengine()) {
2729 if (unload_session (true)) {
2733 ARDOUR_COMMAND_LINE::session_name = "";
2735 if (get_session_parameters (true, false)) {
2739 goto_editor_window ();
2742 /** @param snap_name Snapshot name (without .ardour suffix).
2743 * @return -2 if the load failed because we are not connected to the AudioEngine.
2746 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
2748 Session *new_session;
2752 session_loaded = false;
2754 if (!check_audioengine()) {
2758 unload_status = unload_session ();
2760 if (unload_status < 0) {
2762 } else if (unload_status > 0) {
2767 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
2770 new_session = new Session (*engine, path, snap_name, 0, mix_template);
2773 /* this one is special */
2775 catch (AudioEngine::PortRegistrationFailure& err) {
2777 MessageDialog msg (err.what(),
2780 Gtk::BUTTONS_CLOSE);
2782 msg.set_title (_("Port Registration Error"));
2783 msg.set_secondary_text (_("Click the Close button to try again."));
2784 msg.set_position (Gtk::WIN_POS_CENTER);
2788 int response = msg.run ();
2793 case RESPONSE_CANCEL:
2803 MessageDialog msg (string_compose(
2804 _("Session \"%1 (snapshot %2)\" did not load successfully"),
2810 msg.set_title (_("Loading Error"));
2811 msg.set_secondary_text (_("Click the Refresh button to try again."));
2812 msg.add_button (Stock::REFRESH, 1);
2813 msg.set_position (Gtk::WIN_POS_CENTER);
2817 int response = msg.run ();
2832 list<string> const u = new_session->unknown_processors ();
2834 MissingPluginDialog d (_session, u);
2839 /* Now the session been created, add the transport controls */
2840 new_session->add_controllable(roll_controllable);
2841 new_session->add_controllable(stop_controllable);
2842 new_session->add_controllable(goto_start_controllable);
2843 new_session->add_controllable(goto_end_controllable);
2844 new_session->add_controllable(auto_loop_controllable);
2845 new_session->add_controllable(play_selection_controllable);
2846 new_session->add_controllable(rec_controllable);
2848 set_session (new_session);
2850 session_loaded = true;
2852 goto_editor_window ();
2855 _session->set_clean ();
2866 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
2868 Session *new_session;
2871 if (!check_audioengine()) {
2875 session_loaded = false;
2877 x = unload_session ();
2885 _session_is_new = true;
2888 new_session = new Session (*engine, path, snap_name, &bus_profile);
2893 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
2899 /* Give the new session the default GUI state, if such things exist */
2902 n = Config->instant_xml (X_("Editor"));
2904 new_session->add_instant_xml (*n, false);
2906 n = Config->instant_xml (X_("Mixer"));
2908 new_session->add_instant_xml (*n, false);
2911 /* Put the playhead at 0 and scroll fully left */
2912 n = new_session->instant_xml (X_("Editor"));
2914 n->add_property (X_("playhead"), X_("0"));
2915 n->add_property (X_("left-frame"), X_("0"));
2918 set_session (new_session);
2920 session_loaded = true;
2922 new_session->save_state(new_session->name());
2928 ARDOUR_UI::launch_chat ()
2931 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
2933 open_uri("http://webchat.freenode.net/?channels=ardour");
2938 ARDOUR_UI::show_about ()
2942 about->signal_response().connect(sigc::mem_fun (*this, &ARDOUR_UI::about_signal_response) );
2945 about->set_transient_for(*editor);
2950 ARDOUR_UI::launch_manual ()
2952 PBD::open_uri("http://ardour.org/flossmanual");
2956 ARDOUR_UI::launch_reference ()
2958 PBD::open_uri("http://ardour.org/refmanual");
2962 ARDOUR_UI::hide_about ()
2965 about->get_window()->set_cursor ();
2971 ARDOUR_UI::about_signal_response (int /*response*/)
2977 ARDOUR_UI::show_splash ()
2981 splash = new Splash;
2989 splash->queue_draw ();
2990 splash->get_window()->process_updates (true);
2995 ARDOUR_UI::hide_splash ()
3003 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title,
3004 const string& plural_msg, const string& singular_msg)
3008 removed = rep.paths.size();
3011 MessageDialog msgd (*editor,
3012 _("No files were ready for clean-up"),
3015 (Gtk::ButtonsType)(Gtk::BUTTONS_OK) );
3016 msgd.set_title (_("Clean-up"));
3017 msgd.set_secondary_text (_("If this seems suprising, \n\
3018 check for any existing snapshots.\n\
3019 These may still include regions that\n\
3020 require some unused files to continue to exist."));
3026 ArdourDialog results (_("Clean-up"), true, false);
3028 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
3029 CleanupResultsModelColumns() {
3033 Gtk::TreeModelColumn<std::string> visible_name;
3034 Gtk::TreeModelColumn<std::string> fullpath;
3038 CleanupResultsModelColumns results_columns;
3039 Glib::RefPtr<Gtk::ListStore> results_model;
3040 Gtk::TreeView results_display;
3042 results_model = ListStore::create (results_columns);
3043 results_display.set_model (results_model);
3044 results_display.append_column (list_title, results_columns.visible_name);
3046 results_display.set_name ("CleanupResultsList");
3047 results_display.set_headers_visible (true);
3048 results_display.set_headers_clickable (false);
3049 results_display.set_reorderable (false);
3051 Gtk::ScrolledWindow list_scroller;
3054 Gtk::HBox dhbox; // the hbox for the image and text
3055 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
3056 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
3058 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
3060 const string dead_directory = _session->session_directory().dead_path().to_string();
3063 %1 - number of files removed
3064 %2 - location of "dead"
3065 %3 - size of files affected
3066 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
3069 const char* bprefix;
3070 double space_adjusted = 0;
3072 if (rep.space < 1000) {
3074 space_adjusted = rep.space;
3075 } else if (rep.space < 1000000) {
3076 bprefix = X_("kilo");
3077 space_adjusted = truncf((float)rep.space / 1000.0);
3078 } else if (rep.space < 1000000 * 1000) {
3079 bprefix = X_("mega");
3080 space_adjusted = truncf((float)rep.space / (1000.0 * 1000.0));
3082 bprefix = X_("giga");
3083 space_adjusted = truncf((float)rep.space / (1000.0 * 1000 * 1000.0));
3087 txt.set_text (string_compose (plural_msg, removed, dead_directory, space_adjusted, bprefix));
3089 txt.set_text (string_compose (singular_msg, removed, dead_directory, space_adjusted, bprefix));
3092 dhbox.pack_start (*dimage, true, false, 5);
3093 dhbox.pack_start (txt, true, false, 5);
3095 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
3096 TreeModel::Row row = *(results_model->append());
3097 row[results_columns.visible_name] = *i;
3098 row[results_columns.fullpath] = *i;
3101 list_scroller.add (results_display);
3102 list_scroller.set_size_request (-1, 150);
3103 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
3105 dvbox.pack_start (dhbox, true, false, 5);
3106 dvbox.pack_start (list_scroller, true, false, 5);
3107 ddhbox.pack_start (dvbox, true, false, 5);
3109 results.get_vbox()->pack_start (ddhbox, true, false, 5);
3110 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
3111 results.set_default_response (RESPONSE_CLOSE);
3112 results.set_position (Gtk::WIN_POS_MOUSE);
3114 results_display.show();
3115 list_scroller.show();
3122 //results.get_vbox()->show();
3123 results.set_resizable (false);
3130 ARDOUR_UI::cleanup ()
3132 if (_session == 0) {
3133 /* shouldn't happen: menu item is insensitive */
3138 MessageDialog checker (_("Are you sure you want to clean-up?"),
3140 Gtk::MESSAGE_QUESTION,
3141 (Gtk::ButtonsType)(Gtk::BUTTONS_NONE));
3143 checker.set_title (_("Clean-up"));
3145 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
3146 ALL undo/redo information will be lost if you clean-up.\n\
3147 Clean-up will move all unused files to a \"dead\" location."));
3149 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3150 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
3151 checker.set_default_response (RESPONSE_CANCEL);
3153 checker.set_name (_("CleanupDialog"));
3154 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3155 checker.set_position (Gtk::WIN_POS_MOUSE);
3157 switch (checker.run()) {
3158 case RESPONSE_ACCEPT:
3164 ARDOUR::CleanupReport rep;
3166 editor->prepare_for_cleanup ();
3168 /* do not allow flush until a session is reloaded */
3170 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3172 act->set_sensitive (false);
3175 if (_session->cleanup_sources (rep)) {
3176 editor->finish_cleanup ();
3180 editor->finish_cleanup ();
3183 display_cleanup_results (rep,
3186 The following %1 files were not in use and \n\
3187 have been moved to:\n\n\
3189 After a restart of Ardour,\n\n\
3190 Session -> Clean-up -> Flush Wastebasket\n\n\
3191 will release an additional\n\
3192 %3 %4bytes of disk space.\n"),
3194 The following file was not in use and \n\
3195 has been moved to:\n \
3197 After a restart of Ardour,\n\n\
3198 Session -> Clean-up -> Flush Wastebasket\n\n\
3199 will release an additional\n\
3200 %3 %4bytes of disk space.\n"
3206 ARDOUR_UI::flush_trash ()
3208 if (_session == 0) {
3209 /* shouldn't happen: menu item is insensitive */
3213 ARDOUR::CleanupReport rep;
3215 if (_session->cleanup_trash_sources (rep)) {
3219 display_cleanup_results (rep,
3221 _("The following %1 files were deleted from\n\
3223 releasing %3 %4bytes of disk space"),
3224 _("The following file was deleted from\n\
3226 releasing %3 %4bytes of disk space"));
3230 ARDOUR_UI::add_route (Gtk::Window* float_window)
3238 if (add_route_dialog == 0) {
3239 add_route_dialog = new AddRouteDialog (_session);
3241 add_route_dialog->set_transient_for (*float_window);
3245 if (add_route_dialog->is_visible()) {
3246 /* we're already doing this */
3250 ResponseType r = (ResponseType) add_route_dialog->run ();
3252 add_route_dialog->hide();
3255 case RESPONSE_ACCEPT:
3262 if ((count = add_route_dialog->count()) <= 0) {
3266 string template_path = add_route_dialog->track_template();
3268 if (!template_path.empty()) {
3269 _session->new_route_from_template (count, template_path);
3273 uint32_t input_chan = add_route_dialog->channels ();
3274 uint32_t output_chan;
3275 string name_template = add_route_dialog->name_template ();
3276 bool track = add_route_dialog->track ();
3277 RouteGroup* route_group = add_route_dialog->route_group ();
3279 AutoConnectOption oac = Config->get_output_auto_connect();
3281 if (oac & AutoConnectMaster) {
3282 output_chan = (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan);
3284 output_chan = input_chan;
3287 /* XXX do something with name template */
3289 if (add_route_dialog->type() == ARDOUR::DataType::MIDI) {
3291 session_add_midi_track (route_group, count, name_template);
3293 MessageDialog msg (*editor,
3294 _("Sorry, MIDI Busses are not supported at this time."));
3296 //session_add_midi_bus();
3300 session_add_audio_track (input_chan, output_chan, add_route_dialog->mode(), route_group, count, name_template);
3302 session_add_audio_bus (input_chan, output_chan, route_group, count, name_template);
3308 ARDOUR_UI::mixer_settings () const
3313 node = _session->instant_xml(X_("Mixer"));
3315 node = Config->instant_xml(X_("Mixer"));
3319 node = new XMLNode (X_("Mixer"));
3326 ARDOUR_UI::editor_settings () const
3331 node = _session->instant_xml(X_("Editor"));
3333 node = Config->instant_xml(X_("Editor"));
3337 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
3338 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
3343 node = new XMLNode (X_("Editor"));
3350 ARDOUR_UI::keyboard_settings () const
3354 node = Config->extra_xml(X_("Keyboard"));
3357 node = new XMLNode (X_("Keyboard"));
3364 ARDOUR_UI::create_xrun_marker (framepos_t where)
3366 editor->mouse_add_new_marker (where, false, true);
3370 ARDOUR_UI::halt_on_xrun_message ()
3372 MessageDialog msg (*editor,
3373 _("Recording was stopped because your system could not keep up."));
3378 ARDOUR_UI::xrun_handler (framepos_t where)
3384 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
3386 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
3387 create_xrun_marker(where);
3390 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
3391 halt_on_xrun_message ();
3396 ARDOUR_UI::disk_overrun_handler ()
3398 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
3400 if (!have_disk_speed_dialog_displayed) {
3401 have_disk_speed_dialog_displayed = true;
3402 MessageDialog* msg = new MessageDialog (*editor, string_compose (_("\
3403 The disk system on your computer\n\
3404 was not able to keep up with %1.\n\
3406 Specifically, it failed to write data to disk\n\
3407 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
3408 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3414 ARDOUR_UI::disk_underrun_handler ()
3416 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
3418 if (!have_disk_speed_dialog_displayed) {
3419 have_disk_speed_dialog_displayed = true;
3420 MessageDialog* msg = new MessageDialog (
3421 *editor, string_compose (_("The disk system on your computer\n\
3422 was not able to keep up with %1.\n\
3424 Specifically, it failed to read data from disk\n\
3425 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
3426 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3432 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
3434 have_disk_speed_dialog_displayed = false;
3439 ARDOUR_UI::session_dialog (std::string msg)
3441 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
3446 d = new MessageDialog (*editor, msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3448 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3457 ARDOUR_UI::pending_state_dialog ()
3459 HBox* hbox = new HBox();
3460 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3461 ArdourDialog dialog (_("Crash Recovery"), true);
3463 This session appears to have been in\n\
3464 middle of recording when ardour or\n\
3465 the computer was shutdown.\n\
3467 Ardour can recover any captured audio for\n\
3468 you, or it can ignore it. Please decide\n\
3469 what you would like to do.\n"));
3470 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3471 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3472 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3473 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3474 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
3475 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
3476 dialog.set_default_response (RESPONSE_ACCEPT);
3477 dialog.set_position (WIN_POS_CENTER);
3482 switch (dialog.run ()) {
3483 case RESPONSE_ACCEPT:
3491 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
3493 HBox* hbox = new HBox();
3494 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3495 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
3496 Label message (string_compose (_("\
3497 This session was created with a sample rate of %1 Hz\n\
3499 The audioengine is currently running at %2 Hz\n"), desired, actual));
3501 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3502 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3503 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3504 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3505 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
3506 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
3507 dialog.set_default_response (RESPONSE_ACCEPT);
3508 dialog.set_position (WIN_POS_CENTER);
3513 switch (dialog.run ()) {
3514 case RESPONSE_ACCEPT:
3523 ARDOUR_UI::disconnect_from_jack ()
3526 if( engine->disconnect_from_jack ()) {
3527 MessageDialog msg (*editor, _("Could not disconnect from JACK"));
3531 update_sample_rate (0);
3536 ARDOUR_UI::reconnect_to_jack ()
3539 if (engine->reconnect_to_jack ()) {
3540 MessageDialog msg (*editor, _("Could not reconnect to JACK"));
3544 update_sample_rate (0);
3549 ARDOUR_UI::use_config ()
3551 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
3553 set_transport_controllable_state (*node);
3558 ARDOUR_UI::update_transport_clocks (framepos_t pos)
3560 if (Config->get_primary_clock_delta_edit_cursor()) {
3561 primary_clock->set (pos, false, editor->get_preferred_edit_position(), 1);
3563 primary_clock->set (pos, 0, true);
3566 if (Config->get_secondary_clock_delta_edit_cursor()) {
3567 secondary_clock->set (pos, false, editor->get_preferred_edit_position(), 2);
3569 secondary_clock->set (pos);
3572 if (big_clock_window->get()) {
3573 big_clock->set (pos);
3579 ARDOUR_UI::step_edit_status_change (bool yn)
3581 // XXX should really store pre-step edit status of things
3582 // we make insensitive
3585 rec_button.set_visual_state (3);
3586 rec_button.set_sensitive (false);
3588 rec_button.set_visual_state (0);
3589 rec_button.set_sensitive (true);
3594 ARDOUR_UI::record_state_changed ()
3596 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
3598 if (!_session || !big_clock_window->get()) {
3599 /* why bother - the clock isn't visible */
3603 Session::RecordState const r = _session->record_status ();
3604 bool const h = _session->have_rec_enabled_track ();
3606 if (r == Session::Recording && h) {
3607 big_clock->set_widget_name ("BigClockRecording");
3609 big_clock->set_widget_name ("BigClockNonRecording");
3614 ARDOUR_UI::first_idle ()
3617 _session->allow_auto_play (true);
3621 editor->first_idle();
3624 Keyboard::set_can_save_keybindings (true);
3629 ARDOUR_UI::store_clock_modes ()
3631 XMLNode* node = new XMLNode(X_("ClockModes"));
3633 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
3634 XMLNode* child = new XMLNode (X_("Clock"));
3636 child->add_property (X_("name"), (*x)->name());
3637 child->add_property (X_("mode"), enum_2_string ((*x)->mode()));
3638 child->add_property (X_("on"), ((*x)->off() ? X_("no") : X_("yes")));
3640 node->add_child_nocopy (*child);
3643 _session->add_extra_xml (*node);
3644 _session->set_dirty ();
3647 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
3648 : Controllable (name), ui (u), type(tp)
3654 ARDOUR_UI::TransportControllable::set_value (double val)
3657 /* do nothing: these are radio-style actions */
3661 const char *action = 0;
3665 action = X_("Roll");
3668 action = X_("Stop");
3671 action = X_("Goto Start");
3674 action = X_("Goto End");
3677 action = X_("Loop");
3680 action = X_("Play Selection");
3683 action = X_("Record");
3693 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
3701 ARDOUR_UI::TransportControllable::get_value (void) const
3728 ARDOUR_UI::setup_profile ()
3730 if (gdk_screen_width() < 1200) {
3731 Profile->set_small_screen ();
3735 if (getenv ("ARDOUR_SAE")) {
3736 Profile->set_sae ();
3737 Profile->set_single_package ();
3742 ARDOUR_UI::toggle_translations ()
3744 using namespace Glib;
3746 RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("EnableTranslation"));
3748 RefPtr<ToggleAction> ract = RefPtr<ToggleAction>::cast_dynamic (act);
3751 string i18n_killer = ARDOUR::translation_kill_path();
3753 bool already_enabled = !ARDOUR::translations_are_disabled ();
3755 if (ract->get_active ()) {
3756 /* we don't care about errors */
3757 int fd = ::open (i18n_killer.c_str(), O_RDONLY|O_CREAT, 0644);
3760 /* we don't care about errors */
3761 unlink (i18n_killer.c_str());
3764 if (already_enabled != ract->get_active()) {
3765 MessageDialog win (already_enabled ? _("Translations disabled") : _("Translations enabled"),
3767 Gtk::MESSAGE_WARNING,
3769 win.set_secondary_text (string_compose (_("You must restart %1 for this to take effect."), PROGRAM_NAME));
3770 win.set_position (Gtk::WIN_POS_CENTER);
3778 /** Add a window proxy to our list, so that its state will be saved.
3779 * This call also causes the window to be created and opened if its
3780 * state was saved as `visible'.
3783 ARDOUR_UI::add_window_proxy (WindowProxyBase* p)
3785 _window_proxies.push_back (p);
3789 /** Remove a window proxy from our list. Must be called if a WindowProxy
3790 * is deleted, to prevent hanging pointers.
3793 ARDOUR_UI::remove_window_proxy (WindowProxyBase* p)
3795 _window_proxies.remove (p);
3799 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
3801 MissingFileDialog dialog (s, str, type);
3806 int result = dialog.run ();
3813 return 1; // quit entire session load
3816 result = dialog.get_action ();
3822 ARDOUR_UI::ambiguous_file (std::string file, std::string /*path*/, std::vector<std::string> hits)
3824 AmbiguousFileDialog dialog (file, hits);
3830 return dialog.get_which ();