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_thread.h"
96 #include "location_ui.h"
97 #include "missing_file_dialog.h"
98 #include "missing_plugin_dialog.h"
101 #include "processor_box.h"
102 #include "prompter.h"
103 #include "public_editor.h"
104 #include "route_time_axis.h"
105 #include "session_metadata_dialog.h"
106 #include "shuttle_control.h"
107 #include "speaker_dialog.h"
110 #include "theme_manager.h"
111 #include "time_axis_view_item.h"
113 #include "window_proxy.h"
117 using namespace ARDOUR;
119 using namespace Gtkmm2ext;
122 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
123 UIConfiguration *ARDOUR_UI::ui_config = 0;
125 sigc::signal<void,bool> ARDOUR_UI::Blink;
126 sigc::signal<void> ARDOUR_UI::RapidScreenUpdate;
127 sigc::signal<void> ARDOUR_UI::SuperRapidScreenUpdate;
128 sigc::signal<void, framepos_t, bool, framepos_t> ARDOUR_UI::Clock;
130 bool could_be_a_valid_path (const string& path);
132 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[])
134 : Gtkmm2ext::UI (PROGRAM_NAME, argcp, argvp),
136 primary_clock (X_("primary"), false, X_("TransportClockDisplay"), true, true, false, true),
137 secondary_clock (X_("secondary"), false, X_("SecondaryClockDisplay"), true, true, false, true),
138 preroll_clock (X_("preroll"), false, X_("PreRollClock"), true, false, true),
139 postroll_clock (X_("postroll"), false, X_("PostRollClock"), true, false, true),
143 preroll_button (_("pre\nroll")),
144 postroll_button (_("post\nroll")),
148 big_clock (X_("bigclock"), false, "BigClockNonRecording", true, true, false, false),
152 roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll)),
153 stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop)),
154 goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart)),
155 goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd)),
156 auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop)),
157 play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection)),
158 rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable)),
160 roll_button (roll_controllable),
161 stop_button (stop_controllable),
162 goto_start_button (goto_start_controllable),
163 goto_end_button (goto_end_controllable),
164 auto_loop_button (auto_loop_controllable),
165 play_selection_button (play_selection_controllable),
166 rec_button (rec_controllable),
168 punch_in_button (_("Punch In")),
169 punch_out_button (_("Punch Out")),
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();
211 _session_is_new = false;
212 big_clock_window = 0;
213 big_clock_height = 0;
214 big_clock_resize_in_progress = false;
215 session_selector_window = 0;
216 last_key_press_time = 0;
217 _will_create_new_session_automatically = false;
218 add_route_dialog = 0;
220 rc_option_editor = 0;
221 session_option_editor = 0;
223 open_session_selector = 0;
224 have_configure_timeout = false;
225 have_disk_speed_dialog_displayed = false;
226 session_loaded = false;
227 ignore_dual_punch = false;
228 original_big_clock_width = -1;
229 original_big_clock_height = -1;
230 original_big_clock_font_size = 0;
232 roll_button.unset_flags (Gtk::CAN_FOCUS);
233 stop_button.unset_flags (Gtk::CAN_FOCUS);
234 goto_start_button.unset_flags (Gtk::CAN_FOCUS);
235 goto_end_button.unset_flags (Gtk::CAN_FOCUS);
236 auto_loop_button.unset_flags (Gtk::CAN_FOCUS);
237 play_selection_button.unset_flags (Gtk::CAN_FOCUS);
238 rec_button.unset_flags (Gtk::CAN_FOCUS);
239 join_play_range_button.unset_flags (Gtk::CAN_FOCUS);
240 last_configure_time= 0;
243 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
244 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
246 /* handle dialog requests */
248 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
250 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
252 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
254 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
256 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
258 /* handle requests to quit (coming from JACK session) */
260 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::finish, this), gui_context ());
262 /* handle requests to deal with missing files */
264 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
266 /* and ambiguous files */
268 ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2, _3));
270 /* lets get this party started */
273 if (ARDOUR::init (ARDOUR_COMMAND_LINE::use_vst, ARDOUR_COMMAND_LINE::try_hw_optimization)) {
274 throw failed_constructor ();
277 setup_gtk_ardour_enums ();
280 GainMeter::setup_slider_pix ();
281 RouteTimeAxisView::setup_slider_pix ();
282 SendProcessorEntry::setup_slider_pix ();
283 SessionEvent::create_per_thread_pool ("GUI", 512);
285 } catch (failed_constructor& err) {
286 error << string_compose (_("could not initialize %1."), PROGRAM_NAME) << endmsg;
291 /* we like keyboards */
293 keyboard = new ArdourKeyboard(*this);
296 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
298 keyboard->set_state (*node, Stateful::loading_state_version);
301 /* we don't like certain modifiers */
302 Bindings::set_ignored_state (GDK_LOCK_MASK|GDK_MOD2_MASK|GDK_MOD3_MASK);
306 TimeAxisViewItem::set_constant_heights ();
308 /* The following must happen after ARDOUR::init() so that Config is set up */
310 location_ui = new ActionWindowProxy<LocationUIWindow> (X_("locations"), Config->extra_xml (X_("UI")), X_("ToggleLocations"));
311 big_clock_window = new ActionWindowProxy<Gtk::Window> (X_("bigclock"), Config->extra_xml (X_("UI")), X_("ToggleBigClock"));
312 speaker_config_window = new ActionWindowProxy<SpeakerDialog> (X_("speakerconf"), Config->extra_xml (X_("UI")), X_("toggle-speaker-config"));
314 for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) {
315 _global_port_matrix[*i] = new ActionWindowProxy<GlobalPortMatrixWindow> (
316 string_compose ("GlobalPortMatrix-%1", (*i).to_string()),
317 Config->extra_xml (X_("UI")),
318 string_compose ("toggle-%1-connection-manager", (*i).to_string())
324 SpeakerDialog* s = new SpeakerDialog ();
325 s->signal_unmap().connect (sigc::bind (sigc::ptr_fun (&ActionManager::uncheck_toggleaction), X_("<Actions>/Common/toggle-speaker-config")));
326 speaker_config_window->set (s);
328 starting.connect (sigc::mem_fun(*this, &ARDOUR_UI::startup));
329 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 switch (ask_about_saving_session(_("quit"))) {
817 /* use the default name */
818 if (save_state_canfail ("")) {
819 /* failed - don't quit */
820 MessageDialog msg (*editor,
822 Ardour was unable to save your session.\n\n\
823 If you still wish to quit, please use the\n\n\
824 \"Just quit\" option."));
835 second_connection.disconnect ();
836 point_one_second_connection.disconnect ();
837 point_oh_five_second_connection.disconnect ();
838 point_zero_one_second_connection.disconnect();
841 /* Save state before deleting the session, as that causes some
842 windows to be destroyed before their visible state can be
845 save_ardour_state ();
848 // _session->set_deletion_in_progress ();
849 _session->set_clean ();
850 _session->remove_pending_capture_state ();
855 ArdourDialog::close_all_dialogs ();
861 ARDOUR_UI::ask_about_saving_session (const string & what)
863 ArdourDialog window (_("Unsaved Session"));
864 Gtk::HBox dhbox; // the hbox for the image and text
865 Gtk::Label prompt_label;
866 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
870 msg = string_compose(_("Don't %1"), what);
871 window.add_button (msg, RESPONSE_REJECT);
872 msg = string_compose(_("Just %1"), what);
873 window.add_button (msg, RESPONSE_APPLY);
874 msg = string_compose(_("Save and %1"), what);
875 window.add_button (msg, RESPONSE_ACCEPT);
877 window.set_default_response (RESPONSE_ACCEPT);
879 Gtk::Button noquit_button (msg);
880 noquit_button.set_name ("EditorGTKButton");
885 if (_session->snap_name() == _session->name()) {
888 type = _("snapshot");
890 prompt = string_compose(_("The %1 \"%2\"\nhas not been saved.\n\nAny changes made this time\nwill be lost unless you save it.\n\nWhat do you want to do?"),
891 type, _session->snap_name());
893 prompt_label.set_text (prompt);
894 prompt_label.set_name (X_("PrompterLabel"));
895 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
897 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
898 dhbox.set_homogeneous (false);
899 dhbox.pack_start (*dimage, false, false, 5);
900 dhbox.pack_start (prompt_label, true, false, 5);
901 window.get_vbox()->pack_start (dhbox);
903 window.set_name (_("Prompter"));
904 window.set_position (Gtk::WIN_POS_MOUSE);
905 window.set_modal (true);
906 window.set_resizable (false);
912 window.set_keep_above (true);
915 ResponseType r = (ResponseType) window.run();
920 case RESPONSE_ACCEPT: // save and get out of here
922 case RESPONSE_APPLY: // get out of here
932 ARDOUR_UI::every_second ()
935 update_buffer_load ();
936 update_disk_space ();
941 ARDOUR_UI::every_point_one_seconds ()
943 shuttle_box->update_speed_display ();
944 RapidScreenUpdate(); /* EMIT_SIGNAL */
949 ARDOUR_UI::every_point_zero_one_seconds ()
951 // august 2007: actual update frequency: 40Hz, not 100Hz
953 SuperRapidScreenUpdate(); /* EMIT_SIGNAL */
958 ARDOUR_UI::update_sample_rate (framecnt_t)
962 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
964 if (!engine->connected()) {
966 snprintf (buf, sizeof (buf), _("disconnected"));
970 framecnt_t rate = engine->frame_rate();
972 if (fmod (rate, 1000.0) != 0.0) {
973 snprintf (buf, sizeof (buf), _("%.1f kHz / %4.1f ms"),
974 (float) rate/1000.0f,
975 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
977 snprintf (buf, sizeof (buf), _("%" PRId64 " kHz / %4.1f ms"),
979 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
983 sample_rate_label.set_text (buf);
987 ARDOUR_UI::update_cpu_load ()
990 snprintf (buf, sizeof (buf), _("DSP: %5.1f%%"), engine->get_cpu_load());
991 cpu_load_label.set_text (buf);
995 ARDOUR_UI::update_buffer_load ()
1001 c = _session->capture_load ();
1002 p = _session->playback_load ();
1004 snprintf (buf, sizeof (buf), _("Buffers p:%" PRIu32 "%% c:%" PRIu32 "%%"),
1005 _session->playback_load(), _session->capture_load());
1006 buffer_load_label.set_text (buf);
1008 buffer_load_label.set_text ("");
1013 ARDOUR_UI::count_recenabled_streams (Route& route)
1015 Track* track = dynamic_cast<Track*>(&route);
1016 if (track && track->record_enabled()) {
1017 rec_enabled_streams += track->n_inputs().n_total();
1022 ARDOUR_UI::update_disk_space()
1024 if (_session == 0) {
1028 framecnt_t frames = _session->available_capture_duration();
1030 framecnt_t fr = _session->frame_rate();
1032 if (frames == max_framecnt) {
1033 strcpy (buf, _("Disk: 24hrs+"));
1035 rec_enabled_streams = 0;
1036 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams);
1038 if (rec_enabled_streams) {
1039 frames /= rec_enabled_streams;
1046 hrs = frames / (fr * 3600);
1047 frames -= hrs * fr * 3600;
1048 mins = frames / (fr * 60);
1049 frames -= mins * fr * 60;
1052 snprintf (buf, sizeof(buf), _("Disk: %02dh:%02dm:%02ds"), hrs, mins, secs);
1055 disk_space_label.set_text (buf);
1057 // An attempt to make the disk space label flash red when space has run out.
1059 if (frames < fr * 60 * 5) {
1060 /* disk_space_box.style ("disk_space_label_empty"); */
1062 /* disk_space_box.style ("disk_space_label"); */
1068 ARDOUR_UI::update_wall_clock ()
1075 tm_now = localtime (&now);
1077 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1078 wall_clock_label.set_text (buf);
1084 ARDOUR_UI::session_menu (GdkEventButton */*ev*/)
1086 session_popup_menu->popup (0, 0);
1091 ARDOUR_UI::redisplay_recent_sessions ()
1093 std::vector<sys::path> session_directories;
1094 RecentSessionsSorter cmp;
1096 recent_session_display.set_model (Glib::RefPtr<TreeModel>(0));
1097 recent_session_model->clear ();
1099 ARDOUR::RecentSessions rs;
1100 ARDOUR::read_recent_sessions (rs);
1103 recent_session_display.set_model (recent_session_model);
1107 // sort them alphabetically
1108 sort (rs.begin(), rs.end(), cmp);
1110 for (ARDOUR::RecentSessions::iterator i = rs.begin(); i != rs.end(); ++i) {
1111 session_directories.push_back ((*i).second);
1114 for (vector<sys::path>::const_iterator i = session_directories.begin();
1115 i != session_directories.end(); ++i)
1117 std::vector<sys::path> state_file_paths;
1119 // now get available states for this session
1121 get_state_files_in_directory (*i, state_file_paths);
1123 vector<string*>* states;
1124 vector<const gchar*> item;
1125 string fullpath = (*i).to_string();
1127 /* remove any trailing / */
1129 if (fullpath[fullpath.length()-1] == '/') {
1130 fullpath = fullpath.substr (0, fullpath.length()-1);
1133 /* check whether session still exists */
1134 if (!Glib::file_test(fullpath.c_str(), Glib::FILE_TEST_EXISTS)) {
1135 /* session doesn't exist */
1136 cerr << "skipping non-existent session " << fullpath << endl;
1140 /* now get available states for this session */
1142 if ((states = Session::possible_states (fullpath)) == 0) {
1143 /* no state file? */
1147 std::vector<string> state_file_names(get_file_names_no_extension (state_file_paths));
1149 Gtk::TreeModel::Row row = *(recent_session_model->append());
1151 row[recent_session_columns.visible_name] = Glib::path_get_basename (fullpath);
1152 row[recent_session_columns.fullpath] = fullpath;
1154 if (state_file_names.size() > 1) {
1158 for (std::vector<std::string>::iterator i2 = state_file_names.begin();
1159 i2 != state_file_names.end(); ++i2)
1162 Gtk::TreeModel::Row child_row = *(recent_session_model->append (row.children()));
1164 child_row[recent_session_columns.visible_name] = *i2;
1165 child_row[recent_session_columns.fullpath] = fullpath;
1170 recent_session_display.set_model (recent_session_model);
1174 ARDOUR_UI::build_session_selector ()
1176 session_selector_window = new ArdourDialog (_("Recent Sessions"));
1178 Gtk::ScrolledWindow *scroller = manage (new Gtk::ScrolledWindow);
1180 session_selector_window->add_button (Stock::CANCEL, RESPONSE_CANCEL);
1181 session_selector_window->add_button (Stock::OPEN, RESPONSE_ACCEPT);
1182 session_selector_window->set_default_response (RESPONSE_ACCEPT);
1183 recent_session_model = TreeStore::create (recent_session_columns);
1184 recent_session_display.set_model (recent_session_model);
1185 recent_session_display.append_column (_("Recent Sessions"), recent_session_columns.visible_name);
1186 recent_session_display.set_headers_visible (false);
1187 recent_session_display.get_selection()->set_mode (SELECTION_BROWSE);
1188 recent_session_display.signal_row_activated().connect (sigc::mem_fun (*this, &ARDOUR_UI::recent_session_row_activated));
1190 scroller->add (recent_session_display);
1191 scroller->set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
1193 session_selector_window->set_name ("SessionSelectorWindow");
1194 session_selector_window->set_size_request (200, 400);
1195 session_selector_window->get_vbox()->pack_start (*scroller);
1197 recent_session_display.show();
1199 //session_selector_window->get_vbox()->show();
1203 ARDOUR_UI::recent_session_row_activated (const TreePath& /*path*/, TreeViewColumn* /*col*/)
1205 session_selector_window->response (RESPONSE_ACCEPT);
1209 ARDOUR_UI::open_recent_session ()
1211 bool can_return = (_session != 0);
1213 if (session_selector_window == 0) {
1214 build_session_selector ();
1217 redisplay_recent_sessions ();
1221 session_selector_window->set_position (WIN_POS_MOUSE);
1223 ResponseType r = (ResponseType) session_selector_window->run ();
1226 case RESPONSE_ACCEPT:
1230 session_selector_window->hide();
1237 if (recent_session_display.get_selection()->count_selected_rows() == 0) {
1241 session_selector_window->hide();
1243 Gtk::TreeModel::iterator i = recent_session_display.get_selection()->get_selected();
1245 if (i == recent_session_model->children().end()) {
1249 std::string path = (*i)[recent_session_columns.fullpath];
1250 std::string state = (*i)[recent_session_columns.visible_name];
1252 _session_is_new = false;
1254 if (load_session (path, state) == 0) {
1263 ARDOUR_UI::check_audioengine ()
1266 if (!engine->connected()) {
1267 MessageDialog msg (string_compose (
1268 _("%1 is not connected to JACK\n"
1269 "You cannot open or close sessions in this condition"),
1282 ARDOUR_UI::open_session ()
1284 if (!check_audioengine()) {
1289 /* popup selector window */
1291 if (open_session_selector == 0) {
1293 /* ardour sessions are folders */
1295 open_session_selector = new Gtk::FileChooserDialog (_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1296 open_session_selector->add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1297 open_session_selector->add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1298 open_session_selector->set_default_response(Gtk::RESPONSE_ACCEPT);
1300 FileFilter session_filter;
1301 session_filter.add_pattern ("*.ardour");
1302 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1303 open_session_selector->add_filter (session_filter);
1304 open_session_selector->set_filter (session_filter);
1307 int response = open_session_selector->run();
1308 open_session_selector->hide ();
1311 case RESPONSE_ACCEPT:
1314 open_session_selector->hide();
1318 open_session_selector->hide();
1319 string session_path = open_session_selector->get_filename();
1323 if (session_path.length() > 0) {
1324 if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1325 _session_is_new = isnew;
1326 load_session (path, name);
1333 ARDOUR_UI::session_add_midi_route (bool disk, RouteGroup* route_group, uint32_t how_many, string const & name_template)
1335 list<boost::shared_ptr<MidiTrack> > tracks;
1337 if (_session == 0) {
1338 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1345 tracks = _session->new_midi_track (ARDOUR::Normal, route_group, how_many, name_template);
1347 if (tracks.size() != how_many) {
1348 if (how_many == 1) {
1349 error << _("could not create a new midi track") << endmsg;
1351 error << string_compose (_("could not create %1 new midi tracks"), how_many) << endmsg;
1355 if ((route = _session->new_midi_route ()) == 0) {
1356 error << _("could not create new midi bus") << endmsg;
1362 MessageDialog msg (*editor,
1363 string_compose (_("There are insufficient JACK ports available\n\
1364 to create a new track or bus.\n\
1365 You should save %1, exit and\n\
1366 restart JACK with more ports."), PROGRAM_NAME));
1373 ARDOUR_UI::session_add_audio_route (
1375 int32_t input_channels,
1376 int32_t output_channels,
1377 ARDOUR::TrackMode mode,
1378 RouteGroup* route_group,
1380 string const & name_template
1383 list<boost::shared_ptr<AudioTrack> > tracks;
1386 if (_session == 0) {
1387 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1393 tracks = _session->new_audio_track (input_channels, output_channels, mode, route_group, how_many, name_template);
1395 if (tracks.size() != how_many) {
1396 if (how_many == 1) {
1397 error << _("could not create a new audio track") << endmsg;
1399 error << string_compose (_("could only create %1 of %2 new audio %3"),
1400 tracks.size(), how_many, (track ? _("tracks") : _("busses"))) << endmsg;
1406 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template);
1408 if (routes.size() != how_many) {
1409 if (how_many == 1) {
1410 error << _("could not create a new audio track") << endmsg;
1412 error << string_compose (_("could not create %1 new audio tracks"), how_many) << endmsg;
1419 MessageDialog msg (*editor,
1420 string_compose (_("There are insufficient JACK ports available\n\
1421 to create a new track or bus.\n\
1422 You should save %1, exit and\n\
1423 restart JACK with more ports."), PROGRAM_NAME));
1430 ARDOUR_UI::do_transport_locate (framepos_t new_position, bool with_roll)
1432 framecnt_t _preroll = 0;
1435 // XXX CONFIG_CHANGE FIX - requires AnyTime handling
1436 // _preroll = _session->convert_to_frames_at (new_position, Config->get_preroll());
1438 if (new_position > _preroll) {
1439 new_position -= _preroll;
1444 _session->request_locate (new_position, with_roll);
1449 ARDOUR_UI::transport_goto_start ()
1452 _session->goto_start();
1454 /* force displayed area in editor to start no matter
1455 what "follow playhead" setting is.
1459 editor->center_screen (_session->current_start_frame ());
1465 ARDOUR_UI::transport_goto_zero ()
1468 _session->request_locate (0);
1470 /* force displayed area in editor to start no matter
1471 what "follow playhead" setting is.
1475 editor->reset_x_origin (0);
1481 ARDOUR_UI::transport_goto_wallclock ()
1483 if (_session && editor) {
1490 localtime_r (&now, &tmnow);
1492 frames = tmnow.tm_hour * (60 * 60 * _session->frame_rate());
1493 frames += tmnow.tm_min * (60 * _session->frame_rate());
1494 frames += tmnow.tm_sec * _session->frame_rate();
1496 _session->request_locate (frames, _session->transport_rolling ());
1498 /* force displayed area in editor to start no matter
1499 what "follow playhead" setting is.
1503 editor->center_screen (frames);
1509 ARDOUR_UI::transport_goto_end ()
1512 framepos_t const frame = _session->current_end_frame();
1513 _session->request_locate (frame);
1515 /* force displayed area in editor to start no matter
1516 what "follow playhead" setting is.
1520 editor->center_screen (frame);
1526 ARDOUR_UI::transport_stop ()
1532 if (_session->is_auditioning()) {
1533 _session->cancel_audition ();
1537 _session->request_stop (false, true);
1541 ARDOUR_UI::transport_stop_and_forget_capture ()
1544 _session->request_stop (true, true);
1549 ARDOUR_UI::remove_last_capture()
1552 editor->remove_last_capture();
1557 ARDOUR_UI::transport_record (bool roll)
1561 switch (_session->record_status()) {
1562 case Session::Disabled:
1563 if (_session->ntracks() == 0) {
1564 MessageDialog msg (*editor, _("Please create 1 or more track\nbefore trying to record.\nCheck the Session menu."));
1568 _session->maybe_enable_record ();
1573 case Session::Recording:
1575 _session->request_stop();
1577 _session->disable_record (false, true);
1581 case Session::Enabled:
1582 _session->disable_record (false, true);
1585 //cerr << "ARDOUR_UI::transport_record () called roll = " << roll << " _session->record_status() = " << _session->record_status() << endl;
1589 ARDOUR_UI::transport_roll ()
1595 if (_session->is_auditioning()) {
1600 if (_session->config.get_external_sync()) {
1601 switch (_session->config.get_sync_source()) {
1605 /* transport controlled by the master */
1611 bool rolling = _session->transport_rolling();
1613 if (_session->get_play_loop()) {
1614 /* XXX it is not possible to just leave seamless loop and keep
1615 playing at present (nov 4th 2009)
1617 if (!Config->get_seamless_loop()) {
1618 _session->request_play_loop (false, true);
1620 } else if (_session->get_play_range () && !join_play_range_button.get_active()) {
1621 /* stop playing a range if we currently are */
1622 _session->request_play_range (0, true);
1625 if (join_play_range_button.get_active()) {
1626 _session->request_play_range (&editor->get_selection().time, true);
1630 _session->request_transport_speed (1.0f);
1635 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
1642 if (_session->is_auditioning()) {
1643 _session->cancel_audition ();
1647 if (_session->config.get_external_sync()) {
1648 switch (_session->config.get_sync_source()) {
1652 /* transport controlled by the master */
1657 bool rolling = _session->transport_rolling();
1658 bool affect_transport = true;
1660 if (rolling && roll_out_of_bounded_mode) {
1661 /* drop out of loop/range playback but leave transport rolling */
1662 if (_session->get_play_loop()) {
1663 if (Config->get_seamless_loop()) {
1664 /* the disk buffers contain copies of the loop - we can't
1665 just keep playing, so stop the transport. the user
1666 can restart as they wish.
1668 affect_transport = true;
1670 /* disk buffers are normal, so we can keep playing */
1671 affect_transport = false;
1673 _session->request_play_loop (false, true);
1674 } else if (_session->get_play_range ()) {
1675 affect_transport = false;
1676 _session->request_play_range (0, true);
1680 if (affect_transport) {
1682 _session->request_stop (with_abort, true);
1684 if (join_play_range_button.get_active()) {
1685 _session->request_play_range (&editor->get_selection().time, true);
1688 _session->request_transport_speed (1.0f);
1694 ARDOUR_UI::toggle_session_auto_loop ()
1700 if (_session->get_play_loop()) {
1702 if (_session->transport_rolling()) {
1704 Location * looploc = _session->locations()->auto_loop_location();
1707 _session->request_locate (looploc->start(), true);
1708 _session->request_play_loop (false);
1712 _session->request_play_loop (false);
1716 Location * looploc = _session->locations()->auto_loop_location();
1719 _session->request_play_loop (true);
1725 ARDOUR_UI::transport_play_selection ()
1731 editor->play_selection ();
1735 ARDOUR_UI::transport_rewind (int option)
1737 float current_transport_speed;
1740 current_transport_speed = _session->transport_speed();
1742 if (current_transport_speed >= 0.0f) {
1745 _session->request_transport_speed (-1.0f);
1748 _session->request_transport_speed (-4.0f);
1751 _session->request_transport_speed (-0.5f);
1756 _session->request_transport_speed (current_transport_speed * 1.5f);
1762 ARDOUR_UI::transport_forward (int option)
1764 float current_transport_speed;
1767 current_transport_speed = _session->transport_speed();
1769 if (current_transport_speed <= 0.0f) {
1772 _session->request_transport_speed (1.0f);
1775 _session->request_transport_speed (4.0f);
1778 _session->request_transport_speed (0.5f);
1783 _session->request_transport_speed (current_transport_speed * 1.5f);
1790 ARDOUR_UI::toggle_record_enable (uint32_t rid)
1792 if (_session == 0) {
1796 boost::shared_ptr<Route> r;
1798 if ((r = _session->route_by_remote_id (rid)) != 0) {
1802 if ((t = dynamic_cast<Track*>(r.get())) != 0) {
1803 t->set_record_enabled (!t->record_enabled(), this);
1806 if (_session == 0) {
1812 ARDOUR_UI::map_transport_state ()
1815 auto_loop_button.set_visual_state (0);
1816 play_selection_button.set_visual_state (0);
1817 roll_button.set_visual_state (0);
1818 stop_button.set_visual_state (1);
1822 shuttle_box->map_transport_state ();
1824 float sp = _session->transport_speed();
1830 if (_session->get_play_range()) {
1832 play_selection_button.set_visual_state (1);
1833 roll_button.set_visual_state (0);
1834 auto_loop_button.set_visual_state (0);
1836 } else if (_session->get_play_loop ()) {
1838 auto_loop_button.set_visual_state (1);
1839 play_selection_button.set_visual_state (0);
1840 roll_button.set_visual_state (0);
1844 roll_button.set_visual_state (1);
1845 play_selection_button.set_visual_state (0);
1846 auto_loop_button.set_visual_state (0);
1849 if (join_play_range_button.get_active()) {
1850 /* light up both roll and play-selection if they are joined */
1851 roll_button.set_visual_state (1);
1852 play_selection_button.set_visual_state (1);
1855 stop_button.set_visual_state (0);
1859 stop_button.set_visual_state (1);
1860 roll_button.set_visual_state (0);
1861 play_selection_button.set_visual_state (0);
1862 auto_loop_button.set_visual_state (0);
1863 update_disk_space ();
1868 ARDOUR_UI::engine_stopped ()
1870 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
1871 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1872 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1876 ARDOUR_UI::engine_running ()
1878 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
1879 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, true);
1880 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, false);
1882 Glib::RefPtr<Action> action;
1883 const char* action_name = 0;
1885 switch (engine->frames_per_cycle()) {
1887 action_name = X_("JACKLatency32");
1890 action_name = X_("JACKLatency64");
1893 action_name = X_("JACKLatency128");
1896 action_name = X_("JACKLatency512");
1899 action_name = X_("JACKLatency1024");
1902 action_name = X_("JACKLatency2048");
1905 action_name = X_("JACKLatency4096");
1908 action_name = X_("JACKLatency8192");
1911 /* XXX can we do anything useful ? */
1917 action = ActionManager::get_action (X_("JACK"), action_name);
1920 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (action);
1921 ract->set_active ();
1927 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
1929 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
1930 /* we can't rely on the original string continuing to exist when we are called
1931 again in the GUI thread, so make a copy and note that we need to
1934 char *copy = strdup (reason);
1935 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
1939 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1940 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1942 update_sample_rate (0);
1946 /* if the reason is a non-empty string, it means that the backend was shutdown
1947 rather than just Ardour.
1950 if (strlen (reason)) {
1951 msgstr = string_compose (_("The audio backend (JACK) was shutdown because:\n\n%1"), reason);
1953 msgstr = string_compose (_("\
1954 JACK has either been shutdown or it\n\
1955 disconnected %1 because %1\n\
1956 was not fast enough. Try to restart\n\
1957 JACK, reconnect and save the session."), PROGRAM_NAME);
1960 MessageDialog msg (*editor, msgstr);
1965 free ((char*) reason);
1970 ARDOUR_UI::do_engine_start ()
1978 error << _("Unable to start the session running")
1988 ARDOUR_UI::setup_theme ()
1990 theme_manager->setup_theme();
1994 ARDOUR_UI::update_clocks ()
1996 if (!editor || !editor->dragging_playhead()) {
1997 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position()); /* EMIT_SIGNAL */
2002 ARDOUR_UI::start_clocking ()
2004 clock_signal_connection = RapidScreenUpdate.connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2008 ARDOUR_UI::stop_clocking ()
2010 clock_signal_connection.disconnect ();
2014 ARDOUR_UI::toggle_clocking ()
2017 if (clock_button.get_active()) {
2026 ARDOUR_UI::_blink (void *arg)
2029 ((ARDOUR_UI *) arg)->blink ();
2036 Blink (blink_on = !blink_on); /* EMIT_SIGNAL */
2040 ARDOUR_UI::start_blinking ()
2042 /* Start the blink signal. Everybody with a blinking widget
2043 uses Blink to drive the widget's state.
2046 if (blink_timeout_tag < 0) {
2048 blink_timeout_tag = g_timeout_add (240, _blink, this);
2053 ARDOUR_UI::stop_blinking ()
2055 if (blink_timeout_tag >= 0) {
2056 g_source_remove (blink_timeout_tag);
2057 blink_timeout_tag = -1;
2062 /** Ask the user for the name of a new shapshot and then take it.
2066 ARDOUR_UI::snapshot_session (bool switch_to_it)
2068 ArdourPrompter prompter (true);
2071 prompter.set_name ("Prompter");
2072 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2073 prompter.set_title (_("Take Snapshot"));
2074 prompter.set_title (_("Take Snapshot"));
2075 prompter.set_prompt (_("Name of new snapshot"));
2077 if (!switch_to_it) {
2080 struct tm local_time;
2083 localtime_r (&n, &local_time);
2084 strftime (timebuf, sizeof(timebuf), "%FT%T", &local_time);
2085 prompter.set_initial_text (timebuf);
2089 switch (prompter.run()) {
2090 case RESPONSE_ACCEPT:
2092 prompter.get_result (snapname);
2094 bool do_save = (snapname.length() != 0);
2097 if (snapname.find ('/') != string::npos) {
2098 MessageDialog msg (_("To ensure compatibility with various systems\n"
2099 "snapshot names may not contain a '/' character"));
2103 if (snapname.find ('\\') != string::npos) {
2104 MessageDialog msg (_("To ensure compatibility with various systems\n"
2105 "snapshot names may not contain a '\\' character"));
2111 vector<sys::path> p;
2112 get_state_files_in_directory (_session->session_directory().root_path(), p);
2113 vector<string> n = get_file_names_no_extension (p);
2114 if (find (n.begin(), n.end(), snapname) != n.end()) {
2116 ArdourDialog confirm (_("Confirm Snapshot Overwrite"), true);
2117 Label m (_("A snapshot already exists with that name. Do you want to overwrite it?"));
2118 confirm.get_vbox()->pack_start (m, true, true);
2119 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2120 confirm.add_button (_("Overwrite"), Gtk::RESPONSE_ACCEPT);
2121 confirm.show_all ();
2122 switch (confirm.run()) {
2123 case RESPONSE_CANCEL:
2129 save_state (snapname, switch_to_it);
2140 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2142 XMLNode* node = new XMLNode (X_("UI"));
2144 for (list<WindowProxyBase*>::iterator i = _window_proxies.begin(); i != _window_proxies.end(); ++i) {
2145 if (!(*i)->rc_configured()) {
2146 node->add_child_nocopy (*((*i)->get_state ()));
2150 _session->add_extra_xml (*node);
2152 save_state_canfail (name, switch_to_it);
2156 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2161 if (name.length() == 0) {
2162 name = _session->snap_name();
2165 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2169 cerr << "SS canfail\n";
2170 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2175 ARDOUR_UI::primary_clock_value_changed ()
2178 _session->request_locate (primary_clock.current_time ());
2183 ARDOUR_UI::big_clock_value_changed ()
2186 _session->request_locate (big_clock.current_time ());
2191 ARDOUR_UI::secondary_clock_value_changed ()
2194 _session->request_locate (secondary_clock.current_time ());
2199 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2201 if (_session == 0) {
2205 if (_session->step_editing()) {
2209 Session::RecordState const r = _session->record_status ();
2210 bool const h = _session->have_rec_enabled_track ();
2212 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2214 rec_button.set_visual_state (2);
2216 rec_button.set_visual_state (0);
2218 } else if (r == Session::Recording && h) {
2219 rec_button.set_visual_state (1);
2221 rec_button.set_visual_state (0);
2226 ARDOUR_UI::save_template ()
2228 ArdourPrompter prompter (true);
2231 if (!check_audioengine()) {
2235 prompter.set_name (X_("Prompter"));
2236 prompter.set_title (_("Save Template"));
2237 prompter.set_prompt (_("Name for template:"));
2238 prompter.set_initial_text(_session->name() + _("-template"));
2239 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2241 switch (prompter.run()) {
2242 case RESPONSE_ACCEPT:
2243 prompter.get_result (name);
2245 if (name.length()) {
2246 _session->save_template (name);
2256 ARDOUR_UI::edit_metadata ()
2258 SessionMetadataEditor dialog;
2259 dialog.set_session (_session);
2260 editor->ensure_float (dialog);
2265 ARDOUR_UI::import_metadata ()
2267 SessionMetadataImporter dialog;
2268 dialog.set_session (_session);
2269 editor->ensure_float (dialog);
2274 ARDOUR_UI::fontconfig_dialog ()
2277 /* X11 users will always have fontconfig info around, but new GTK-OSX users
2278 may not and it can take a while to build it. Warn them.
2281 std::string fontconfig = Glib::build_filename (Glib::get_home_dir(), ".fontconfig");
2283 if (!Glib::file_test (fontconfig, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_DIR)) {
2284 MessageDialog msg (*_startup,
2285 string_compose (_("Welcome to %1.\n\n"
2286 "The program will take a bit longer to start up\n"
2287 "while the system fonts are checked.\n\n"
2288 "This will only be done once, and you will\n"
2289 "not see this message again\n"), PROGRAM_NAME),
2302 ARDOUR_UI::parse_cmdline_path (const std::string& cmdline_path, std::string& session_name, std::string& session_path, bool& existing_session)
2304 existing_session = false;
2306 if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_DIR)) {
2307 session_path = cmdline_path;
2308 existing_session = true;
2309 } else if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_REGULAR)) {
2310 session_path = Glib::path_get_dirname (string (cmdline_path));
2311 existing_session = true;
2313 /* it doesn't exist, assume the best */
2314 session_path = Glib::path_get_dirname (string (cmdline_path));
2317 session_name = basename_nosuffix (string (cmdline_path));
2321 ARDOUR_UI::load_cmdline_session (const std::string& session_name, const std::string& session_path, bool& existing_session)
2323 /* when this is called, the backend audio system must be running */
2325 /* the main idea here is to deal with the fact that a cmdline argument for the session
2326 can be interpreted in different ways - it could be a directory or a file, and before
2327 we load, we need to know both the session directory and the snapshot (statefile) within it
2328 that we are supposed to use.
2331 if (session_name.length() == 0 || session_path.length() == 0) {
2335 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_DIR)) {
2337 std::string predicted_session_file;
2339 predicted_session_file = session_path;
2340 predicted_session_file += '/';
2341 predicted_session_file += session_name;
2342 predicted_session_file += ARDOUR::statefile_suffix;
2344 if (Glib::file_test (predicted_session_file, Glib::FILE_TEST_EXISTS)) {
2345 existing_session = true;
2348 } else if (Glib::file_test (session_path, Glib::FILE_TEST_EXISTS)) {
2350 if (session_path.find (ARDOUR::statefile_suffix) == session_path.length() - 7) {
2351 /* existing .ardour file */
2352 existing_session = true;
2356 existing_session = false;
2359 /* lets just try to load it */
2361 if (create_engine ()) {
2362 backend_audio_error (false, _startup);
2366 return load_session (session_path, session_name);
2370 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
2372 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2374 MessageDialog msg (str,
2376 Gtk::MESSAGE_WARNING,
2377 Gtk::BUTTONS_YES_NO,
2381 msg.set_name (X_("OpenExistingDialog"));
2382 msg.set_title (_("Open Existing Session"));
2383 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
2384 msg.set_position (Gtk::WIN_POS_MOUSE);
2387 switch (msg.run()) {
2396 ARDOUR_UI::build_session_from_nsd (const std::string& session_path, const std::string& session_name)
2398 BusProfile bus_profile;
2400 if (Profile->get_sae()) {
2402 bus_profile.master_out_channels = 2;
2403 bus_profile.input_ac = AutoConnectPhysical;
2404 bus_profile.output_ac = AutoConnectMaster;
2405 bus_profile.requested_physical_in = 0; // use all available
2406 bus_profile.requested_physical_out = 0; // use all available
2410 /* get settings from advanced section of NSD */
2412 if (_startup->create_master_bus()) {
2413 bus_profile.master_out_channels = (uint32_t) _startup->master_channel_count();
2415 bus_profile.master_out_channels = 0;
2418 if (_startup->connect_inputs()) {
2419 bus_profile.input_ac = AutoConnectPhysical;
2421 bus_profile.input_ac = AutoConnectOption (0);
2424 /// @todo some minor tweaks.
2426 bus_profile.output_ac = AutoConnectOption (0);
2428 if (_startup->connect_outputs ()) {
2429 if (_startup->connect_outs_to_master()) {
2430 bus_profile.output_ac = AutoConnectMaster;
2431 } else if (_startup->connect_outs_to_physical()) {
2432 bus_profile.output_ac = AutoConnectPhysical;
2436 bus_profile.requested_physical_in = (uint32_t) _startup->input_limit_count();
2437 bus_profile.requested_physical_out = (uint32_t) _startup->output_limit_count();
2440 if (build_session (session_path, session_name, bus_profile)) {
2448 ARDOUR_UI::idle_load (const std::string& path)
2451 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2452 /* /path/to/foo => /path/to/foo, foo */
2453 load_session (path, basename_nosuffix (path));
2455 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2456 load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2460 ARDOUR_COMMAND_LINE::session_name = path;
2463 * new_session_dialog doens't exist in A3
2464 * Try to remove all references to it to
2465 * see if it will compile. NOTE: this will
2466 * likely cause a runtime issue is my somewhat
2470 //if (new_session_dialog) {
2473 /* make it break out of Dialog::run() and
2477 //new_session_dialog->response (1);
2483 ARDOUR_UI::end_loading_messages ()
2489 ARDOUR_UI::loading_message (const std::string& /*msg*/)
2492 // splash->message (msg);
2496 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
2498 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
2500 string session_name;
2501 string session_path;
2502 string template_name;
2504 bool likely_new = false;
2506 if (! load_template.empty()) {
2507 should_be_new = true;
2508 template_name = load_template;
2513 if (!should_be_new && !ARDOUR_COMMAND_LINE::session_name.empty()) {
2515 /* if they named a specific statefile, use it, otherwise they are
2516 just giving a session folder, and we want to use it as is
2517 to find the session.
2520 if (ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix) != string::npos) {
2521 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
2523 session_path = ARDOUR_COMMAND_LINE::session_name;
2526 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
2530 bool const apply = run_startup (should_be_new, load_template);
2533 if (quit_on_cancel) {
2540 /* if we run the startup dialog again, offer more than just "new session" */
2542 should_be_new = false;
2544 session_name = _startup->session_name (likely_new);
2546 /* this shouldn't happen, but we catch it just in case it does */
2548 if (session_name.empty()) {
2552 if (_startup->use_session_template()) {
2553 template_name = _startup->session_template_name();
2554 _session_is_new = true;
2557 if (session_name[0] == G_DIR_SEPARATOR ||
2558 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
2559 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)) {
2561 /* absolute path or cwd-relative path specified for session name: infer session folder
2562 from what was given.
2565 session_path = Glib::path_get_dirname (session_name);
2566 session_name = Glib::path_get_basename (session_name);
2570 session_path = _startup->session_folder();
2572 if (session_name.find ('/') != string::npos) {
2573 MessageDialog msg (*_startup,
2574 _("To ensure compatibility with various systems\n"
2575 "session names may not contain a '/' character"));
2577 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2581 if (session_name.find ('\\') != string::npos) {
2582 MessageDialog msg (*_startup,
2583 _("To ensure compatibility with various systems\n"
2584 "session names may not contain a '\\' character"));
2586 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2592 if (create_engine ()) {
2596 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
2600 std::string existing = Glib::build_filename (session_path, session_name);
2602 if (!ask_about_loading_existing_session (existing)) {
2603 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2608 _session_is_new = false;
2613 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
2615 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2619 if (session_name.find ('/') != std::string::npos) {
2620 MessageDialog msg (*_startup,
2621 _("To ensure compatibility with various systems\n"
2622 "session names may not contain a '/' character"));
2624 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2628 if (session_name.find ('\\') != std::string::npos) {
2629 MessageDialog msg (*_startup,
2630 _("To ensure compatibility with various systems\n"
2631 "session names may not contain a '\\' character"));
2633 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2637 _session_is_new = true;
2640 if (likely_new && template_name.empty()) {
2642 ret = build_session_from_nsd (session_path, session_name);
2646 ret = load_session (session_path, session_name, template_name);
2649 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
2653 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
2654 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
2664 ARDOUR_UI::close_session()
2666 if (!check_audioengine()) {
2670 if (unload_session (true)) {
2674 ARDOUR_COMMAND_LINE::session_name = "";
2676 if (get_session_parameters (true, false)) {
2680 goto_editor_window ();
2683 /** @return -2 if the load failed because we are not connected to the AudioEngine */
2685 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
2687 Session *new_session;
2691 session_loaded = false;
2693 if (!check_audioengine()) {
2697 unload_status = unload_session ();
2699 if (unload_status < 0) {
2701 } else if (unload_status > 0) {
2706 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
2709 new_session = new Session (*engine, path, snap_name, 0, mix_template);
2712 /* this one is special */
2714 catch (AudioEngine::PortRegistrationFailure& err) {
2716 MessageDialog msg (err.what(),
2719 Gtk::BUTTONS_CLOSE);
2721 msg.set_title (_("Port Registration Error"));
2722 msg.set_secondary_text (_("Click the Close button to try again."));
2723 msg.set_position (Gtk::WIN_POS_CENTER);
2727 int response = msg.run ();
2732 case RESPONSE_CANCEL:
2742 MessageDialog msg (string_compose(
2743 _("Session \"%1 (snapshot %2)\" did not load successfully"),
2749 msg.set_title (_("Loading Error"));
2750 msg.set_secondary_text (_("Click the Refresh button to try again."));
2751 msg.add_button (Stock::REFRESH, 1);
2752 msg.set_position (Gtk::WIN_POS_CENTER);
2756 int response = msg.run ();
2771 list<string> const u = new_session->unknown_processors ();
2773 MissingPluginDialog d (_session, u);
2778 /* Now the session been created, add the transport controls */
2779 new_session->add_controllable(roll_controllable);
2780 new_session->add_controllable(stop_controllable);
2781 new_session->add_controllable(goto_start_controllable);
2782 new_session->add_controllable(goto_end_controllable);
2783 new_session->add_controllable(auto_loop_controllable);
2784 new_session->add_controllable(play_selection_controllable);
2785 new_session->add_controllable(rec_controllable);
2787 set_session (new_session);
2789 session_loaded = true;
2791 goto_editor_window ();
2794 _session->set_clean ();
2805 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
2807 Session *new_session;
2810 if (!check_audioengine()) {
2814 session_loaded = false;
2816 x = unload_session ();
2824 _session_is_new = true;
2827 new_session = new Session (*engine, path, snap_name, &bus_profile);
2832 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
2838 /* Give the new session the default GUI state, if such things exist */
2841 n = Config->instant_xml (X_("Editor"));
2843 new_session->add_instant_xml (*n, false);
2845 n = Config->instant_xml (X_("Mixer"));
2847 new_session->add_instant_xml (*n, false);
2850 /* Put the playhead at 0 and scroll fully left */
2851 n = new_session->instant_xml (X_("Editor"));
2853 n->add_property (X_("playhead"), X_("0"));
2854 n->add_property (X_("left-frame"), X_("0"));
2857 set_session (new_session);
2859 session_loaded = true;
2861 new_session->save_state(new_session->name());
2867 ARDOUR_UI::launch_chat ()
2870 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
2872 open_uri("http://webchat.freenode.net/?channels=ardour");
2877 ARDOUR_UI::show_about ()
2881 about->signal_response().connect(sigc::mem_fun (*this, &ARDOUR_UI::about_signal_response) );
2884 about->set_transient_for(*editor);
2889 ARDOUR_UI::launch_manual ()
2891 PBD::open_uri("http://ardour.org/flossmanual");
2895 ARDOUR_UI::launch_reference ()
2897 PBD::open_uri("http://ardour.org/refmanual");
2901 ARDOUR_UI::hide_about ()
2904 about->get_window()->set_cursor ();
2910 ARDOUR_UI::about_signal_response (int /*response*/)
2916 ARDOUR_UI::show_splash ()
2920 splash = new Splash;
2928 splash->queue_draw ();
2929 splash->get_window()->process_updates (true);
2934 ARDOUR_UI::hide_splash ()
2942 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title,
2943 const string& plural_msg, const string& singular_msg)
2947 removed = rep.paths.size();
2950 MessageDialog msgd (*editor,
2951 _("No files were ready for clean-up"),
2954 (Gtk::ButtonsType)(Gtk::BUTTONS_OK) );
2955 msgd.set_title (_("Clean-up"));
2956 msgd.set_secondary_text (_("If this seems suprising, \n\
2957 check for any existing snapshots.\n\
2958 These may still include regions that\n\
2959 require some unused files to continue to exist."));
2965 ArdourDialog results (_("Clean-up"), true, false);
2967 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
2968 CleanupResultsModelColumns() {
2972 Gtk::TreeModelColumn<std::string> visible_name;
2973 Gtk::TreeModelColumn<std::string> fullpath;
2977 CleanupResultsModelColumns results_columns;
2978 Glib::RefPtr<Gtk::ListStore> results_model;
2979 Gtk::TreeView results_display;
2981 results_model = ListStore::create (results_columns);
2982 results_display.set_model (results_model);
2983 results_display.append_column (list_title, results_columns.visible_name);
2985 results_display.set_name ("CleanupResultsList");
2986 results_display.set_headers_visible (true);
2987 results_display.set_headers_clickable (false);
2988 results_display.set_reorderable (false);
2990 Gtk::ScrolledWindow list_scroller;
2993 Gtk::HBox dhbox; // the hbox for the image and text
2994 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
2995 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
2997 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
2999 const string dead_directory = _session->session_directory().dead_path().to_string();
3002 %1 - number of files removed
3003 %2 - location of "dead"
3004 %3 - size of files affected
3005 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
3008 const char* bprefix;
3009 double space_adjusted = 0;
3011 if (rep.space < 1000) {
3013 space_adjusted = rep.space;
3014 } else if (rep.space < 1000000) {
3015 bprefix = X_("kilo");
3016 space_adjusted = truncf((float)rep.space / 1000.0);
3017 } else if (rep.space < 1000000 * 1000) {
3018 bprefix = X_("mega");
3019 space_adjusted = truncf((float)rep.space / (1000.0 * 1000.0));
3021 bprefix = X_("giga");
3022 space_adjusted = truncf((float)rep.space / (1000.0 * 1000 * 1000.0));
3026 txt.set_text (string_compose (plural_msg, removed, dead_directory, space_adjusted, bprefix));
3028 txt.set_text (string_compose (singular_msg, removed, dead_directory, space_adjusted, bprefix));
3031 dhbox.pack_start (*dimage, true, false, 5);
3032 dhbox.pack_start (txt, true, false, 5);
3034 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
3035 TreeModel::Row row = *(results_model->append());
3036 row[results_columns.visible_name] = *i;
3037 row[results_columns.fullpath] = *i;
3040 list_scroller.add (results_display);
3041 list_scroller.set_size_request (-1, 150);
3042 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
3044 dvbox.pack_start (dhbox, true, false, 5);
3045 dvbox.pack_start (list_scroller, true, false, 5);
3046 ddhbox.pack_start (dvbox, true, false, 5);
3048 results.get_vbox()->pack_start (ddhbox, true, false, 5);
3049 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
3050 results.set_default_response (RESPONSE_CLOSE);
3051 results.set_position (Gtk::WIN_POS_MOUSE);
3053 results_display.show();
3054 list_scroller.show();
3061 //results.get_vbox()->show();
3062 results.set_resizable (false);
3069 ARDOUR_UI::cleanup ()
3071 if (_session == 0) {
3072 /* shouldn't happen: menu item is insensitive */
3077 MessageDialog checker (_("Are you sure you want to clean-up?"),
3079 Gtk::MESSAGE_QUESTION,
3080 (Gtk::ButtonsType)(Gtk::BUTTONS_NONE));
3082 checker.set_title (_("Clean-up"));
3084 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
3085 ALL undo/redo information will be lost if you clean-up.\n\
3086 Clean-up will move all unused files to a \"dead\" location."));
3088 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3089 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
3090 checker.set_default_response (RESPONSE_CANCEL);
3092 checker.set_name (_("CleanupDialog"));
3093 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3094 checker.set_position (Gtk::WIN_POS_MOUSE);
3096 switch (checker.run()) {
3097 case RESPONSE_ACCEPT:
3103 ARDOUR::CleanupReport rep;
3105 editor->prepare_for_cleanup ();
3107 /* do not allow flush until a session is reloaded */
3109 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3111 act->set_sensitive (false);
3114 if (_session->cleanup_sources (rep)) {
3115 editor->finish_cleanup ();
3119 editor->finish_cleanup ();
3122 display_cleanup_results (rep,
3125 The following %1 files were not in use and \n\
3126 have been moved to:\n\n\
3128 After a restart of Ardour,\n\n\
3129 Session -> Clean-up -> Flush Wastebasket\n\n\
3130 will release an additional\n\
3131 %3 %4bytes of disk space.\n"),
3133 The following file was not in use and \n\
3134 has been moved to:\n \
3136 After a restart of Ardour,\n\n\
3137 Session -> Clean-up -> Flush Wastebasket\n\n\
3138 will release an additional\n\
3139 %3 %4bytes of disk space.\n"
3145 ARDOUR_UI::flush_trash ()
3147 if (_session == 0) {
3148 /* shouldn't happen: menu item is insensitive */
3152 ARDOUR::CleanupReport rep;
3154 if (_session->cleanup_trash_sources (rep)) {
3158 display_cleanup_results (rep,
3160 _("The following %1 files were deleted from\n\
3162 releasing %3 %4bytes of disk space"),
3163 _("The following file was deleted from\n\
3165 releasing %3 %4bytes of disk space"));
3169 ARDOUR_UI::add_route (Gtk::Window* float_window)
3177 if (add_route_dialog == 0) {
3178 add_route_dialog = new AddRouteDialog (_session);
3180 add_route_dialog->set_transient_for (*float_window);
3184 if (add_route_dialog->is_visible()) {
3185 /* we're already doing this */
3189 ResponseType r = (ResponseType) add_route_dialog->run ();
3191 add_route_dialog->hide();
3194 case RESPONSE_ACCEPT:
3201 if ((count = add_route_dialog->count()) <= 0) {
3205 string template_path = add_route_dialog->track_template();
3207 if (!template_path.empty()) {
3208 _session->new_route_from_template (count, template_path);
3212 uint32_t input_chan = add_route_dialog->channels ();
3213 uint32_t output_chan;
3214 string name_template = add_route_dialog->name_template ();
3215 bool track = add_route_dialog->track ();
3216 RouteGroup* route_group = add_route_dialog->route_group ();
3218 AutoConnectOption oac = Config->get_output_auto_connect();
3220 if (oac & AutoConnectMaster) {
3221 output_chan = (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan);
3223 output_chan = input_chan;
3226 /* XXX do something with name template */
3228 if (add_route_dialog->type() == ARDOUR::DataType::MIDI) {
3230 session_add_midi_track (route_group, count, name_template);
3232 MessageDialog msg (*editor,
3233 _("Sorry, MIDI Busses are not supported at this time."));
3235 //session_add_midi_bus();
3239 session_add_audio_track (input_chan, output_chan, add_route_dialog->mode(), route_group, count, name_template);
3241 session_add_audio_bus (input_chan, output_chan, route_group, count, name_template);
3247 ARDOUR_UI::mixer_settings () const
3252 node = _session->instant_xml(X_("Mixer"));
3254 node = Config->instant_xml(X_("Mixer"));
3258 node = new XMLNode (X_("Mixer"));
3265 ARDOUR_UI::editor_settings () const
3270 node = _session->instant_xml(X_("Editor"));
3272 node = Config->instant_xml(X_("Editor"));
3276 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
3277 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
3282 node = new XMLNode (X_("Editor"));
3289 ARDOUR_UI::keyboard_settings () const
3293 node = Config->extra_xml(X_("Keyboard"));
3296 node = new XMLNode (X_("Keyboard"));
3303 ARDOUR_UI::create_xrun_marker (framepos_t where)
3305 editor->mouse_add_new_marker (where, false, true);
3309 ARDOUR_UI::halt_on_xrun_message ()
3311 MessageDialog msg (*editor,
3312 _("Recording was stopped because your system could not keep up."));
3317 ARDOUR_UI::xrun_handler (framepos_t where)
3323 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
3325 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
3326 create_xrun_marker(where);
3329 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
3330 halt_on_xrun_message ();
3335 ARDOUR_UI::disk_overrun_handler ()
3337 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
3339 if (!have_disk_speed_dialog_displayed) {
3340 have_disk_speed_dialog_displayed = true;
3341 MessageDialog* msg = new MessageDialog (*editor, string_compose (_("\
3342 The disk system on your computer\n\
3343 was not able to keep up with %1.\n\
3345 Specifically, it failed to write data to disk\n\
3346 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
3347 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3353 ARDOUR_UI::disk_underrun_handler ()
3355 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
3357 if (!have_disk_speed_dialog_displayed) {
3358 have_disk_speed_dialog_displayed = true;
3359 MessageDialog* msg = new MessageDialog (
3360 *editor, string_compose (_("The disk system on your computer\n\
3361 was not able to keep up with %1.\n\
3363 Specifically, it failed to read data from disk\n\
3364 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
3365 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3371 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
3373 have_disk_speed_dialog_displayed = false;
3378 ARDOUR_UI::session_dialog (std::string msg)
3380 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
3385 d = new MessageDialog (*editor, msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3387 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3396 ARDOUR_UI::pending_state_dialog ()
3398 HBox* hbox = new HBox();
3399 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3400 ArdourDialog dialog (_("Crash Recovery"), true);
3402 This session appears to have been in\n\
3403 middle of recording when ardour or\n\
3404 the computer was shutdown.\n\
3406 Ardour can recover any captured audio for\n\
3407 you, or it can ignore it. Please decide\n\
3408 what you would like to do.\n"));
3409 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3410 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3411 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3412 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3413 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
3414 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
3415 dialog.set_default_response (RESPONSE_ACCEPT);
3416 dialog.set_position (WIN_POS_CENTER);
3421 switch (dialog.run ()) {
3422 case RESPONSE_ACCEPT:
3430 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
3432 HBox* hbox = new HBox();
3433 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3434 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
3435 Label message (string_compose (_("\
3436 This session was created with a sample rate of %1 Hz\n\
3438 The audioengine is currently running at %2 Hz\n"), desired, actual));
3440 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3441 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3442 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3443 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3444 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
3445 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
3446 dialog.set_default_response (RESPONSE_ACCEPT);
3447 dialog.set_position (WIN_POS_CENTER);
3452 switch (dialog.run ()) {
3453 case RESPONSE_ACCEPT:
3462 ARDOUR_UI::disconnect_from_jack ()
3465 if( engine->disconnect_from_jack ()) {
3466 MessageDialog msg (*editor, _("Could not disconnect from JACK"));
3470 update_sample_rate (0);
3475 ARDOUR_UI::reconnect_to_jack ()
3478 if (engine->reconnect_to_jack ()) {
3479 MessageDialog msg (*editor, _("Could not reconnect to JACK"));
3483 update_sample_rate (0);
3488 ARDOUR_UI::use_config ()
3490 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
3492 set_transport_controllable_state (*node);
3497 ARDOUR_UI::update_transport_clocks (framepos_t pos)
3499 if (Config->get_primary_clock_delta_edit_cursor()) {
3500 primary_clock.set (pos, false, editor->get_preferred_edit_position(), 1);
3502 primary_clock.set (pos, 0, true);
3505 if (Config->get_secondary_clock_delta_edit_cursor()) {
3506 secondary_clock.set (pos, false, editor->get_preferred_edit_position(), 2);
3508 secondary_clock.set (pos);
3511 if (big_clock_window->get()) {
3512 big_clock.set (pos);
3518 ARDOUR_UI::step_edit_status_change (bool yn)
3520 // XXX should really store pre-step edit status of things
3521 // we make insensitive
3524 rec_button.set_visual_state (3);
3525 rec_button.set_sensitive (false);
3527 rec_button.set_visual_state (0);
3528 rec_button.set_sensitive (true);
3533 ARDOUR_UI::record_state_changed ()
3535 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
3537 if (!_session || !big_clock_window->get()) {
3538 /* why bother - the clock isn't visible */
3542 Session::RecordState const r = _session->record_status ();
3543 bool const h = _session->have_rec_enabled_track ();
3545 if (r == Session::Recording && h) {
3546 big_clock.set_widget_name ("BigClockRecording");
3548 big_clock.set_widget_name ("BigClockNonRecording");
3553 ARDOUR_UI::first_idle ()
3556 _session->allow_auto_play (true);
3560 editor->first_idle();
3563 Keyboard::set_can_save_keybindings (true);
3568 ARDOUR_UI::store_clock_modes ()
3570 XMLNode* node = new XMLNode(X_("ClockModes"));
3572 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
3573 node->add_property ((*x)->name().c_str(), enum_2_string ((*x)->mode()));
3576 _session->add_extra_xml (*node);
3577 _session->set_dirty ();
3582 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
3583 : Controllable (name), ui (u), type(tp)
3589 ARDOUR_UI::TransportControllable::set_value (double val)
3592 /* do nothing: these are radio-style actions */
3596 const char *action = 0;
3600 action = X_("Roll");
3603 action = X_("Stop");
3606 action = X_("Goto Start");
3609 action = X_("Goto End");
3612 action = X_("Loop");
3615 action = X_("Play Selection");
3618 action = X_("Record");
3628 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
3636 ARDOUR_UI::TransportControllable::get_value (void) const
3663 ARDOUR_UI::TransportControllable::set_id (const string& str)
3669 ARDOUR_UI::setup_profile ()
3671 if (gdk_screen_width() < 1200) {
3672 Profile->set_small_screen ();
3676 if (getenv ("ARDOUR_SAE")) {
3677 Profile->set_sae ();
3678 Profile->set_single_package ();
3683 ARDOUR_UI::toggle_translations ()
3685 using namespace Glib;
3687 RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("EnableTranslation"));
3689 RefPtr<ToggleAction> ract = RefPtr<ToggleAction>::cast_dynamic (act);
3692 string i18n_killer = ARDOUR::translation_kill_path();
3694 bool already_enabled = !ARDOUR::translations_are_disabled ();
3696 if (ract->get_active ()) {
3697 /* we don't care about errors */
3698 int fd = ::open (i18n_killer.c_str(), O_RDONLY|O_CREAT, 0644);
3701 /* we don't care about errors */
3702 unlink (i18n_killer.c_str());
3705 if (already_enabled != ract->get_active()) {
3706 MessageDialog win (already_enabled ? _("Translations disabled") : _("Translations enabled"),
3708 Gtk::MESSAGE_WARNING,
3710 win.set_secondary_text (string_compose (_("You must restart %1 for this to take effect."), PROGRAM_NAME));
3711 win.set_position (Gtk::WIN_POS_CENTER);
3719 /** Add a window proxy to our list, so that its state will be saved.
3720 * This call also causes the window to be created and opened if its
3721 * state was saved as `visible'.
3724 ARDOUR_UI::add_window_proxy (WindowProxyBase* p)
3726 _window_proxies.push_back (p);
3730 /** Remove a window proxy from our list. Must be called if a WindowProxy
3731 * is deleted, to prevent hanging pointers.
3734 ARDOUR_UI::remove_window_proxy (WindowProxyBase* p)
3736 _window_proxies.remove (p);
3740 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
3742 MissingFileDialog dialog (s, str, type);
3747 int result = dialog.run ();
3754 return 1; // quit entire session load
3757 result = dialog.get_action ();
3763 ARDOUR_UI::ambiguous_file (std::string file, std::string path, std::vector<std::string> hits)
3765 AmbiguousFileDialog dialog (file, hits);
3771 return dialog.get_which ();