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/gtk_ui.h"
53 #include "gtkmm2ext/utils.h"
54 #include "gtkmm2ext/click_box.h"
55 #include "gtkmm2ext/fastmeter.h"
56 #include "gtkmm2ext/popup.h"
57 #include "gtkmm2ext/window_title.h"
59 #include "midi++/manager.h"
61 #include "ardour/ardour.h"
62 #include "ardour/callback.h"
63 #include "ardour/profile.h"
64 #include "ardour/session_directory.h"
65 #include "ardour/session_route.h"
66 #include "ardour/session_state_utils.h"
67 #include "ardour/session_utils.h"
68 #include "ardour/port.h"
69 #include "ardour/audioengine.h"
70 #include "ardour/playlist.h"
71 #include "ardour/utils.h"
72 #include "ardour/audio_diskstream.h"
73 #include "ardour/audiofilesource.h"
74 #include "ardour/recent_sessions.h"
75 #include "ardour/port.h"
76 #include "ardour/audio_track.h"
77 #include "ardour/midi_track.h"
78 #include "ardour/filesystem_paths.h"
79 #include "ardour/filename_extensions.h"
81 typedef uint64_t microseconds_t;
84 #include "ardour_ui.h"
85 #include "public_editor.h"
86 #include "audio_clock.h"
91 #include "add_route_dialog.h"
95 #include "gui_thread.h"
96 #include "theme_manager.h"
97 #include "bundle_manager.h"
98 #include "session_metadata_dialog.h"
99 #include "gain_meter.h"
100 #include "route_time_axis.h"
102 #include "engine_dialog.h"
103 #include "processor_box.h"
104 #include "time_axis_view_item.h"
105 #include "window_proxy.h"
106 #include "global_port_matrix.h"
107 #include "location_ui.h"
108 #include "missing_file_dialog.h"
109 #include "missing_plugin_dialog.h"
110 #include "ambiguous_file_dialog.h"
114 using namespace ARDOUR;
116 using namespace Gtkmm2ext;
119 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
120 UIConfiguration *ARDOUR_UI::ui_config = 0;
122 sigc::signal<void,bool> ARDOUR_UI::Blink;
123 sigc::signal<void> ARDOUR_UI::RapidScreenUpdate;
124 sigc::signal<void> ARDOUR_UI::SuperRapidScreenUpdate;
125 sigc::signal<void, framepos_t, bool, framepos_t> ARDOUR_UI::Clock;
127 bool could_be_a_valid_path (const string& path);
129 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[])
131 : Gtkmm2ext::UI (PROGRAM_NAME, argcp, argvp),
133 primary_clock (X_("primary"), false, X_("TransportClockDisplay"), true, true, false, true),
134 secondary_clock (X_("secondary"), false, X_("SecondaryClockDisplay"), true, true, false, true),
135 preroll_clock (X_("preroll"), false, X_("PreRollClock"), true, false, true),
136 postroll_clock (X_("postroll"), false, X_("PostRollClock"), true, false, true),
140 preroll_button (_("pre\nroll")),
141 postroll_button (_("post\nroll")),
145 big_clock (X_("bigclock"), false, "BigClockNonRecording", true, true, false, false),
149 roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll)),
150 stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop)),
151 goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart)),
152 goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd)),
153 auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop)),
154 play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection)),
155 rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable)),
156 shuttle_controllable (new TransportControllable ("shuttle", *this, TransportControllable::ShuttleControl)),
157 shuttle_controller_binding_proxy (shuttle_controllable),
159 roll_button (roll_controllable),
160 stop_button (stop_controllable),
161 goto_start_button (goto_start_controllable),
162 goto_end_button (goto_end_controllable),
163 auto_loop_button (auto_loop_controllable),
164 play_selection_button (play_selection_controllable),
165 rec_button (rec_controllable),
167 shuttle_units_button (_("% ")),
169 punch_in_button (_("Punch In")),
170 punch_out_button (_("Punch Out")),
171 auto_return_button (_("Auto Return")),
172 auto_play_button (_("Auto Play")),
173 auto_input_button (_("Auto Input")),
174 click_button (_("Click")),
175 time_master_button (_("time\nmaster")),
177 auditioning_alert_button (_("AUDITION")),
178 solo_alert_button (_("SOLO")),
180 error_log_button (_("Errors"))
183 using namespace Gtk::Menu_Helpers;
189 // _auto_display_errors = false;
191 * This was commented out as it wasn't defined
192 * in A3 IIRC. If this is not needed it should
193 * be completely removed.
201 if (theArdourUI == 0) {
205 ui_config = new UIConfiguration();
206 theme_manager = new ThemeManager();
212 _session_is_new = false;
213 big_clock_window = 0;
214 big_clock_height = 0;
215 big_clock_resize_in_progress = false;
216 session_selector_window = 0;
217 last_key_press_time = 0;
218 _will_create_new_session_automatically = false;
219 add_route_dialog = 0;
221 rc_option_editor = 0;
222 session_option_editor = 0;
224 open_session_selector = 0;
225 have_configure_timeout = false;
226 have_disk_speed_dialog_displayed = false;
227 session_loaded = false;
228 last_speed_displayed = -1.0f;
229 ignore_dual_punch = false;
230 original_big_clock_width = -1;
231 original_big_clock_height = -1;
232 original_big_clock_font_size = 0;
234 roll_button.unset_flags (Gtk::CAN_FOCUS);
235 stop_button.unset_flags (Gtk::CAN_FOCUS);
236 goto_start_button.unset_flags (Gtk::CAN_FOCUS);
237 goto_end_button.unset_flags (Gtk::CAN_FOCUS);
238 auto_loop_button.unset_flags (Gtk::CAN_FOCUS);
239 play_selection_button.unset_flags (Gtk::CAN_FOCUS);
240 rec_button.unset_flags (Gtk::CAN_FOCUS);
242 last_configure_time= 0;
244 shuttle_grabbed = false;
246 shuttle_max_speed = 8.0f;
248 shuttle_style_menu = 0;
249 shuttle_unit_menu = 0;
251 // We do not have jack linked in yet so;
253 last_shuttle_request = last_peak_grab = 0; // get_microseconds();
255 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
256 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
258 /* handle dialog requests */
260 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
262 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
264 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
266 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
268 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
270 /* handle requests to quit (coming from JACK session) */
272 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::finish, this), gui_context ());
274 /* handle requests to deal with missing files */
276 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
278 /* and ambiguous files */
280 ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2, _3));
282 /* lets get this party started */
285 if (ARDOUR::init (ARDOUR_COMMAND_LINE::use_vst, ARDOUR_COMMAND_LINE::try_hw_optimization)) {
286 throw failed_constructor ();
289 setup_gtk_ardour_enums ();
292 GainMeter::setup_slider_pix ();
293 RouteTimeAxisView::setup_slider_pix ();
294 SendProcessorEntry::setup_slider_pix ();
295 SessionEvent::create_per_thread_pool ("GUI", 512);
297 } catch (failed_constructor& err) {
298 error << string_compose (_("could not initialize %1."), PROGRAM_NAME) << endmsg;
303 /* we like keyboards */
305 keyboard = new ArdourKeyboard(*this);
307 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
309 keyboard->set_state (*node, Stateful::loading_state_version);
314 TimeAxisViewItem::set_constant_heights ();
316 /* The following must happen after ARDOUR::init() so that Config is set up */
318 location_ui = new ActionWindowProxy<LocationUIWindow> (X_("locations"), Config->extra_xml (X_("UI")), X_("ToggleLocations"));
319 big_clock_window = new ActionWindowProxy<Gtk::Window> (X_("bigclock"), Config->extra_xml (X_("UI")), X_("ToggleBigClock"));
321 for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) {
322 _global_port_matrix[*i] = new ActionWindowProxy<GlobalPortMatrixWindow> (
323 string_compose ("GlobalPortMatrix-%1", (*i).to_string()),
324 Config->extra_xml (X_("UI")),
325 string_compose ("toggle-%1-connection-manager", (*i).to_string())
331 starting.connect (sigc::mem_fun(*this, &ARDOUR_UI::startup));
332 stopping.connect (sigc::mem_fun(*this, &ARDOUR_UI::shutdown));
337 /** @return true if a session was chosen and `apply' clicked, otherwise false if `cancel' was clicked */
339 ARDOUR_UI::run_startup (bool should_be_new, string load_template)
342 _startup = new ArdourStartup ();
344 XMLNode* audio_setup = Config->extra_xml ("AudioSetup");
346 if (audio_setup && _startup->engine_control()) {
347 _startup->engine_control()->set_state (*audio_setup);
350 _startup->set_new_only (should_be_new);
351 if (!load_template.empty()) {
352 _startup->set_load_template( load_template );
354 _startup->present ();
360 switch (_startup->response()) {
369 ARDOUR_UI::create_engine ()
371 // this gets called every time by new_session()
377 loading_message (_("Starting audio engine"));
380 engine = new ARDOUR::AudioEngine (ARDOUR_COMMAND_LINE::jack_client_name, ARDOUR_COMMAND_LINE::jack_session_uuid);
387 engine->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
388 engine->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
389 engine->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
391 engine->Halted.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
393 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
401 ARDOUR_UI::post_engine ()
403 /* Things to be done once we create the AudioEngine
406 ARDOUR::init_post_engine ();
408 ActionManager::init ();
411 if (setup_windows ()) {
412 throw failed_constructor ();
415 check_memory_locking();
417 /* this is the first point at which all the keybindings are available */
419 if (ARDOUR_COMMAND_LINE::show_key_actions) {
420 vector<string> names;
421 vector<string> paths;
423 vector<AccelKey> bindings;
425 ActionManager::get_all_actions (names, paths, keys, bindings);
427 vector<string>::iterator n;
428 vector<string>::iterator k;
429 for (n = names.begin(), k = keys.begin(); n != names.end(); ++n, ++k) {
430 cerr << "Action: " << (*n) << " bound to " << (*k) << endl;
436 blink_timeout_tag = -1;
438 /* this being a GUI and all, we want peakfiles */
440 AudioFileSource::set_build_peakfiles (true);
441 AudioFileSource::set_build_missing_peakfiles (true);
443 /* set default clock modes */
445 if (Profile->get_sae()) {
446 primary_clock.set_mode (AudioClock::BBT);
447 secondary_clock.set_mode (AudioClock::MinSec);
449 primary_clock.set_mode (AudioClock::Timecode);
450 secondary_clock.set_mode (AudioClock::BBT);
453 /* start the time-of-day-clock */
456 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
457 update_wall_clock ();
458 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 60000);
461 update_disk_space ();
463 update_sample_rate (engine->frame_rate());
465 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
466 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
467 Config->map_parameters (pc);
469 /* now start and maybe save state */
471 if (do_engine_start () == 0) {
472 if (_session && _session_is_new) {
473 /* we need to retain initial visual
474 settings for a new session
476 _session->save_state ("");
481 ARDOUR_UI::~ARDOUR_UI ()
486 delete add_route_dialog;
490 ARDOUR_UI::pop_back_splash ()
492 if (Splash::instance()) {
493 // Splash::instance()->pop_back();
494 Splash::instance()->hide ();
499 ARDOUR_UI::configure_timeout ()
501 if (last_configure_time == 0) {
502 /* no configure events yet */
506 /* force a gap of 0.5 seconds since the last configure event
509 if (get_microseconds() - last_configure_time < 500000) {
512 have_configure_timeout = false;
513 cerr << "config event-driven save\n";
514 save_ardour_state ();
520 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
522 if (have_configure_timeout) {
523 last_configure_time = get_microseconds();
525 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
526 have_configure_timeout = true;
533 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
535 const XMLProperty* prop;
537 if ((prop = node.property ("roll")) != 0) {
538 roll_controllable->set_id (prop->value());
540 if ((prop = node.property ("stop")) != 0) {
541 stop_controllable->set_id (prop->value());
543 if ((prop = node.property ("goto-start")) != 0) {
544 goto_start_controllable->set_id (prop->value());
546 if ((prop = node.property ("goto-end")) != 0) {
547 goto_end_controllable->set_id (prop->value());
549 if ((prop = node.property ("auto-loop")) != 0) {
550 auto_loop_controllable->set_id (prop->value());
552 if ((prop = node.property ("play-selection")) != 0) {
553 play_selection_controllable->set_id (prop->value());
555 if ((prop = node.property ("rec")) != 0) {
556 rec_controllable->set_id (prop->value());
558 if ((prop = node.property ("shuttle")) != 0) {
559 shuttle_controllable->set_id (prop->value());
564 ARDOUR_UI::get_transport_controllable_state ()
566 XMLNode* node = new XMLNode(X_("TransportControllables"));
569 roll_controllable->id().print (buf, sizeof (buf));
570 node->add_property (X_("roll"), buf);
571 stop_controllable->id().print (buf, sizeof (buf));
572 node->add_property (X_("stop"), buf);
573 goto_start_controllable->id().print (buf, sizeof (buf));
574 node->add_property (X_("goto_start"), buf);
575 goto_end_controllable->id().print (buf, sizeof (buf));
576 node->add_property (X_("goto_end"), buf);
577 auto_loop_controllable->id().print (buf, sizeof (buf));
578 node->add_property (X_("auto_loop"), buf);
579 play_selection_controllable->id().print (buf, sizeof (buf));
580 node->add_property (X_("play_selection"), buf);
581 rec_controllable->id().print (buf, sizeof (buf));
582 node->add_property (X_("rec"), buf);
583 shuttle_controllable->id().print (buf, sizeof (buf));
584 node->add_property (X_("shuttle"), buf);
591 ARDOUR_UI::autosave_session ()
593 if (g_main_depth() > 1) {
594 /* inside a recursive main loop,
595 give up because we may not be able to
601 if (!Config->get_periodic_safety_backups()) {
606 _session->maybe_write_autosave();
613 ARDOUR_UI::update_autosave ()
615 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_autosave)
617 if (_session && _session->dirty()) {
618 if (_autosave_connection.connected()) {
619 _autosave_connection.disconnect();
622 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
623 Config->get_periodic_safety_backup_interval() * 1000);
626 if (_autosave_connection.connected()) {
627 _autosave_connection.disconnect();
633 ARDOUR_UI::backend_audio_error (bool we_set_params, Gtk::Window* toplevel)
637 title = string_compose (_("%1 could not start JACK"), PROGRAM_NAME);
639 title = string_compose (_("%1 could not connect to JACK."), PROGRAM_NAME);
642 MessageDialog win (title,
648 win.set_secondary_text(_("There are several possible reasons:\n\
650 1) You requested audio parameters that are not supported..\n\
651 2) JACK is running as another user.\n\
653 Please consider the possibilities, and perhaps try different parameters."));
655 win.set_secondary_text(_("There are several possible reasons:\n\
657 1) JACK is not running.\n\
658 2) JACK is running as another user, perhaps root.\n\
659 3) There is already another client called \"ardour\".\n\
661 Please consider the possibilities, and perhaps (re)start JACK."));
665 win.set_transient_for (*toplevel);
669 win.add_button (Stock::OK, RESPONSE_CLOSE);
671 win.add_button (Stock::QUIT, RESPONSE_CLOSE);
674 win.set_default_response (RESPONSE_CLOSE);
677 win.set_position (Gtk::WIN_POS_CENTER);
680 /* we just don't care about the result, but we want to block */
686 ARDOUR_UI::startup ()
688 Application* app = Application::instance ();
690 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
691 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::idle_load));
694 call_the_mothership (VERSIONSTRING);
699 if (get_session_parameters (true, ARDOUR_COMMAND_LINE::new_session, ARDOUR_COMMAND_LINE::load_template)) {
705 goto_editor_window ();
707 /* Add the window proxies here; their addition may cause windows to be opened, and we want them
708 to be opened on top of the editor window that goto_editor_window() just opened.
710 add_window_proxy (location_ui);
711 add_window_proxy (big_clock_window);
712 for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) {
713 add_window_proxy (_global_port_matrix[*i]);
716 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
720 ARDOUR_UI::no_memory_warning ()
722 XMLNode node (X_("no-memory-warning"));
723 Config->add_instant_xml (node);
727 ARDOUR_UI::check_memory_locking ()
730 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
734 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
736 if (engine->is_realtime() && memory_warning_node == 0) {
738 struct rlimit limits;
740 long pages, page_size;
742 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0) {
745 ram = (int64_t) pages * (int64_t) page_size;
748 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
752 if (limits.rlim_cur != RLIM_INFINITY) {
754 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
758 string_compose (_("WARNING: Your system has a limit for maximum amount of locked memory. "
759 "This might cause %1 to run out of memory before your system "
760 "runs out of memory. \n\n"
761 "You can view the memory limit with 'ulimit -l', "
762 "and it is normally controlled by /etc/security/limits.conf"),
763 PROGRAM_NAME).c_str());
765 VBox* vbox = msg.get_vbox();
767 CheckButton cb (_("Do not show this window again"));
769 cb.signal_toggled().connect (sigc::mem_fun (*this, &ARDOUR_UI::no_memory_warning));
771 hbox.pack_start (cb, true, false);
772 vbox->pack_start (hbox);
779 editor->ensure_float (msg);
789 ARDOUR_UI::queue_finish ()
791 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
795 ARDOUR_UI::idle_finish ()
798 return false; /* do not call again */
807 if (_session->transport_rolling() && (++tries < 8)) {
808 _session->request_stop (false, true);
812 if (_session->dirty()) {
813 switch (ask_about_saving_session(_("quit"))) {
818 /* use the default name */
819 if (save_state_canfail ("")) {
820 /* failed - don't quit */
821 MessageDialog msg (*editor,
823 Ardour was unable to save your session.\n\n\
824 If you still wish to quit, please use the\n\n\
825 \"Just quit\" option."));
836 second_connection.disconnect ();
837 point_one_second_connection.disconnect ();
838 point_oh_five_second_connection.disconnect ();
839 point_zero_one_second_connection.disconnect();
842 /* Save state before deleting the session, as that causes some
843 windows to be destroyed before their visible state can be
846 save_ardour_state ();
849 // _session->set_deletion_in_progress ();
850 _session->set_clean ();
851 _session->remove_pending_capture_state ();
856 ArdourDialog::close_all_dialogs ();
862 ARDOUR_UI::ask_about_saving_session (const string & what)
864 ArdourDialog window (_("Unsaved Session"));
865 Gtk::HBox dhbox; // the hbox for the image and text
866 Gtk::Label prompt_label;
867 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
871 msg = string_compose(_("Don't %1"), what);
872 window.add_button (msg, RESPONSE_REJECT);
873 msg = string_compose(_("Just %1"), what);
874 window.add_button (msg, RESPONSE_APPLY);
875 msg = string_compose(_("Save and %1"), what);
876 window.add_button (msg, RESPONSE_ACCEPT);
878 window.set_default_response (RESPONSE_ACCEPT);
880 Gtk::Button noquit_button (msg);
881 noquit_button.set_name ("EditorGTKButton");
886 if (_session->snap_name() == _session->name()) {
889 type = _("snapshot");
891 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?"),
892 type, _session->snap_name());
894 prompt_label.set_text (prompt);
895 prompt_label.set_name (X_("PrompterLabel"));
896 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
898 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
899 dhbox.set_homogeneous (false);
900 dhbox.pack_start (*dimage, false, false, 5);
901 dhbox.pack_start (prompt_label, true, false, 5);
902 window.get_vbox()->pack_start (dhbox);
904 window.set_name (_("Prompter"));
905 window.set_position (Gtk::WIN_POS_MOUSE);
906 window.set_modal (true);
907 window.set_resizable (false);
913 window.set_keep_above (true);
916 ResponseType r = (ResponseType) window.run();
921 case RESPONSE_ACCEPT: // save and get out of here
923 case RESPONSE_APPLY: // get out of here
933 ARDOUR_UI::every_second ()
936 update_buffer_load ();
937 update_disk_space ();
942 ARDOUR_UI::every_point_one_seconds ()
944 update_speed_display ();
945 RapidScreenUpdate(); /* EMIT_SIGNAL */
950 ARDOUR_UI::every_point_zero_one_seconds ()
952 // august 2007: actual update frequency: 40Hz, not 100Hz
954 SuperRapidScreenUpdate(); /* EMIT_SIGNAL */
959 ARDOUR_UI::update_sample_rate (framecnt_t)
963 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
965 if (!engine->connected()) {
967 snprintf (buf, sizeof (buf), _("disconnected"));
971 framecnt_t rate = engine->frame_rate();
973 if (fmod (rate, 1000.0) != 0.0) {
974 snprintf (buf, sizeof (buf), _("%.1f kHz / %4.1f ms"),
975 (float) rate/1000.0f,
976 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
978 snprintf (buf, sizeof (buf), _("%" PRId64 " kHz / %4.1f ms"),
980 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
984 sample_rate_label.set_text (buf);
988 ARDOUR_UI::update_cpu_load ()
991 snprintf (buf, sizeof (buf), _("DSP: %5.1f%%"), engine->get_cpu_load());
992 cpu_load_label.set_text (buf);
996 ARDOUR_UI::update_buffer_load ()
1002 c = _session->capture_load ();
1003 p = _session->playback_load ();
1005 snprintf (buf, sizeof (buf), _("Buffers p:%" PRIu32 "%% c:%" PRIu32 "%%"),
1006 _session->playback_load(), _session->capture_load());
1007 buffer_load_label.set_text (buf);
1009 buffer_load_label.set_text ("");
1014 ARDOUR_UI::count_recenabled_streams (Route& route)
1016 Track* track = dynamic_cast<Track*>(&route);
1017 if (track && track->record_enabled()) {
1018 rec_enabled_streams += track->n_inputs().n_total();
1023 ARDOUR_UI::update_disk_space()
1025 if (_session == 0) {
1029 framecnt_t frames = _session->available_capture_duration();
1031 framecnt_t fr = _session->frame_rate();
1033 if (frames == max_framecnt) {
1034 strcpy (buf, _("Disk: 24hrs+"));
1036 rec_enabled_streams = 0;
1037 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams);
1039 if (rec_enabled_streams) {
1040 frames /= rec_enabled_streams;
1047 hrs = frames / (fr * 3600);
1048 frames -= hrs * fr * 3600;
1049 mins = frames / (fr * 60);
1050 frames -= mins * fr * 60;
1053 snprintf (buf, sizeof(buf), _("Disk: %02dh:%02dm:%02ds"), hrs, mins, secs);
1056 disk_space_label.set_text (buf);
1058 // An attempt to make the disk space label flash red when space has run out.
1060 if (frames < fr * 60 * 5) {
1061 /* disk_space_box.style ("disk_space_label_empty"); */
1063 /* disk_space_box.style ("disk_space_label"); */
1069 ARDOUR_UI::update_wall_clock ()
1076 tm_now = localtime (&now);
1078 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1079 wall_clock_label.set_text (buf);
1085 ARDOUR_UI::session_menu (GdkEventButton */*ev*/)
1087 session_popup_menu->popup (0, 0);
1092 ARDOUR_UI::redisplay_recent_sessions ()
1094 std::vector<sys::path> session_directories;
1095 RecentSessionsSorter cmp;
1097 recent_session_display.set_model (Glib::RefPtr<TreeModel>(0));
1098 recent_session_model->clear ();
1100 ARDOUR::RecentSessions rs;
1101 ARDOUR::read_recent_sessions (rs);
1104 recent_session_display.set_model (recent_session_model);
1108 // sort them alphabetically
1109 sort (rs.begin(), rs.end(), cmp);
1111 for (ARDOUR::RecentSessions::iterator i = rs.begin(); i != rs.end(); ++i) {
1112 session_directories.push_back ((*i).second);
1115 for (vector<sys::path>::const_iterator i = session_directories.begin();
1116 i != session_directories.end(); ++i)
1118 std::vector<sys::path> state_file_paths;
1120 // now get available states for this session
1122 get_state_files_in_directory (*i, state_file_paths);
1124 vector<string*>* states;
1125 vector<const gchar*> item;
1126 string fullpath = (*i).to_string();
1128 /* remove any trailing / */
1130 if (fullpath[fullpath.length()-1] == '/') {
1131 fullpath = fullpath.substr (0, fullpath.length()-1);
1134 /* check whether session still exists */
1135 if (!Glib::file_test(fullpath.c_str(), Glib::FILE_TEST_EXISTS)) {
1136 /* session doesn't exist */
1137 cerr << "skipping non-existent session " << fullpath << endl;
1141 /* now get available states for this session */
1143 if ((states = Session::possible_states (fullpath)) == 0) {
1144 /* no state file? */
1148 std::vector<string> state_file_names(get_file_names_no_extension (state_file_paths));
1150 Gtk::TreeModel::Row row = *(recent_session_model->append());
1152 row[recent_session_columns.visible_name] = Glib::path_get_basename (fullpath);
1153 row[recent_session_columns.fullpath] = fullpath;
1155 if (state_file_names.size() > 1) {
1159 for (std::vector<std::string>::iterator i2 = state_file_names.begin();
1160 i2 != state_file_names.end(); ++i2)
1163 Gtk::TreeModel::Row child_row = *(recent_session_model->append (row.children()));
1165 child_row[recent_session_columns.visible_name] = *i2;
1166 child_row[recent_session_columns.fullpath] = fullpath;
1171 recent_session_display.set_model (recent_session_model);
1175 ARDOUR_UI::build_session_selector ()
1177 session_selector_window = new ArdourDialog (_("Recent Sessions"));
1179 Gtk::ScrolledWindow *scroller = manage (new Gtk::ScrolledWindow);
1181 session_selector_window->add_button (Stock::CANCEL, RESPONSE_CANCEL);
1182 session_selector_window->add_button (Stock::OPEN, RESPONSE_ACCEPT);
1183 session_selector_window->set_default_response (RESPONSE_ACCEPT);
1184 recent_session_model = TreeStore::create (recent_session_columns);
1185 recent_session_display.set_model (recent_session_model);
1186 recent_session_display.append_column (_("Recent Sessions"), recent_session_columns.visible_name);
1187 recent_session_display.set_headers_visible (false);
1188 recent_session_display.get_selection()->set_mode (SELECTION_BROWSE);
1189 recent_session_display.signal_row_activated().connect (sigc::mem_fun (*this, &ARDOUR_UI::recent_session_row_activated));
1191 scroller->add (recent_session_display);
1192 scroller->set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
1194 session_selector_window->set_name ("SessionSelectorWindow");
1195 session_selector_window->set_size_request (200, 400);
1196 session_selector_window->get_vbox()->pack_start (*scroller);
1198 recent_session_display.show();
1200 //session_selector_window->get_vbox()->show();
1204 ARDOUR_UI::recent_session_row_activated (const TreePath& /*path*/, TreeViewColumn* /*col*/)
1206 session_selector_window->response (RESPONSE_ACCEPT);
1210 ARDOUR_UI::open_recent_session ()
1212 bool can_return = (_session != 0);
1214 if (session_selector_window == 0) {
1215 build_session_selector ();
1218 redisplay_recent_sessions ();
1222 session_selector_window->set_position (WIN_POS_MOUSE);
1224 ResponseType r = (ResponseType) session_selector_window->run ();
1227 case RESPONSE_ACCEPT:
1231 session_selector_window->hide();
1238 if (recent_session_display.get_selection()->count_selected_rows() == 0) {
1242 session_selector_window->hide();
1244 Gtk::TreeModel::iterator i = recent_session_display.get_selection()->get_selected();
1246 if (i == recent_session_model->children().end()) {
1250 std::string path = (*i)[recent_session_columns.fullpath];
1251 std::string state = (*i)[recent_session_columns.visible_name];
1253 _session_is_new = false;
1255 if (load_session (path, state) == 0) {
1264 ARDOUR_UI::check_audioengine ()
1267 if (!engine->connected()) {
1268 MessageDialog msg (string_compose (_("%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)
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);
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 (bool track, int32_t input_channels, int32_t output_channels, ARDOUR::TrackMode mode, RouteGroup* route_group, uint32_t how_many)
1375 list<boost::shared_ptr<AudioTrack> > tracks;
1378 if (_session == 0) {
1379 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1385 tracks = _session->new_audio_track (input_channels, output_channels, mode, route_group, how_many);
1387 if (tracks.size() != how_many) {
1388 if (how_many == 1) {
1389 error << _("could not create a new audio track") << endmsg;
1391 error << string_compose (_("could only create %1 of %2 new audio %3"),
1392 tracks.size(), how_many, (track ? _("tracks") : _("busses"))) << endmsg;
1398 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many);
1400 if (routes.size() != how_many) {
1401 if (how_many == 1) {
1402 error << _("could not create a new audio track") << endmsg;
1404 error << string_compose (_("could not create %1 new audio tracks"), how_many) << endmsg;
1411 MessageDialog msg (*editor,
1412 string_compose (_("There are insufficient JACK ports available\n\
1413 to create a new track or bus.\n\
1414 You should save %1, exit and\n\
1415 restart JACK with more ports."), PROGRAM_NAME));
1422 ARDOUR_UI::do_transport_locate (framepos_t new_position, bool with_roll)
1424 framecnt_t _preroll = 0;
1427 // XXX CONFIG_CHANGE FIX - requires AnyTime handling
1428 // _preroll = _session->convert_to_frames_at (new_position, Config->get_preroll());
1430 if (new_position > _preroll) {
1431 new_position -= _preroll;
1436 _session->request_locate (new_position, with_roll);
1441 ARDOUR_UI::transport_goto_start ()
1444 _session->goto_start();
1446 /* force displayed area in editor to start no matter
1447 what "follow playhead" setting is.
1451 editor->center_screen (_session->current_start_frame ());
1457 ARDOUR_UI::transport_goto_zero ()
1460 _session->request_locate (0);
1462 /* force displayed area in editor to start no matter
1463 what "follow playhead" setting is.
1467 editor->reset_x_origin (0);
1473 ARDOUR_UI::transport_goto_wallclock ()
1475 if (_session && editor) {
1482 localtime_r (&now, &tmnow);
1484 frames = tmnow.tm_hour * (60 * 60 * _session->frame_rate());
1485 frames += tmnow.tm_min * (60 * _session->frame_rate());
1486 frames += tmnow.tm_sec * _session->frame_rate();
1488 _session->request_locate (frames, _session->transport_rolling ());
1490 /* force displayed area in editor to start no matter
1491 what "follow playhead" setting is.
1495 editor->center_screen (frames);
1501 ARDOUR_UI::transport_goto_end ()
1504 framepos_t const frame = _session->current_end_frame();
1505 _session->request_locate (frame);
1507 /* force displayed area in editor to start no matter
1508 what "follow playhead" setting is.
1512 editor->center_screen (frame);
1518 ARDOUR_UI::transport_stop ()
1524 if (_session->is_auditioning()) {
1525 _session->cancel_audition ();
1529 _session->request_stop (false, true);
1533 ARDOUR_UI::transport_stop_and_forget_capture ()
1536 _session->request_stop (true, true);
1541 ARDOUR_UI::remove_last_capture()
1544 editor->remove_last_capture();
1549 ARDOUR_UI::transport_record (bool roll)
1553 switch (_session->record_status()) {
1554 case Session::Disabled:
1555 if (_session->ntracks() == 0) {
1556 MessageDialog msg (*editor, _("Please create 1 or more track\nbefore trying to record.\nCheck the Session menu."));
1560 _session->maybe_enable_record ();
1565 case Session::Recording:
1567 _session->request_stop();
1569 _session->disable_record (false, true);
1573 case Session::Enabled:
1574 _session->disable_record (false, true);
1577 //cerr << "ARDOUR_UI::transport_record () called roll = " << roll << " _session->record_status() = " << _session->record_status() << endl;
1581 ARDOUR_UI::transport_roll ()
1587 if (_session->is_auditioning()) {
1592 if (_session->config.get_external_sync()) {
1593 switch (_session->config.get_sync_source()) {
1597 /* transport controlled by the master */
1603 bool rolling = _session->transport_rolling();
1605 if (_session->get_play_loop()) {
1606 /* XXX it is not possible to just leave seamless loop and keep
1607 playing at present (nov 4th 2009)
1609 if (!Config->get_seamless_loop()) {
1610 _session->request_play_loop (false, true);
1612 } else if (_session->get_play_range () && !join_play_range_button.get_active()) {
1613 /* stop playing a range if we currently are */
1614 _session->request_play_range (0, true);
1617 if (join_play_range_button.get_active()) {
1618 _session->request_play_range (&editor->get_selection().time, true);
1622 _session->request_transport_speed (1.0f);
1627 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
1634 if (_session->is_auditioning()) {
1635 _session->cancel_audition ();
1640 if (_session->config.get_external_sync()) {
1641 switch (_session->config.get_sync_source()) {
1645 /* transport controlled by the master */
1651 bool rolling = _session->transport_rolling();
1652 bool affect_transport = true;
1654 if (rolling && roll_out_of_bounded_mode) {
1655 /* drop out of loop/range playback but leave transport rolling */
1656 if (_session->get_play_loop()) {
1657 if (Config->get_seamless_loop()) {
1658 /* the disk buffers contain copies of the loop - we can't
1659 just keep playing, so stop the transport. the user
1660 can restart as they wish.
1662 affect_transport = true;
1664 /* disk buffers are normal, so we can keep playing */
1665 affect_transport = false;
1667 _session->request_play_loop (false, true);
1668 } else if (_session->get_play_range ()) {
1669 affect_transport = false;
1670 _session->request_play_range (0, true);
1674 if (affect_transport) {
1676 _session->request_stop (with_abort, true);
1678 if (join_play_range_button.get_active()) {
1679 _session->request_play_range (&editor->get_selection().time, true);
1682 _session->request_transport_speed (1.0f);
1688 ARDOUR_UI::toggle_session_auto_loop ()
1691 if (_session->get_play_loop()) {
1692 if (_session->transport_rolling()) {
1693 Location * looploc = _session->locations()->auto_loop_location();
1695 _session->request_locate (looploc->start(), true);
1698 _session->request_play_loop (false);
1701 Location * looploc = _session->locations()->auto_loop_location();
1703 _session->request_play_loop (true);
1710 ARDOUR_UI::transport_play_selection ()
1716 editor->play_selection ();
1720 ARDOUR_UI::transport_rewind (int option)
1722 float current_transport_speed;
1725 current_transport_speed = _session->transport_speed();
1727 if (current_transport_speed >= 0.0f) {
1730 _session->request_transport_speed (-1.0f);
1733 _session->request_transport_speed (-4.0f);
1736 _session->request_transport_speed (-0.5f);
1741 _session->request_transport_speed (current_transport_speed * 1.5f);
1747 ARDOUR_UI::transport_forward (int option)
1749 float current_transport_speed;
1752 current_transport_speed = _session->transport_speed();
1754 if (current_transport_speed <= 0.0f) {
1757 _session->request_transport_speed (1.0f);
1760 _session->request_transport_speed (4.0f);
1763 _session->request_transport_speed (0.5f);
1768 _session->request_transport_speed (current_transport_speed * 1.5f);
1775 ARDOUR_UI::toggle_record_enable (uint32_t rid)
1777 if (_session == 0) {
1781 boost::shared_ptr<Route> r;
1783 if ((r = _session->route_by_remote_id (rid)) != 0) {
1787 if ((t = dynamic_cast<Track*>(r.get())) != 0) {
1788 t->set_record_enabled (!t->record_enabled(), this);
1791 if (_session == 0) {
1797 ARDOUR_UI::map_transport_state ()
1799 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::map_transport_state)
1802 auto_loop_button.set_visual_state (0);
1803 play_selection_button.set_visual_state (0);
1804 roll_button.set_visual_state (0);
1805 stop_button.set_visual_state (1);
1809 float sp = _session->transport_speed();
1812 shuttle_fract = SHUTTLE_FRACT_SPEED1; /* speed = 1.0, believe it or not */
1813 shuttle_box.queue_draw ();
1814 } else if (sp == 0.0f) {
1816 shuttle_box.queue_draw ();
1817 update_disk_space ();
1824 if (_session->get_play_range()) {
1826 play_selection_button.set_visual_state (1);
1827 roll_button.set_visual_state (0);
1828 auto_loop_button.set_visual_state (0);
1830 } else if (_session->get_play_loop ()) {
1832 auto_loop_button.set_visual_state (1);
1833 play_selection_button.set_visual_state (0);
1834 roll_button.set_visual_state (0);
1838 roll_button.set_visual_state (1);
1839 play_selection_button.set_visual_state (0);
1840 auto_loop_button.set_visual_state (0);
1843 if (join_play_range_button.get_active()) {
1844 /* light up both roll and play-selection if they are joined */
1845 roll_button.set_visual_state (1);
1846 play_selection_button.set_visual_state (1);
1849 stop_button.set_visual_state (0);
1853 stop_button.set_visual_state (1);
1854 roll_button.set_visual_state (0);
1855 play_selection_button.set_visual_state (0);
1856 auto_loop_button.set_visual_state (0);
1861 ARDOUR_UI::engine_stopped ()
1863 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
1864 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1865 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1869 ARDOUR_UI::engine_running ()
1871 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
1872 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, true);
1873 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, false);
1875 Glib::RefPtr<Action> action;
1876 const char* action_name = 0;
1878 switch (engine->frames_per_cycle()) {
1880 action_name = X_("JACKLatency32");
1883 action_name = X_("JACKLatency64");
1886 action_name = X_("JACKLatency128");
1889 action_name = X_("JACKLatency512");
1892 action_name = X_("JACKLatency1024");
1895 action_name = X_("JACKLatency2048");
1898 action_name = X_("JACKLatency4096");
1901 action_name = X_("JACKLatency8192");
1904 /* XXX can we do anything useful ? */
1910 action = ActionManager::get_action (X_("JACK"), action_name);
1913 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (action);
1914 ract->set_active ();
1920 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
1922 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
1923 /* we can't rely on the original string continuing to exist when we are called
1924 again in the GUI thread, so make a copy and note that we need to
1927 char *copy = strdup (reason);
1928 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
1932 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1933 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1935 update_sample_rate (0);
1939 /* if the reason is a non-empty string, it means that the backend was shutdown
1940 rather than just Ardour.
1943 if (strlen (reason)) {
1944 msgstr = string_compose (_("The audio backend (JACK) was shutdown because:\n\n%1"), reason);
1946 msgstr = string_compose (_("\
1947 JACK has either been shutdown or it\n\
1948 disconnected %1 because %1\n\
1949 was not fast enough. Try to restart\n\
1950 JACK, reconnect and save the session."), PROGRAM_NAME);
1953 MessageDialog msg (*editor, msgstr);
1958 free ((char*) reason);
1963 ARDOUR_UI::do_engine_start ()
1971 error << _("Unable to start the session running")
1981 ARDOUR_UI::setup_theme ()
1983 theme_manager->setup_theme();
1987 ARDOUR_UI::update_clocks ()
1989 if (!editor || !editor->dragging_playhead()) {
1990 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position()); /* EMIT_SIGNAL */
1995 ARDOUR_UI::start_clocking ()
1997 clock_signal_connection = RapidScreenUpdate.connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2001 ARDOUR_UI::stop_clocking ()
2003 clock_signal_connection.disconnect ();
2007 ARDOUR_UI::toggle_clocking ()
2010 if (clock_button.get_active()) {
2019 ARDOUR_UI::_blink (void *arg)
2022 ((ARDOUR_UI *) arg)->blink ();
2029 Blink (blink_on = !blink_on); /* EMIT_SIGNAL */
2033 ARDOUR_UI::start_blinking ()
2035 /* Start the blink signal. Everybody with a blinking widget
2036 uses Blink to drive the widget's state.
2039 if (blink_timeout_tag < 0) {
2041 blink_timeout_tag = g_timeout_add (240, _blink, this);
2046 ARDOUR_UI::stop_blinking ()
2048 if (blink_timeout_tag >= 0) {
2049 g_source_remove (blink_timeout_tag);
2050 blink_timeout_tag = -1;
2055 /** Ask the user for the name of a new shapshot and then take it.
2059 ARDOUR_UI::snapshot_session (bool switch_to_it)
2061 ArdourPrompter prompter (true);
2064 prompter.set_name ("Prompter");
2065 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2066 prompter.set_title (_("Take Snapshot"));
2067 prompter.set_title (_("Take Snapshot"));
2068 prompter.set_prompt (_("Name of new snapshot"));
2070 if (!switch_to_it) {
2073 struct tm local_time;
2076 localtime_r (&n, &local_time);
2077 strftime (timebuf, sizeof(timebuf), "%FT%T", &local_time);
2078 prompter.set_initial_text (timebuf);
2082 switch (prompter.run()) {
2083 case RESPONSE_ACCEPT:
2085 prompter.get_result (snapname);
2087 bool do_save = (snapname.length() != 0);
2090 if (snapname.find ('/') != string::npos) {
2091 MessageDialog msg (_("To ensure compatibility with various systems\n"
2092 "snapshot names may not contain a '/' character"));
2096 if (snapname.find ('\\') != string::npos) {
2097 MessageDialog msg (_("To ensure compatibility with various systems\n"
2098 "snapshot names may not contain a '\\' character"));
2104 vector<sys::path> p;
2105 get_state_files_in_directory (_session->session_directory().root_path(), p);
2106 vector<string> n = get_file_names_no_extension (p);
2107 if (find (n.begin(), n.end(), snapname) != n.end()) {
2109 ArdourDialog confirm (_("Confirm Snapshot Overwrite"), true);
2110 Label m (_("A snapshot already exists with that name. Do you want to overwrite it?"));
2111 confirm.get_vbox()->pack_start (m, true, true);
2112 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2113 confirm.add_button (_("Overwrite"), Gtk::RESPONSE_ACCEPT);
2114 confirm.show_all ();
2115 switch (confirm.run()) {
2116 case RESPONSE_CANCEL:
2122 save_state (snapname, switch_to_it);
2133 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2135 XMLNode* node = new XMLNode (X_("UI"));
2137 for (list<WindowProxyBase*>::iterator i = _window_proxies.begin(); i != _window_proxies.end(); ++i) {
2138 if (!(*i)->rc_configured()) {
2139 node->add_child_nocopy (*((*i)->get_state ()));
2143 _session->add_extra_xml (*node);
2145 save_state_canfail (name, switch_to_it);
2149 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2154 if (name.length() == 0) {
2155 name = _session->snap_name();
2158 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2162 cerr << "SS canfail\n";
2163 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2168 ARDOUR_UI::primary_clock_value_changed ()
2171 _session->request_locate (primary_clock.current_time ());
2176 ARDOUR_UI::big_clock_value_changed ()
2179 _session->request_locate (big_clock.current_time ());
2184 ARDOUR_UI::secondary_clock_value_changed ()
2187 _session->request_locate (secondary_clock.current_time ());
2192 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2194 if (_session == 0) {
2198 if (_session->step_editing()) {
2202 Session::RecordState const r = _session->record_status ();
2203 bool const h = _session->have_rec_enabled_track ();
2205 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2207 rec_button.set_visual_state (2);
2209 rec_button.set_visual_state (0);
2211 } else if (r == Session::Recording && h) {
2212 rec_button.set_visual_state (1);
2214 rec_button.set_visual_state (0);
2219 ARDOUR_UI::save_template ()
2221 ArdourPrompter prompter (true);
2224 if (!check_audioengine()) {
2228 prompter.set_name (X_("Prompter"));
2229 prompter.set_title (_("Save Mix Template"));
2230 prompter.set_prompt (_("Name for mix template:"));
2231 prompter.set_initial_text(_session->name() + _("-template"));
2232 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2234 switch (prompter.run()) {
2235 case RESPONSE_ACCEPT:
2236 prompter.get_result (name);
2238 if (name.length()) {
2239 _session->save_template (name);
2249 ARDOUR_UI::edit_metadata ()
2251 SessionMetadataEditor dialog;
2252 dialog.set_session (_session);
2253 editor->ensure_float (dialog);
2258 ARDOUR_UI::import_metadata ()
2260 SessionMetadataImporter dialog;
2261 dialog.set_session (_session);
2262 editor->ensure_float (dialog);
2267 ARDOUR_UI::fontconfig_dialog ()
2270 /* X11 users will always have fontconfig info around, but new GTK-OSX users
2271 may not and it can take a while to build it. Warn them.
2274 std::string fontconfig = Glib::build_filename (Glib::get_home_dir(), ".fontconfig");
2276 if (!Glib::file_test (fontconfig, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_DIR)) {
2277 MessageDialog msg (*_startup,
2278 string_compose (_("Welcome to %1.\n\n"
2279 "The program will take a bit longer to start up\n"
2280 "while the system fonts are checked.\n\n"
2281 "This will only be done once, and you will\n"
2282 "not see this message again\n"), PROGRAM_NAME),
2295 ARDOUR_UI::parse_cmdline_path (const std::string& cmdline_path, std::string& session_name, std::string& session_path, bool& existing_session)
2297 existing_session = false;
2299 if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_DIR)) {
2300 session_path = cmdline_path;
2301 existing_session = true;
2302 } else if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_REGULAR)) {
2303 session_path = Glib::path_get_dirname (string (cmdline_path));
2304 existing_session = true;
2306 /* it doesn't exist, assume the best */
2307 session_path = Glib::path_get_dirname (string (cmdline_path));
2310 session_name = basename_nosuffix (string (cmdline_path));
2314 ARDOUR_UI::load_cmdline_session (const std::string& session_name, const std::string& session_path, bool& existing_session)
2316 /* when this is called, the backend audio system must be running */
2318 /* the main idea here is to deal with the fact that a cmdline argument for the session
2319 can be interpreted in different ways - it could be a directory or a file, and before
2320 we load, we need to know both the session directory and the snapshot (statefile) within it
2321 that we are supposed to use.
2324 if (session_name.length() == 0 || session_path.length() == 0) {
2328 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_DIR)) {
2330 std::string predicted_session_file;
2332 predicted_session_file = session_path;
2333 predicted_session_file += '/';
2334 predicted_session_file += session_name;
2335 predicted_session_file += ARDOUR::statefile_suffix;
2337 if (Glib::file_test (predicted_session_file, Glib::FILE_TEST_EXISTS)) {
2338 existing_session = true;
2341 } else if (Glib::file_test (session_path, Glib::FILE_TEST_EXISTS)) {
2343 if (session_path.find (ARDOUR::statefile_suffix) == session_path.length() - 7) {
2344 /* existing .ardour file */
2345 existing_session = true;
2349 existing_session = false;
2352 /* lets just try to load it */
2354 if (create_engine ()) {
2355 backend_audio_error (false, _startup);
2359 return load_session (session_path, session_name);
2363 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
2365 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2367 MessageDialog msg (str,
2369 Gtk::MESSAGE_WARNING,
2370 Gtk::BUTTONS_YES_NO,
2374 msg.set_name (X_("OpenExistingDialog"));
2375 msg.set_title (_("Open Existing Session"));
2376 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
2377 msg.set_position (Gtk::WIN_POS_MOUSE);
2380 switch (msg.run()) {
2389 ARDOUR_UI::build_session_from_nsd (const std::string& session_path, const std::string& session_name)
2391 BusProfile bus_profile;
2393 if (Profile->get_sae()) {
2395 bus_profile.master_out_channels = 2;
2396 bus_profile.input_ac = AutoConnectPhysical;
2397 bus_profile.output_ac = AutoConnectMaster;
2398 bus_profile.requested_physical_in = 0; // use all available
2399 bus_profile.requested_physical_out = 0; // use all available
2403 /* get settings from advanced section of NSD */
2405 if (_startup->create_master_bus()) {
2406 bus_profile.master_out_channels = (uint32_t) _startup->master_channel_count();
2408 bus_profile.master_out_channels = 0;
2411 if (_startup->connect_inputs()) {
2412 bus_profile.input_ac = AutoConnectPhysical;
2414 bus_profile.input_ac = AutoConnectOption (0);
2417 /// @todo some minor tweaks.
2419 bus_profile.output_ac = AutoConnectOption (0);
2421 if (_startup->connect_outputs ()) {
2422 if (_startup->connect_outs_to_master()) {
2423 bus_profile.output_ac = AutoConnectMaster;
2424 } else if (_startup->connect_outs_to_physical()) {
2425 bus_profile.output_ac = AutoConnectPhysical;
2429 bus_profile.requested_physical_in = (uint32_t) _startup->input_limit_count();
2430 bus_profile.requested_physical_out = (uint32_t) _startup->output_limit_count();
2433 if (build_session (session_path, session_name, bus_profile)) {
2441 ARDOUR_UI::idle_load (const std::string& path)
2444 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2445 /* /path/to/foo => /path/to/foo, foo */
2446 load_session (path, basename_nosuffix (path));
2448 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2449 load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2453 ARDOUR_COMMAND_LINE::session_name = path;
2456 * new_session_dialog doens't exist in A3
2457 * Try to remove all references to it to
2458 * see if it will compile. NOTE: this will
2459 * likely cause a runtime issue is my somewhat
2463 //if (new_session_dialog) {
2466 /* make it break out of Dialog::run() and
2470 //new_session_dialog->response (1);
2476 ARDOUR_UI::end_loading_messages ()
2482 ARDOUR_UI::loading_message (const std::string& /*msg*/)
2485 // splash->message (msg);
2489 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
2491 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
2493 string session_name;
2494 string session_path;
2495 string template_name;
2497 bool likely_new = false;
2499 if (! load_template.empty()) {
2500 should_be_new = true;
2501 template_name = load_template;
2506 if (!should_be_new && !ARDOUR_COMMAND_LINE::session_name.empty()) {
2508 /* if they named a specific statefile, use it, otherwise they are
2509 just giving a session folder, and we want to use it as is
2510 to find the session.
2513 if (ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix) != string::npos) {
2514 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
2516 session_path = ARDOUR_COMMAND_LINE::session_name;
2519 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
2523 bool const apply = run_startup (should_be_new, load_template);
2526 if (quit_on_cancel) {
2533 /* if we run the startup dialog again, offer more than just "new session" */
2535 should_be_new = false;
2537 session_name = _startup->session_name (likely_new);
2539 /* this shouldn't happen, but we catch it just in case it does */
2541 if (session_name.empty()) {
2545 if (_startup->use_session_template()) {
2546 template_name = _startup->session_template_name();
2547 _session_is_new = true;
2550 if (session_name[0] == G_DIR_SEPARATOR ||
2551 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
2552 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)) {
2554 /* absolute path or cwd-relative path specified for session name: infer session folder
2555 from what was given.
2558 session_path = Glib::path_get_dirname (session_name);
2559 session_name = Glib::path_get_basename (session_name);
2563 session_path = _startup->session_folder();
2565 if (session_name.find ('/') != string::npos) {
2566 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2567 "session names may not contain a '/' character"));
2569 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2573 if (session_name.find ('\\') != string::npos) {
2574 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2575 "session names may not contain a '\\' character"));
2577 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2583 if (create_engine ()) {
2587 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
2591 std::string existing = Glib::build_filename (session_path, session_name);
2593 if (!ask_about_loading_existing_session (existing)) {
2594 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2599 _session_is_new = false;
2604 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
2606 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2610 if (session_name.find ('/') != std::string::npos) {
2611 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2612 "session names may not contain a '/' character"));
2614 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2618 if (session_name.find ('\\') != std::string::npos) {
2619 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2620 "session names may not contain a '\\' character"));
2622 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2626 _session_is_new = true;
2629 if (likely_new && template_name.empty()) {
2631 ret = build_session_from_nsd (session_path, session_name);
2635 ret = load_session (session_path, session_name, template_name);
2636 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
2637 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
2647 ARDOUR_UI::close_session()
2649 if (!check_audioengine()) {
2653 if (unload_session (true)) {
2657 ARDOUR_COMMAND_LINE::session_name = "";
2659 if (get_session_parameters (true, false)) {
2663 goto_editor_window ();
2667 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
2669 Session *new_session;
2673 session_loaded = false;
2675 if (!check_audioengine()) {
2679 unload_status = unload_session ();
2681 if (unload_status < 0) {
2683 } else if (unload_status > 0) {
2688 loading_message (string_compose (_("Please wait while %1loads your session"), PROGRAM_NAME));
2691 new_session = new Session (*engine, path, snap_name, 0, mix_template);
2694 /* this one is special */
2696 catch (AudioEngine::PortRegistrationFailure& err) {
2698 MessageDialog msg (err.what(),
2701 Gtk::BUTTONS_CLOSE);
2703 msg.set_title (_("Port Registration Error"));
2704 msg.set_secondary_text (_("Click the Close button to try again."));
2705 msg.set_position (Gtk::WIN_POS_CENTER);
2709 int response = msg.run ();
2714 case RESPONSE_CANCEL:
2724 MessageDialog msg (string_compose(_("Session \"%1 (snapshot %2)\" did not load successfully"),path, snap_name),
2729 msg.set_title (_("Loading Error"));
2730 msg.set_secondary_text (_("Click the Refresh button to try again."));
2731 msg.add_button (Stock::REFRESH, 1);
2732 msg.set_position (Gtk::WIN_POS_CENTER);
2736 int response = msg.run ();
2751 list<string> const u = new_session->unknown_processors ();
2753 MissingPluginDialog d (_session, u);
2758 /* Now the session been created, add the transport controls */
2759 new_session->add_controllable(roll_controllable);
2760 new_session->add_controllable(stop_controllable);
2761 new_session->add_controllable(goto_start_controllable);
2762 new_session->add_controllable(goto_end_controllable);
2763 new_session->add_controllable(auto_loop_controllable);
2764 new_session->add_controllable(play_selection_controllable);
2765 new_session->add_controllable(rec_controllable);
2767 set_session (new_session);
2769 session_loaded = true;
2771 goto_editor_window ();
2774 _session->set_clean ();
2785 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
2787 Session *new_session;
2790 if (!check_audioengine()) {
2794 session_loaded = false;
2796 x = unload_session ();
2804 _session_is_new = true;
2807 new_session = new Session (*engine, path, snap_name, &bus_profile);
2812 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
2818 /* Give the new session the default GUI state, if such things exist */
2821 n = Config->instant_xml (X_("Editor"));
2823 new_session->add_instant_xml (*n, false);
2825 n = Config->instant_xml (X_("Mixer"));
2827 new_session->add_instant_xml (*n, false);
2830 set_session (new_session);
2832 session_loaded = true;
2834 new_session->save_state(new_session->name());
2840 ARDOUR_UI::launch_chat ()
2843 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
2845 open_uri("http://webchat.freenode.net/?channels=ardour");
2850 ARDOUR_UI::show_about ()
2854 about->signal_response().connect(sigc::mem_fun (*this, &ARDOUR_UI::about_signal_response) );
2857 about->set_transient_for(*editor);
2862 ARDOUR_UI::launch_manual ()
2864 PBD::open_uri("http://ardour.org/flossmanual");
2868 ARDOUR_UI::launch_reference ()
2870 PBD::open_uri("http://ardour.org/refmanual");
2874 ARDOUR_UI::hide_about ()
2877 about->get_window()->set_cursor ();
2883 ARDOUR_UI::about_signal_response (int /*response*/)
2889 ARDOUR_UI::show_splash ()
2893 splash = new Splash;
2901 splash->queue_draw ();
2902 splash->get_window()->process_updates (true);
2907 ARDOUR_UI::hide_splash ()
2915 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title,
2916 const string& plural_msg, const string& singular_msg)
2920 removed = rep.paths.size();
2923 MessageDialog msgd (*editor,
2924 _("No audio files were ready for cleanup"),
2927 (Gtk::ButtonsType)(Gtk::BUTTONS_OK) );
2928 msgd.set_secondary_text (_("If this seems suprising, \n\
2929 check for any existing snapshots.\n\
2930 These may still include regions that\n\
2931 require some unused files to continue to exist."));
2937 ArdourDialog results (_("Clean-up"), true, false);
2939 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
2940 CleanupResultsModelColumns() {
2944 Gtk::TreeModelColumn<std::string> visible_name;
2945 Gtk::TreeModelColumn<std::string> fullpath;
2949 CleanupResultsModelColumns results_columns;
2950 Glib::RefPtr<Gtk::ListStore> results_model;
2951 Gtk::TreeView results_display;
2953 results_model = ListStore::create (results_columns);
2954 results_display.set_model (results_model);
2955 results_display.append_column (list_title, results_columns.visible_name);
2957 results_display.set_name ("CleanupResultsList");
2958 results_display.set_headers_visible (true);
2959 results_display.set_headers_clickable (false);
2960 results_display.set_reorderable (false);
2962 Gtk::ScrolledWindow list_scroller;
2965 Gtk::HBox dhbox; // the hbox for the image and text
2966 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
2967 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
2969 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
2971 const string dead_sound_directory = _session->session_directory().dead_sound_path().to_string();
2974 %1 - number of files removed
2975 %2 - location of "dead_sounds"
2976 %3 - size of files affected
2977 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
2980 const char* bprefix;
2981 double space_adjusted = 0;
2983 if (rep.space < 100000.0f) {
2984 bprefix = X_("kilo");
2985 } else if (rep.space < 1000000.0f * 1000) {
2986 bprefix = X_("mega");
2987 space_adjusted = truncf((float)rep.space / 1000.0);
2989 bprefix = X_("giga");
2990 space_adjusted = truncf((float)rep.space / (1000000.0 * 1000));
2994 txt.set_text (string_compose (plural_msg, removed, _session->path() + "dead_sounds", space_adjusted, bprefix));
2996 txt.set_text (string_compose (singular_msg, removed, _session->path() + "dead_sounds", space_adjusted, bprefix));
2999 dhbox.pack_start (*dimage, true, false, 5);
3000 dhbox.pack_start (txt, true, false, 5);
3002 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
3003 TreeModel::Row row = *(results_model->append());
3004 row[results_columns.visible_name] = *i;
3005 row[results_columns.fullpath] = *i;
3008 list_scroller.add (results_display);
3009 list_scroller.set_size_request (-1, 150);
3010 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
3012 dvbox.pack_start (dhbox, true, false, 5);
3013 dvbox.pack_start (list_scroller, true, false, 5);
3014 ddhbox.pack_start (dvbox, true, false, 5);
3016 results.get_vbox()->pack_start (ddhbox, true, false, 5);
3017 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
3018 results.set_default_response (RESPONSE_CLOSE);
3019 results.set_position (Gtk::WIN_POS_MOUSE);
3021 results_display.show();
3022 list_scroller.show();
3029 //results.get_vbox()->show();
3030 results.set_resizable (false);
3037 ARDOUR_UI::cleanup ()
3039 if (_session == 0) {
3040 /* shouldn't happen: menu item is insensitive */
3045 MessageDialog checker (_("Are you sure you want to cleanup?"),
3047 Gtk::MESSAGE_QUESTION,
3048 (Gtk::ButtonsType)(Gtk::BUTTONS_NONE));
3050 checker.set_secondary_text(_("Cleanup is a destructive operation.\n\
3051 ALL undo/redo information will be lost if you cleanup.\n\
3052 After cleanup, unused audio files will be moved to a \
3053 \"dead sounds\" location."));
3055 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3056 checker.add_button (_("Clean Up"), RESPONSE_ACCEPT);
3057 checker.set_default_response (RESPONSE_CANCEL);
3059 checker.set_name (_("CleanupDialog"));
3060 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3061 checker.set_position (Gtk::WIN_POS_MOUSE);
3063 switch (checker.run()) {
3064 case RESPONSE_ACCEPT:
3070 ARDOUR::CleanupReport rep;
3072 editor->prepare_for_cleanup ();
3074 /* do not allow flush until a session is reloaded */
3076 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3078 act->set_sensitive (false);
3081 if (_session->cleanup_sources (rep)) {
3082 editor->finish_cleanup ();
3086 editor->finish_cleanup ();
3089 display_cleanup_results (rep,
3092 The following %1 files were not in use and \n\
3093 have been moved to:\n\
3095 Flushing the wastebasket will \n\
3096 release an additional\n\
3097 %3 %4bytes of disk space.\n"),
3099 The following file was not in use and \n \
3100 has been moved to:\n \
3102 Flushing the wastebasket will \n\
3103 release an additional\n\
3104 %3 %4bytes of disk space.\n"
3110 ARDOUR_UI::flush_trash ()
3112 if (_session == 0) {
3113 /* shouldn't happen: menu item is insensitive */
3117 ARDOUR::CleanupReport rep;
3119 if (_session->cleanup_trash_sources (rep)) {
3123 display_cleanup_results (rep,
3125 _("The following %1 files were deleted from\n\
3127 releasing %3 %4bytes of disk space"),
3128 _("The following file was deleted from\n\
3130 releasing %3 %4bytes of disk space"));
3134 ARDOUR_UI::add_route (Gtk::Window* float_window)
3142 if (add_route_dialog == 0) {
3143 add_route_dialog = new AddRouteDialog (_session);
3145 add_route_dialog->set_transient_for (*float_window);
3149 if (add_route_dialog->is_visible()) {
3150 /* we're already doing this */
3154 ResponseType r = (ResponseType) add_route_dialog->run ();
3156 add_route_dialog->hide();
3159 case RESPONSE_ACCEPT:
3166 if ((count = add_route_dialog->count()) <= 0) {
3170 string template_path = add_route_dialog->track_template();
3172 if (!template_path.empty()) {
3173 _session->new_route_from_template (count, template_path);
3177 uint32_t input_chan = add_route_dialog->channels ();
3178 uint32_t output_chan;
3179 string name_template = add_route_dialog->name_template ();
3180 bool track = add_route_dialog->track ();
3181 RouteGroup* route_group = add_route_dialog->route_group ();
3183 AutoConnectOption oac = Config->get_output_auto_connect();
3185 if (oac & AutoConnectMaster) {
3186 output_chan = (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan);
3188 output_chan = input_chan;
3191 /* XXX do something with name template */
3193 if (add_route_dialog->type() == ARDOUR::DataType::MIDI) {
3195 session_add_midi_track (route_group, count);
3197 MessageDialog msg (*editor,
3198 _("Sorry, MIDI Busses are not supported at this time."));
3200 //session_add_midi_bus();
3204 session_add_audio_track (input_chan, output_chan, add_route_dialog->mode(), route_group, count);
3206 session_add_audio_bus (input_chan, output_chan, route_group, count);
3212 ARDOUR_UI::mixer_settings () const
3217 node = _session->instant_xml(X_("Mixer"));
3219 node = Config->instant_xml(X_("Mixer"));
3223 node = new XMLNode (X_("Mixer"));
3230 ARDOUR_UI::editor_settings () const
3235 node = _session->instant_xml(X_("Editor"));
3237 node = Config->instant_xml(X_("Editor"));
3241 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
3242 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
3247 node = new XMLNode (X_("Editor"));
3254 ARDOUR_UI::keyboard_settings () const
3258 node = Config->extra_xml(X_("Keyboard"));
3261 node = new XMLNode (X_("Keyboard"));
3267 ARDOUR_UI::create_xrun_marker (framepos_t where)
3269 editor->mouse_add_new_marker (where, false, true);
3273 ARDOUR_UI::halt_on_xrun_message ()
3275 MessageDialog msg (*editor,
3276 _("Recording was stopped because your system could not keep up."));
3281 ARDOUR_UI::xrun_handler (framepos_t where)
3287 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
3289 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
3290 create_xrun_marker(where);
3293 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
3294 halt_on_xrun_message ();
3299 ARDOUR_UI::disk_overrun_handler ()
3301 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
3303 if (!have_disk_speed_dialog_displayed) {
3304 have_disk_speed_dialog_displayed = true;
3305 MessageDialog* msg = new MessageDialog (*editor, string_compose (_("\
3306 The disk system on your computer\n\
3307 was not able to keep up with %1.\n\
3309 Specifically, it failed to write data to disk\n\
3310 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
3311 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3317 ARDOUR_UI::disk_underrun_handler ()
3319 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
3321 if (!have_disk_speed_dialog_displayed) {
3322 have_disk_speed_dialog_displayed = true;
3323 MessageDialog* msg = new MessageDialog (*editor,
3324 string_compose (_("The disk system on your computer\n\
3325 was not able to keep up with %1.\n\
3327 Specifically, it failed to read data from disk\n\
3328 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
3329 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3335 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
3337 have_disk_speed_dialog_displayed = false;
3342 ARDOUR_UI::session_dialog (std::string msg)
3344 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
3349 d = new MessageDialog (*editor, msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3351 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3360 ARDOUR_UI::pending_state_dialog ()
3362 HBox* hbox = new HBox();
3363 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3364 ArdourDialog dialog (_("Crash Recovery"), true);
3366 This session appears to have been in\n\
3367 middle of recording when ardour or\n\
3368 the computer was shutdown.\n\
3370 Ardour can recover any captured audio for\n\
3371 you, or it can ignore it. Please decide\n\
3372 what you would like to do.\n"));
3373 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3374 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3375 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3376 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3377 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
3378 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
3379 dialog.set_default_response (RESPONSE_ACCEPT);
3380 dialog.set_position (WIN_POS_CENTER);
3385 switch (dialog.run ()) {
3386 case RESPONSE_ACCEPT:
3394 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
3396 HBox* hbox = new HBox();
3397 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3398 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
3399 Label message (string_compose (_("\
3400 This session was created with a sample rate of %1 Hz\n\
3402 The audioengine is currently running at %2 Hz\n"), desired, actual));
3404 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3405 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3406 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3407 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3408 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
3409 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
3410 dialog.set_default_response (RESPONSE_ACCEPT);
3411 dialog.set_position (WIN_POS_CENTER);
3416 switch (dialog.run ()) {
3417 case RESPONSE_ACCEPT:
3426 ARDOUR_UI::disconnect_from_jack ()
3429 if( engine->disconnect_from_jack ()) {
3430 MessageDialog msg (*editor, _("Could not disconnect from JACK"));
3434 update_sample_rate (0);
3439 ARDOUR_UI::reconnect_to_jack ()
3442 if (engine->reconnect_to_jack ()) {
3443 MessageDialog msg (*editor, _("Could not reconnect to JACK"));
3447 update_sample_rate (0);
3452 ARDOUR_UI::use_config ()
3454 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
3456 set_transport_controllable_state (*node);
3461 ARDOUR_UI::update_transport_clocks (framepos_t pos)
3463 if (Config->get_primary_clock_delta_edit_cursor()) {
3464 primary_clock.set (pos, false, editor->get_preferred_edit_position(), 1);
3466 primary_clock.set (pos, 0, true);
3469 if (Config->get_secondary_clock_delta_edit_cursor()) {
3470 secondary_clock.set (pos, false, editor->get_preferred_edit_position(), 2);
3472 secondary_clock.set (pos);
3475 if (big_clock_window->get()) {
3476 big_clock.set (pos);
3482 ARDOUR_UI::step_edit_status_change (bool yn)
3484 // XXX should really store pre-step edit status of things
3485 // we make insensitive
3488 rec_button.set_visual_state (3);
3489 rec_button.set_sensitive (false);
3491 rec_button.set_visual_state (0);
3492 rec_button.set_sensitive (true);
3497 ARDOUR_UI::record_state_changed ()
3499 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
3501 if (!_session || !big_clock_window->get()) {
3502 /* why bother - the clock isn't visible */
3506 Session::RecordState const r = _session->record_status ();
3507 bool const h = _session->have_rec_enabled_track ();
3509 if (r == Session::Recording && h) {
3510 big_clock.set_widget_name ("BigClockRecording");
3512 big_clock.set_widget_name ("BigClockNonRecording");
3517 ARDOUR_UI::first_idle ()
3520 _session->allow_auto_play (true);
3524 editor->first_idle();
3527 Keyboard::set_can_save_keybindings (true);
3532 ARDOUR_UI::store_clock_modes ()
3534 XMLNode* node = new XMLNode(X_("ClockModes"));
3536 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
3537 node->add_property ((*x)->name().c_str(), enum_2_string ((*x)->mode()));
3540 _session->add_extra_xml (*node);
3541 _session->set_dirty ();
3546 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
3547 : Controllable (name), ui (u), type(tp)
3553 ARDOUR_UI::TransportControllable::set_value (double val)
3555 if (type == ShuttleControl) {
3562 fract = -((0.5 - val)/0.5);
3564 fract = ((val - 0.5)/0.5);
3568 ui.set_shuttle_fract (fract);
3573 /* do nothing: these are radio-style actions */
3577 const char *action = 0;
3581 action = X_("Roll");
3584 action = X_("Stop");
3587 action = X_("Goto Start");
3590 action = X_("Goto End");
3593 action = X_("Loop");
3596 action = X_("Play Selection");
3599 action = X_("Record");
3609 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
3617 ARDOUR_UI::TransportControllable::get_value (void) const
3636 case ShuttleControl:
3646 ARDOUR_UI::TransportControllable::set_id (const string& str)
3652 ARDOUR_UI::setup_profile ()
3654 if (gdk_screen_width() < 1200) {
3655 Profile->set_small_screen ();
3659 if (getenv ("ARDOUR_SAE")) {
3660 Profile->set_sae ();
3661 Profile->set_single_package ();
3666 ARDOUR_UI::toggle_translations ()
3668 using namespace Glib;
3670 RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("EnableTranslation"));
3672 RefPtr<ToggleAction> ract = RefPtr<ToggleAction>::cast_dynamic (act);
3675 string i18n_killer = ARDOUR::translation_kill_path();
3677 bool already_enabled = !ARDOUR::translations_are_disabled ();
3679 if (ract->get_active ()) {
3680 /* we don't care about errors */
3681 int fd = ::open (i18n_killer.c_str(), O_RDONLY|O_CREAT, 0644);
3684 /* we don't care about errors */
3685 unlink (i18n_killer.c_str());
3688 if (already_enabled != ract->get_active()) {
3689 MessageDialog win (already_enabled ? _("Translations disabled") : _("Translations enabled"),
3691 Gtk::MESSAGE_WARNING,
3693 win.set_secondary_text (string_compose (_("You must restart %1 for this to take effect."), PROGRAM_NAME));
3694 win.set_position (Gtk::WIN_POS_CENTER);
3702 /** Add a window proxy to our list, so that its state will be saved.
3703 * This call also causes the window to be created and opened if its
3704 * state was saved as `visible'.
3707 ARDOUR_UI::add_window_proxy (WindowProxyBase* p)
3709 _window_proxies.push_back (p);
3713 /** Remove a window proxy from our list. Must be called if a WindowProxy
3714 * is deleted, to prevent hanging pointers.
3717 ARDOUR_UI::remove_window_proxy (WindowProxyBase* p)
3719 _window_proxies.remove (p);
3723 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
3725 MissingFileDialog dialog (s, str, type);
3730 int result = dialog.run ();
3737 return 1; // quit entire session load
3740 result = dialog.get_action ();
3746 ARDOUR_UI::ambiguous_file (std::string file, std::string path, std::vector<std::string> hits)
3748 AmbiguousFileDialog dialog (file, hits);
3754 return dialog.get_which ();