make AU Cocoa plugin views with "client-side-windows" versions of GTK+; make keyboard...
[ardour2.git] / gtk2_ardour / ardour_ui.cc
blobcd0504f7df73303cabbff02730234759c819e3a1
1 /*
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.
20 #include <algorithm>
21 #include <cmath>
22 #include <fcntl.h>
23 #include <signal.h>
24 #include <unistd.h>
25 #include <time.h>
26 #include <cerrno>
27 #include <fstream>
28 #include <stdlib.h>
29 #include <cstring>
31 #include <iostream>
33 #include <sys/resource.h>
35 #include <gtkmm/messagedialog.h>
36 #include <gtkmm/accelmap.h>
38 #include <pbd/error.h>
39 #include <pbd/basename.h>
40 #include <pbd/compose.h>
41 #include <pbd/pathscanner.h>
42 #include <pbd/failed_constructor.h>
43 #include <pbd/enumwriter.h>
44 #include <pbd/stacktrace.h>
45 #include <gtkmm2ext/gtk_ui.h>
46 #include <gtkmm2ext/utils.h>
47 #include <gtkmm2ext/click_box.h>
48 #include <gtkmm2ext/fastmeter.h>
49 #include <gtkmm2ext/stop_signal.h>
50 #include <gtkmm2ext/popup.h>
51 #include <gtkmm2ext/window_title.h>
53 #include <midi++/port.h>
54 #include <midi++/mmc.h>
56 #include <ardour/ardour.h>
57 #include <ardour/profile.h>
58 #include <ardour/session_route.h>
59 #include <ardour/port.h>
60 #include <ardour/audioengine.h>
61 #include <ardour/playlist.h>
62 #include <ardour/utils.h>
63 #include <ardour/plugin.h>
64 #include <ardour/audio_diskstream.h>
65 #include <ardour/audiofilesource.h>
66 #include <ardour/recent_sessions.h>
67 #include <ardour/port.h>
68 #include <ardour/audio_track.h>
69 #include <ardour/control_protocol_manager.h>
71 typedef uint64_t microseconds_t;
73 #include "actions.h"
74 #include "ardour_ui.h"
75 #include "public_editor.h"
76 #include "audio_clock.h"
77 #include "keyboard.h"
78 #include "mixer_ui.h"
79 #include "prompter.h"
80 #include "opts.h"
81 #include "add_route_dialog.h"
82 #include "new_session_dialog.h"
83 #include "about.h"
84 #include "splash.h"
85 #include "nag.h"
86 #include "utils.h"
87 #include "gui_thread.h"
88 #include "theme_manager.h"
89 #include "engine_dialog.h"
90 #include "gain_meter.h"
91 #include "route_time_axis.h"
93 #include "i18n.h"
95 using namespace ARDOUR;
96 using namespace PBD;
97 using namespace Gtkmm2ext;
98 using namespace Gtk;
99 using namespace sigc;
101 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
102 UIConfiguration *ARDOUR_UI::ui_config = 0;
104 sigc::signal<void,bool> ARDOUR_UI::Blink;
105 sigc::signal<void> ARDOUR_UI::RapidScreenUpdate;
106 sigc::signal<void> ARDOUR_UI::SuperRapidScreenUpdate;
107 sigc::signal<void,nframes_t, bool, nframes_t> ARDOUR_UI::Clock;
109 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[])
111 : Gtkmm2ext::UI (PROGRAM_NAME, argcp, argvp),
113 primary_clock (X_("primary"), false, X_("TransportClockDisplay"), true, false, true),
114 secondary_clock (X_("secondary"), false, X_("SecondaryClockDisplay"), true, false, true),
115 preroll_clock (X_("preroll"), false, X_("PreRollClock"), true, true),
116 postroll_clock (X_("postroll"), false, X_("PostRollClock"), true, true),
118 /* preroll stuff */
120 preroll_button (_("pre\nroll")),
121 postroll_button (_("post\nroll")),
123 /* big clock */
125 big_clock (X_("bigclock"), false, "BigClockNonRecording", true, false, true),
127 /* transport */
129 roll_controllable ("transport roll", *this, TransportControllable::Roll),
130 stop_controllable ("transport stop", *this, TransportControllable::Stop),
131 goto_start_controllable ("transport goto start", *this, TransportControllable::GotoStart),
132 goto_end_controllable ("transport goto end", *this, TransportControllable::GotoEnd),
133 auto_loop_controllable ("transport auto loop", *this, TransportControllable::AutoLoop),
134 play_selection_controllable ("transport play selection", *this, TransportControllable::PlaySelection),
135 rec_controllable ("transport rec-enable", *this, TransportControllable::RecordEnable),
136 shuttle_controllable ("shuttle", *this, TransportControllable::ShuttleControl),
137 shuttle_controller_binding_proxy (shuttle_controllable),
139 roll_button (&roll_controllable),
140 stop_button (&stop_controllable),
141 goto_start_button (&goto_start_controllable),
142 goto_end_button (&goto_end_controllable),
143 auto_loop_button (&auto_loop_controllable),
144 play_selection_button (&play_selection_controllable),
145 rec_button (&rec_controllable),
147 shuttle_units_button (_("% ")),
149 punch_in_button (_("Punch In")),
150 punch_out_button (_("Punch Out")),
151 auto_return_button (_("Auto Return")),
152 auto_play_button (_("Auto Play")),
153 auto_input_button (_("Auto Input")),
154 click_button (_("Click")),
155 time_master_button (_("time\nmaster")),
157 auditioning_alert_button (_("AUDITION")),
158 solo_alert_button (_("SOLO")),
159 shown_flag (false),
160 error_log_button (_("Errors"))
162 using namespace Gtk::Menu_Helpers;
164 Gtkmm2ext::init();
166 #ifdef TOP_MENUBAR
167 _auto_display_errors = false;
168 #endif
170 about = 0;
171 splash = 0;
173 if (ARDOUR_COMMAND_LINE::session_name.length()) {
174 /* only show this if we're not going to post the new session dialog */
175 show_splash ();
178 if (theArdourUI == 0) {
179 theArdourUI = this;
182 ui_config = new UIConfiguration();
183 theme_manager = new ThemeManager();
185 engine = 0;
186 editor = 0;
187 mixer = 0;
188 session = 0;
189 _session_is_new = false;
190 big_clock_window = 0;
191 session_selector_window = 0;
192 new_session_dialog = 0;
193 last_key_press_time = 0;
194 connection_editor = 0;
195 add_route_dialog = 0;
196 route_params = 0;
197 option_editor = 0;
198 location_ui = 0;
199 key_editor = 0;
200 open_session_selector = 0;
201 have_configure_timeout = false;
202 have_disk_speed_dialog_displayed = false;
203 _will_create_new_session_automatically = false;
204 session_loaded = false;
205 last_speed_displayed = -1.0f;
206 ignore_dual_punch = false;
207 _mixer_on_top = false;
209 roll_button.unset_flags (Gtk::CAN_FOCUS);
210 stop_button.unset_flags (Gtk::CAN_FOCUS);
211 goto_start_button.unset_flags (Gtk::CAN_FOCUS);
212 goto_end_button.unset_flags (Gtk::CAN_FOCUS);
213 auto_loop_button.unset_flags (Gtk::CAN_FOCUS);
214 play_selection_button.unset_flags (Gtk::CAN_FOCUS);
215 rec_button.unset_flags (Gtk::CAN_FOCUS);
217 last_configure_time= 0;
219 shuttle_grabbed = false;
220 shuttle_fract = 0.0;
221 shuttle_max_speed = 8.0f;
223 shuttle_style_menu = 0;
224 shuttle_unit_menu = 0;
226 // We do not have jack linked in yet so;
228 last_shuttle_request = last_peak_grab = 0; // get_microseconds();
230 ARDOUR::Diskstream::DiskOverrun.connect (mem_fun(*this, &ARDOUR_UI::disk_overrun_handler));
231 ARDOUR::Diskstream::DiskUnderrun.connect (mem_fun(*this, &ARDOUR_UI::disk_underrun_handler));
233 ARDOUR::Plugin::PresetFileExists.connect (mem_fun(*this, &ARDOUR_UI::preset_file_exists_handler));
235 /* handle dialog requests */
237 ARDOUR::Session::Dialog.connect (mem_fun(*this, &ARDOUR_UI::session_dialog));
239 /* handle pending state with a dialog */
241 ARDOUR::Session::AskAboutPendingState.connect (mem_fun(*this, &ARDOUR_UI::pending_state_dialog));
243 /* handle sr mismatch with a dialog */
245 ARDOUR::Session::AskAboutSampleRateMismatch.connect (mem_fun(*this, &ARDOUR_UI::sr_mismatch_dialog));
247 /* lets get this party started */
249 try {
250 if (ARDOUR::init (ARDOUR_COMMAND_LINE::use_vst, ARDOUR_COMMAND_LINE::try_hw_optimization)) {
251 throw failed_constructor ();
254 setup_gtk_ardour_enums ();
255 Config->set_current_owner (ConfigVariableBase::Interface);
256 setup_profile ();
258 GainMeter::setup_slider_pix ();
259 RouteTimeAxisView::setup_slider_pix ();
261 } catch (failed_constructor& err) {
262 error << string_compose (_("could not initialize %1."), PROGRAM_NAME) << endmsg;
263 // pass it on up
264 throw;
267 /* we like keyboards */
269 keyboard = new Keyboard;
271 reset_dpi();
273 starting.connect (mem_fun(*this, &ARDOUR_UI::startup));
274 stopping.connect (mem_fun(*this, &ARDOUR_UI::shutdown));
276 platform_setup ();
280 ARDOUR_UI::create_engine ()
282 // this gets called every time by new_session()
284 if (engine) {
285 return 0;
288 loading_message (_("Starting audio engine"));
290 try {
291 engine = new ARDOUR::AudioEngine (ARDOUR_COMMAND_LINE::jack_client_name);
293 } catch (...) {
295 return -1;
298 engine->Stopped.connect (mem_fun(*this, &ARDOUR_UI::engine_stopped));
299 engine->Running.connect (mem_fun(*this, &ARDOUR_UI::engine_running));
300 engine->Halted.connect (bind (mem_fun(*this, &ARDOUR_UI::engine_halted), false));
301 engine->SampleRateChanged.connect (mem_fun(*this, &ARDOUR_UI::update_sample_rate));
303 post_engine ();
305 return 0;
308 void
309 ARDOUR_UI::post_engine ()
311 /* Things to be done once we create the AudioEngine
314 check_memory_locking();
316 ActionManager::init ();
317 _tooltips.enable();
319 if (setup_windows ()) {
320 throw failed_constructor ();
323 /* this is the first point at which all the keybindings are available */
325 if (ARDOUR_COMMAND_LINE::show_key_actions) {
326 vector<string> names;
327 vector<string> paths;
328 vector<string> keys;
329 vector<AccelKey> bindings;
331 ActionManager::get_all_actions (names, paths, keys, bindings);
333 vector<string>::iterator n;
334 vector<string>::iterator k;
335 for (n = names.begin(), k = keys.begin(); n != names.end(); ++n, ++k) {
336 cerr << "Action: " << (*n) << " bound to " << (*k) << endl;
339 exit (0);
342 blink_timeout_tag = -1;
344 /* the global configuration object is now valid */
346 use_config ();
348 /* this being a GUI and all, we want peakfiles */
350 AudioFileSource::set_build_peakfiles (true);
351 AudioFileSource::set_build_missing_peakfiles (true);
353 /* set default clock modes */
355 if (Profile->get_sae()) {
356 primary_clock.set_mode (AudioClock::BBT);
357 secondary_clock.set_mode (AudioClock::MinSec);
358 } else {
359 primary_clock.set_mode (AudioClock::SMPTE);
360 secondary_clock.set_mode (AudioClock::BBT);
363 /* start the time-of-day-clock */
365 #ifndef GTKOSX
366 /* OS X provides an always visible wallclock, so don't be stupid */
367 update_wall_clock ();
368 Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::update_wall_clock), 60000);
369 #endif
371 update_disk_space ();
372 update_cpu_load ();
373 update_sample_rate (engine->frame_rate());
375 platform_specific ();
377 /* now start and maybe save state */
379 if (do_engine_start () == 0) {
380 if (session && _session_is_new) {
381 /* we need to retain initial visual
382 settings for a new session
384 session->save_state ("");
389 ARDOUR_UI::~ARDOUR_UI ()
391 save_ardour_state ();
393 if (keyboard) {
394 delete keyboard;
397 if (editor) {
398 delete editor;
401 if (mixer) {
402 delete mixer;
405 if (add_route_dialog) {
406 delete add_route_dialog;
409 if (new_session_dialog) {
410 delete new_session_dialog;
414 void
415 ARDOUR_UI::pop_back_splash ()
417 if (Splash::instance()) {
418 // Splash::instance()->pop_back();
419 Splash::instance()->hide ();
423 gint
424 ARDOUR_UI::configure_timeout ()
426 if (last_configure_time == 0) {
427 /* no configure events yet */
428 return TRUE;
431 /* force a gap of 0.5 seconds since the last configure event
434 if (get_microseconds() - last_configure_time < 500000) {
435 return TRUE;
436 } else {
437 have_configure_timeout = false;
438 save_ardour_state ();
439 return FALSE;
443 gboolean
444 ARDOUR_UI::configure_handler (GdkEventConfigure* conf)
446 if (have_configure_timeout) {
447 last_configure_time = get_microseconds();
448 } else {
449 Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
450 have_configure_timeout = true;
453 return FALSE;
456 void
457 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
459 const XMLProperty* prop;
461 if ((prop = node.property ("roll")) != 0) {
462 roll_controllable.set_id (prop->value());
464 if ((prop = node.property ("stop")) != 0) {
465 stop_controllable.set_id (prop->value());
467 if ((prop = node.property ("goto_start")) != 0) {
468 goto_start_controllable.set_id (prop->value());
470 if ((prop = node.property ("goto_end")) != 0) {
471 goto_end_controllable.set_id (prop->value());
473 if ((prop = node.property ("auto_loop")) != 0) {
474 auto_loop_controllable.set_id (prop->value());
476 if ((prop = node.property ("play_selection")) != 0) {
477 play_selection_controllable.set_id (prop->value());
479 if ((prop = node.property ("rec")) != 0) {
480 rec_controllable.set_id (prop->value());
482 if ((prop = node.property ("shuttle")) != 0) {
483 shuttle_controllable.set_id (prop->value());
487 XMLNode&
488 ARDOUR_UI::get_transport_controllable_state ()
490 XMLNode* node = new XMLNode(X_("TransportControllables"));
491 char buf[64];
493 roll_controllable.id().print (buf, sizeof (buf));
494 node->add_property (X_("roll"), buf);
495 stop_controllable.id().print (buf, sizeof (buf));
496 node->add_property (X_("stop"), buf);
497 goto_start_controllable.id().print (buf, sizeof (buf));
498 node->add_property (X_("goto_start"), buf);
499 goto_end_controllable.id().print (buf, sizeof (buf));
500 node->add_property (X_("goto_end"), buf);
501 auto_loop_controllable.id().print (buf, sizeof (buf));
502 node->add_property (X_("auto_loop"), buf);
503 play_selection_controllable.id().print (buf, sizeof (buf));
504 node->add_property (X_("play_selection"), buf);
505 rec_controllable.id().print (buf, sizeof (buf));
506 node->add_property (X_("rec"), buf);
507 shuttle_controllable.id().print (buf, sizeof (buf));
508 node->add_property (X_("shuttle"), buf);
510 return *node;
513 void
514 ARDOUR_UI::save_ardour_state ()
516 if (!keyboard || !mixer || !editor) {
517 return;
520 /* XXX this is all a bit dubious. add_extra_xml() uses
521 a different lifetime model from add_instant_xml().
524 XMLNode* node = new XMLNode (keyboard->get_state());
525 Config->add_extra_xml (*node);
526 Config->add_extra_xml (get_transport_controllable_state());
527 if (new_session_dialog) {
528 if (new_session_dialog->engine_control.was_used()) {
529 Config->add_extra_xml (new_session_dialog->engine_control.get_state());
532 Config->save_state();
533 ui_config->save_state ();
535 XMLNode enode(static_cast<Stateful*>(editor)->get_state());
536 XMLNode mnode(mixer->get_state());
538 if (session) {
539 session->add_instant_xml (enode, session->path());
540 session->add_instant_xml (mnode, session->path());
541 } else {
542 Config->add_instant_xml (enode, get_user_ardour_path());
543 Config->add_instant_xml (mnode, get_user_ardour_path());
546 Keyboard::save_keybindings ();
549 gint
550 ARDOUR_UI::autosave_session ()
552 if (g_main_depth() > 1) {
553 /* inside a recursive main loop,
554 give up because we may not be able to
555 take a lock.
557 return 1;
560 if (!Config->get_periodic_safety_backups())
561 return 1;
563 if (session) {
564 session->maybe_write_autosave();
567 return 1;
570 void
571 ARDOUR_UI::update_autosave ()
573 ENSURE_GUI_THREAD (mem_fun (*this, &ARDOUR_UI::update_autosave));
575 if (session && session->dirty()) {
576 if (_autosave_connection.connected()) {
577 _autosave_connection.disconnect();
580 _autosave_connection = Glib::signal_timeout().connect (mem_fun (*this, &ARDOUR_UI::autosave_session),
581 Config->get_periodic_safety_backup_interval() * 1000);
583 } else {
584 if (_autosave_connection.connected()) {
585 _autosave_connection.disconnect();
590 void
591 ARDOUR_UI::backend_audio_error (bool we_set_params, Gtk::Window* toplevel)
593 string title;
594 if (we_set_params) {
595 title = string_compose (_("%1 could not start JACK"), PROGRAM_NAME);
596 } else {
597 title = string_compose (_("%1 could not connect to JACK."), PROGRAM_NAME);
600 MessageDialog win (title,
601 false,
602 Gtk::MESSAGE_INFO,
603 Gtk::BUTTONS_NONE);
605 if (we_set_params) {
606 win.set_secondary_text(_("There are several possible reasons:\n\
608 1) You requested audio parameters that are not supported..\n\
609 2) JACK is running as another user.\n\
611 Please consider the possibilities, and perhaps try different parameters."));
612 } else {
613 win.set_secondary_text(_("There are several possible reasons:\n\
615 1) JACK is not running.\n\
616 2) JACK is running as another user, perhaps root.\n\
617 3) There is already another client called \"ardour\".\n\
619 Please consider the possibilities, and perhaps (re)start JACK."));
622 if (toplevel) {
623 win.set_transient_for (*toplevel);
626 if (we_set_params) {
627 win.add_button (Stock::OK, RESPONSE_CLOSE);
628 } else {
629 win.add_button (Stock::QUIT, RESPONSE_CLOSE);
632 win.set_default_response (RESPONSE_CLOSE);
634 win.show_all ();
635 win.set_position (Gtk::WIN_POS_CENTER);
636 pop_back_splash ();
638 /* we just don't care about the result, but we want to block */
640 win.run ();
643 void
644 ARDOUR_UI::startup ()
646 string name, path;
648 new_session_dialog = new NewSessionDialog();
650 bool backend_audio_is_running = EngineControl::engine_running();
651 XMLNode* audio_setup = Config->extra_xml ("AudioSetup");
653 if (audio_setup) {
654 new_session_dialog->engine_control.set_state (*audio_setup);
657 if (!get_session_parameters (backend_audio_is_running, ARDOUR_COMMAND_LINE::new_session)) {
658 return;
661 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
662 show ();
665 void
666 ARDOUR_UI::no_memory_warning ()
668 XMLNode node (X_("no-memory-warning"));
669 Config->add_instant_xml (node, get_user_ardour_path());
672 void
673 ARDOUR_UI::check_memory_locking ()
675 #ifdef __APPLE__
676 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
677 return;
678 #else // !__APPLE__
680 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"), get_user_ardour_path());
682 if (engine->is_realtime() && memory_warning_node == 0) {
684 struct rlimit limits;
685 int64_t ram;
686 long pages, page_size;
688 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0) {
689 ram = 0;
690 } else {
691 ram = (int64_t) pages * (int64_t) page_size;
694 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
695 return;
698 if (limits.rlim_cur != RLIM_INFINITY) {
700 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
703 MessageDialog msg (string_compose (_("WARNING: Your system has a limit for maximum amount of locked memory. "
704 "This might cause %1 to run out of memory before your system "
705 "runs out of memory. \n\n"
706 "You can view the memory limit with 'ulimit -l', "
707 "and it is normally controlled by /etc/security/limits.conf"), PROGRAM_NAME));
709 VBox* vbox = msg.get_vbox();
710 HBox hbox;
711 CheckButton cb (_("Do not show this window again"));
713 cb.signal_toggled().connect (mem_fun (*this, &ARDOUR_UI::no_memory_warning));
715 hbox.pack_start (cb, true, false);
716 vbox->pack_start (hbox);
717 hbox.show_all ();
719 pop_back_splash ();
721 msg.run ();
725 #endif // !__APPLE__
728 void
729 ARDOUR_UI::queue_finish ()
731 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
734 bool
735 ARDOUR_UI::idle_finish ()
737 finish ();
738 return false; /* do not call again */
741 void
742 ARDOUR_UI::finish()
744 if (session) {
746 int tries = 0;
748 while (session->transport_rolling() && (++tries < 8)) {
749 /* stop but do not abort capture */
750 session->request_stop (false, true);
751 usleep (10000);
754 if (session->dirty()) {
755 switch (ask_about_saving_session(_("quit"))) {
756 case -1:
757 return;
758 break;
759 case 1:
760 /* use the default name */
761 if (save_state_canfail ("")) {
762 /* failed - don't quit */
763 MessageDialog msg (*editor,
764 _("\
765 Ardour was unable to save your session.\n\n\
766 If you still wish to quit, please use the\n\n\
767 \"Just quit\" option."));
768 pop_back_splash();
769 msg.run ();
770 return;
772 break;
773 case 0:
774 break;
778 session->set_clean();
779 session->set_deletion_in_progress ();
780 unload_session(true);
783 ArdourDialog::close_all_dialogs ();
784 engine->stop (true);
785 save_ardour_state ();
786 quit ();
790 ARDOUR_UI::ask_about_saving_session (const string & what)
792 ArdourDialog window (_("ardour: save session?"));
793 Gtk::HBox dhbox; // the hbox for the image and text
794 Gtk::Label prompt_label;
795 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
797 string msg;
799 msg = string_compose(_("Don't %1"), what);
800 window.add_button (msg, RESPONSE_REJECT);
801 msg = string_compose(_("Just %1"), what);
802 window.add_button (msg, RESPONSE_APPLY);
803 msg = string_compose(_("Save and %1"), what);
804 window.add_button (msg, RESPONSE_ACCEPT);
806 window.set_default_response (RESPONSE_ACCEPT);
808 Gtk::Button noquit_button (msg);
809 noquit_button.set_name ("EditorGTKButton");
811 string prompt;
812 string type;
814 if (session->snap_name() == session->name()) {
815 type = _("session");
816 } else {
817 type = _("snapshot");
819 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?"),
820 type, session->snap_name());
822 prompt_label.set_text (prompt);
823 prompt_label.set_name (X_("PrompterLabel"));
824 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
826 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP)
828 dhbox.set_homogeneous (false);
829 dhbox.pack_start (*dimage, false, false, 5);
830 dhbox.pack_start (prompt_label, true, false, 5);
831 window.get_vbox()->pack_start (dhbox);
833 window.set_name (_("Prompter"));
834 window.set_position (Gtk::WIN_POS_MOUSE);
835 window.set_modal (true);
836 window.set_resizable (false);
837 window.show_all ();
839 window.set_keep_above (true);
840 window.present ();
842 ResponseType r = (ResponseType) window.run();
844 window.hide ();
846 switch (r) {
847 case RESPONSE_ACCEPT: // save and get out of here
848 return 1;
849 case RESPONSE_APPLY: // get out of here
850 return 0;
851 default:
852 break;
855 return -1;
859 ARDOUR_UI::every_second ()
861 update_cpu_load ();
862 update_buffer_load ();
863 update_disk_space ();
864 return TRUE;
867 gint
868 ARDOUR_UI::every_point_one_seconds ()
870 update_speed_display ();
871 RapidScreenUpdate(); /* EMIT_SIGNAL */
872 return TRUE;
875 gint
876 ARDOUR_UI::every_point_zero_one_seconds ()
878 // august 2007: actual update frequency: 40Hz, not 100Hz
880 SuperRapidScreenUpdate(); /* EMIT_SIGNAL */
881 return TRUE;
884 void
885 ARDOUR_UI::update_sample_rate (nframes_t ignored)
887 char buf[32];
889 ENSURE_GUI_THREAD (bind (mem_fun(*this, &ARDOUR_UI::update_sample_rate), ignored));
891 if (!engine->connected()) {
893 snprintf (buf, sizeof (buf), _("disconnected"));
895 } else {
897 nframes_t rate = engine->frame_rate();
899 if (fmod (rate, 1000.0) != 0.0) {
900 snprintf (buf, sizeof (buf), _("%.1f kHz / %4.1f ms"),
901 (float) rate/1000.0f,
902 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
903 } else {
904 snprintf (buf, sizeof (buf), _("%u kHz / %4.1f ms"),
905 rate/1000,
906 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
910 sample_rate_label.set_text (buf);
913 void
914 ARDOUR_UI::update_cpu_load ()
916 char buf[32];
917 snprintf (buf, sizeof (buf), _("DSP: %5.1f%%"), engine->get_cpu_load());
918 cpu_load_label.set_text (buf);
921 void
922 ARDOUR_UI::update_buffer_load ()
924 char buf[64];
925 uint32_t c, p;
927 if (session) {
928 c = session->capture_load ();
929 p = session->playback_load ();
931 snprintf (buf, sizeof (buf), _("Buffers p:%" PRIu32 "%% c:%" PRIu32 "%%"),
932 session->playback_load(), session->capture_load());
933 buffer_load_label.set_text (buf);
934 } else {
935 buffer_load_label.set_text ("");
939 void
940 ARDOUR_UI::count_recenabled_streams (Route& route)
942 Track* track = dynamic_cast<Track*>(&route);
943 if (track && track->diskstream()->record_enabled()) {
944 rec_enabled_streams += track->n_inputs();
948 void
949 ARDOUR_UI::update_disk_space()
951 if (session == 0) {
952 return;
955 nframes_t frames = session->available_capture_duration();
956 char buf[64];
958 if (frames == max_frames) {
959 strcpy (buf, _("Disk: 24hrs+"));
960 } else {
961 int hrs;
962 int mins;
963 int secs;
964 nframes_t fr = session->frame_rate();
966 rec_enabled_streams = 0;
967 session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams);
969 if (rec_enabled_streams) {
970 frames /= rec_enabled_streams;
973 hrs = frames / (fr * 3600);
974 frames -= hrs * fr * 3600;
975 mins = frames / (fr * 60);
976 frames -= mins * fr * 60;
977 secs = frames / fr;
979 snprintf (buf, sizeof(buf), _("Disk: %02dh:%02dm:%02ds"), hrs, mins, secs);
982 disk_space_label.set_text (buf);
985 gint
986 ARDOUR_UI::update_wall_clock ()
988 time_t now;
989 struct tm *tm_now;
990 char buf[16];
992 time (&now);
993 tm_now = localtime (&now);
995 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
996 wall_clock_label.set_text (buf);
998 return TRUE;
1001 gint
1002 ARDOUR_UI::session_menu (GdkEventButton *ev)
1004 session_popup_menu->popup (0, 0);
1005 return TRUE;
1008 void
1009 ARDOUR_UI::redisplay_recent_sessions ()
1011 vector<string *> *sessions;
1012 vector<string *>::iterator i;
1013 RecentSessionsSorter cmp;
1015 recent_session_display.set_model (Glib::RefPtr<TreeModel>(0));
1016 recent_session_model->clear ();
1018 RecentSessions rs;
1019 ARDOUR::read_recent_sessions (rs);
1021 if (rs.empty()) {
1022 recent_session_display.set_model (recent_session_model);
1023 return;
1026 /* sort them alphabetically */
1027 sort (rs.begin(), rs.end(), cmp);
1028 sessions = new vector<string*>;
1030 for (RecentSessions::iterator i = rs.begin(); i != rs.end(); ++i) {
1031 sessions->push_back (new string ((*i).second));
1034 for (i = sessions->begin(); i != sessions->end(); ++i) {
1036 vector<string*>* states;
1037 vector<const gchar*> item;
1038 string fullpath = *(*i);
1040 /* remove any trailing / */
1042 if (fullpath[fullpath.length()-1] == G_DIR_SEPARATOR) {
1043 fullpath = fullpath.substr (0, fullpath.length()-1);
1046 /* check whether session still exists */
1047 if (!Glib::file_test(fullpath.c_str(), Glib::FILE_TEST_EXISTS)) {
1048 /* session doesn't exist */
1049 cerr << "skipping non-existent session " << fullpath << endl;
1050 continue;
1053 /* now get available states for this session */
1055 if ((states = Session::possible_states (fullpath)) == 0) {
1056 /* no state file? */
1057 continue;
1060 TreeModel::Row row = *(recent_session_model->append());
1062 row[recent_session_columns.visible_name] = Glib::path_get_basename (fullpath);
1063 row[recent_session_columns.fullpath] = fullpath;
1065 if (states->size() > 1) {
1067 /* add the children */
1069 for (vector<string*>::iterator i2 = states->begin(); i2 != states->end(); ++i2) {
1071 TreeModel::Row child_row = *(recent_session_model->append (row.children()));
1073 child_row[recent_session_columns.visible_name] = **i2;
1074 child_row[recent_session_columns.fullpath] = fullpath;
1076 delete *i2;
1080 delete states;
1083 recent_session_display.set_model (recent_session_model);
1084 delete sessions;
1087 void
1088 ARDOUR_UI::build_session_selector ()
1090 session_selector_window = new ArdourDialog ("session selector");
1092 Gtk::ScrolledWindow *scroller = manage (new Gtk::ScrolledWindow);
1094 session_selector_window->add_button (Stock::CANCEL, RESPONSE_CANCEL);
1095 session_selector_window->add_button (Stock::OPEN, RESPONSE_ACCEPT);
1096 session_selector_window->set_default_response (RESPONSE_ACCEPT);
1097 recent_session_model = TreeStore::create (recent_session_columns);
1098 recent_session_display.set_model (recent_session_model);
1099 recent_session_display.append_column (_("Recent Sessions"), recent_session_columns.visible_name);
1100 recent_session_display.set_headers_visible (false);
1101 recent_session_display.get_selection()->set_mode (SELECTION_BROWSE);
1102 recent_session_display.signal_row_activated().connect (mem_fun (*this, &ARDOUR_UI::recent_session_row_activated));
1104 scroller->add (recent_session_display);
1105 scroller->set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
1107 session_selector_window->set_name ("SessionSelectorWindow");
1108 session_selector_window->set_size_request (200, 400);
1109 session_selector_window->get_vbox()->pack_start (*scroller);
1110 session_selector_window->show_all_children();
1113 void
1114 ARDOUR_UI::recent_session_row_activated (const TreePath& path, TreeViewColumn* col)
1116 session_selector_window->response (RESPONSE_ACCEPT);
1119 void
1120 ARDOUR_UI::open_recent_session ()
1122 bool can_return = (session != 0);
1124 if (session_selector_window == 0) {
1125 build_session_selector ();
1128 redisplay_recent_sessions ();
1130 while (true) {
1132 session_selector_window->set_position (WIN_POS_MOUSE);
1134 ResponseType r = (ResponseType) session_selector_window->run ();
1136 switch (r) {
1137 case RESPONSE_ACCEPT:
1138 break;
1139 default:
1140 if (can_return) {
1141 session_selector_window->hide();
1142 return;
1143 } else {
1144 exit (1);
1148 if (recent_session_display.get_selection()->count_selected_rows() == 0) {
1149 continue;
1152 session_selector_window->hide();
1154 Gtk::TreeModel::iterator i = recent_session_display.get_selection()->get_selected();
1156 if (i == recent_session_model->children().end()) {
1157 return;
1160 Glib::ustring path = (*i)[recent_session_columns.fullpath];
1161 Glib::ustring state = (*i)[recent_session_columns.visible_name];
1163 _session_is_new = false;
1165 if (load_session (path, state) == 0) {
1166 break;
1169 can_return = false;
1173 bool
1174 ARDOUR_UI::check_audioengine ()
1176 if (engine) {
1177 if (!engine->connected()) {
1178 MessageDialog msg (string_compose (_("%1 is not connected to JACK\n"
1179 "You cannot open or close sessions in this condition"), PROGRAM_NAME));
1180 pop_back_splash ();
1181 msg.set_position (WIN_POS_CENTER);
1182 msg.run ();
1183 return false;
1185 return true;
1186 } else {
1187 return false;
1191 void
1192 ARDOUR_UI::open_session ()
1194 if (!check_audioengine()) {
1195 return;
1198 /* popup selector window */
1200 if (open_session_selector == 0) {
1202 /* ardour sessions are folders */
1204 open_session_selector = new Gtk::FileChooserDialog (_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1205 open_session_selector->add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1206 open_session_selector->add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1207 open_session_selector->set_default_response(Gtk::RESPONSE_ACCEPT);
1209 FileFilter session_filter;
1210 session_filter.add_pattern ("*.ardour");
1211 session_filter.set_name (_("Ardour sessions"));
1212 open_session_selector->add_filter (session_filter);
1213 open_session_selector->set_filter (session_filter);
1216 int response = open_session_selector->run();
1217 open_session_selector->hide ();
1219 switch (response) {
1220 case RESPONSE_ACCEPT:
1221 break;
1222 default:
1223 open_session_selector->hide();
1224 return;
1227 open_session_selector->hide();
1228 string session_path = open_session_selector->get_filename();
1229 string path, name;
1230 bool isnew;
1232 if (session_path.length() > 0) {
1233 if (Session::find_session (session_path, path, name, isnew) == 0) {
1234 _session_is_new = isnew;
1235 load_session (path, name);
1241 void
1242 ARDOUR_UI::session_add_midi_track ()
1244 cerr << _("Patience is a virtue.\n");
1247 void
1248 ARDOUR_UI::session_add_audio_route (bool track, int32_t input_channels, int32_t output_channels, ARDOUR::TrackMode mode, uint32_t how_many)
1250 list<boost::shared_ptr<AudioTrack> > tracks;
1251 Session::RouteList routes;
1253 if (session == 0) {
1254 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1255 return;
1258 try {
1259 if (track) {
1260 tracks = session->new_audio_track (input_channels, output_channels, mode, how_many);
1262 if (tracks.size() != how_many) {
1263 if (how_many == 1) {
1264 error << _("could not create a new audio track") << endmsg;
1265 } else {
1266 error << string_compose (_("could only create %1 of %2 new audio %3"),
1267 tracks.size(), how_many, (track ? _("tracks") : _("busses"))) << endmsg;
1271 } else {
1273 routes = session->new_audio_route (input_channels, output_channels, how_many);
1275 if (routes.size() != how_many) {
1276 if (how_many == 1) {
1277 error << _("could not create a new audio track") << endmsg;
1278 } else {
1279 error << string_compose (_("could not create %1 new audio tracks"), how_many) << endmsg;
1284 #if CONTROLOUTS
1285 if (need_control_room_outs) {
1286 pan_t pans[2];
1288 pans[0] = 0.5;
1289 pans[1] = 0.5;
1291 route->set_stereo_control_outs (control_lr_channels);
1292 route->control_outs()->set_stereo_pan (pans, this);
1294 #endif /* CONTROLOUTS */
1297 catch (...) {
1298 MessageDialog msg (*editor,
1299 _("There are insufficient JACK ports available\n\
1300 to create a new track or bus.\n\
1301 You should save Ardour, exit and\n\
1302 restart JACK with more ports."));
1303 pop_back_splash ();
1304 msg.run ();
1308 void
1309 ARDOUR_UI::do_transport_locate (nframes_t new_position)
1311 nframes_t _preroll = 0;
1313 if (session) {
1314 // XXX CONFIG_CHANGE FIX - requires AnyTime handling
1315 // _preroll = session->convert_to_frames_at (new_position, Config->get_preroll());
1317 if (new_position > _preroll) {
1318 new_position -= _preroll;
1319 } else {
1320 new_position = 0;
1323 session->request_locate (new_position);
1327 void
1328 ARDOUR_UI::transport_goto_start ()
1330 if (session) {
1331 session->goto_start();
1334 /* force displayed area in editor to start no matter
1335 what "follow playhead" setting is.
1338 if (editor) {
1339 editor->reset_x_origin (session->current_start_frame());
1344 void
1345 ARDOUR_UI::transport_goto_zero ()
1347 if (session) {
1348 session->request_locate (0);
1351 /* force displayed area in editor to start no matter
1352 what "follow playhead" setting is.
1355 if (editor) {
1356 editor->reset_x_origin (0);
1361 void
1362 ARDOUR_UI::transport_goto_wallclock ()
1364 if (session && editor) {
1366 time_t now;
1367 struct tm tmnow;
1368 nframes64_t frames;
1370 time (&now);
1371 localtime_r (&now, &tmnow);
1373 frames = tmnow.tm_hour * (60 * 60 * session->frame_rate());
1374 frames += tmnow.tm_min * (60 * session->frame_rate());
1375 frames += tmnow.tm_sec * session->frame_rate();
1377 session->request_locate (frames);
1379 /* force displayed area in editor to start no matter
1380 what "follow playhead" setting is.
1383 if (editor) {
1384 editor->reset_x_origin (frames - (editor->current_page_frames()/2));
1389 void
1390 ARDOUR_UI::transport_goto_end ()
1392 if (session) {
1393 nframes_t frame = session->current_end_frame();
1394 session->request_locate (frame);
1396 /* force displayed area in editor to start no matter
1397 what "follow playhead" setting is.
1400 if (editor) {
1401 editor->reset_x_origin (frame);
1406 void
1407 ARDOUR_UI::transport_stop ()
1409 if (!session) {
1410 return;
1413 if (session->is_auditioning()) {
1414 session->cancel_audition ();
1415 return;
1418 session->request_stop (false, true);
1421 void
1422 ARDOUR_UI::transport_stop_and_forget_capture ()
1424 if (session) {
1425 session->request_stop (true, true);
1429 void
1430 ARDOUR_UI::remove_last_capture()
1432 if (editor) {
1433 editor->remove_last_capture();
1437 void
1438 ARDOUR_UI::transport_record (bool roll)
1441 if (session) {
1442 switch (session->record_status()) {
1443 case Session::Disabled:
1444 if (session->ntracks() == 0) {
1445 MessageDialog msg (*editor, _("Please create 1 or more track\nbefore trying to record.\nCheck the Session menu."));
1446 msg.run ();
1447 return;
1449 session->maybe_enable_record ();
1450 if (roll) {
1451 transport_roll ();
1453 break;
1454 case Session::Recording:
1455 if (roll) {
1456 session->request_stop();
1457 } else {
1458 session->disable_record (false, true);
1460 break;
1462 case Session::Enabled:
1463 session->disable_record (false, true);
1466 //cerr << "ARDOUR_UI::transport_record () called roll = " << roll << " session->record_status() = " << session->record_status() << endl;
1469 void
1470 ARDOUR_UI::transport_roll ()
1472 if (!session) {
1473 return;
1476 if (session->is_auditioning()) {
1477 return;
1480 switch (Config->get_slave_source()) {
1481 case None:
1482 case JACK:
1483 break;
1484 default:
1485 /* transport controlled by the master */
1486 return;
1489 bool rolling = session->transport_rolling();
1491 if (session->get_play_loop()) {
1492 /* XXX it is not possible to just leave seamless loop and keep
1493 playing at present (nov 4th 2009)
1495 if (!Config->get_seamless_loop()) {
1496 /* off, and stop */
1497 session->request_play_loop (false, true);
1498 } else {
1499 return;
1501 } else if (session->get_play_range ()) {
1502 session->request_play_range (0, true);
1505 if (!rolling) {
1506 session->request_transport_speed (1.0f);
1509 map_transport_state ();
1512 void
1513 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
1516 if (!session) {
1517 return;
1520 if (session->is_auditioning()) {
1521 session->cancel_audition ();
1522 return;
1525 switch (Config->get_slave_source()) {
1526 case None:
1527 case JACK:
1528 break;
1529 default:
1530 /* transport controlled by the master */
1531 return;
1534 bool rolling = session->transport_rolling();
1535 bool affect_transport = true;
1537 if (rolling && roll_out_of_bounded_mode) {
1538 /* drop out of loop/range playback but leave transport rolling */
1539 if (session->get_play_loop()) {
1540 if (Config->get_seamless_loop()) {
1541 /* the disk buffers contain copies of the loop - we can't
1542 just keep playing, so stop the transport. the user
1543 can restart as they wish.
1545 affect_transport = true;
1546 } else {
1547 /* disk buffers are normal, so we can keep playing */
1548 affect_transport = false;
1550 session->request_play_loop (false, true);
1551 } else if (session->get_play_range ()) {
1552 affect_transport = false;
1553 session->request_play_range (0, true);
1557 if (affect_transport) {
1558 if (rolling) {
1559 session->request_stop (with_abort, true);
1560 } else {
1561 session->request_transport_speed (1.0f);
1565 map_transport_state ();
1568 void
1569 ARDOUR_UI::toggle_session_auto_loop ()
1571 if (session) {
1572 if (session->get_play_loop()) {
1573 if (session->transport_rolling()) {
1574 Location * looploc = session->locations()->auto_loop_location();
1575 if (looploc) {
1576 session->request_locate (looploc->start(), true);
1578 } else {
1579 session->request_play_loop (false);
1581 } else {
1582 Location * looploc = session->locations()->auto_loop_location();
1583 if (looploc) {
1584 session->request_play_loop (true);
1590 void
1591 ARDOUR_UI::transport_play_selection ()
1593 if (!session) {
1594 return;
1597 editor->play_selection ();
1600 void
1601 ARDOUR_UI::transport_rewind (int option)
1603 float current_transport_speed;
1605 if (session) {
1606 current_transport_speed = session->transport_speed();
1608 if (current_transport_speed >= 0.0f) {
1609 switch (option) {
1610 case 0:
1611 session->request_transport_speed (-1.0f);
1612 break;
1613 case 1:
1614 session->request_transport_speed (-4.0f);
1615 break;
1616 case -1:
1617 session->request_transport_speed (-0.5f);
1618 break;
1620 } else {
1621 /* speed up */
1622 session->request_transport_speed (current_transport_speed * 1.5f);
1627 void
1628 ARDOUR_UI::transport_forward (int option)
1630 float current_transport_speed;
1632 if (session) {
1633 current_transport_speed = session->transport_speed();
1635 if (current_transport_speed <= 0.0f) {
1636 switch (option) {
1637 case 0:
1638 session->request_transport_speed (1.0f);
1639 break;
1640 case 1:
1641 session->request_transport_speed (4.0f);
1642 break;
1643 case -1:
1644 session->request_transport_speed (0.5f);
1645 break;
1647 } else {
1648 /* speed up */
1649 session->request_transport_speed (current_transport_speed * 1.5f);
1654 void
1655 ARDOUR_UI::toggle_record_enable (uint32_t dstream)
1657 if (session == 0) {
1658 return;
1661 boost::shared_ptr<Route> r;
1663 if ((r = session->route_by_remote_id (dstream)) != 0) {
1665 Track* t;
1667 if ((t = dynamic_cast<Track*>(r.get())) != 0) {
1668 t->diskstream()->set_record_enabled (!t->diskstream()->record_enabled());
1673 void
1674 ARDOUR_UI::queue_transport_change ()
1676 Gtkmm2ext::UI::instance()->call_slot (mem_fun(*this, &ARDOUR_UI::map_transport_state));
1679 void
1680 ARDOUR_UI::map_transport_state ()
1682 if (!session) {
1683 auto_loop_button.set_visual_state (0);
1684 play_selection_button.set_visual_state (0);
1685 roll_button.set_visual_state (0);
1686 stop_button.set_visual_state (1);
1687 return;
1690 float sp = session->transport_speed();
1692 if (sp == 1.0f) {
1693 shuttle_fract = SHUTTLE_FRACT_SPEED1; /* speed = 1.0, believe it or not */
1694 shuttle_box.queue_draw ();
1695 } else if (sp == 0.0f) {
1696 shuttle_fract = 0;
1697 shuttle_box.queue_draw ();
1698 update_disk_space ();
1701 if (sp != 0.0) {
1703 if (session->get_play_range()) {
1705 play_selection_button.set_visual_state (1);
1706 roll_button.set_visual_state (0);
1707 auto_loop_button.set_visual_state (0);
1709 } else if (session->get_play_loop ()) {
1711 auto_loop_button.set_visual_state (1);
1712 play_selection_button.set_visual_state (0);
1713 roll_button.set_visual_state (0);
1715 } else {
1717 roll_button.set_visual_state (1);
1718 play_selection_button.set_visual_state (0);
1719 auto_loop_button.set_visual_state (0);
1722 stop_button.set_visual_state (0);
1724 } else {
1726 stop_button.set_visual_state (1);
1727 roll_button.set_visual_state (0);
1728 play_selection_button.set_visual_state (0);
1729 auto_loop_button.set_visual_state (0);
1734 void
1735 ARDOUR_UI::GlobalClickBox::printer (char buf[32], Adjustment &adj, void *arg)
1737 snprintf (buf, sizeof(buf), "%s", ((GlobalClickBox *) arg)->strings[
1738 (int) adj.get_value()].c_str());
1741 void
1742 ARDOUR_UI::engine_stopped ()
1744 ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::engine_stopped));
1745 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1746 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1749 void
1750 ARDOUR_UI::engine_running ()
1752 ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::engine_running));
1753 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, true);
1754 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, false);
1756 Glib::RefPtr<Action> action;
1757 const char* action_name = 0;
1759 switch (engine->frames_per_cycle()) {
1760 case 32:
1761 action_name = X_("JACKLatency32");
1762 break;
1763 case 64:
1764 action_name = X_("JACKLatency64");
1765 break;
1766 case 128:
1767 action_name = X_("JACKLatency128");
1768 break;
1769 case 512:
1770 action_name = X_("JACKLatency512");
1771 break;
1772 case 1024:
1773 action_name = X_("JACKLatency1024");
1774 break;
1775 case 2048:
1776 action_name = X_("JACKLatency2048");
1777 break;
1778 case 4096:
1779 action_name = X_("JACKLatency4096");
1780 break;
1781 case 8192:
1782 action_name = X_("JACKLatency8192");
1783 break;
1784 default:
1785 /* XXX can we do anything useful ? */
1786 break;
1789 if (action_name) {
1791 action = ActionManager::get_action (X_("JACK"), action_name);
1793 if (action) {
1794 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (action);
1795 ract->set_active ();
1800 void
1801 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
1803 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
1804 /* we can't rely on the original string continuing to exist when we are called
1805 again in the GUI thread, so make a copy and note that we need to
1806 free it later.
1808 char *copy = strdup (reason);
1809 Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun (*this, &ARDOUR_UI::engine_halted), copy, true));
1810 return;
1813 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1814 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1816 update_sample_rate (0);
1818 string msgstr;
1820 /* if the reason is a non-empty string, it means that the backend was shutdown
1821 rather than just Ardour.
1824 if (strlen (reason)) {
1825 msgstr = string_compose (_("The audio backend (JACK) was shutdown because:\n\n%1"), reason);
1826 } else {
1827 msgstr = _("\
1828 JACK has either been shutdown or it\n\
1829 disconnected Ardour because Ardour\n\
1830 was not fast enough. Try to restart\n\
1831 JACK, reconnect and save the session.");
1834 MessageDialog msg (*editor, msgstr);
1835 pop_back_splash ();
1836 msg.run ();
1838 if (free_reason) {
1839 free ((char *) reason);
1843 int32_t
1844 ARDOUR_UI::do_engine_start ()
1846 try {
1847 engine->start();
1850 catch (...) {
1851 engine->stop ();
1852 error << _("Unable to start the session running")
1853 << endmsg;
1854 unload_session ();
1855 return -2;
1858 return 0;
1861 void
1862 ARDOUR_UI::setup_theme ()
1864 theme_manager->setup_theme();
1867 void
1868 ARDOUR_UI::update_clocks ()
1870 if (!editor || !editor->dragging_playhead()) {
1871 Clock (session->audible_frame(), false, editor->get_preferred_edit_position()); /* EMIT_SIGNAL */
1875 void
1876 ARDOUR_UI::start_clocking ()
1878 clock_signal_connection = RapidScreenUpdate.connect (mem_fun(*this, &ARDOUR_UI::update_clocks));
1881 void
1882 ARDOUR_UI::stop_clocking ()
1884 clock_signal_connection.disconnect ();
1887 void
1888 ARDOUR_UI::toggle_clocking ()
1890 #if 0
1891 if (clock_button.get_active()) {
1892 start_clocking ();
1893 } else {
1894 stop_clocking ();
1896 #endif
1899 gint
1900 ARDOUR_UI::_blink (void *arg)
1903 ((ARDOUR_UI *) arg)->blink ();
1904 return TRUE;
1907 void
1908 ARDOUR_UI::blink ()
1910 Blink (blink_on = !blink_on); /* EMIT_SIGNAL */
1913 void
1914 ARDOUR_UI::start_blinking ()
1916 /* Start the blink signal. Everybody with a blinking widget
1917 uses Blink to drive the widget's state.
1920 if (blink_timeout_tag < 0) {
1921 blink_on = false;
1922 blink_timeout_tag = g_timeout_add (240, _blink, this);
1926 void
1927 ARDOUR_UI::stop_blinking ()
1929 if (blink_timeout_tag >= 0) {
1930 g_source_remove (blink_timeout_tag);
1931 blink_timeout_tag = -1;
1935 void
1936 ARDOUR_UI::name_io_setup (AudioEngine& engine,
1937 string& buf,
1938 IO& io,
1939 bool in)
1941 if (in) {
1942 if (io.n_inputs() == 0) {
1943 buf = _("none");
1944 return;
1947 /* XXX we're not handling multiple ports yet. */
1949 const char **connections = io.input(0)->get_connections();
1951 if (connections == 0 || connections[0] == '\0') {
1952 buf = _("off");
1953 } else {
1954 buf = connections[0];
1957 free (connections);
1959 } else {
1961 if (io.n_outputs() == 0) {
1962 buf = _("none");
1963 return;
1966 /* XXX we're not handling multiple ports yet. */
1968 const char **connections = io.output(0)->get_connections();
1970 if (connections == 0 || connections[0] == '\0') {
1971 buf = _("off");
1972 } else {
1973 buf = connections[0];
1976 free (connections);
1980 /** Ask the user for the name of a new shapshot and then take it.
1982 void
1983 ARDOUR_UI::snapshot_session (bool switch_to_it)
1985 ArdourPrompter prompter (true);
1986 string snapname;
1988 prompter.set_name ("Prompter");
1989 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1990 prompter.set_title (_("Take Snapshot"));
1991 prompter.set_prompt (_("Name of New Snapshot"));
1993 if (!switch_to_it) {
1994 char timebuf[128];
1995 time_t n;
1996 struct tm local_time;
1998 time (&n);
1999 localtime_r (&n, &local_time);
2000 strftime (timebuf, sizeof(timebuf), "%FT%T", &local_time);
2002 prompter.set_initial_text (timebuf);
2005 again:
2006 switch (prompter.run()) {
2007 case RESPONSE_ACCEPT:
2008 prompter.get_result (snapname);
2009 if (snapname.length()){
2010 if (snapname.find ('/') != string::npos) {
2011 MessageDialog msg (_("To ensure compatibility with various systems\n"
2012 "snapshot names may not contain a '/' character"));
2013 msg.run ();
2014 goto again;
2016 if (snapname.find ('\\') != string::npos) {
2017 MessageDialog msg (_("To ensure compatibility with various systems\n"
2018 "snapshot names may not contain a '\\' character"));
2019 msg.run ();
2020 goto again;
2022 save_state (snapname, switch_to_it);
2024 break;
2026 default:
2027 break;
2031 void
2032 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2034 (void) save_state_canfail (name, switch_to_it);
2038 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2040 if (session) {
2041 int ret;
2043 if (name.length() == 0) {
2044 name = session->snap_name();
2047 if ((ret = session->save_state (name, false, switch_to_it)) != 0) {
2048 return ret;
2051 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2052 return 0;
2055 void
2056 ARDOUR_UI::primary_clock_value_changed ()
2058 if (session) {
2059 session->request_locate (primary_clock.current_time ());
2063 void
2064 ARDOUR_UI::big_clock_value_changed ()
2066 if (session) {
2067 session->request_locate (big_clock.current_time ());
2071 void
2072 ARDOUR_UI::secondary_clock_value_changed ()
2074 if (session) {
2075 session->request_locate (secondary_clock.current_time ());
2079 void
2080 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2082 if (session == 0) {
2083 return;
2086 switch (session->record_status()) {
2087 case Session::Enabled:
2088 if (onoff) {
2089 rec_button.set_visual_state (2);
2090 } else {
2091 rec_button.set_visual_state (0);
2093 break;
2095 case Session::Recording:
2096 rec_button.set_visual_state (1);
2097 break;
2099 default:
2100 rec_button.set_visual_state (0);
2101 break;
2105 void
2106 ARDOUR_UI::save_template ()
2108 ArdourPrompter prompter (true);
2109 string name;
2111 if (!check_audioengine()) {
2112 return;
2115 prompter.set_name (X_("Prompter"));
2116 prompter.set_title (_("Save Mix Template"));
2117 prompter.set_prompt (_("Name for mix template:"));
2118 prompter.set_initial_text(session->name() + _("-template"));
2119 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2121 switch (prompter.run()) {
2122 case RESPONSE_ACCEPT:
2123 prompter.get_result (name);
2125 if (name.length()) {
2126 session->save_template (name);
2128 break;
2130 default:
2131 break;
2135 void
2136 ARDOUR_UI::fontconfig_dialog ()
2138 #if 0
2139 /* this issue seems to have gone away with changes to font handling in GTK/Quartz
2141 #ifdef GTKOSX
2142 /* X11 users will always have fontconfig info around, but new GTK-OSX users
2143 may not and it can take a while to build it. Warn them.
2146 Glib::ustring fontconfig = Glib::build_filename (Glib::get_home_dir(), ".fontconfig");
2148 if (!Glib::file_test (fontconfig, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_DIR)) {
2149 MessageDialog msg (*new_session_dialog,
2150 string_compose (_("Welcome to %1.\n\n"
2151 "The program will take a bit longer to start up\n"
2152 "while the system fonts are checked.\n\n"
2153 "This will only be done once, and you will\n"
2154 "not see this message again\n"), PROGRAM_NAME),
2155 true,
2156 Gtk::MESSAGE_INFO,
2157 Gtk::BUTTONS_OK);
2158 pop_back_splash ();
2159 msg.show_all ();
2160 msg.present ();
2161 msg.run ();
2163 #endif
2164 #endif
2167 void
2168 ARDOUR_UI::parse_cmdline_path (const Glib::ustring& cmdline_path, Glib::ustring& session_name, Glib::ustring& session_path, bool& existing_session)
2170 existing_session = false;
2172 if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_DIR)) {
2173 session_path = cmdline_path;
2174 existing_session = true;
2175 } else if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_REGULAR)) {
2176 session_path = Glib::path_get_dirname (string (cmdline_path));
2177 existing_session = true;
2178 } else {
2179 /* it doesn't exist, assume the best */
2180 session_path = Glib::path_get_dirname (string (cmdline_path));
2183 session_name = basename_nosuffix (string (cmdline_path));
2187 ARDOUR_UI::load_cmdline_session (const Glib::ustring& session_name, const Glib::ustring& session_path, bool& existing_session)
2189 /* when this is called, the backend audio system must be running */
2191 /* the main idea here is to deal with the fact that a cmdline argument for the session
2192 can be interpreted in different ways - it could be a directory or a file, and before
2193 we load, we need to know both the session directory and the snapshot (statefile) within it
2194 that we are supposed to use.
2197 if (session_name.length() == 0 || session_path.length() == 0) {
2198 return false;
2201 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_DIR)) {
2203 Glib::ustring predicted_session_file;
2205 predicted_session_file = Glib::build_filename (session_path, session_name + Session::statefile_suffix());
2207 if (Glib::file_test (predicted_session_file, Glib::FILE_TEST_EXISTS)) {
2208 existing_session = true;
2211 } else if (Glib::file_test (session_path, Glib::FILE_TEST_EXISTS)) {
2213 if (session_path.find (Session::statefile_suffix()) == session_path.length() - 7) {
2214 /* existing .ardour file */
2215 existing_session = true;
2218 } else {
2219 existing_session = false;
2222 /* lets just try to load it */
2224 if (create_engine ()) {
2225 backend_audio_error (false, new_session_dialog);
2226 return -1;
2229 return load_session (session_path, session_name);
2232 bool
2233 ARDOUR_UI::ask_about_loading_existing_session (const Glib::ustring& session_path)
2235 Glib::ustring str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2237 MessageDialog msg (str,
2238 false,
2239 Gtk::MESSAGE_WARNING,
2240 Gtk::BUTTONS_YES_NO,
2241 true);
2244 msg.set_name (X_("CleanupDialog"));
2245 msg.set_title (_("Cleanup Unused Sources"));
2246 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
2247 msg.set_position (Gtk::WIN_POS_MOUSE);
2248 pop_back_splash ();
2250 switch (msg.run()) {
2251 case RESPONSE_YES:
2252 return true;
2253 break;
2255 return false;
2259 ARDOUR_UI::build_session_from_nsd (const Glib::ustring& session_path, const Glib::ustring& session_name)
2262 uint32_t cchns;
2263 uint32_t mchns;
2264 AutoConnectOption iconnect;
2265 AutoConnectOption oconnect;
2266 uint32_t nphysin;
2267 uint32_t nphysout;
2269 if (Profile->get_sae()) {
2271 cchns = 0;
2272 mchns = 2;
2273 iconnect = AutoConnectPhysical;
2274 oconnect = AutoConnectMaster;
2275 nphysin = 0; // use all available
2276 nphysout = 0; // use all available
2278 } else {
2280 /* get settings from advanced section of NSD */
2282 if (new_session_dialog->create_control_bus()) {
2283 cchns = (uint32_t) new_session_dialog->control_channel_count();
2284 } else {
2285 cchns = 0;
2288 if (new_session_dialog->create_master_bus()) {
2289 mchns = (uint32_t) new_session_dialog->master_channel_count();
2290 } else {
2291 mchns = 0;
2294 if (new_session_dialog->connect_inputs()) {
2295 iconnect = AutoConnectPhysical;
2296 } else {
2297 iconnect = AutoConnectOption (0);
2300 /// @todo some minor tweaks.
2302 oconnect = AutoConnectOption (0);
2304 if (new_session_dialog->connect_outputs()) {
2305 if (new_session_dialog->connect_outs_to_master()) {
2306 oconnect = AutoConnectMaster;
2307 } else if (new_session_dialog->connect_outs_to_physical()) {
2308 oconnect = AutoConnectPhysical;
2312 nphysin = (uint32_t) new_session_dialog->input_limit_count();
2313 nphysout = (uint32_t) new_session_dialog->output_limit_count();
2316 if (build_session (session_path,
2317 session_name,
2318 cchns,
2319 mchns,
2320 iconnect,
2321 oconnect,
2322 nphysin,
2323 nphysout,
2324 engine->frame_rate() * 60 * 5)) {
2326 return -1;
2329 return 0;
2332 void
2333 ARDOUR_UI::end_loading_messages ()
2335 // hide_splash ();
2338 void
2339 ARDOUR_UI::loading_message (const std::string& msg)
2341 show_splash ();
2342 splash->message (msg);
2343 flush_pending ();
2346 void
2347 ARDOUR_UI::idle_load (const Glib::ustring& path)
2349 if (session) {
2350 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2351 /* /path/to/foo => /path/to/foo, foo */
2352 load_session (path, basename_nosuffix (path));
2353 } else {
2354 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2355 load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2357 } else {
2359 ARDOUR_COMMAND_LINE::session_name = path;
2361 if (new_session_dialog) {
2364 /* make it break out of Dialog::run() and
2365 start again.
2368 new_session_dialog->response (1);
2373 bool
2374 ARDOUR_UI::get_session_parameters (bool backend_audio_is_running, bool should_be_new)
2376 bool existing_session = false;
2377 Glib::ustring session_name;
2378 Glib::ustring session_path;
2379 Glib::ustring template_name;
2380 int response;
2382 begin:
2383 response = Gtk::RESPONSE_NONE;
2385 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
2387 parse_cmdline_path (ARDOUR_COMMAND_LINE::session_name, session_name, session_path, existing_session);
2389 /* don't ever reuse this */
2391 ARDOUR_COMMAND_LINE::session_name = string();
2393 if (existing_session && backend_audio_is_running) {
2395 /* just load the thing already */
2397 if (load_cmdline_session (session_name, session_path, existing_session) == 0) {
2398 return true;
2402 /* make the NSD use whatever information we have */
2404 new_session_dialog->set_session_name (session_name);
2405 new_session_dialog->set_session_folder (session_path);
2408 /* loading failed, or we need the NSD for something */
2410 new_session_dialog->set_modal (false);
2411 new_session_dialog->set_position (WIN_POS_CENTER);
2412 new_session_dialog->set_current_page (0);
2413 new_session_dialog->set_existing_session (existing_session);
2414 new_session_dialog->reset_recent();
2416 do {
2417 new_session_dialog->set_have_engine (backend_audio_is_running);
2418 new_session_dialog->present ();
2419 response = new_session_dialog->run ();
2421 _session_is_new = false;
2423 /* handle possible negative responses */
2425 switch (response) {
2426 case 1:
2427 /* sent by idle_load, meaning restart the whole process again */
2428 new_session_dialog->hide();
2429 new_session_dialog->reset();
2430 goto begin;
2431 break;
2433 case Gtk::RESPONSE_CANCEL:
2434 case Gtk::RESPONSE_DELETE_EVENT:
2435 if (!session) {
2436 if (engine && engine->running()) {
2437 engine->stop (true);
2439 quit();
2441 new_session_dialog->hide ();
2442 return false;
2444 case Gtk::RESPONSE_NONE:
2445 /* "Clear" was pressed */
2446 goto try_again;
2449 fontconfig_dialog();
2451 if (!backend_audio_is_running) {
2452 int ret = new_session_dialog->engine_control.setup_engine ();
2453 if (ret < 0) {
2454 return false;
2455 } else if (ret > 0) {
2456 response = Gtk::RESPONSE_REJECT;
2457 goto try_again;
2460 /* hide the NSD while we start up the engine */
2462 new_session_dialog->hide ();
2463 flush_pending ();
2466 if (create_engine ()) {
2468 backend_audio_error (!backend_audio_is_running, new_session_dialog);
2469 flush_pending ();
2471 new_session_dialog->set_existing_session (false);
2472 new_session_dialog->set_current_page (0); // new engine page
2473 new_session_dialog->engine_control.unset_interface_chosen ();
2475 response = Gtk::RESPONSE_NONE;
2476 goto try_again;
2479 backend_audio_is_running = true;
2481 if (response == Gtk::RESPONSE_OK) {
2483 session_name = new_session_dialog->session_name();
2485 if (session_name.empty()) {
2486 response = Gtk::RESPONSE_NONE;
2487 goto try_again;
2490 /* if the user mistakenly typed path information into the session filename entry,
2491 convert what they typed into a path & a name
2494 if (Glib::path_is_absolute (session_name) ||
2495 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
2496 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)) {
2498 session_path = Glib::path_get_dirname (session_name);
2499 session_name = Glib::path_get_basename (session_name);
2501 } else {
2503 session_path = new_session_dialog->session_folder();
2507 template_name = Glib::ustring();
2508 switch (new_session_dialog->which_page()) {
2510 case NewSessionDialog::OpenPage:
2511 goto loadit;
2512 break;
2514 case NewSessionDialog::EnginePage:
2515 if (new_session_dialog->engine_control.interface_chosen() && !session_path.empty()) {
2516 goto loadit;
2517 } else {
2518 goto try_again;
2520 break;
2522 case NewSessionDialog::NewPage: /* nominally the "new" session creator, but could be in use for an old session */
2524 should_be_new = true;
2526 if (session_name.find ('/') != Glib::ustring::npos) {
2527 MessageDialog msg (*new_session_dialog, _("To ensure compatibility with various systems\n"
2528 "session names may not contain a '/' character"));
2529 msg.run ();
2530 response = RESPONSE_NONE;
2531 goto try_again;
2534 if (session_name.find ('\\') != Glib::ustring::npos) {
2535 MessageDialog msg (*new_session_dialog, _("To ensure compatibility with various systems\n"
2536 "session names may not contain a '\\' character"));
2537 msg.run ();
2538 response = RESPONSE_NONE;
2539 goto try_again;
2542 //XXX This is needed because session constructor wants a
2543 //non-existant path. hopefully this will be fixed at some point.
2545 session_path = Glib::build_filename (session_path, session_name);
2547 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
2549 new_session_dialog->hide ();
2551 if (ask_about_loading_existing_session (session_path)) {
2552 goto loadit;
2553 } else {
2554 response = RESPONSE_NONE;
2555 goto try_again;
2559 _session_is_new = true;
2561 if (new_session_dialog->use_session_template()) {
2563 template_name = new_session_dialog->session_template_name();
2564 goto loadit;
2566 } else {
2567 if (build_session_from_nsd (session_path, session_name)) {
2568 response = RESPONSE_NONE;
2569 goto try_again;
2571 goto done;
2573 break;
2575 default:
2576 break;
2579 loadit:
2580 new_session_dialog->hide ();
2582 if (load_session (session_path, session_name, template_name)) {
2583 /* force a retry */
2584 response = Gtk::RESPONSE_NONE;
2587 try_again:
2588 if (response == Gtk::RESPONSE_NONE) {
2589 new_session_dialog->set_existing_session (false);
2590 new_session_dialog->reset ();
2594 } while (response == Gtk::RESPONSE_NONE || response == Gtk::RESPONSE_REJECT);
2596 done:
2597 show();
2598 new_session_dialog->hide();
2599 new_session_dialog->reset();
2600 goto_editor_window ();
2601 return true;
2604 void
2605 ARDOUR_UI::close_session ()
2607 if (!check_audioengine()) {
2608 return;
2611 if (unload_session (true)) {
2612 return;
2615 get_session_parameters (true, false);
2619 ARDOUR_UI::load_session (const Glib::ustring& path, const Glib::ustring& snap_name, Glib::ustring mix_template)
2621 Session *new_session;
2622 int unload_status;
2623 int retval = -1;
2625 session_loaded = false;
2627 if (!check_audioengine()) {
2628 return -1;
2631 unload_status = unload_session ();
2633 if (unload_status < 0) {
2634 goto out;
2635 } else if (unload_status > 0) {
2636 retval = 0;
2637 goto out;
2640 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
2642 try {
2643 new_session = new Session (*engine, path, snap_name, mix_template);
2646 /* this one is special */
2648 catch (AudioEngine::PortRegistrationFailure& err) {
2650 MessageDialog msg (err.what(),
2651 true,
2652 Gtk::MESSAGE_INFO,
2653 Gtk::BUTTONS_CLOSE);
2655 msg.set_title (_("Port Registration Error"));
2656 msg.set_secondary_text (_("Click the Close button to try again."));
2657 msg.set_position (Gtk::WIN_POS_CENTER);
2658 pop_back_splash ();
2659 msg.present ();
2661 int response = msg.run ();
2663 msg.hide ();
2665 switch (response) {
2666 case RESPONSE_CANCEL:
2667 exit (1);
2668 default:
2669 break;
2671 goto out;
2674 /* this exception is also special */
2676 catch (Session::SRMismatchRejected& err) {
2677 goto out; /* just go back and reload something else, etc. */
2680 catch (...) {
2682 MessageDialog msg (string_compose(_("Session \"%1 (snapshot %2)\" did not load successfully"), path, snap_name),
2683 true,
2684 Gtk::MESSAGE_INFO,
2685 Gtk::BUTTONS_CLOSE);
2687 msg.set_title (_("Loading Error"));
2688 msg.set_secondary_text (_("Click the Close button to try again."));
2689 msg.set_position (Gtk::WIN_POS_CENTER);
2690 pop_back_splash ();
2691 msg.present ();
2693 int response = msg.run ();
2695 msg.hide ();
2697 switch (response) {
2698 case RESPONSE_CANCEL:
2699 exit (1);
2700 default:
2701 break;
2703 goto out;
2706 /* Now the session been created, add the transport controls */
2707 new_session->add_controllable(&roll_controllable);
2708 new_session->add_controllable(&stop_controllable);
2709 new_session->add_controllable(&goto_start_controllable);
2710 new_session->add_controllable(&goto_end_controllable);
2711 new_session->add_controllable(&auto_loop_controllable);
2712 new_session->add_controllable(&play_selection_controllable);
2713 new_session->add_controllable(&rec_controllable);
2715 /* Once the transport controlls have been added, the ControlProtocolManager
2716 is okay to instantiate the various protocols. */
2717 BootMessage (_("Reset Control Protocols"));
2718 ControlProtocolManager::instance().set_session (*new_session);
2720 connect_to_session (new_session);
2722 Config->set_current_owner (ConfigVariableBase::Interface);
2724 session_loaded = true;
2726 goto_editor_window ();
2728 if (session) {
2729 session->set_clean ();
2732 flush_pending ();
2733 retval = 0;
2735 out:
2736 return retval;
2740 ARDOUR_UI::build_session (const Glib::ustring& path, const Glib::ustring& snap_name,
2741 uint32_t control_channels,
2742 uint32_t master_channels,
2743 AutoConnectOption input_connect,
2744 AutoConnectOption output_connect,
2745 uint32_t nphysin,
2746 uint32_t nphysout,
2747 nframes_t initial_length)
2749 Session *new_session;
2750 int x;
2752 if (!check_audioengine()) {
2753 return -1;
2756 session_loaded = false;
2758 x = unload_session ();
2760 if (x < 0) {
2761 return -1;
2762 } else if (x > 0) {
2763 return 0;
2766 _session_is_new = true;
2768 try {
2769 new_session = new Session (*engine, path, snap_name, input_connect, output_connect,
2770 control_channels, master_channels, nphysin, nphysout, initial_length);
2773 catch (...) {
2775 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
2776 pop_back_splash ();
2777 msg.run ();
2778 return -1;
2781 connect_to_session (new_session);
2783 session_loaded = true;
2785 new_session->save_state(new_session->name());
2787 return 0;
2790 void
2791 ARDOUR_UI::show ()
2793 if (editor) {
2794 editor->show_window ();
2796 if (!shown_flag) {
2797 editor->present ();
2800 shown_flag = true;
2804 void
2805 ARDOUR_UI::show_about ()
2807 if (about == 0) {
2808 about = new About;
2809 about->signal_response().connect(mem_fun (*this, &ARDOUR_UI::about_signal_response) );
2812 about->set_transient_for(*editor);
2814 about->show_all ();
2817 void
2818 ARDOUR_UI::launch_chat ()
2820 #ifdef __APPLE__
2821 NagScreen::open_uri("http://webchat.freenode.net/?channels=ardour-osx");
2822 #else
2823 NagScreen::open_uri("http://webchat.freenode.net/?channels=ardour");
2824 #endif
2827 void
2828 ARDOUR_UI::launch_manual ()
2830 NagScreen::open_uri("http://ardour.org/flossmanual");
2833 void
2834 ARDOUR_UI::launch_reference ()
2836 NagScreen::open_uri("http://ardour.org/refmanual");
2839 void
2840 ARDOUR_UI::hide_about ()
2842 if (about) {
2843 about->get_window()->set_cursor ();
2844 about->hide ();
2848 void
2849 ARDOUR_UI::about_signal_response(int response)
2851 hide_about();
2854 void
2855 ARDOUR_UI::show_splash ()
2857 if (splash == 0) {
2858 try {
2859 splash = new Splash;
2860 } catch (...) {
2861 return;
2865 splash->show ();
2866 splash->present ();
2867 splash->queue_draw ();
2868 splash->get_window()->process_updates (true);
2869 flush_pending ();
2872 void
2873 ARDOUR_UI::hide_splash ()
2875 if (splash) {
2876 splash->hide();
2880 void
2881 ARDOUR_UI::display_cleanup_results (Session::cleanup_report& rep, const gchar* list_title,
2882 const string& plural_msg, const string& singular_msg)
2884 size_t removed;
2886 removed = rep.paths.size();
2888 if (removed == 0) {
2889 MessageDialog msgd (*editor,
2890 _("No audio files were ready for cleanup"),
2891 true,
2892 Gtk::MESSAGE_INFO,
2893 (Gtk::ButtonsType)(Gtk::BUTTONS_OK) );
2894 msgd.set_secondary_text (_("If this seems suprising, \n\
2895 check for any existing snapshots.\n\
2896 These may still include regions that\n\
2897 require some unused files to continue to exist."));
2899 msgd.run ();
2900 return;
2903 ArdourDialog results (_("ardour: cleanup"), true, false);
2905 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
2906 CleanupResultsModelColumns() {
2907 add (visible_name);
2908 add (fullpath);
2910 Gtk::TreeModelColumn<Glib::ustring> visible_name;
2911 Gtk::TreeModelColumn<Glib::ustring> fullpath;
2915 CleanupResultsModelColumns results_columns;
2916 Glib::RefPtr<Gtk::ListStore> results_model;
2917 Gtk::TreeView results_display;
2919 results_model = ListStore::create (results_columns);
2920 results_display.set_model (results_model);
2921 results_display.append_column (list_title, results_columns.visible_name);
2923 results_display.set_name ("CleanupResultsList");
2924 results_display.set_headers_visible (true);
2925 results_display.set_headers_clickable (false);
2926 results_display.set_reorderable (false);
2928 Gtk::ScrolledWindow list_scroller;
2929 Gtk::Label txt;
2930 Gtk::VBox dvbox;
2931 Gtk::HBox dhbox; // the hbox for the image and text
2932 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
2933 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
2935 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
2938 /* subst:
2939 %1 - number of files removed
2940 %2 - location of "dead_sounds"
2941 %3 - size of files affected
2942 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
2945 const char* bprefix;
2946 float space_adjusted;
2948 if (rep.space < 1000000.0f) {
2949 bprefix = X_("kilo");
2950 space_adjusted = truncf((float)rep.space / 1000.0f);
2951 } else if (rep.space < (1000000.0f * 1000)) {
2952 bprefix = X_("mega");
2953 space_adjusted = truncf((float)rep.space / (1000000.0f));
2954 } else {
2955 bprefix = X_("giga");
2956 space_adjusted = truncf((float)rep.space / (1000000.0f * 1000));
2959 if (removed > 1) {
2960 txt.set_text (string_compose (plural_msg, removed, session->path() + "dead_sounds", space_adjusted, bprefix));
2961 } else {
2962 txt.set_text (string_compose (singular_msg, removed, session->path() + "dead_sounds", space_adjusted, bprefix));
2965 dhbox.pack_start (*dimage, true, false, 5);
2966 dhbox.pack_start (txt, true, false, 5);
2968 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
2969 TreeModel::Row row = *(results_model->append());
2970 row[results_columns.visible_name] = *i;
2971 row[results_columns.fullpath] = *i;
2974 list_scroller.add (results_display);
2975 list_scroller.set_size_request (-1, 150);
2976 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
2978 dvbox.pack_start (dhbox, true, false, 5);
2979 dvbox.pack_start (list_scroller, true, false, 5);
2980 ddhbox.pack_start (dvbox, true, false, 5);
2982 results.get_vbox()->pack_start (ddhbox, true, false, 5);
2983 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
2984 results.set_default_response (RESPONSE_CLOSE);
2985 results.set_position (Gtk::WIN_POS_MOUSE);
2986 results.show_all_children ();
2987 results.set_resizable (false);
2989 results.run ();
2993 void
2994 ARDOUR_UI::cleanup ()
2996 if (session == 0) {
2997 /* shouldn't happen: menu item is insensitive */
2998 return;
3002 MessageDialog checker (_("Are you sure you want to cleanup?"),
3003 true,
3004 Gtk::MESSAGE_QUESTION,
3005 (Gtk::ButtonsType)(Gtk::BUTTONS_NONE));
3007 checker.set_secondary_text(_("Cleanup is a destructive operation.\n\
3008 ALL undo/redo information will be lost if you cleanup.\n\
3009 After cleanup, unused audio files will be moved to a \
3010 \"dead sounds\" location."));
3012 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3013 checker.add_button (_("Clean Up"), RESPONSE_ACCEPT);
3014 checker.set_default_response (RESPONSE_CANCEL);
3016 checker.set_name (_("CleanupDialog"));
3017 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3018 checker.set_position (Gtk::WIN_POS_MOUSE);
3020 switch (checker.run()) {
3021 case RESPONSE_ACCEPT:
3022 break;
3023 default:
3024 return;
3027 Session::cleanup_report rep;
3029 editor->prepare_for_cleanup ();
3031 /* do not allow flush until a session is reloaded */
3033 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3034 if (act) {
3035 act->set_sensitive (false);
3038 if (session->cleanup_sources (rep)) {
3039 editor->finish_cleanup ();
3040 return;
3043 editor->finish_cleanup ();
3045 checker.hide();
3046 display_cleanup_results (rep,
3047 _("cleaned files"),
3048 _("\
3049 The following %1 files were not in use and \n\
3050 have been moved to:\n\
3051 %2. \n\n\
3052 Flushing the wastebasket will \n\
3053 release an additional\n\
3054 %3 %4bytes of disk space.\n"),
3055 _("\
3056 The following file was not in use and \n \
3057 has been moved to:\n \
3058 %2. \n\n\
3059 Flushing the wastebasket will \n\
3060 release an additional\n\
3061 %3 %4bytes of disk space.\n"
3066 void
3067 ARDOUR_UI::flush_trash ()
3069 if (session == 0) {
3070 /* shouldn't happen: menu item is insensitive */
3071 return;
3074 Session::cleanup_report rep;
3076 if (session->cleanup_trash_sources (rep)) {
3077 return;
3080 display_cleanup_results (rep,
3081 _("deleted file"),
3082 _("The following %1 files were deleted from\n\
3083 %2,\n\
3084 releasing %3 %4bytes of disk space"),
3085 _("The following file was deleted from\n\
3086 %2,\n\
3087 releasing %3 %4bytes of disk space"));
3090 void
3091 ARDOUR_UI::add_route (Gtk::Window* float_window)
3093 int count;
3095 if (!session) {
3096 return;
3099 if (add_route_dialog == 0) {
3100 add_route_dialog = new AddRouteDialog;
3101 if (float_window) {
3102 add_route_dialog->set_transient_for (*float_window);
3106 if (add_route_dialog->is_visible()) {
3107 /* we're already doing this */
3108 return;
3111 ResponseType r = (ResponseType) add_route_dialog->run ();
3113 add_route_dialog->hide();
3115 switch (r) {
3116 case RESPONSE_ACCEPT:
3117 break;
3118 default:
3119 return;
3120 break;
3123 if ((count = add_route_dialog->count()) <= 0) {
3124 return;
3127 string template_path = add_route_dialog->track_template();
3129 if (!template_path.empty()) {
3130 session->new_route_from_template (count, template_path);
3131 return;
3134 uint32_t input_chan = add_route_dialog->channels ();
3135 uint32_t output_chan;
3136 string name_template = add_route_dialog->name_template ();
3137 bool track = add_route_dialog->track ();
3139 AutoConnectOption oac = Config->get_output_auto_connect();
3141 if (oac & AutoConnectMaster) {
3142 output_chan = (session->master_out() ? session->master_out()->n_inputs() : input_chan);
3143 } else {
3144 output_chan = input_chan;
3147 /* XXX do something with name template */
3149 if (track) {
3150 session_add_audio_track (input_chan, output_chan, add_route_dialog->mode(), count);
3151 } else {
3152 session_add_audio_bus (input_chan, output_chan, count);
3156 XMLNode*
3157 ARDOUR_UI::mixer_settings () const
3159 XMLNode* node = 0;
3161 if (session) {
3162 node = session->instant_xml(X_("Mixer"), session->path());
3163 } else {
3164 node = Config->instant_xml(X_("Mixer"), get_user_ardour_path());
3167 if (!node) {
3168 node = new XMLNode (X_("Mixer"));
3171 return node;
3174 XMLNode*
3175 ARDOUR_UI::editor_settings () const
3177 XMLNode* node = 0;
3179 if (session) {
3180 node = session->instant_xml(X_("Editor"), session->path());
3181 } else {
3182 node = Config->instant_xml(X_("Editor"), get_user_ardour_path());
3185 if (!node) {
3186 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
3187 node = Config->instant_xml(X_("Editor"), getenv("ARDOUR_INSTANT_XML_PATH"));
3191 if (!node) {
3192 node = new XMLNode (X_("Editor"));
3194 return node;
3197 XMLNode*
3198 ARDOUR_UI::keyboard_settings () const
3200 XMLNode* node = 0;
3202 node = Config->extra_xml(X_("Keyboard"));
3204 if (!node) {
3205 node = new XMLNode (X_("Keyboard"));
3207 return node;
3210 void
3211 ARDOUR_UI::create_xrun_marker(nframes_t where)
3213 editor->mouse_add_new_marker (where, false, true);
3216 void
3217 ARDOUR_UI::halt_on_xrun_message ()
3219 MessageDialog msg (*editor,
3220 _("Recording was stopped because your system could not keep up."));
3221 msg.run ();
3224 void
3225 ARDOUR_UI::xrun_handler(nframes_t where)
3227 if (!session) {
3228 return;
3231 ENSURE_GUI_THREAD (bind(mem_fun(*this, &ARDOUR_UI::xrun_handler), where));
3233 if (session && Config->get_create_xrun_marker() && session->actively_recording()) {
3234 create_xrun_marker(where);
3237 if (session && Config->get_stop_recording_on_xrun() && session->actively_recording()) {
3238 halt_on_xrun_message ();
3242 bool
3243 ARDOUR_UI::preset_file_exists_handler ()
3245 /* if driven from another thread, say "do not overwrite" and show the user nothing.
3248 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) { \
3249 return false;
3252 HBox* hbox = new HBox();
3253 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3254 Gtk::Dialog dialog (_("Preset Exists"), true, false);
3255 Label message (_("\
3256 A preset with this name already exists for this plugin.\n\
3258 What you would like to do?\n"));
3259 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3260 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3261 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3262 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3263 dialog.add_button (_("Overwrite the existing preset"), RESPONSE_ACCEPT);
3264 dialog.add_button (_("Leave the existing preset alone"), RESPONSE_REJECT);
3265 dialog.set_default_response (RESPONSE_ACCEPT);
3266 dialog.set_position (WIN_POS_MOUSE);
3267 dialog.set_type_hint (Gdk::WINDOW_TYPE_HINT_UTILITY); // need to make it float above the preset name dialog
3269 message.show();
3270 image->show();
3271 hbox->show();
3273 switch (dialog.run ()) {
3274 case RESPONSE_ACCEPT:
3275 return true;
3276 default:
3277 return false;
3281 void
3282 ARDOUR_UI::disk_overrun_handler ()
3285 ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::disk_overrun_handler));
3287 if (!have_disk_speed_dialog_displayed) {
3288 have_disk_speed_dialog_displayed = true;
3289 MessageDialog* msg = new MessageDialog (*editor, _("\
3290 The disk system on your computer\n\
3291 was not able to keep up with Ardour.\n\
3293 Specifically, it failed to write data to disk\n\
3294 quickly enough to keep up with recording.\n"));
3295 msg->signal_response().connect (bind (mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3296 msg->show_all ();
3300 void
3301 ARDOUR_UI::disk_underrun_handler ()
3304 ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::disk_underrun_handler));
3306 if (!have_disk_speed_dialog_displayed) {
3307 have_disk_speed_dialog_displayed = true;
3308 MessageDialog* msg = new MessageDialog (*editor,
3309 _("The disk system on your computer\n\
3310 was not able to keep up with Ardour.\n\
3312 Specifically, it failed to read data from disk\n\
3313 quickly enough to keep up with playback.\n"));
3314 msg->signal_response().connect (bind (mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3315 msg->show_all ();
3319 void
3320 ARDOUR_UI::disk_speed_dialog_gone (int ignored_response, MessageDialog* msg)
3322 have_disk_speed_dialog_displayed = false;
3323 delete msg;
3326 void
3327 ARDOUR_UI::session_dialog (std::string msg)
3329 ENSURE_GUI_THREAD (bind (mem_fun(*this, &ARDOUR_UI::session_dialog), msg));
3331 MessageDialog* d;
3333 if (editor) {
3334 d = new MessageDialog (*editor, msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3335 } else {
3336 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3339 d->show_all ();
3340 d->run ();
3341 delete d;
3345 ARDOUR_UI::pending_state_dialog ()
3347 HBox* hbox = new HBox();
3348 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3349 ArdourDialog dialog (_("Crash Recovery"), true);
3350 Label message (_("\
3351 This session appears to have been in\n\
3352 middle of recording when ardour or\n\
3353 the computer was shutdown.\n\
3355 Ardour can recover any captured audio for\n\
3356 you, or it can ignore it. Please decide\n\
3357 what you would like to do.\n"));
3358 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3359 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3360 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3361 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3362 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
3363 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
3364 dialog.set_default_response (RESPONSE_ACCEPT);
3365 dialog.set_position (WIN_POS_CENTER);
3366 message.show();
3367 image->show();
3368 hbox->show();
3370 pop_back_splash ();
3372 switch (dialog.run ()) {
3373 case RESPONSE_ACCEPT:
3374 return 1;
3375 default:
3376 return 0;
3381 ARDOUR_UI::sr_mismatch_dialog (nframes_t desired, nframes_t actual)
3383 HBox* hbox = new HBox();
3384 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3385 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
3386 Label message (string_compose (_("\
3387 This session was created with a sample rate of %1 Hz\n\
3389 The audioengine is currently running at %2 Hz\n"), desired, actual));
3391 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3392 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3393 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3394 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3395 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
3396 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
3397 dialog.set_default_response (RESPONSE_ACCEPT);
3398 dialog.set_position (WIN_POS_CENTER);
3399 message.show();
3400 image->show();
3401 hbox->show();
3403 switch (dialog.run ()) {
3404 case RESPONSE_ACCEPT:
3405 return 0;
3406 default:
3407 return 1;
3412 void
3413 ARDOUR_UI::disconnect_from_jack ()
3415 if (engine) {
3416 if( engine->disconnect_from_jack ()) {
3417 MessageDialog msg (*editor, _("Could not disconnect from JACK"));
3418 msg.run ();
3421 update_sample_rate (0);
3425 void
3426 ARDOUR_UI::reconnect_to_jack ()
3428 if (engine) {
3429 if (engine->reconnect_to_jack ()) {
3430 MessageDialog msg (*editor, _("Could not reconnect to JACK"));
3431 msg.run ();
3434 update_sample_rate (0);
3438 void
3439 ARDOUR_UI::use_config ()
3441 Glib::RefPtr<Action> act;
3443 switch (Config->get_native_file_data_format ()) {
3444 case FormatFloat:
3445 act = ActionManager::get_action (X_("options"), X_("FileDataFormatFloat"));
3446 break;
3447 case FormatInt24:
3448 act = ActionManager::get_action (X_("options"), X_("FileDataFormat24bit"));
3449 break;
3450 case FormatInt16:
3451 act = ActionManager::get_action (X_("options"), X_("FileDataFormat16bit"));
3452 break;
3455 if (act) {
3456 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic(act);
3457 ract->set_active ();
3460 switch (Config->get_native_file_header_format ()) {
3461 case BWF:
3462 act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatBWF"));
3463 break;
3464 case WAVE:
3465 act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatWAVE"));
3466 break;
3467 case WAVE64:
3468 act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatWAVE64"));
3469 break;
3470 case iXML:
3471 act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatiXML"));
3472 break;
3473 case RF64:
3474 act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatRF64"));
3475 break;
3476 case CAF:
3477 act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatCAF"));
3478 break;
3479 case AIFF:
3480 act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatAIFF"));
3481 break;
3484 if (act) {
3485 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic(act);
3486 ract->set_active ();
3489 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
3490 if (node) {
3491 set_transport_controllable_state (*node);
3495 void
3496 ARDOUR_UI::update_transport_clocks (nframes_t pos)
3498 if (Config->get_primary_clock_delta_edit_cursor()) {
3499 primary_clock.set (pos, false, editor->get_preferred_edit_position(), 1);
3500 } else {
3501 primary_clock.set (pos, 0, true);
3504 if (Config->get_secondary_clock_delta_edit_cursor()) {
3505 secondary_clock.set (pos, false, editor->get_preferred_edit_position(), 2);
3506 } else {
3507 secondary_clock.set (pos);
3510 if (big_clock_window) {
3511 big_clock.set (pos);
3515 void
3516 ARDOUR_UI::record_state_changed ()
3518 ENSURE_GUI_THREAD (mem_fun (*this, &ARDOUR_UI::record_state_changed));
3520 if (!session || !big_clock_window) {
3521 /* why bother - the clock isn't visible */
3522 return;
3525 switch (session->record_status()) {
3526 case Session::Recording:
3527 big_clock.set_widget_name ("BigClockRecording");
3528 break;
3529 default:
3530 big_clock.set_widget_name ("BigClockNonRecording");
3531 break;
3535 bool
3536 ARDOUR_UI::first_idle ()
3538 if (session) {
3539 session->allow_auto_play (true);
3542 if (editor) {
3543 editor->first_idle();
3546 Keyboard::set_can_save_keybindings (true);
3547 return false;
3550 void
3551 ARDOUR_UI::store_clock_modes ()
3553 XMLNode* node = new XMLNode(X_("ClockModes"));
3555 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
3556 node->add_property ((*x)->name().c_str(), enum_2_string ((*x)->mode()));
3559 session->add_extra_xml (*node);
3560 session->set_dirty ();
3565 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
3566 : Controllable (name), ui (u), type(tp)
3571 void
3572 ARDOUR_UI::TransportControllable::set_value (float val)
3574 if (type == ShuttleControl) {
3575 double fract;
3577 if (val == 0.5f) {
3578 fract = 0.0;
3579 } else {
3580 if (val < 0.5f) {
3581 fract = -((0.5f - val)/0.5f);
3582 } else {
3583 fract = ((val - 0.5f)/0.5f);
3587 ui.set_shuttle_fract (fract);
3588 return;
3591 if (val < 0.5f) {
3592 /* do nothing: these are radio-style actions */
3593 return;
3596 const char *action = 0;
3598 switch (type) {
3599 case Roll:
3600 action = X_("Roll");
3601 break;
3602 case Stop:
3603 action = X_("Stop");
3604 break;
3605 case GotoStart:
3606 action = X_("Goto Start");
3607 break;
3608 case GotoEnd:
3609 action = X_("Goto End");
3610 break;
3611 case AutoLoop:
3612 action = X_("Loop");
3613 break;
3614 case PlaySelection:
3615 action = X_("Play Selection");
3616 break;
3617 case RecordEnable:
3618 action = X_("Record");
3619 break;
3620 default:
3621 break;
3624 if (action == 0) {
3625 return;
3628 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
3630 if (act) {
3631 act->activate ();
3635 float
3636 ARDOUR_UI::TransportControllable::get_value (void) const
3638 float val = 0.0f;
3640 switch (type) {
3641 case Roll:
3642 break;
3643 case Stop:
3644 break;
3645 case GotoStart:
3646 break;
3647 case GotoEnd:
3648 break;
3649 case AutoLoop:
3650 break;
3651 case PlaySelection:
3652 break;
3653 case RecordEnable:
3654 break;
3655 case ShuttleControl:
3656 break;
3657 default:
3658 break;
3661 return val;
3664 void
3665 ARDOUR_UI::TransportControllable::set_id (const string& str)
3667 _id = str;
3670 void
3671 ARDOUR_UI::setup_profile ()
3673 if (gdk_screen_width() < 1200) {
3674 Profile->set_small_screen ();
3677 if (getenv ("ARDOUR_SAE")) {
3678 Profile->set_sae ();
3679 Profile->set_single_package ();
3684 void
3685 ARDOUR_UI::toggle_translations ()
3687 using namespace Glib;
3689 RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("EnableTranslation"));
3690 if (act) {
3691 RefPtr<ToggleAction> ract = RefPtr<ToggleAction>::cast_dynamic (act);
3692 if (ract) {
3694 string i18n_killer = ARDOUR::translation_kill_path();
3696 bool already_enabled = !ARDOUR::translations_are_disabled ();
3698 if (ract->get_active ()) {
3699 /* we don't care about errors */
3700 int fd = ::open (i18n_killer.c_str(), O_RDONLY|O_CREAT, 0644);
3701 close (fd);
3702 } else {
3703 /* we don't care about errors */
3704 unlink (i18n_killer.c_str());
3707 if (already_enabled != ract->get_active()) {
3708 MessageDialog win (already_enabled ? _("Translations disabled") : _("Translations enabled"),
3709 false,
3710 Gtk::MESSAGE_WARNING,
3711 Gtk::BUTTONS_OK);
3712 win.set_secondary_text (string_compose (_("You must restart %1 for this to take effect."), PROGRAM_NAME));
3713 win.set_position (Gtk::WIN_POS_CENTER);
3714 win.present ();
3715 win.run ();