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, bool aux, 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 (aux, 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()) {
1591 if (_session->config.get_external_sync()) {
1592 switch (_session->config.get_sync_source()) {
1596 /* transport controlled by the master */
1601 bool rolling = _session->transport_rolling();
1603 if (_session->get_play_loop()) {
1604 /* XXX it is not possible to just leave seamless loop and keep
1605 playing at present (nov 4th 2009)
1607 if (!Config->get_seamless_loop()) {
1608 _session->request_play_loop (false, true);
1610 } else if (_session->get_play_range () && !join_play_range_button.get_active()) {
1611 /* stop playing a range if we currently are */
1612 _session->request_play_range (0, true);
1615 if (join_play_range_button.get_active()) {
1616 _session->request_play_range (&editor->get_selection().time, true);
1620 _session->request_transport_speed (1.0f);
1625 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
1632 if (_session->is_auditioning()) {
1633 _session->cancel_audition ();
1637 if (_session->config.get_external_sync()) {
1638 switch (_session->config.get_sync_source()) {
1642 /* transport controlled by the master */
1647 bool rolling = _session->transport_rolling();
1648 bool affect_transport = true;
1650 if (rolling && roll_out_of_bounded_mode) {
1651 /* drop out of loop/range playback but leave transport rolling */
1652 if (_session->get_play_loop()) {
1653 if (Config->get_seamless_loop()) {
1654 /* the disk buffers contain copies of the loop - we can't
1655 just keep playing, so stop the transport. the user
1656 can restart as they wish.
1658 affect_transport = true;
1660 /* disk buffers are normal, so we can keep playing */
1661 affect_transport = false;
1663 _session->request_play_loop (false, true);
1664 } else if (_session->get_play_range ()) {
1665 affect_transport = false;
1666 _session->request_play_range (0, true);
1670 if (affect_transport) {
1672 _session->request_stop (with_abort, true);
1674 if (join_play_range_button.get_active()) {
1675 _session->request_play_range (&editor->get_selection().time, true);
1678 _session->request_transport_speed (1.0f);
1684 ARDOUR_UI::toggle_session_auto_loop ()
1687 if (_session->get_play_loop()) {
1688 if (_session->transport_rolling()) {
1689 Location * looploc = _session->locations()->auto_loop_location();
1691 _session->request_locate (looploc->start(), true);
1694 _session->request_play_loop (false);
1697 Location * looploc = _session->locations()->auto_loop_location();
1699 _session->request_play_loop (true);
1706 ARDOUR_UI::transport_play_selection ()
1712 editor->play_selection ();
1716 ARDOUR_UI::transport_rewind (int option)
1718 float current_transport_speed;
1721 current_transport_speed = _session->transport_speed();
1723 if (current_transport_speed >= 0.0f) {
1726 _session->request_transport_speed (-1.0f);
1729 _session->request_transport_speed (-4.0f);
1732 _session->request_transport_speed (-0.5f);
1737 _session->request_transport_speed (current_transport_speed * 1.5f);
1743 ARDOUR_UI::transport_forward (int option)
1745 float current_transport_speed;
1748 current_transport_speed = _session->transport_speed();
1750 if (current_transport_speed <= 0.0f) {
1753 _session->request_transport_speed (1.0f);
1756 _session->request_transport_speed (4.0f);
1759 _session->request_transport_speed (0.5f);
1764 _session->request_transport_speed (current_transport_speed * 1.5f);
1771 ARDOUR_UI::toggle_record_enable (uint32_t rid)
1773 if (_session == 0) {
1777 boost::shared_ptr<Route> r;
1779 if ((r = _session->route_by_remote_id (rid)) != 0) {
1783 if ((t = dynamic_cast<Track*>(r.get())) != 0) {
1784 t->set_record_enabled (!t->record_enabled(), this);
1787 if (_session == 0) {
1793 ARDOUR_UI::map_transport_state ()
1795 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::map_transport_state)
1798 auto_loop_button.set_visual_state (0);
1799 play_selection_button.set_visual_state (0);
1800 roll_button.set_visual_state (0);
1801 stop_button.set_visual_state (1);
1805 float sp = _session->transport_speed();
1808 shuttle_fract = SHUTTLE_FRACT_SPEED1; /* speed = 1.0, believe it or not */
1809 shuttle_box.queue_draw ();
1810 } else if (sp == 0.0f) {
1812 shuttle_box.queue_draw ();
1813 update_disk_space ();
1820 if (_session->get_play_range()) {
1822 play_selection_button.set_visual_state (1);
1823 roll_button.set_visual_state (0);
1824 auto_loop_button.set_visual_state (0);
1826 } else if (_session->get_play_loop ()) {
1828 auto_loop_button.set_visual_state (1);
1829 play_selection_button.set_visual_state (0);
1830 roll_button.set_visual_state (0);
1834 roll_button.set_visual_state (1);
1835 play_selection_button.set_visual_state (0);
1836 auto_loop_button.set_visual_state (0);
1839 if (join_play_range_button.get_active()) {
1840 /* light up both roll and play-selection if they are joined */
1841 roll_button.set_visual_state (1);
1842 play_selection_button.set_visual_state (1);
1845 stop_button.set_visual_state (0);
1849 stop_button.set_visual_state (1);
1850 roll_button.set_visual_state (0);
1851 play_selection_button.set_visual_state (0);
1852 auto_loop_button.set_visual_state (0);
1857 ARDOUR_UI::engine_stopped ()
1859 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
1860 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1861 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1865 ARDOUR_UI::engine_running ()
1867 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
1868 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, true);
1869 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, false);
1871 Glib::RefPtr<Action> action;
1872 const char* action_name = 0;
1874 switch (engine->frames_per_cycle()) {
1876 action_name = X_("JACKLatency32");
1879 action_name = X_("JACKLatency64");
1882 action_name = X_("JACKLatency128");
1885 action_name = X_("JACKLatency512");
1888 action_name = X_("JACKLatency1024");
1891 action_name = X_("JACKLatency2048");
1894 action_name = X_("JACKLatency4096");
1897 action_name = X_("JACKLatency8192");
1900 /* XXX can we do anything useful ? */
1906 action = ActionManager::get_action (X_("JACK"), action_name);
1909 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (action);
1910 ract->set_active ();
1916 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
1918 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
1919 /* we can't rely on the original string continuing to exist when we are called
1920 again in the GUI thread, so make a copy and note that we need to
1923 char *copy = strdup (reason);
1924 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
1928 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1929 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1931 update_sample_rate (0);
1935 /* if the reason is a non-empty string, it means that the backend was shutdown
1936 rather than just Ardour.
1939 if (strlen (reason)) {
1940 msgstr = string_compose (_("The audio backend (JACK) was shutdown because:\n\n%1"), reason);
1942 msgstr = string_compose (_("\
1943 JACK has either been shutdown or it\n\
1944 disconnected %1 because %1\n\
1945 was not fast enough. Try to restart\n\
1946 JACK, reconnect and save the session."), PROGRAM_NAME);
1949 MessageDialog msg (*editor, msgstr);
1954 free ((char*) reason);
1959 ARDOUR_UI::do_engine_start ()
1967 error << _("Unable to start the session running")
1977 ARDOUR_UI::setup_theme ()
1979 theme_manager->setup_theme();
1983 ARDOUR_UI::update_clocks ()
1985 if (!editor || !editor->dragging_playhead()) {
1986 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position()); /* EMIT_SIGNAL */
1991 ARDOUR_UI::start_clocking ()
1993 clock_signal_connection = RapidScreenUpdate.connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
1997 ARDOUR_UI::stop_clocking ()
1999 clock_signal_connection.disconnect ();
2003 ARDOUR_UI::toggle_clocking ()
2006 if (clock_button.get_active()) {
2015 ARDOUR_UI::_blink (void *arg)
2018 ((ARDOUR_UI *) arg)->blink ();
2025 Blink (blink_on = !blink_on); /* EMIT_SIGNAL */
2029 ARDOUR_UI::start_blinking ()
2031 /* Start the blink signal. Everybody with a blinking widget
2032 uses Blink to drive the widget's state.
2035 if (blink_timeout_tag < 0) {
2037 blink_timeout_tag = g_timeout_add (240, _blink, this);
2042 ARDOUR_UI::stop_blinking ()
2044 if (blink_timeout_tag >= 0) {
2045 g_source_remove (blink_timeout_tag);
2046 blink_timeout_tag = -1;
2051 /** Ask the user for the name of a new shapshot and then take it.
2055 ARDOUR_UI::snapshot_session (bool switch_to_it)
2057 ArdourPrompter prompter (true);
2060 prompter.set_name ("Prompter");
2061 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2062 prompter.set_title (_("Take Snapshot"));
2063 prompter.set_title (_("Take Snapshot"));
2064 prompter.set_prompt (_("Name of new snapshot"));
2066 if (!switch_to_it) {
2069 struct tm local_time;
2072 localtime_r (&n, &local_time);
2073 strftime (timebuf, sizeof(timebuf), "%FT%T", &local_time);
2074 prompter.set_initial_text (timebuf);
2078 switch (prompter.run()) {
2079 case RESPONSE_ACCEPT:
2081 prompter.get_result (snapname);
2083 bool do_save = (snapname.length() != 0);
2086 if (snapname.find ('/') != string::npos) {
2087 MessageDialog msg (_("To ensure compatibility with various systems\n"
2088 "snapshot names may not contain a '/' character"));
2092 if (snapname.find ('\\') != string::npos) {
2093 MessageDialog msg (_("To ensure compatibility with various systems\n"
2094 "snapshot names may not contain a '\\' character"));
2100 vector<sys::path> p;
2101 get_state_files_in_directory (_session->session_directory().root_path(), p);
2102 vector<string> n = get_file_names_no_extension (p);
2103 if (find (n.begin(), n.end(), snapname) != n.end()) {
2105 ArdourDialog confirm (_("Confirm Snapshot Overwrite"), true);
2106 Label m (_("A snapshot already exists with that name. Do you want to overwrite it?"));
2107 confirm.get_vbox()->pack_start (m, true, true);
2108 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2109 confirm.add_button (_("Overwrite"), Gtk::RESPONSE_ACCEPT);
2110 confirm.show_all ();
2111 switch (confirm.run()) {
2112 case RESPONSE_CANCEL:
2118 save_state (snapname, switch_to_it);
2129 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2131 XMLNode* node = new XMLNode (X_("UI"));
2133 for (list<WindowProxyBase*>::iterator i = _window_proxies.begin(); i != _window_proxies.end(); ++i) {
2134 if (!(*i)->rc_configured()) {
2135 node->add_child_nocopy (*((*i)->get_state ()));
2139 _session->add_extra_xml (*node);
2141 save_state_canfail (name, switch_to_it);
2145 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2150 if (name.length() == 0) {
2151 name = _session->snap_name();
2154 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2158 cerr << "SS canfail\n";
2159 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2164 ARDOUR_UI::primary_clock_value_changed ()
2167 _session->request_locate (primary_clock.current_time ());
2172 ARDOUR_UI::big_clock_value_changed ()
2175 _session->request_locate (big_clock.current_time ());
2180 ARDOUR_UI::secondary_clock_value_changed ()
2183 _session->request_locate (secondary_clock.current_time ());
2188 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2190 if (_session == 0) {
2194 if (_session->step_editing()) {
2198 Session::RecordState const r = _session->record_status ();
2199 bool const h = _session->have_rec_enabled_track ();
2201 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2203 rec_button.set_visual_state (2);
2205 rec_button.set_visual_state (0);
2207 } else if (r == Session::Recording && h) {
2208 rec_button.set_visual_state (1);
2210 rec_button.set_visual_state (0);
2215 ARDOUR_UI::save_template ()
2217 ArdourPrompter prompter (true);
2220 if (!check_audioengine()) {
2224 prompter.set_name (X_("Prompter"));
2225 prompter.set_title (_("Save Mix Template"));
2226 prompter.set_prompt (_("Name for mix template:"));
2227 prompter.set_initial_text(_session->name() + _("-template"));
2228 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2230 switch (prompter.run()) {
2231 case RESPONSE_ACCEPT:
2232 prompter.get_result (name);
2234 if (name.length()) {
2235 _session->save_template (name);
2245 ARDOUR_UI::edit_metadata ()
2247 SessionMetadataEditor dialog;
2248 dialog.set_session (_session);
2249 editor->ensure_float (dialog);
2254 ARDOUR_UI::import_metadata ()
2256 SessionMetadataImporter dialog;
2257 dialog.set_session (_session);
2258 editor->ensure_float (dialog);
2263 ARDOUR_UI::fontconfig_dialog ()
2266 /* X11 users will always have fontconfig info around, but new GTK-OSX users
2267 may not and it can take a while to build it. Warn them.
2270 std::string fontconfig = Glib::build_filename (Glib::get_home_dir(), ".fontconfig");
2272 if (!Glib::file_test (fontconfig, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_DIR)) {
2273 MessageDialog msg (*_startup,
2274 string_compose (_("Welcome to %1.\n\n"
2275 "The program will take a bit longer to start up\n"
2276 "while the system fonts are checked.\n\n"
2277 "This will only be done once, and you will\n"
2278 "not see this message again\n"), PROGRAM_NAME),
2291 ARDOUR_UI::parse_cmdline_path (const std::string& cmdline_path, std::string& session_name, std::string& session_path, bool& existing_session)
2293 existing_session = false;
2295 if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_DIR)) {
2296 session_path = cmdline_path;
2297 existing_session = true;
2298 } else if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_REGULAR)) {
2299 session_path = Glib::path_get_dirname (string (cmdline_path));
2300 existing_session = true;
2302 /* it doesn't exist, assume the best */
2303 session_path = Glib::path_get_dirname (string (cmdline_path));
2306 session_name = basename_nosuffix (string (cmdline_path));
2310 ARDOUR_UI::load_cmdline_session (const std::string& session_name, const std::string& session_path, bool& existing_session)
2312 /* when this is called, the backend audio system must be running */
2314 /* the main idea here is to deal with the fact that a cmdline argument for the session
2315 can be interpreted in different ways - it could be a directory or a file, and before
2316 we load, we need to know both the session directory and the snapshot (statefile) within it
2317 that we are supposed to use.
2320 if (session_name.length() == 0 || session_path.length() == 0) {
2324 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_DIR)) {
2326 std::string predicted_session_file;
2328 predicted_session_file = session_path;
2329 predicted_session_file += '/';
2330 predicted_session_file += session_name;
2331 predicted_session_file += ARDOUR::statefile_suffix;
2333 if (Glib::file_test (predicted_session_file, Glib::FILE_TEST_EXISTS)) {
2334 existing_session = true;
2337 } else if (Glib::file_test (session_path, Glib::FILE_TEST_EXISTS)) {
2339 if (session_path.find (ARDOUR::statefile_suffix) == session_path.length() - 7) {
2340 /* existing .ardour file */
2341 existing_session = true;
2345 existing_session = false;
2348 /* lets just try to load it */
2350 if (create_engine ()) {
2351 backend_audio_error (false, _startup);
2355 return load_session (session_path, session_name);
2359 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
2361 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2363 MessageDialog msg (str,
2365 Gtk::MESSAGE_WARNING,
2366 Gtk::BUTTONS_YES_NO,
2370 msg.set_name (X_("OpenExistingDialog"));
2371 msg.set_title (_("Open Existing Session"));
2372 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
2373 msg.set_position (Gtk::WIN_POS_MOUSE);
2376 switch (msg.run()) {
2385 ARDOUR_UI::build_session_from_nsd (const std::string& session_path, const std::string& session_name)
2387 BusProfile bus_profile;
2389 if (Profile->get_sae()) {
2391 bus_profile.master_out_channels = 2;
2392 bus_profile.input_ac = AutoConnectPhysical;
2393 bus_profile.output_ac = AutoConnectMaster;
2394 bus_profile.requested_physical_in = 0; // use all available
2395 bus_profile.requested_physical_out = 0; // use all available
2399 /* get settings from advanced section of NSD */
2401 if (_startup->create_master_bus()) {
2402 bus_profile.master_out_channels = (uint32_t) _startup->master_channel_count();
2404 bus_profile.master_out_channels = 0;
2407 if (_startup->connect_inputs()) {
2408 bus_profile.input_ac = AutoConnectPhysical;
2410 bus_profile.input_ac = AutoConnectOption (0);
2413 /// @todo some minor tweaks.
2415 bus_profile.output_ac = AutoConnectOption (0);
2417 if (_startup->connect_outputs ()) {
2418 if (_startup->connect_outs_to_master()) {
2419 bus_profile.output_ac = AutoConnectMaster;
2420 } else if (_startup->connect_outs_to_physical()) {
2421 bus_profile.output_ac = AutoConnectPhysical;
2425 bus_profile.requested_physical_in = (uint32_t) _startup->input_limit_count();
2426 bus_profile.requested_physical_out = (uint32_t) _startup->output_limit_count();
2429 if (build_session (session_path, session_name, bus_profile)) {
2437 ARDOUR_UI::idle_load (const std::string& path)
2440 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2441 /* /path/to/foo => /path/to/foo, foo */
2442 load_session (path, basename_nosuffix (path));
2444 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2445 load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2449 ARDOUR_COMMAND_LINE::session_name = path;
2452 * new_session_dialog doens't exist in A3
2453 * Try to remove all references to it to
2454 * see if it will compile. NOTE: this will
2455 * likely cause a runtime issue is my somewhat
2459 //if (new_session_dialog) {
2462 /* make it break out of Dialog::run() and
2466 //new_session_dialog->response (1);
2472 ARDOUR_UI::end_loading_messages ()
2478 ARDOUR_UI::loading_message (const std::string& /*msg*/)
2481 // splash->message (msg);
2485 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
2487 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
2489 string session_name;
2490 string session_path;
2491 string template_name;
2493 bool likely_new = false;
2495 if (! load_template.empty()) {
2496 should_be_new = true;
2497 template_name = load_template;
2502 if (!should_be_new && !ARDOUR_COMMAND_LINE::session_name.empty()) {
2504 /* if they named a specific statefile, use it, otherwise they are
2505 just giving a session folder, and we want to use it as is
2506 to find the session.
2509 if (ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix) != string::npos) {
2510 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
2512 session_path = ARDOUR_COMMAND_LINE::session_name;
2515 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
2519 bool const apply = run_startup (should_be_new, load_template);
2522 if (quit_on_cancel) {
2529 /* if we run the startup dialog again, offer more than just "new session" */
2531 should_be_new = false;
2533 session_name = _startup->session_name (likely_new);
2535 /* this shouldn't happen, but we catch it just in case it does */
2537 if (session_name.empty()) {
2541 if (_startup->use_session_template()) {
2542 template_name = _startup->session_template_name();
2543 _session_is_new = true;
2546 if (session_name[0] == G_DIR_SEPARATOR ||
2547 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
2548 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)) {
2550 /* absolute path or cwd-relative path specified for session name: infer session folder
2551 from what was given.
2554 session_path = Glib::path_get_dirname (session_name);
2555 session_name = Glib::path_get_basename (session_name);
2559 session_path = _startup->session_folder();
2561 if (session_name.find ('/') != string::npos) {
2562 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2563 "session names may not contain a '/' character"));
2565 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2569 if (session_name.find ('\\') != string::npos) {
2570 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2571 "session names may not contain a '\\' character"));
2573 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2579 if (create_engine ()) {
2583 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
2587 std::string existing = Glib::build_filename (session_path, session_name);
2589 if (!ask_about_loading_existing_session (existing)) {
2590 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2595 _session_is_new = false;
2600 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
2602 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2606 if (session_name.find ('/') != std::string::npos) {
2607 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2608 "session names may not contain a '/' character"));
2610 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2614 if (session_name.find ('\\') != std::string::npos) {
2615 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2616 "session names may not contain a '\\' character"));
2618 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2622 _session_is_new = true;
2625 if (likely_new && template_name.empty()) {
2627 ret = build_session_from_nsd (session_path, session_name);
2631 ret = load_session (session_path, session_name, template_name);
2632 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
2633 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
2643 ARDOUR_UI::close_session()
2645 if (!check_audioengine()) {
2649 if (unload_session (true)) {
2653 ARDOUR_COMMAND_LINE::session_name = "";
2655 if (get_session_parameters (true, false)) {
2659 goto_editor_window ();
2663 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
2665 Session *new_session;
2669 session_loaded = false;
2671 if (!check_audioengine()) {
2675 unload_status = unload_session ();
2677 if (unload_status < 0) {
2679 } else if (unload_status > 0) {
2684 loading_message (string_compose (_("Please wait while %1loads your session"), PROGRAM_NAME));
2687 new_session = new Session (*engine, path, snap_name, 0, mix_template);
2690 /* this one is special */
2692 catch (AudioEngine::PortRegistrationFailure& err) {
2694 MessageDialog msg (err.what(),
2697 Gtk::BUTTONS_CLOSE);
2699 msg.set_title (_("Port Registration Error"));
2700 msg.set_secondary_text (_("Click the Close button to try again."));
2701 msg.set_position (Gtk::WIN_POS_CENTER);
2705 int response = msg.run ();
2710 case RESPONSE_CANCEL:
2720 MessageDialog msg (string_compose(_("Session \"%1 (snapshot %2)\" did not load successfully"),path, snap_name),
2725 msg.set_title (_("Loading Error"));
2726 msg.set_secondary_text (_("Click the Refresh button to try again."));
2727 msg.add_button (Stock::REFRESH, 1);
2728 msg.set_position (Gtk::WIN_POS_CENTER);
2732 int response = msg.run ();
2747 list<string> const u = new_session->unknown_processors ();
2749 MissingPluginDialog d (_session, u);
2754 /* Now the session been created, add the transport controls */
2755 new_session->add_controllable(roll_controllable);
2756 new_session->add_controllable(stop_controllable);
2757 new_session->add_controllable(goto_start_controllable);
2758 new_session->add_controllable(goto_end_controllable);
2759 new_session->add_controllable(auto_loop_controllable);
2760 new_session->add_controllable(play_selection_controllable);
2761 new_session->add_controllable(rec_controllable);
2763 set_session (new_session);
2765 session_loaded = true;
2767 goto_editor_window ();
2770 _session->set_clean ();
2781 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
2783 Session *new_session;
2786 if (!check_audioengine()) {
2790 session_loaded = false;
2792 x = unload_session ();
2800 _session_is_new = true;
2803 new_session = new Session (*engine, path, snap_name, &bus_profile);
2808 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
2814 /* Give the new session the default GUI state, if such things exist */
2817 n = Config->instant_xml (X_("Editor"));
2819 new_session->add_instant_xml (*n, false);
2821 n = Config->instant_xml (X_("Mixer"));
2823 new_session->add_instant_xml (*n, false);
2826 set_session (new_session);
2828 session_loaded = true;
2830 new_session->save_state(new_session->name());
2836 ARDOUR_UI::launch_chat ()
2839 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
2841 open_uri("http://webchat.freenode.net/?channels=ardour");
2846 ARDOUR_UI::show_about ()
2850 about->signal_response().connect(sigc::mem_fun (*this, &ARDOUR_UI::about_signal_response) );
2853 about->set_transient_for(*editor);
2858 ARDOUR_UI::launch_manual ()
2860 PBD::open_uri("http://ardour.org/flossmanual");
2864 ARDOUR_UI::launch_reference ()
2866 PBD::open_uri("http://ardour.org/refmanual");
2870 ARDOUR_UI::hide_about ()
2873 about->get_window()->set_cursor ();
2879 ARDOUR_UI::about_signal_response (int /*response*/)
2885 ARDOUR_UI::show_splash ()
2889 splash = new Splash;
2897 splash->queue_draw ();
2898 splash->get_window()->process_updates (true);
2903 ARDOUR_UI::hide_splash ()
2911 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title,
2912 const string& plural_msg, const string& singular_msg)
2916 removed = rep.paths.size();
2919 MessageDialog msgd (*editor,
2920 _("No audio files were ready for cleanup"),
2923 (Gtk::ButtonsType)(Gtk::BUTTONS_OK) );
2924 msgd.set_secondary_text (_("If this seems suprising, \n\
2925 check for any existing snapshots.\n\
2926 These may still include regions that\n\
2927 require some unused files to continue to exist."));
2933 ArdourDialog results (_("Clean-up"), true, false);
2935 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
2936 CleanupResultsModelColumns() {
2940 Gtk::TreeModelColumn<std::string> visible_name;
2941 Gtk::TreeModelColumn<std::string> fullpath;
2945 CleanupResultsModelColumns results_columns;
2946 Glib::RefPtr<Gtk::ListStore> results_model;
2947 Gtk::TreeView results_display;
2949 results_model = ListStore::create (results_columns);
2950 results_display.set_model (results_model);
2951 results_display.append_column (list_title, results_columns.visible_name);
2953 results_display.set_name ("CleanupResultsList");
2954 results_display.set_headers_visible (true);
2955 results_display.set_headers_clickable (false);
2956 results_display.set_reorderable (false);
2958 Gtk::ScrolledWindow list_scroller;
2961 Gtk::HBox dhbox; // the hbox for the image and text
2962 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
2963 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
2965 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
2967 const string dead_sound_directory = _session->session_directory().dead_sound_path().to_string();
2970 %1 - number of files removed
2971 %2 - location of "dead_sounds"
2972 %3 - size of files affected
2973 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
2976 const char* bprefix;
2977 double space_adjusted = 0;
2979 if (rep.space < 100000.0f) {
2980 bprefix = X_("kilo");
2981 } else if (rep.space < 1000000.0f * 1000) {
2982 bprefix = X_("mega");
2983 space_adjusted = truncf((float)rep.space / 1000.0);
2985 bprefix = X_("giga");
2986 space_adjusted = truncf((float)rep.space / (1000000.0 * 1000));
2990 txt.set_text (string_compose (plural_msg, removed, _session->path() + "dead_sounds", space_adjusted, bprefix));
2992 txt.set_text (string_compose (singular_msg, removed, _session->path() + "dead_sounds", space_adjusted, bprefix));
2995 dhbox.pack_start (*dimage, true, false, 5);
2996 dhbox.pack_start (txt, true, false, 5);
2998 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
2999 TreeModel::Row row = *(results_model->append());
3000 row[results_columns.visible_name] = *i;
3001 row[results_columns.fullpath] = *i;
3004 list_scroller.add (results_display);
3005 list_scroller.set_size_request (-1, 150);
3006 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
3008 dvbox.pack_start (dhbox, true, false, 5);
3009 dvbox.pack_start (list_scroller, true, false, 5);
3010 ddhbox.pack_start (dvbox, true, false, 5);
3012 results.get_vbox()->pack_start (ddhbox, true, false, 5);
3013 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
3014 results.set_default_response (RESPONSE_CLOSE);
3015 results.set_position (Gtk::WIN_POS_MOUSE);
3017 results_display.show();
3018 list_scroller.show();
3025 //results.get_vbox()->show();
3026 results.set_resizable (false);
3033 ARDOUR_UI::cleanup ()
3035 if (_session == 0) {
3036 /* shouldn't happen: menu item is insensitive */
3041 MessageDialog checker (_("Are you sure you want to cleanup?"),
3043 Gtk::MESSAGE_QUESTION,
3044 (Gtk::ButtonsType)(Gtk::BUTTONS_NONE));
3046 checker.set_secondary_text(_("Cleanup is a destructive operation.\n\
3047 ALL undo/redo information will be lost if you cleanup.\n\
3048 After cleanup, unused audio files will be moved to a \
3049 \"dead sounds\" location."));
3051 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3052 checker.add_button (_("Clean Up"), RESPONSE_ACCEPT);
3053 checker.set_default_response (RESPONSE_CANCEL);
3055 checker.set_name (_("CleanupDialog"));
3056 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3057 checker.set_position (Gtk::WIN_POS_MOUSE);
3059 switch (checker.run()) {
3060 case RESPONSE_ACCEPT:
3066 ARDOUR::CleanupReport rep;
3068 editor->prepare_for_cleanup ();
3070 /* do not allow flush until a session is reloaded */
3072 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3074 act->set_sensitive (false);
3077 if (_session->cleanup_sources (rep)) {
3078 editor->finish_cleanup ();
3082 editor->finish_cleanup ();
3085 display_cleanup_results (rep,
3088 The following %1 files were not in use and \n\
3089 have been moved to:\n\
3091 Flushing the wastebasket will \n\
3092 release an additional\n\
3093 %3 %4bytes of disk space.\n"),
3095 The following file was not in use and \n \
3096 has been moved to:\n \
3098 Flushing the wastebasket will \n\
3099 release an additional\n\
3100 %3 %4bytes of disk space.\n"
3106 ARDOUR_UI::flush_trash ()
3108 if (_session == 0) {
3109 /* shouldn't happen: menu item is insensitive */
3113 ARDOUR::CleanupReport rep;
3115 if (_session->cleanup_trash_sources (rep)) {
3119 display_cleanup_results (rep,
3121 _("The following %1 files were deleted from\n\
3123 releasing %3 %4bytes of disk space"),
3124 _("The following file was deleted from\n\
3126 releasing %3 %4bytes of disk space"));
3130 ARDOUR_UI::add_route (Gtk::Window* float_window)
3138 if (add_route_dialog == 0) {
3139 add_route_dialog = new AddRouteDialog (_session);
3141 add_route_dialog->set_transient_for (*float_window);
3145 if (add_route_dialog->is_visible()) {
3146 /* we're already doing this */
3150 ResponseType r = (ResponseType) add_route_dialog->run ();
3152 add_route_dialog->hide();
3155 case RESPONSE_ACCEPT:
3162 if ((count = add_route_dialog->count()) <= 0) {
3166 string template_path = add_route_dialog->track_template();
3168 if (!template_path.empty()) {
3169 _session->new_route_from_template (count, template_path);
3173 uint32_t input_chan = add_route_dialog->channels ();
3174 uint32_t output_chan;
3175 string name_template = add_route_dialog->name_template ();
3176 bool track = add_route_dialog->track ();
3177 bool aux = !track && add_route_dialog->aux();
3178 RouteGroup* route_group = add_route_dialog->route_group ();
3180 AutoConnectOption oac = Config->get_output_auto_connect();
3182 if (oac & AutoConnectMaster) {
3183 output_chan = (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan);
3185 output_chan = input_chan;
3188 /* XXX do something with name template */
3190 if (add_route_dialog->type() == ARDOUR::DataType::MIDI) {
3192 session_add_midi_track (route_group, count);
3194 MessageDialog msg (*editor,
3195 _("Sorry, MIDI Busses are not supported at this time."));
3197 //session_add_midi_bus();
3201 session_add_audio_track (input_chan, output_chan, add_route_dialog->mode(), route_group, count);
3203 session_add_audio_bus (aux, input_chan, output_chan, route_group, count);
3209 ARDOUR_UI::mixer_settings () const
3214 node = _session->instant_xml(X_("Mixer"));
3216 node = Config->instant_xml(X_("Mixer"));
3220 node = new XMLNode (X_("Mixer"));
3227 ARDOUR_UI::editor_settings () const
3232 node = _session->instant_xml(X_("Editor"));
3234 node = Config->instant_xml(X_("Editor"));
3238 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
3239 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
3244 node = new XMLNode (X_("Editor"));
3251 ARDOUR_UI::keyboard_settings () const
3255 node = Config->extra_xml(X_("Keyboard"));
3258 node = new XMLNode (X_("Keyboard"));
3264 ARDOUR_UI::create_xrun_marker (framepos_t where)
3266 editor->mouse_add_new_marker (where, false, true);
3270 ARDOUR_UI::halt_on_xrun_message ()
3272 MessageDialog msg (*editor,
3273 _("Recording was stopped because your system could not keep up."));
3278 ARDOUR_UI::xrun_handler (framepos_t where)
3284 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
3286 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
3287 create_xrun_marker(where);
3290 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
3291 halt_on_xrun_message ();
3296 ARDOUR_UI::disk_overrun_handler ()
3298 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
3300 if (!have_disk_speed_dialog_displayed) {
3301 have_disk_speed_dialog_displayed = true;
3302 MessageDialog* msg = new MessageDialog (*editor, string_compose (_("\
3303 The disk system on your computer\n\
3304 was not able to keep up with %1.\n\
3306 Specifically, it failed to write data to disk\n\
3307 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
3308 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3314 ARDOUR_UI::disk_underrun_handler ()
3316 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
3318 if (!have_disk_speed_dialog_displayed) {
3319 have_disk_speed_dialog_displayed = true;
3320 MessageDialog* msg = new MessageDialog (*editor,
3321 string_compose (_("The disk system on your computer\n\
3322 was not able to keep up with %1.\n\
3324 Specifically, it failed to read data from disk\n\
3325 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
3326 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3332 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
3334 have_disk_speed_dialog_displayed = false;
3339 ARDOUR_UI::session_dialog (std::string msg)
3341 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
3346 d = new MessageDialog (*editor, msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3348 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3357 ARDOUR_UI::pending_state_dialog ()
3359 HBox* hbox = new HBox();
3360 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3361 ArdourDialog dialog (_("Crash Recovery"), true);
3363 This session appears to have been in\n\
3364 middle of recording when ardour or\n\
3365 the computer was shutdown.\n\
3367 Ardour can recover any captured audio for\n\
3368 you, or it can ignore it. Please decide\n\
3369 what you would like to do.\n"));
3370 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3371 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3372 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3373 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3374 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
3375 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
3376 dialog.set_default_response (RESPONSE_ACCEPT);
3377 dialog.set_position (WIN_POS_CENTER);
3382 switch (dialog.run ()) {
3383 case RESPONSE_ACCEPT:
3391 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
3393 HBox* hbox = new HBox();
3394 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3395 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
3396 Label message (string_compose (_("\
3397 This session was created with a sample rate of %1 Hz\n\
3399 The audioengine is currently running at %2 Hz\n"), desired, actual));
3401 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3402 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3403 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3404 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3405 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
3406 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
3407 dialog.set_default_response (RESPONSE_ACCEPT);
3408 dialog.set_position (WIN_POS_CENTER);
3413 switch (dialog.run ()) {
3414 case RESPONSE_ACCEPT:
3423 ARDOUR_UI::disconnect_from_jack ()
3426 if( engine->disconnect_from_jack ()) {
3427 MessageDialog msg (*editor, _("Could not disconnect from JACK"));
3431 update_sample_rate (0);
3436 ARDOUR_UI::reconnect_to_jack ()
3439 if (engine->reconnect_to_jack ()) {
3440 MessageDialog msg (*editor, _("Could not reconnect to JACK"));
3444 update_sample_rate (0);
3449 ARDOUR_UI::use_config ()
3451 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
3453 set_transport_controllable_state (*node);
3458 ARDOUR_UI::update_transport_clocks (framepos_t pos)
3460 if (Config->get_primary_clock_delta_edit_cursor()) {
3461 primary_clock.set (pos, false, editor->get_preferred_edit_position(), 1);
3463 primary_clock.set (pos, 0, true);
3466 if (Config->get_secondary_clock_delta_edit_cursor()) {
3467 secondary_clock.set (pos, false, editor->get_preferred_edit_position(), 2);
3469 secondary_clock.set (pos);
3472 if (big_clock_window->get()) {
3473 big_clock.set (pos);
3479 ARDOUR_UI::step_edit_status_change (bool yn)
3481 // XXX should really store pre-step edit status of things
3482 // we make insensitive
3485 rec_button.set_visual_state (3);
3486 rec_button.set_sensitive (false);
3488 rec_button.set_visual_state (0);
3489 rec_button.set_sensitive (true);
3494 ARDOUR_UI::record_state_changed ()
3496 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
3498 if (!_session || !big_clock_window->get()) {
3499 /* why bother - the clock isn't visible */
3503 Session::RecordState const r = _session->record_status ();
3504 bool const h = _session->have_rec_enabled_track ();
3506 if (r == Session::Recording && h) {
3507 big_clock.set_widget_name ("BigClockRecording");
3509 big_clock.set_widget_name ("BigClockNonRecording");
3514 ARDOUR_UI::first_idle ()
3517 _session->allow_auto_play (true);
3521 editor->first_idle();
3524 Keyboard::set_can_save_keybindings (true);
3529 ARDOUR_UI::store_clock_modes ()
3531 XMLNode* node = new XMLNode(X_("ClockModes"));
3533 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
3534 node->add_property ((*x)->name().c_str(), enum_2_string ((*x)->mode()));
3537 _session->add_extra_xml (*node);
3538 _session->set_dirty ();
3543 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
3544 : Controllable (name), ui (u), type(tp)
3550 ARDOUR_UI::TransportControllable::set_value (double val)
3552 if (type == ShuttleControl) {
3559 fract = -((0.5 - val)/0.5);
3561 fract = ((val - 0.5)/0.5);
3565 ui.set_shuttle_fract (fract);
3570 /* do nothing: these are radio-style actions */
3574 const char *action = 0;
3578 action = X_("Roll");
3581 action = X_("Stop");
3584 action = X_("Goto Start");
3587 action = X_("Goto End");
3590 action = X_("Loop");
3593 action = X_("Play Selection");
3596 action = X_("Record");
3606 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
3614 ARDOUR_UI::TransportControllable::get_value (void) const
3633 case ShuttleControl:
3643 ARDOUR_UI::TransportControllable::set_id (const string& str)
3649 ARDOUR_UI::setup_profile ()
3651 if (gdk_screen_width() < 1200) {
3652 Profile->set_small_screen ();
3656 if (getenv ("ARDOUR_SAE")) {
3657 Profile->set_sae ();
3658 Profile->set_single_package ();
3663 ARDOUR_UI::toggle_translations ()
3665 using namespace Glib;
3667 RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("EnableTranslation"));
3669 RefPtr<ToggleAction> ract = RefPtr<ToggleAction>::cast_dynamic (act);
3672 string i18n_killer = ARDOUR::translation_kill_path();
3674 bool already_enabled = !ARDOUR::translations_are_disabled ();
3676 if (ract->get_active ()) {
3677 /* we don't care about errors */
3678 int fd = ::open (i18n_killer.c_str(), O_RDONLY|O_CREAT, 0644);
3681 /* we don't care about errors */
3682 unlink (i18n_killer.c_str());
3685 if (already_enabled != ract->get_active()) {
3686 MessageDialog win (already_enabled ? _("Translations disabled") : _("Translations enabled"),
3688 Gtk::MESSAGE_WARNING,
3690 win.set_secondary_text (string_compose (_("You must restart %1 for this to take effect."), PROGRAM_NAME));
3691 win.set_position (Gtk::WIN_POS_CENTER);
3699 /** Add a window proxy to our list, so that its state will be saved.
3700 * This call also causes the window to be created and opened if its
3701 * state was saved as `visible'.
3704 ARDOUR_UI::add_window_proxy (WindowProxyBase* p)
3706 _window_proxies.push_back (p);
3710 /** Remove a window proxy from our list. Must be called if a WindowProxy
3711 * is deleted, to prevent hanging pointers.
3714 ARDOUR_UI::remove_window_proxy (WindowProxyBase* p)
3716 _window_proxies.remove (p);
3720 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
3722 MissingFileDialog dialog (s, str, type);
3727 int result = dialog.run ();
3734 return 1; // quit entire session load
3737 result = dialog.get_action ();
3743 ARDOUR_UI::ambiguous_file (std::string file, std::string path, std::vector<std::string> hits)
3745 AmbiguousFileDialog dialog (file, hits);
3751 return dialog.get_which ();