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 ()
1694 if (_session->get_play_loop()) {
1696 if (_session->transport_rolling()) {
1698 Location * looploc = _session->locations()->auto_loop_location();
1701 _session->request_locate (looploc->start(), true);
1702 _session->request_play_loop (false);
1706 _session->request_play_loop (false);
1710 Location * looploc = _session->locations()->auto_loop_location();
1713 _session->request_play_loop (true);
1719 ARDOUR_UI::transport_play_selection ()
1725 editor->play_selection ();
1729 ARDOUR_UI::transport_rewind (int option)
1731 float current_transport_speed;
1734 current_transport_speed = _session->transport_speed();
1736 if (current_transport_speed >= 0.0f) {
1739 _session->request_transport_speed (-1.0f);
1742 _session->request_transport_speed (-4.0f);
1745 _session->request_transport_speed (-0.5f);
1750 _session->request_transport_speed (current_transport_speed * 1.5f);
1756 ARDOUR_UI::transport_forward (int option)
1758 float current_transport_speed;
1761 current_transport_speed = _session->transport_speed();
1763 if (current_transport_speed <= 0.0f) {
1766 _session->request_transport_speed (1.0f);
1769 _session->request_transport_speed (4.0f);
1772 _session->request_transport_speed (0.5f);
1777 _session->request_transport_speed (current_transport_speed * 1.5f);
1784 ARDOUR_UI::toggle_record_enable (uint32_t rid)
1786 if (_session == 0) {
1790 boost::shared_ptr<Route> r;
1792 if ((r = _session->route_by_remote_id (rid)) != 0) {
1796 if ((t = dynamic_cast<Track*>(r.get())) != 0) {
1797 t->set_record_enabled (!t->record_enabled(), this);
1800 if (_session == 0) {
1806 ARDOUR_UI::map_transport_state ()
1808 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::map_transport_state)
1811 auto_loop_button.set_visual_state (0);
1812 play_selection_button.set_visual_state (0);
1813 roll_button.set_visual_state (0);
1814 stop_button.set_visual_state (1);
1818 float sp = _session->transport_speed();
1821 shuttle_fract = SHUTTLE_FRACT_SPEED1; /* speed = 1.0, believe it or not */
1822 shuttle_box.queue_draw ();
1823 } else if (sp == 0.0f) {
1825 shuttle_box.queue_draw ();
1826 update_disk_space ();
1833 if (_session->get_play_range()) {
1835 play_selection_button.set_visual_state (1);
1836 roll_button.set_visual_state (0);
1837 auto_loop_button.set_visual_state (0);
1839 } else if (_session->get_play_loop ()) {
1841 auto_loop_button.set_visual_state (1);
1842 play_selection_button.set_visual_state (0);
1843 roll_button.set_visual_state (0);
1847 roll_button.set_visual_state (1);
1848 play_selection_button.set_visual_state (0);
1849 auto_loop_button.set_visual_state (0);
1852 if (join_play_range_button.get_active()) {
1853 /* light up both roll and play-selection if they are joined */
1854 roll_button.set_visual_state (1);
1855 play_selection_button.set_visual_state (1);
1858 stop_button.set_visual_state (0);
1862 stop_button.set_visual_state (1);
1863 roll_button.set_visual_state (0);
1864 play_selection_button.set_visual_state (0);
1865 auto_loop_button.set_visual_state (0);
1870 ARDOUR_UI::engine_stopped ()
1872 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
1873 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1874 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1878 ARDOUR_UI::engine_running ()
1880 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
1881 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, true);
1882 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, false);
1884 Glib::RefPtr<Action> action;
1885 const char* action_name = 0;
1887 switch (engine->frames_per_cycle()) {
1889 action_name = X_("JACKLatency32");
1892 action_name = X_("JACKLatency64");
1895 action_name = X_("JACKLatency128");
1898 action_name = X_("JACKLatency512");
1901 action_name = X_("JACKLatency1024");
1904 action_name = X_("JACKLatency2048");
1907 action_name = X_("JACKLatency4096");
1910 action_name = X_("JACKLatency8192");
1913 /* XXX can we do anything useful ? */
1919 action = ActionManager::get_action (X_("JACK"), action_name);
1922 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (action);
1923 ract->set_active ();
1929 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
1931 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
1932 /* we can't rely on the original string continuing to exist when we are called
1933 again in the GUI thread, so make a copy and note that we need to
1936 char *copy = strdup (reason);
1937 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
1941 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1942 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1944 update_sample_rate (0);
1948 /* if the reason is a non-empty string, it means that the backend was shutdown
1949 rather than just Ardour.
1952 if (strlen (reason)) {
1953 msgstr = string_compose (_("The audio backend (JACK) was shutdown because:\n\n%1"), reason);
1955 msgstr = string_compose (_("\
1956 JACK has either been shutdown or it\n\
1957 disconnected %1 because %1\n\
1958 was not fast enough. Try to restart\n\
1959 JACK, reconnect and save the session."), PROGRAM_NAME);
1962 MessageDialog msg (*editor, msgstr);
1967 free ((char*) reason);
1972 ARDOUR_UI::do_engine_start ()
1980 error << _("Unable to start the session running")
1990 ARDOUR_UI::setup_theme ()
1992 theme_manager->setup_theme();
1996 ARDOUR_UI::update_clocks ()
1998 if (!editor || !editor->dragging_playhead()) {
1999 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position()); /* EMIT_SIGNAL */
2004 ARDOUR_UI::start_clocking ()
2006 clock_signal_connection = RapidScreenUpdate.connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2010 ARDOUR_UI::stop_clocking ()
2012 clock_signal_connection.disconnect ();
2016 ARDOUR_UI::toggle_clocking ()
2019 if (clock_button.get_active()) {
2028 ARDOUR_UI::_blink (void *arg)
2031 ((ARDOUR_UI *) arg)->blink ();
2038 Blink (blink_on = !blink_on); /* EMIT_SIGNAL */
2042 ARDOUR_UI::start_blinking ()
2044 /* Start the blink signal. Everybody with a blinking widget
2045 uses Blink to drive the widget's state.
2048 if (blink_timeout_tag < 0) {
2050 blink_timeout_tag = g_timeout_add (240, _blink, this);
2055 ARDOUR_UI::stop_blinking ()
2057 if (blink_timeout_tag >= 0) {
2058 g_source_remove (blink_timeout_tag);
2059 blink_timeout_tag = -1;
2064 /** Ask the user for the name of a new shapshot and then take it.
2068 ARDOUR_UI::snapshot_session (bool switch_to_it)
2070 ArdourPrompter prompter (true);
2073 prompter.set_name ("Prompter");
2074 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2075 prompter.set_title (_("Take Snapshot"));
2076 prompter.set_title (_("Take Snapshot"));
2077 prompter.set_prompt (_("Name of new snapshot"));
2079 if (!switch_to_it) {
2082 struct tm local_time;
2085 localtime_r (&n, &local_time);
2086 strftime (timebuf, sizeof(timebuf), "%FT%T", &local_time);
2087 prompter.set_initial_text (timebuf);
2091 switch (prompter.run()) {
2092 case RESPONSE_ACCEPT:
2094 prompter.get_result (snapname);
2096 bool do_save = (snapname.length() != 0);
2099 if (snapname.find ('/') != string::npos) {
2100 MessageDialog msg (_("To ensure compatibility with various systems\n"
2101 "snapshot names may not contain a '/' character"));
2105 if (snapname.find ('\\') != string::npos) {
2106 MessageDialog msg (_("To ensure compatibility with various systems\n"
2107 "snapshot names may not contain a '\\' character"));
2113 vector<sys::path> p;
2114 get_state_files_in_directory (_session->session_directory().root_path(), p);
2115 vector<string> n = get_file_names_no_extension (p);
2116 if (find (n.begin(), n.end(), snapname) != n.end()) {
2118 ArdourDialog confirm (_("Confirm Snapshot Overwrite"), true);
2119 Label m (_("A snapshot already exists with that name. Do you want to overwrite it?"));
2120 confirm.get_vbox()->pack_start (m, true, true);
2121 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2122 confirm.add_button (_("Overwrite"), Gtk::RESPONSE_ACCEPT);
2123 confirm.show_all ();
2124 switch (confirm.run()) {
2125 case RESPONSE_CANCEL:
2131 save_state (snapname, switch_to_it);
2142 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2144 XMLNode* node = new XMLNode (X_("UI"));
2146 for (list<WindowProxyBase*>::iterator i = _window_proxies.begin(); i != _window_proxies.end(); ++i) {
2147 if (!(*i)->rc_configured()) {
2148 node->add_child_nocopy (*((*i)->get_state ()));
2152 _session->add_extra_xml (*node);
2154 save_state_canfail (name, switch_to_it);
2158 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2163 if (name.length() == 0) {
2164 name = _session->snap_name();
2167 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2171 cerr << "SS canfail\n";
2172 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2177 ARDOUR_UI::primary_clock_value_changed ()
2180 _session->request_locate (primary_clock.current_time ());
2185 ARDOUR_UI::big_clock_value_changed ()
2188 _session->request_locate (big_clock.current_time ());
2193 ARDOUR_UI::secondary_clock_value_changed ()
2196 _session->request_locate (secondary_clock.current_time ());
2201 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2203 if (_session == 0) {
2207 if (_session->step_editing()) {
2211 Session::RecordState const r = _session->record_status ();
2212 bool const h = _session->have_rec_enabled_track ();
2214 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2216 rec_button.set_visual_state (2);
2218 rec_button.set_visual_state (0);
2220 } else if (r == Session::Recording && h) {
2221 rec_button.set_visual_state (1);
2223 rec_button.set_visual_state (0);
2228 ARDOUR_UI::save_template ()
2230 ArdourPrompter prompter (true);
2233 if (!check_audioengine()) {
2237 prompter.set_name (X_("Prompter"));
2238 prompter.set_title (_("Save Mix Template"));
2239 prompter.set_prompt (_("Name for mix template:"));
2240 prompter.set_initial_text(_session->name() + _("-template"));
2241 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2243 switch (prompter.run()) {
2244 case RESPONSE_ACCEPT:
2245 prompter.get_result (name);
2247 if (name.length()) {
2248 _session->save_template (name);
2258 ARDOUR_UI::edit_metadata ()
2260 SessionMetadataEditor dialog;
2261 dialog.set_session (_session);
2262 editor->ensure_float (dialog);
2267 ARDOUR_UI::import_metadata ()
2269 SessionMetadataImporter dialog;
2270 dialog.set_session (_session);
2271 editor->ensure_float (dialog);
2276 ARDOUR_UI::fontconfig_dialog ()
2279 /* X11 users will always have fontconfig info around, but new GTK-OSX users
2280 may not and it can take a while to build it. Warn them.
2283 std::string fontconfig = Glib::build_filename (Glib::get_home_dir(), ".fontconfig");
2285 if (!Glib::file_test (fontconfig, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_DIR)) {
2286 MessageDialog msg (*_startup,
2287 string_compose (_("Welcome to %1.\n\n"
2288 "The program will take a bit longer to start up\n"
2289 "while the system fonts are checked.\n\n"
2290 "This will only be done once, and you will\n"
2291 "not see this message again\n"), PROGRAM_NAME),
2304 ARDOUR_UI::parse_cmdline_path (const std::string& cmdline_path, std::string& session_name, std::string& session_path, bool& existing_session)
2306 existing_session = false;
2308 if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_DIR)) {
2309 session_path = cmdline_path;
2310 existing_session = true;
2311 } else if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_REGULAR)) {
2312 session_path = Glib::path_get_dirname (string (cmdline_path));
2313 existing_session = true;
2315 /* it doesn't exist, assume the best */
2316 session_path = Glib::path_get_dirname (string (cmdline_path));
2319 session_name = basename_nosuffix (string (cmdline_path));
2323 ARDOUR_UI::load_cmdline_session (const std::string& session_name, const std::string& session_path, bool& existing_session)
2325 /* when this is called, the backend audio system must be running */
2327 /* the main idea here is to deal with the fact that a cmdline argument for the session
2328 can be interpreted in different ways - it could be a directory or a file, and before
2329 we load, we need to know both the session directory and the snapshot (statefile) within it
2330 that we are supposed to use.
2333 if (session_name.length() == 0 || session_path.length() == 0) {
2337 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_DIR)) {
2339 std::string predicted_session_file;
2341 predicted_session_file = session_path;
2342 predicted_session_file += '/';
2343 predicted_session_file += session_name;
2344 predicted_session_file += ARDOUR::statefile_suffix;
2346 if (Glib::file_test (predicted_session_file, Glib::FILE_TEST_EXISTS)) {
2347 existing_session = true;
2350 } else if (Glib::file_test (session_path, Glib::FILE_TEST_EXISTS)) {
2352 if (session_path.find (ARDOUR::statefile_suffix) == session_path.length() - 7) {
2353 /* existing .ardour file */
2354 existing_session = true;
2358 existing_session = false;
2361 /* lets just try to load it */
2363 if (create_engine ()) {
2364 backend_audio_error (false, _startup);
2368 return load_session (session_path, session_name);
2372 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
2374 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2376 MessageDialog msg (str,
2378 Gtk::MESSAGE_WARNING,
2379 Gtk::BUTTONS_YES_NO,
2383 msg.set_name (X_("OpenExistingDialog"));
2384 msg.set_title (_("Open Existing Session"));
2385 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
2386 msg.set_position (Gtk::WIN_POS_MOUSE);
2389 switch (msg.run()) {
2398 ARDOUR_UI::build_session_from_nsd (const std::string& session_path, const std::string& session_name)
2400 BusProfile bus_profile;
2402 if (Profile->get_sae()) {
2404 bus_profile.master_out_channels = 2;
2405 bus_profile.input_ac = AutoConnectPhysical;
2406 bus_profile.output_ac = AutoConnectMaster;
2407 bus_profile.requested_physical_in = 0; // use all available
2408 bus_profile.requested_physical_out = 0; // use all available
2412 /* get settings from advanced section of NSD */
2414 if (_startup->create_master_bus()) {
2415 bus_profile.master_out_channels = (uint32_t) _startup->master_channel_count();
2417 bus_profile.master_out_channels = 0;
2420 if (_startup->connect_inputs()) {
2421 bus_profile.input_ac = AutoConnectPhysical;
2423 bus_profile.input_ac = AutoConnectOption (0);
2426 /// @todo some minor tweaks.
2428 bus_profile.output_ac = AutoConnectOption (0);
2430 if (_startup->connect_outputs ()) {
2431 if (_startup->connect_outs_to_master()) {
2432 bus_profile.output_ac = AutoConnectMaster;
2433 } else if (_startup->connect_outs_to_physical()) {
2434 bus_profile.output_ac = AutoConnectPhysical;
2438 bus_profile.requested_physical_in = (uint32_t) _startup->input_limit_count();
2439 bus_profile.requested_physical_out = (uint32_t) _startup->output_limit_count();
2442 if (build_session (session_path, session_name, bus_profile)) {
2450 ARDOUR_UI::idle_load (const std::string& path)
2453 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2454 /* /path/to/foo => /path/to/foo, foo */
2455 load_session (path, basename_nosuffix (path));
2457 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2458 load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2462 ARDOUR_COMMAND_LINE::session_name = path;
2465 * new_session_dialog doens't exist in A3
2466 * Try to remove all references to it to
2467 * see if it will compile. NOTE: this will
2468 * likely cause a runtime issue is my somewhat
2472 //if (new_session_dialog) {
2475 /* make it break out of Dialog::run() and
2479 //new_session_dialog->response (1);
2485 ARDOUR_UI::end_loading_messages ()
2491 ARDOUR_UI::loading_message (const std::string& /*msg*/)
2494 // splash->message (msg);
2498 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
2500 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
2502 string session_name;
2503 string session_path;
2504 string template_name;
2506 bool likely_new = false;
2508 if (! load_template.empty()) {
2509 should_be_new = true;
2510 template_name = load_template;
2515 if (!should_be_new && !ARDOUR_COMMAND_LINE::session_name.empty()) {
2517 /* if they named a specific statefile, use it, otherwise they are
2518 just giving a session folder, and we want to use it as is
2519 to find the session.
2522 if (ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix) != string::npos) {
2523 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
2525 session_path = ARDOUR_COMMAND_LINE::session_name;
2528 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
2532 bool const apply = run_startup (should_be_new, load_template);
2535 if (quit_on_cancel) {
2542 /* if we run the startup dialog again, offer more than just "new session" */
2544 should_be_new = false;
2546 session_name = _startup->session_name (likely_new);
2548 /* this shouldn't happen, but we catch it just in case it does */
2550 if (session_name.empty()) {
2554 if (_startup->use_session_template()) {
2555 template_name = _startup->session_template_name();
2556 _session_is_new = true;
2559 if (session_name[0] == G_DIR_SEPARATOR ||
2560 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
2561 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)) {
2563 /* absolute path or cwd-relative path specified for session name: infer session folder
2564 from what was given.
2567 session_path = Glib::path_get_dirname (session_name);
2568 session_name = Glib::path_get_basename (session_name);
2572 session_path = _startup->session_folder();
2574 if (session_name.find ('/') != string::npos) {
2575 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2576 "session names may not contain a '/' character"));
2578 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2582 if (session_name.find ('\\') != string::npos) {
2583 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2584 "session names may not contain a '\\' character"));
2586 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2592 if (create_engine ()) {
2596 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
2600 std::string existing = Glib::build_filename (session_path, session_name);
2602 if (!ask_about_loading_existing_session (existing)) {
2603 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2608 _session_is_new = false;
2613 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
2615 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2619 if (session_name.find ('/') != std::string::npos) {
2620 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2621 "session names may not contain a '/' character"));
2623 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2627 if (session_name.find ('\\') != std::string::npos) {
2628 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2629 "session names may not contain a '\\' character"));
2631 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2635 _session_is_new = true;
2638 if (likely_new && template_name.empty()) {
2640 ret = build_session_from_nsd (session_path, session_name);
2644 ret = load_session (session_path, session_name, template_name);
2645 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
2646 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
2656 ARDOUR_UI::close_session()
2658 if (!check_audioengine()) {
2662 if (unload_session (true)) {
2666 ARDOUR_COMMAND_LINE::session_name = "";
2668 if (get_session_parameters (true, false)) {
2672 goto_editor_window ();
2676 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
2678 Session *new_session;
2682 session_loaded = false;
2684 if (!check_audioengine()) {
2688 unload_status = unload_session ();
2690 if (unload_status < 0) {
2692 } else if (unload_status > 0) {
2697 loading_message (string_compose (_("Please wait while %1loads your session"), PROGRAM_NAME));
2700 new_session = new Session (*engine, path, snap_name, 0, mix_template);
2703 /* this one is special */
2705 catch (AudioEngine::PortRegistrationFailure& err) {
2707 MessageDialog msg (err.what(),
2710 Gtk::BUTTONS_CLOSE);
2712 msg.set_title (_("Port Registration Error"));
2713 msg.set_secondary_text (_("Click the Close button to try again."));
2714 msg.set_position (Gtk::WIN_POS_CENTER);
2718 int response = msg.run ();
2723 case RESPONSE_CANCEL:
2733 MessageDialog msg (string_compose(_("Session \"%1 (snapshot %2)\" did not load successfully"),path, snap_name),
2738 msg.set_title (_("Loading Error"));
2739 msg.set_secondary_text (_("Click the Refresh button to try again."));
2740 msg.add_button (Stock::REFRESH, 1);
2741 msg.set_position (Gtk::WIN_POS_CENTER);
2745 int response = msg.run ();
2760 list<string> const u = new_session->unknown_processors ();
2762 MissingPluginDialog d (_session, u);
2767 /* Now the session been created, add the transport controls */
2768 new_session->add_controllable(roll_controllable);
2769 new_session->add_controllable(stop_controllable);
2770 new_session->add_controllable(goto_start_controllable);
2771 new_session->add_controllable(goto_end_controllable);
2772 new_session->add_controllable(auto_loop_controllable);
2773 new_session->add_controllable(play_selection_controllable);
2774 new_session->add_controllable(rec_controllable);
2776 set_session (new_session);
2778 session_loaded = true;
2780 goto_editor_window ();
2783 _session->set_clean ();
2794 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
2796 Session *new_session;
2799 if (!check_audioengine()) {
2803 session_loaded = false;
2805 x = unload_session ();
2813 _session_is_new = true;
2816 new_session = new Session (*engine, path, snap_name, &bus_profile);
2821 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
2827 /* Give the new session the default GUI state, if such things exist */
2830 n = Config->instant_xml (X_("Editor"));
2832 new_session->add_instant_xml (*n, false);
2834 n = Config->instant_xml (X_("Mixer"));
2836 new_session->add_instant_xml (*n, false);
2839 set_session (new_session);
2841 session_loaded = true;
2843 new_session->save_state(new_session->name());
2849 ARDOUR_UI::launch_chat ()
2852 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
2854 open_uri("http://webchat.freenode.net/?channels=ardour");
2859 ARDOUR_UI::show_about ()
2863 about->signal_response().connect(sigc::mem_fun (*this, &ARDOUR_UI::about_signal_response) );
2866 about->set_transient_for(*editor);
2871 ARDOUR_UI::launch_manual ()
2873 PBD::open_uri("http://ardour.org/flossmanual");
2877 ARDOUR_UI::launch_reference ()
2879 PBD::open_uri("http://ardour.org/refmanual");
2883 ARDOUR_UI::hide_about ()
2886 about->get_window()->set_cursor ();
2892 ARDOUR_UI::about_signal_response (int /*response*/)
2898 ARDOUR_UI::show_splash ()
2902 splash = new Splash;
2910 splash->queue_draw ();
2911 splash->get_window()->process_updates (true);
2916 ARDOUR_UI::hide_splash ()
2924 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title,
2925 const string& plural_msg, const string& singular_msg)
2929 removed = rep.paths.size();
2932 MessageDialog msgd (*editor,
2933 _("No audio files were ready for cleanup"),
2936 (Gtk::ButtonsType)(Gtk::BUTTONS_OK) );
2937 msgd.set_secondary_text (_("If this seems suprising, \n\
2938 check for any existing snapshots.\n\
2939 These may still include regions that\n\
2940 require some unused files to continue to exist."));
2946 ArdourDialog results (_("Clean-up"), true, false);
2948 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
2949 CleanupResultsModelColumns() {
2953 Gtk::TreeModelColumn<std::string> visible_name;
2954 Gtk::TreeModelColumn<std::string> fullpath;
2958 CleanupResultsModelColumns results_columns;
2959 Glib::RefPtr<Gtk::ListStore> results_model;
2960 Gtk::TreeView results_display;
2962 results_model = ListStore::create (results_columns);
2963 results_display.set_model (results_model);
2964 results_display.append_column (list_title, results_columns.visible_name);
2966 results_display.set_name ("CleanupResultsList");
2967 results_display.set_headers_visible (true);
2968 results_display.set_headers_clickable (false);
2969 results_display.set_reorderable (false);
2971 Gtk::ScrolledWindow list_scroller;
2974 Gtk::HBox dhbox; // the hbox for the image and text
2975 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
2976 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
2978 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
2980 const string dead_sound_directory = _session->session_directory().dead_sound_path().to_string();
2983 %1 - number of files removed
2984 %2 - location of "dead_sounds"
2985 %3 - size of files affected
2986 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
2989 const char* bprefix;
2990 double space_adjusted = 0;
2992 if (rep.space < 100000.0f) {
2993 bprefix = X_("kilo");
2994 } else if (rep.space < 1000000.0f * 1000) {
2995 bprefix = X_("mega");
2996 space_adjusted = truncf((float)rep.space / 1000.0);
2998 bprefix = X_("giga");
2999 space_adjusted = truncf((float)rep.space / (1000000.0 * 1000));
3003 txt.set_text (string_compose (plural_msg, removed, _session->path() + "dead_sounds", space_adjusted, bprefix));
3005 txt.set_text (string_compose (singular_msg, removed, _session->path() + "dead_sounds", space_adjusted, bprefix));
3008 dhbox.pack_start (*dimage, true, false, 5);
3009 dhbox.pack_start (txt, true, false, 5);
3011 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
3012 TreeModel::Row row = *(results_model->append());
3013 row[results_columns.visible_name] = *i;
3014 row[results_columns.fullpath] = *i;
3017 list_scroller.add (results_display);
3018 list_scroller.set_size_request (-1, 150);
3019 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
3021 dvbox.pack_start (dhbox, true, false, 5);
3022 dvbox.pack_start (list_scroller, true, false, 5);
3023 ddhbox.pack_start (dvbox, true, false, 5);
3025 results.get_vbox()->pack_start (ddhbox, true, false, 5);
3026 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
3027 results.set_default_response (RESPONSE_CLOSE);
3028 results.set_position (Gtk::WIN_POS_MOUSE);
3030 results_display.show();
3031 list_scroller.show();
3038 //results.get_vbox()->show();
3039 results.set_resizable (false);
3046 ARDOUR_UI::cleanup ()
3048 if (_session == 0) {
3049 /* shouldn't happen: menu item is insensitive */
3054 MessageDialog checker (_("Are you sure you want to cleanup?"),
3056 Gtk::MESSAGE_QUESTION,
3057 (Gtk::ButtonsType)(Gtk::BUTTONS_NONE));
3059 checker.set_secondary_text(_("Cleanup is a destructive operation.\n\
3060 ALL undo/redo information will be lost if you cleanup.\n\
3061 After cleanup, unused audio files will be moved to a \
3062 \"dead sounds\" location."));
3064 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3065 checker.add_button (_("Clean Up"), RESPONSE_ACCEPT);
3066 checker.set_default_response (RESPONSE_CANCEL);
3068 checker.set_name (_("CleanupDialog"));
3069 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3070 checker.set_position (Gtk::WIN_POS_MOUSE);
3072 switch (checker.run()) {
3073 case RESPONSE_ACCEPT:
3079 ARDOUR::CleanupReport rep;
3081 editor->prepare_for_cleanup ();
3083 /* do not allow flush until a session is reloaded */
3085 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3087 act->set_sensitive (false);
3090 if (_session->cleanup_sources (rep)) {
3091 editor->finish_cleanup ();
3095 editor->finish_cleanup ();
3098 display_cleanup_results (rep,
3101 The following %1 files were not in use and \n\
3102 have been moved to:\n\
3104 Flushing the wastebasket will \n\
3105 release an additional\n\
3106 %3 %4bytes of disk space.\n"),
3108 The following file was not in use and \n \
3109 has been moved to:\n \
3111 Flushing the wastebasket will \n\
3112 release an additional\n\
3113 %3 %4bytes of disk space.\n"
3119 ARDOUR_UI::flush_trash ()
3121 if (_session == 0) {
3122 /* shouldn't happen: menu item is insensitive */
3126 ARDOUR::CleanupReport rep;
3128 if (_session->cleanup_trash_sources (rep)) {
3132 display_cleanup_results (rep,
3134 _("The following %1 files were deleted from\n\
3136 releasing %3 %4bytes of disk space"),
3137 _("The following file was deleted from\n\
3139 releasing %3 %4bytes of disk space"));
3143 ARDOUR_UI::add_route (Gtk::Window* float_window)
3151 if (add_route_dialog == 0) {
3152 add_route_dialog = new AddRouteDialog (_session);
3154 add_route_dialog->set_transient_for (*float_window);
3158 if (add_route_dialog->is_visible()) {
3159 /* we're already doing this */
3163 ResponseType r = (ResponseType) add_route_dialog->run ();
3165 add_route_dialog->hide();
3168 case RESPONSE_ACCEPT:
3175 if ((count = add_route_dialog->count()) <= 0) {
3179 string template_path = add_route_dialog->track_template();
3181 if (!template_path.empty()) {
3182 _session->new_route_from_template (count, template_path);
3186 uint32_t input_chan = add_route_dialog->channels ();
3187 uint32_t output_chan;
3188 string name_template = add_route_dialog->name_template ();
3189 bool track = add_route_dialog->track ();
3190 RouteGroup* route_group = add_route_dialog->route_group ();
3192 AutoConnectOption oac = Config->get_output_auto_connect();
3194 if (oac & AutoConnectMaster) {
3195 output_chan = (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan);
3197 output_chan = input_chan;
3200 /* XXX do something with name template */
3202 if (add_route_dialog->type() == ARDOUR::DataType::MIDI) {
3204 session_add_midi_track (route_group, count);
3206 MessageDialog msg (*editor,
3207 _("Sorry, MIDI Busses are not supported at this time."));
3209 //session_add_midi_bus();
3213 session_add_audio_track (input_chan, output_chan, add_route_dialog->mode(), route_group, count);
3215 session_add_audio_bus (input_chan, output_chan, route_group, count);
3221 ARDOUR_UI::mixer_settings () const
3226 node = _session->instant_xml(X_("Mixer"));
3228 node = Config->instant_xml(X_("Mixer"));
3232 node = new XMLNode (X_("Mixer"));
3239 ARDOUR_UI::editor_settings () const
3244 node = _session->instant_xml(X_("Editor"));
3246 node = Config->instant_xml(X_("Editor"));
3250 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
3251 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
3256 node = new XMLNode (X_("Editor"));
3263 ARDOUR_UI::keyboard_settings () const
3267 node = Config->extra_xml(X_("Keyboard"));
3270 node = new XMLNode (X_("Keyboard"));
3276 ARDOUR_UI::create_xrun_marker (framepos_t where)
3278 editor->mouse_add_new_marker (where, false, true);
3282 ARDOUR_UI::halt_on_xrun_message ()
3284 MessageDialog msg (*editor,
3285 _("Recording was stopped because your system could not keep up."));
3290 ARDOUR_UI::xrun_handler (framepos_t where)
3296 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
3298 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
3299 create_xrun_marker(where);
3302 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
3303 halt_on_xrun_message ();
3308 ARDOUR_UI::disk_overrun_handler ()
3310 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
3312 if (!have_disk_speed_dialog_displayed) {
3313 have_disk_speed_dialog_displayed = true;
3314 MessageDialog* msg = new MessageDialog (*editor, string_compose (_("\
3315 The disk system on your computer\n\
3316 was not able to keep up with %1.\n\
3318 Specifically, it failed to write data to disk\n\
3319 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
3320 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3326 ARDOUR_UI::disk_underrun_handler ()
3328 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
3330 if (!have_disk_speed_dialog_displayed) {
3331 have_disk_speed_dialog_displayed = true;
3332 MessageDialog* msg = new MessageDialog (*editor,
3333 string_compose (_("The disk system on your computer\n\
3334 was not able to keep up with %1.\n\
3336 Specifically, it failed to read data from disk\n\
3337 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
3338 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3344 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
3346 have_disk_speed_dialog_displayed = false;
3351 ARDOUR_UI::session_dialog (std::string msg)
3353 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
3358 d = new MessageDialog (*editor, msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3360 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3369 ARDOUR_UI::pending_state_dialog ()
3371 HBox* hbox = new HBox();
3372 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3373 ArdourDialog dialog (_("Crash Recovery"), true);
3375 This session appears to have been in\n\
3376 middle of recording when ardour or\n\
3377 the computer was shutdown.\n\
3379 Ardour can recover any captured audio for\n\
3380 you, or it can ignore it. Please decide\n\
3381 what you would like to do.\n"));
3382 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3383 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3384 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3385 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3386 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
3387 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
3388 dialog.set_default_response (RESPONSE_ACCEPT);
3389 dialog.set_position (WIN_POS_CENTER);
3394 switch (dialog.run ()) {
3395 case RESPONSE_ACCEPT:
3403 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
3405 HBox* hbox = new HBox();
3406 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3407 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
3408 Label message (string_compose (_("\
3409 This session was created with a sample rate of %1 Hz\n\
3411 The audioengine is currently running at %2 Hz\n"), desired, actual));
3413 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3414 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3415 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3416 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3417 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
3418 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
3419 dialog.set_default_response (RESPONSE_ACCEPT);
3420 dialog.set_position (WIN_POS_CENTER);
3425 switch (dialog.run ()) {
3426 case RESPONSE_ACCEPT:
3435 ARDOUR_UI::disconnect_from_jack ()
3438 if( engine->disconnect_from_jack ()) {
3439 MessageDialog msg (*editor, _("Could not disconnect from JACK"));
3443 update_sample_rate (0);
3448 ARDOUR_UI::reconnect_to_jack ()
3451 if (engine->reconnect_to_jack ()) {
3452 MessageDialog msg (*editor, _("Could not reconnect to JACK"));
3456 update_sample_rate (0);
3461 ARDOUR_UI::use_config ()
3463 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
3465 set_transport_controllable_state (*node);
3470 ARDOUR_UI::update_transport_clocks (framepos_t pos)
3472 if (Config->get_primary_clock_delta_edit_cursor()) {
3473 primary_clock.set (pos, false, editor->get_preferred_edit_position(), 1);
3475 primary_clock.set (pos, 0, true);
3478 if (Config->get_secondary_clock_delta_edit_cursor()) {
3479 secondary_clock.set (pos, false, editor->get_preferred_edit_position(), 2);
3481 secondary_clock.set (pos);
3484 if (big_clock_window->get()) {
3485 big_clock.set (pos);
3491 ARDOUR_UI::step_edit_status_change (bool yn)
3493 // XXX should really store pre-step edit status of things
3494 // we make insensitive
3497 rec_button.set_visual_state (3);
3498 rec_button.set_sensitive (false);
3500 rec_button.set_visual_state (0);
3501 rec_button.set_sensitive (true);
3506 ARDOUR_UI::record_state_changed ()
3508 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
3510 if (!_session || !big_clock_window->get()) {
3511 /* why bother - the clock isn't visible */
3515 Session::RecordState const r = _session->record_status ();
3516 bool const h = _session->have_rec_enabled_track ();
3518 if (r == Session::Recording && h) {
3519 big_clock.set_widget_name ("BigClockRecording");
3521 big_clock.set_widget_name ("BigClockNonRecording");
3526 ARDOUR_UI::first_idle ()
3529 _session->allow_auto_play (true);
3533 editor->first_idle();
3536 Keyboard::set_can_save_keybindings (true);
3541 ARDOUR_UI::store_clock_modes ()
3543 XMLNode* node = new XMLNode(X_("ClockModes"));
3545 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
3546 node->add_property ((*x)->name().c_str(), enum_2_string ((*x)->mode()));
3549 _session->add_extra_xml (*node);
3550 _session->set_dirty ();
3555 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
3556 : Controllable (name), ui (u), type(tp)
3562 ARDOUR_UI::TransportControllable::set_value (double val)
3564 if (type == ShuttleControl) {
3571 fract = -((0.5 - val)/0.5);
3573 fract = ((val - 0.5)/0.5);
3577 ui.set_shuttle_fract (fract);
3582 /* do nothing: these are radio-style actions */
3586 const char *action = 0;
3590 action = X_("Roll");
3593 action = X_("Stop");
3596 action = X_("Goto Start");
3599 action = X_("Goto End");
3602 action = X_("Loop");
3605 action = X_("Play Selection");
3608 action = X_("Record");
3618 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
3626 ARDOUR_UI::TransportControllable::get_value (void) const
3645 case ShuttleControl:
3655 ARDOUR_UI::TransportControllable::set_id (const string& str)
3661 ARDOUR_UI::setup_profile ()
3663 if (gdk_screen_width() < 1200) {
3664 Profile->set_small_screen ();
3668 if (getenv ("ARDOUR_SAE")) {
3669 Profile->set_sae ();
3670 Profile->set_single_package ();
3675 ARDOUR_UI::toggle_translations ()
3677 using namespace Glib;
3679 RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("EnableTranslation"));
3681 RefPtr<ToggleAction> ract = RefPtr<ToggleAction>::cast_dynamic (act);
3684 string i18n_killer = ARDOUR::translation_kill_path();
3686 bool already_enabled = !ARDOUR::translations_are_disabled ();
3688 if (ract->get_active ()) {
3689 /* we don't care about errors */
3690 int fd = ::open (i18n_killer.c_str(), O_RDONLY|O_CREAT, 0644);
3693 /* we don't care about errors */
3694 unlink (i18n_killer.c_str());
3697 if (already_enabled != ract->get_active()) {
3698 MessageDialog win (already_enabled ? _("Translations disabled") : _("Translations enabled"),
3700 Gtk::MESSAGE_WARNING,
3702 win.set_secondary_text (string_compose (_("You must restart %1 for this to take effect."), PROGRAM_NAME));
3703 win.set_position (Gtk::WIN_POS_CENTER);
3711 /** Add a window proxy to our list, so that its state will be saved.
3712 * This call also causes the window to be created and opened if its
3713 * state was saved as `visible'.
3716 ARDOUR_UI::add_window_proxy (WindowProxyBase* p)
3718 _window_proxies.push_back (p);
3722 /** Remove a window proxy from our list. Must be called if a WindowProxy
3723 * is deleted, to prevent hanging pointers.
3726 ARDOUR_UI::remove_window_proxy (WindowProxyBase* p)
3728 _window_proxies.remove (p);
3732 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
3734 MissingFileDialog dialog (s, str, type);
3739 int result = dialog.run ();
3746 return 1; // quit entire session load
3749 result = dialog.get_action ();
3755 ARDOUR_UI::ambiguous_file (std::string file, std::string path, std::vector<std::string> hits)
3757 AmbiguousFileDialog dialog (file, hits);
3763 return dialog.get_which ();