increase threshold for drag-playhead-does-vertical-zoom
[ardour2.git] / gtk2_ardour / ardour_ui.cc
blob0418119c397ddac08542573c435c23639ffeb222
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 #ifdef WAF_BUILD
21 #include "gtk2ardour-config.h"
22 #endif
24 #include <stdint.h>
26 #include <algorithm>
27 #include <cmath>
28 #include <fcntl.h>
29 #include <signal.h>
30 #include <unistd.h>
31 #include <time.h>
32 #include <cerrno>
33 #include <fstream>
35 #include <iostream>
37 #include <sys/resource.h>
39 #include <gtkmm/messagedialog.h>
40 #include <gtkmm/accelmap.h>
42 #include "pbd/error.h"
43 #include "pbd/basename.h"
44 #include "pbd/compose.h"
45 #include "pbd/failed_constructor.h"
46 #include "pbd/enumwriter.h"
47 #include "pbd/memento_command.h"
48 #include "pbd/openuri.h"
49 #include "pbd/file_utils.h"
51 #include "gtkmm2ext/application.h"
52 #include "gtkmm2ext/bindings.h"
53 #include "gtkmm2ext/gtk_ui.h"
54 #include "gtkmm2ext/utils.h"
55 #include "gtkmm2ext/click_box.h"
56 #include "gtkmm2ext/fastmeter.h"
57 #include "gtkmm2ext/popup.h"
58 #include "gtkmm2ext/window_title.h"
60 #include "midi++/manager.h"
62 #include "ardour/ardour.h"
63 #include "ardour/callback.h"
64 #include "ardour/profile.h"
65 #include "ardour/session_directory.h"
66 #include "ardour/session_route.h"
67 #include "ardour/session_state_utils.h"
68 #include "ardour/session_utils.h"
69 #include "ardour/port.h"
70 #include "ardour/audioengine.h"
71 #include "ardour/playlist.h"
72 #include "ardour/utils.h"
73 #include "ardour/audio_diskstream.h"
74 #include "ardour/audiofilesource.h"
75 #include "ardour/recent_sessions.h"
76 #include "ardour/port.h"
77 #include "ardour/audio_track.h"
78 #include "ardour/midi_track.h"
79 #include "ardour/filesystem_paths.h"
80 #include "ardour/filename_extensions.h"
82 typedef uint64_t microseconds_t;
84 #include "about.h"
85 #include "actions.h"
86 #include "add_route_dialog.h"
87 #include "ambiguous_file_dialog.h"
88 #include "ardour_ui.h"
89 #include "audio_clock.h"
90 #include "bundle_manager.h"
91 #include "engine_dialog.h"
92 #include "gain_meter.h"
93 #include "global_port_matrix.h"
94 #include "gui_thread.h"
95 #include "keyboard.h"
96 #include "location_ui.h"
97 #include "missing_file_dialog.h"
98 #include "missing_plugin_dialog.h"
99 #include "mixer_ui.h"
100 #include "opts.h"
101 #include "processor_box.h"
102 #include "prompter.h"
103 #include "public_editor.h"
104 #include "route_time_axis.h"
105 #include "session_metadata_dialog.h"
106 #include "shuttle_control.h"
107 #include "speaker_dialog.h"
108 #include "splash.h"
109 #include "startup.h"
110 #include "theme_manager.h"
111 #include "time_axis_view_item.h"
112 #include "utils.h"
113 #include "window_proxy.h"
115 #include "i18n.h"
117 using namespace ARDOUR;
118 using namespace PBD;
119 using namespace Gtkmm2ext;
120 using namespace Gtk;
122 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
123 UIConfiguration *ARDOUR_UI::ui_config = 0;
125 sigc::signal<void,bool> ARDOUR_UI::Blink;
126 sigc::signal<void> ARDOUR_UI::RapidScreenUpdate;
127 sigc::signal<void> ARDOUR_UI::SuperRapidScreenUpdate;
128 sigc::signal<void, framepos_t, bool, framepos_t> ARDOUR_UI::Clock;
130 bool could_be_a_valid_path (const string& path);
132 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[])
134 : Gtkmm2ext::UI (PROGRAM_NAME, argcp, argvp)
136 , primary_clock (new AudioClock (X_("primary"), false, X_("TransportClockDisplay"), true, true, false, true))
137 , secondary_clock (new AudioClock (X_("secondary"), false, X_("SecondaryClockDisplay"), true, true, false, true))
138 , preroll_clock (new AudioClock (X_("preroll"), false, X_("PreRollClock"), true, false, true))
139 , postroll_clock (new AudioClock (X_("postroll"), false, X_("PostRollClock"), true, false, true))
141 /* preroll stuff */
143 , preroll_button (_("pre\nroll"))
144 , postroll_button (_("post\nroll"))
146 /* big clock */
148 , big_clock (new AudioClock (X_("bigclock"), false, "BigClockNonRecording", true, true, false, false))
150 /* transport */
152 , roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll))
153 , stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop))
154 , goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart))
155 , goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd))
156 , auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop))
157 , play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection))
158 , rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable))
160 , roll_button (roll_controllable)
161 , stop_button (stop_controllable)
162 , goto_start_button (goto_start_controllable)
163 , goto_end_button (goto_end_controllable)
164 , auto_loop_button (auto_loop_controllable)
165 , play_selection_button (play_selection_controllable)
166 , rec_button (rec_controllable)
168 , auto_return_button (_("Auto Return"))
169 , auto_play_button (_("Auto Play"))
170 , auto_input_button (_("Auto Input"))
171 // , click_button (_("Click"))
172 , time_master_button (_("time\nmaster"))
174 , auditioning_alert_button (_("AUDITION"))
175 , solo_alert_button (_("SOLO"))
177 , error_log_button (_("Errors"))
180 using namespace Gtk::Menu_Helpers;
182 Gtkmm2ext::init();
185 #ifdef TOP_MENUBAR
186 // _auto_display_errors = false;
188 * This was commented out as it wasn't defined
189 * in A3 IIRC. If this is not needed it should
190 * be completely removed.
192 #endif
194 about = 0;
195 splash = 0;
196 _startup = 0;
198 if (theArdourUI == 0) {
199 theArdourUI = this;
202 ui_config = new UIConfiguration();
203 theme_manager = new ThemeManager();
205 key_editor = 0;
207 editor = 0;
208 mixer = 0;
209 editor = 0;
210 engine = 0;
211 _session_is_new = false;
212 big_clock_window = 0;
213 big_clock_height = 0;
214 big_clock_resize_in_progress = false;
215 session_selector_window = 0;
216 last_key_press_time = 0;
217 _will_create_new_session_automatically = false;
218 add_route_dialog = 0;
219 route_params = 0;
220 bundle_manager = 0;
221 rc_option_editor = 0;
222 session_option_editor = 0;
223 location_ui = 0;
224 open_session_selector = 0;
225 have_configure_timeout = false;
226 have_disk_speed_dialog_displayed = false;
227 session_loaded = false;
228 ignore_dual_punch = false;
229 original_big_clock_width = -1;
230 original_big_clock_height = -1;
231 original_big_clock_font_size = 0;
233 roll_button.unset_flags (Gtk::CAN_FOCUS);
234 stop_button.unset_flags (Gtk::CAN_FOCUS);
235 goto_start_button.unset_flags (Gtk::CAN_FOCUS);
236 goto_end_button.unset_flags (Gtk::CAN_FOCUS);
237 auto_loop_button.unset_flags (Gtk::CAN_FOCUS);
238 play_selection_button.unset_flags (Gtk::CAN_FOCUS);
239 rec_button.unset_flags (Gtk::CAN_FOCUS);
240 join_play_range_button.unset_flags (Gtk::CAN_FOCUS);
241 last_configure_time= 0;
242 last_peak_grab = 0;
244 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
245 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
247 /* handle dialog requests */
249 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
251 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
253 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
255 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
257 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
259 /* handle requests to quit (coming from JACK session) */
261 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::finish, this), gui_context ());
263 /* handle requests to deal with missing files */
265 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
267 /* and ambiguous files */
269 ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2, _3));
271 /* lets get this party started */
273 try {
274 if (ARDOUR::init (ARDOUR_COMMAND_LINE::use_vst, ARDOUR_COMMAND_LINE::try_hw_optimization)) {
275 throw failed_constructor ();
278 setup_gtk_ardour_enums ();
279 setup_profile ();
281 GainMeter::setup_slider_pix ();
282 RouteTimeAxisView::setup_slider_pix ();
283 SendProcessorEntry::setup_slider_pix ();
284 SessionEvent::create_per_thread_pool ("GUI", 512);
286 } catch (failed_constructor& err) {
287 error << string_compose (_("could not initialize %1."), PROGRAM_NAME) << endmsg;
288 // pass it on up
289 throw;
292 /* we like keyboards */
294 keyboard = new ArdourKeyboard(*this);
297 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
298 if (node) {
299 keyboard->set_state (*node, Stateful::loading_state_version);
302 /* we don't like certain modifiers */
303 Bindings::set_ignored_state (GDK_LOCK_MASK|GDK_MOD2_MASK|GDK_MOD3_MASK);
305 reset_dpi();
307 TimeAxisViewItem::set_constant_heights ();
309 /* The following must happen after ARDOUR::init() so that Config is set up */
311 location_ui = new ActionWindowProxy<LocationUIWindow> (X_("locations"), Config->extra_xml (X_("UI")), X_("ToggleLocations"));
312 big_clock_window = new ActionWindowProxy<Gtk::Window> (X_("bigclock"), Config->extra_xml (X_("UI")), X_("ToggleBigClock"));
313 speaker_config_window = new ActionWindowProxy<SpeakerDialog> (X_("speakerconf"), Config->extra_xml (X_("UI")), X_("toggle-speaker-config"));
315 for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) {
316 _global_port_matrix[*i] = new ActionWindowProxy<GlobalPortMatrixWindow> (
317 string_compose ("GlobalPortMatrix-%1", (*i).to_string()),
318 Config->extra_xml (X_("UI")),
319 string_compose ("toggle-%1-connection-manager", (*i).to_string())
323 setup_clock ();
325 SpeakerDialog* s = new SpeakerDialog ();
326 s->signal_unmap().connect (sigc::bind (sigc::ptr_fun (&ActionManager::uncheck_toggleaction), X_("<Actions>/Common/toggle-speaker-config")));
327 speaker_config_window->set (s);
329 starting.connect (sigc::mem_fun(*this, &ARDOUR_UI::startup));
330 stopping.connect (sigc::mem_fun(*this, &ARDOUR_UI::shutdown));
333 /** @return true if a session was chosen and `apply' clicked, otherwise false if `cancel' was clicked */
334 bool
335 ARDOUR_UI::run_startup (bool should_be_new, string load_template)
337 delete _startup;
338 _startup = new ArdourStartup ();
340 XMLNode* audio_setup = Config->extra_xml ("AudioSetup");
342 if (audio_setup && _startup->engine_control()) {
343 _startup->engine_control()->set_state (*audio_setup);
346 _startup->set_new_only (should_be_new);
347 if (!load_template.empty()) {
348 _startup->set_load_template( load_template );
350 _startup->present ();
352 main().run();
354 _startup->hide ();
356 switch (_startup->response()) {
357 case RESPONSE_OK:
358 return true;
359 default:
360 return false;
365 ARDOUR_UI::create_engine ()
367 // this gets called every time by new_session()
369 if (engine) {
370 return 0;
373 loading_message (_("Starting audio engine"));
375 try {
376 engine = new ARDOUR::AudioEngine (ARDOUR_COMMAND_LINE::jack_client_name, ARDOUR_COMMAND_LINE::jack_session_uuid);
378 } catch (...) {
380 return -1;
383 engine->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
384 engine->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
385 engine->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
387 engine->Halted.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
389 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
391 post_engine ();
393 return 0;
396 void
397 ARDOUR_UI::post_engine ()
399 /* Things to be done once we create the AudioEngine
402 ARDOUR::init_post_engine ();
404 ActionManager::init ();
405 _tooltips.enable();
407 if (setup_windows ()) {
408 throw failed_constructor ();
411 check_memory_locking();
413 /* this is the first point at which all the keybindings are available */
415 if (ARDOUR_COMMAND_LINE::show_key_actions) {
416 vector<string> names;
417 vector<string> paths;
418 vector<string> tooltips;
419 vector<string> keys;
420 vector<AccelKey> bindings;
422 ActionManager::get_all_actions (names, paths, tooltips, keys, bindings);
424 vector<string>::iterator n;
425 vector<string>::iterator k;
426 for (n = names.begin(), k = keys.begin(); n != names.end(); ++n, ++k) {
427 cerr << "Action: " << (*n) << " bound to " << (*k) << endl;
430 exit (0);
433 blink_timeout_tag = -1;
435 /* this being a GUI and all, we want peakfiles */
437 AudioFileSource::set_build_peakfiles (true);
438 AudioFileSource::set_build_missing_peakfiles (true);
440 /* set default clock modes */
442 if (Profile->get_sae()) {
443 primary_clock->set_mode (AudioClock::BBT);
444 secondary_clock->set_mode (AudioClock::MinSec);
445 } else {
446 primary_clock->set_mode (AudioClock::Timecode);
447 secondary_clock->set_mode (AudioClock::BBT);
450 /* start the time-of-day-clock */
452 #ifndef GTKOSX
453 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
454 update_wall_clock ();
455 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 60000);
456 #endif
458 update_disk_space ();
459 update_cpu_load ();
460 update_sample_rate (engine->frame_rate());
462 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
463 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
464 Config->map_parameters (pc);
466 /* now start and maybe save state */
468 if (do_engine_start () == 0) {
469 if (_session && _session_is_new) {
470 /* we need to retain initial visual
471 settings for a new session
473 _session->save_state ("");
478 ARDOUR_UI::~ARDOUR_UI ()
480 delete keyboard;
481 delete editor;
482 delete mixer;
483 delete add_route_dialog;
486 void
487 ARDOUR_UI::pop_back_splash ()
489 if (Splash::instance()) {
490 // Splash::instance()->pop_back();
491 Splash::instance()->hide ();
495 gint
496 ARDOUR_UI::configure_timeout ()
498 if (last_configure_time == 0) {
499 /* no configure events yet */
500 return true;
503 /* force a gap of 0.5 seconds since the last configure event
506 if (get_microseconds() - last_configure_time < 500000) {
507 return true;
508 } else {
509 have_configure_timeout = false;
510 cerr << "config event-driven save\n";
511 save_ardour_state ();
512 return false;
516 gboolean
517 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
519 if (have_configure_timeout) {
520 last_configure_time = get_microseconds();
521 } else {
522 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
523 have_configure_timeout = true;
526 return FALSE;
529 void
530 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
532 const XMLProperty* prop;
534 if ((prop = node.property ("roll")) != 0) {
535 roll_controllable->set_id (prop->value());
537 if ((prop = node.property ("stop")) != 0) {
538 stop_controllable->set_id (prop->value());
540 if ((prop = node.property ("goto-start")) != 0) {
541 goto_start_controllable->set_id (prop->value());
543 if ((prop = node.property ("goto-end")) != 0) {
544 goto_end_controllable->set_id (prop->value());
546 if ((prop = node.property ("auto-loop")) != 0) {
547 auto_loop_controllable->set_id (prop->value());
549 if ((prop = node.property ("play-selection")) != 0) {
550 play_selection_controllable->set_id (prop->value());
552 if ((prop = node.property ("rec")) != 0) {
553 rec_controllable->set_id (prop->value());
555 if ((prop = node.property ("shuttle")) != 0) {
556 shuttle_box->controllable()->set_id (prop->value());
561 XMLNode&
562 ARDOUR_UI::get_transport_controllable_state ()
564 XMLNode* node = new XMLNode(X_("TransportControllables"));
565 char buf[64];
567 roll_controllable->id().print (buf, sizeof (buf));
568 node->add_property (X_("roll"), buf);
569 stop_controllable->id().print (buf, sizeof (buf));
570 node->add_property (X_("stop"), buf);
571 goto_start_controllable->id().print (buf, sizeof (buf));
572 node->add_property (X_("goto_start"), buf);
573 goto_end_controllable->id().print (buf, sizeof (buf));
574 node->add_property (X_("goto_end"), buf);
575 auto_loop_controllable->id().print (buf, sizeof (buf));
576 node->add_property (X_("auto_loop"), buf);
577 play_selection_controllable->id().print (buf, sizeof (buf));
578 node->add_property (X_("play_selection"), buf);
579 rec_controllable->id().print (buf, sizeof (buf));
580 node->add_property (X_("rec"), buf);
581 shuttle_box->controllable()->id().print (buf, sizeof (buf));
582 node->add_property (X_("shuttle"), buf);
584 return *node;
588 gint
589 ARDOUR_UI::autosave_session ()
591 if (g_main_depth() > 1) {
592 /* inside a recursive main loop,
593 give up because we may not be able to
594 take a lock.
596 return 1;
599 if (!Config->get_periodic_safety_backups()) {
600 return 1;
603 if (_session) {
604 _session->maybe_write_autosave();
607 return 1;
610 void
611 ARDOUR_UI::update_autosave ()
613 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_autosave)
615 if (_session && _session->dirty()) {
616 if (_autosave_connection.connected()) {
617 _autosave_connection.disconnect();
620 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
621 Config->get_periodic_safety_backup_interval() * 1000);
623 } else {
624 if (_autosave_connection.connected()) {
625 _autosave_connection.disconnect();
630 void
631 ARDOUR_UI::backend_audio_error (bool we_set_params, Gtk::Window* toplevel)
633 string title;
634 if (we_set_params) {
635 title = string_compose (_("%1 could not start JACK"), PROGRAM_NAME);
636 } else {
637 title = string_compose (_("%1 could not connect to JACK."), PROGRAM_NAME);
640 MessageDialog win (title,
641 false,
642 Gtk::MESSAGE_INFO,
643 Gtk::BUTTONS_NONE);
645 if (we_set_params) {
646 win.set_secondary_text(_("There are several possible reasons:\n\
648 1) You requested audio parameters that are not supported..\n\
649 2) JACK is running as another user.\n\
651 Please consider the possibilities, and perhaps try different parameters."));
652 } else {
653 win.set_secondary_text(_("There are several possible reasons:\n\
655 1) JACK is not running.\n\
656 2) JACK is running as another user, perhaps root.\n\
657 3) There is already another client called \"ardour\".\n\
659 Please consider the possibilities, and perhaps (re)start JACK."));
662 if (toplevel) {
663 win.set_transient_for (*toplevel);
666 if (we_set_params) {
667 win.add_button (Stock::OK, RESPONSE_CLOSE);
668 } else {
669 win.add_button (Stock::QUIT, RESPONSE_CLOSE);
672 win.set_default_response (RESPONSE_CLOSE);
674 win.show_all ();
675 win.set_position (Gtk::WIN_POS_CENTER);
676 pop_back_splash ();
678 /* we just don't care about the result, but we want to block */
680 win.run ();
683 void
684 ARDOUR_UI::startup ()
686 Application* app = Application::instance ();
688 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
689 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::idle_load));
691 #ifdef PHONE_HOME
692 call_the_mothership (VERSIONSTRING);
693 #endif
695 app->ready ();
697 if (get_session_parameters (true, ARDOUR_COMMAND_LINE::new_session, ARDOUR_COMMAND_LINE::load_template)) {
698 exit (1);
701 use_config ();
703 goto_editor_window ();
705 /* Add the window proxies here; their addition may cause windows to be opened, and we want them
706 to be opened on top of the editor window that goto_editor_window() just opened.
708 add_window_proxy (location_ui);
709 add_window_proxy (big_clock_window);
710 for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) {
711 add_window_proxy (_global_port_matrix[*i]);
714 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
717 void
718 ARDOUR_UI::no_memory_warning ()
720 XMLNode node (X_("no-memory-warning"));
721 Config->add_instant_xml (node);
724 void
725 ARDOUR_UI::check_memory_locking ()
727 #ifdef __APPLE__
728 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
729 return;
730 #else // !__APPLE__
732 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
734 if (engine->is_realtime() && memory_warning_node == 0) {
736 struct rlimit limits;
737 int64_t ram;
738 long pages, page_size;
740 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0) {
741 ram = 0;
742 } else {
743 ram = (int64_t) pages * (int64_t) page_size;
746 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
747 return;
750 if (limits.rlim_cur != RLIM_INFINITY) {
752 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
754 MessageDialog msg (
755 string_compose (
756 _("WARNING: Your system has a limit for maximum amount of locked memory. "
757 "This might cause %1 to run out of memory before your system "
758 "runs out of memory. \n\n"
759 "You can view the memory limit with 'ulimit -l', "
760 "and it is normally controlled by /etc/security/limits.conf"),
761 PROGRAM_NAME).c_str());
763 VBox* vbox = msg.get_vbox();
764 HBox hbox;
765 CheckButton cb (_("Do not show this window again"));
767 cb.signal_toggled().connect (sigc::mem_fun (*this, &ARDOUR_UI::no_memory_warning));
769 hbox.pack_start (cb, true, false);
770 vbox->pack_start (hbox);
771 cb.show();
772 vbox->show();
773 hbox.show ();
775 pop_back_splash ();
777 editor->ensure_float (msg);
778 msg.run ();
782 #endif // !__APPLE__
786 void
787 ARDOUR_UI::queue_finish ()
789 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
792 bool
793 ARDOUR_UI::idle_finish ()
795 finish ();
796 return false; /* do not call again */
799 void
800 ARDOUR_UI::finish()
802 if (_session) {
803 int tries = 0;
805 if (_session->transport_rolling() && (++tries < 8)) {
806 _session->request_stop (false, true);
807 usleep (10000);
810 if (_session->dirty()) {
811 vector<string> actions;
812 actions.push_back (_("Don't quit"));
813 actions.push_back (_("Just quit"));
814 actions.push_back (_("Save and quit"));
815 switch (ask_about_saving_session(actions)) {
816 case -1:
817 return;
818 break;
819 case 1:
820 /* use the default name */
821 if (save_state_canfail ("")) {
822 /* failed - don't quit */
823 MessageDialog msg (*editor,
824 _("\
825 Ardour was unable to save your session.\n\n\
826 If you still wish to quit, please use the\n\n\
827 \"Just quit\" option."));
828 pop_back_splash();
829 msg.run ();
830 return;
832 break;
833 case 0:
834 break;
838 second_connection.disconnect ();
839 point_one_second_connection.disconnect ();
840 point_oh_five_second_connection.disconnect ();
841 point_zero_one_second_connection.disconnect();
844 /* Save state before deleting the session, as that causes some
845 windows to be destroyed before their visible state can be
846 saved.
848 save_ardour_state ();
850 if (_session) {
851 // _session->set_deletion_in_progress ();
852 _session->set_clean ();
853 _session->remove_pending_capture_state ();
854 delete _session;
855 _session = 0;
858 ArdourDialog::close_all_dialogs ();
859 engine->stop (true);
860 quit ();
864 ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
866 ArdourDialog window (_("Unsaved Session"));
867 Gtk::HBox dhbox; // the hbox for the image and text
868 Gtk::Label prompt_label;
869 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
871 string msg;
873 assert (actions.size() >= 3);
875 window.add_button (actions[0], RESPONSE_REJECT);
876 window.add_button (actions[1], RESPONSE_APPLY);
877 window.add_button (actions[2], RESPONSE_ACCEPT);
879 window.set_default_response (RESPONSE_ACCEPT);
881 Gtk::Button noquit_button (msg);
882 noquit_button.set_name ("EditorGTKButton");
884 string prompt;
886 if (_session->snap_name() == _session->name()) {
887 prompt = string_compose(_("The session \"%1\"\nhas not been saved.\n\nAny changes made this time\nwill be lost unless you save it.\n\nWhat do you want to do?"),
888 _session->snap_name());
889 } else {
890 prompt = string_compose(_("The snapshot \"%1\"\nhas not been saved.\n\nAny changes made this time\nwill be lost unless you save it.\n\nWhat do you want to do?"),
891 _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);
909 dhbox.show();
910 prompt_label.show();
911 dimage->show();
912 window.show();
913 window.set_keep_above (true);
914 window.present ();
916 ResponseType r = (ResponseType) window.run();
918 window.hide ();
920 switch (r) {
921 case RESPONSE_ACCEPT: // save and get out of here
922 return 1;
923 case RESPONSE_APPLY: // get out of here
924 return 0;
925 default:
926 break;
929 return -1;
932 gint
933 ARDOUR_UI::every_second ()
935 update_cpu_load ();
936 update_buffer_load ();
937 update_disk_space ();
938 return TRUE;
941 gint
942 ARDOUR_UI::every_point_one_seconds ()
944 shuttle_box->update_speed_display ();
945 RapidScreenUpdate(); /* EMIT_SIGNAL */
946 return TRUE;
949 gint
950 ARDOUR_UI::every_point_zero_one_seconds ()
952 // august 2007: actual update frequency: 40Hz, not 100Hz
954 SuperRapidScreenUpdate(); /* EMIT_SIGNAL */
955 return TRUE;
958 void
959 ARDOUR_UI::update_sample_rate (framecnt_t)
961 char buf[32];
963 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
965 if (!engine->connected()) {
967 snprintf (buf, sizeof (buf), _("disconnected"));
969 } else {
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);
977 } else {
978 snprintf (buf, sizeof (buf), _("%" PRId64 " kHz / %4.1f ms"),
979 rate/1000,
980 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
984 sample_rate_label.set_text (buf);
987 void
988 ARDOUR_UI::update_cpu_load ()
990 char buf[32];
991 snprintf (buf, sizeof (buf), _("DSP: %5.1f%%"), engine->get_cpu_load());
992 cpu_load_label.set_text (buf);
995 void
996 ARDOUR_UI::update_buffer_load ()
998 char buf[64];
999 uint32_t c, p;
1001 if (_session) {
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);
1008 } else {
1009 buffer_load_label.set_text ("");
1013 void
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();
1022 void
1023 ARDOUR_UI::update_disk_space()
1025 if (_session == 0) {
1026 return;
1029 framecnt_t frames = _session->available_capture_duration();
1030 char buf[64];
1031 framecnt_t fr = _session->frame_rate();
1033 if (frames == max_framecnt) {
1034 strcpy (buf, _("Disk: 24hrs+"));
1035 } else {
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;
1043 int hrs;
1044 int mins;
1045 int secs;
1047 hrs = frames / (fr * 3600);
1048 frames -= hrs * fr * 3600;
1049 mins = frames / (fr * 60);
1050 frames -= mins * fr * 60;
1051 secs = frames / fr;
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"); */
1062 } else {
1063 /* disk_space_box.style ("disk_space_label"); */
1068 gint
1069 ARDOUR_UI::update_wall_clock ()
1071 time_t now;
1072 struct tm *tm_now;
1073 char buf[16];
1075 time (&now);
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);
1081 return TRUE;
1084 gint
1085 ARDOUR_UI::session_menu (GdkEventButton */*ev*/)
1087 session_popup_menu->popup (0, 0);
1088 return TRUE;
1091 void
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);
1103 if (rs.empty()) {
1104 recent_session_display.set_model (recent_session_model);
1105 return;
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;
1138 continue;
1141 /* now get available states for this session */
1143 if ((states = Session::possible_states (fullpath)) == 0) {
1144 /* no state file? */
1145 continue;
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) {
1157 // add the children
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);
1174 void
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();
1199 scroller->show();
1200 //session_selector_window->get_vbox()->show();
1203 void
1204 ARDOUR_UI::recent_session_row_activated (const TreePath& /*path*/, TreeViewColumn* /*col*/)
1206 session_selector_window->response (RESPONSE_ACCEPT);
1209 void
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 ();
1220 while (true) {
1222 session_selector_window->set_position (WIN_POS_MOUSE);
1224 ResponseType r = (ResponseType) session_selector_window->run ();
1226 switch (r) {
1227 case RESPONSE_ACCEPT:
1228 break;
1229 default:
1230 if (can_return) {
1231 session_selector_window->hide();
1232 return;
1233 } else {
1234 exit (1);
1238 if (recent_session_display.get_selection()->count_selected_rows() == 0) {
1239 continue;
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()) {
1247 return;
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) {
1256 break;
1259 can_return = false;
1263 bool
1264 ARDOUR_UI::check_audioengine ()
1266 if (engine) {
1267 if (!engine->connected()) {
1268 MessageDialog msg (string_compose (
1269 _("%1 is not connected to JACK\n"
1270 "You cannot open or close sessions in this condition"),
1271 PROGRAM_NAME));
1272 pop_back_splash ();
1273 msg.run ();
1274 return false;
1276 return true;
1277 } else {
1278 return false;
1282 void
1283 ARDOUR_UI::open_session ()
1285 if (!check_audioengine()) {
1286 return;
1290 /* popup selector window */
1292 if (open_session_selector == 0) {
1294 /* ardour sessions are folders */
1296 open_session_selector = new Gtk::FileChooserDialog (_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1297 open_session_selector->add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1298 open_session_selector->add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1299 open_session_selector->set_default_response(Gtk::RESPONSE_ACCEPT);
1301 FileFilter session_filter;
1302 session_filter.add_pattern ("*.ardour");
1303 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1304 open_session_selector->add_filter (session_filter);
1305 open_session_selector->set_filter (session_filter);
1308 int response = open_session_selector->run();
1309 open_session_selector->hide ();
1311 switch (response) {
1312 case RESPONSE_ACCEPT:
1313 break;
1314 default:
1315 open_session_selector->hide();
1316 return;
1319 open_session_selector->hide();
1320 string session_path = open_session_selector->get_filename();
1321 string path, name;
1322 bool isnew;
1324 if (session_path.length() > 0) {
1325 if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1326 _session_is_new = isnew;
1327 load_session (path, name);
1333 void
1334 ARDOUR_UI::session_add_midi_route (bool disk, RouteGroup* route_group, uint32_t how_many, string const & name_template)
1336 list<boost::shared_ptr<MidiTrack> > tracks;
1338 if (_session == 0) {
1339 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1340 return;
1343 try {
1344 if (disk) {
1346 tracks = _session->new_midi_track (ARDOUR::Normal, route_group, how_many, name_template);
1348 if (tracks.size() != how_many) {
1349 if (how_many == 1) {
1350 error << _("could not create a new midi track") << endmsg;
1351 } else {
1352 error << string_compose (_("could not create %1 new midi tracks"), how_many) << endmsg;
1355 } /*else {
1356 if ((route = _session->new_midi_route ()) == 0) {
1357 error << _("could not create new midi bus") << endmsg;
1362 catch (...) {
1363 MessageDialog msg (*editor,
1364 string_compose (_("There are insufficient JACK ports available\n\
1365 to create a new track or bus.\n\
1366 You should save %1, exit and\n\
1367 restart JACK with more ports."), PROGRAM_NAME));
1368 msg.run ();
1373 void
1374 ARDOUR_UI::session_add_audio_route (
1375 bool track,
1376 int32_t input_channels,
1377 int32_t output_channels,
1378 ARDOUR::TrackMode mode,
1379 RouteGroup* route_group,
1380 uint32_t how_many,
1381 string const & name_template
1384 list<boost::shared_ptr<AudioTrack> > tracks;
1385 RouteList routes;
1387 if (_session == 0) {
1388 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1389 return;
1392 try {
1393 if (track) {
1394 tracks = _session->new_audio_track (input_channels, output_channels, mode, route_group, how_many, name_template);
1396 if (tracks.size() != how_many) {
1397 if (how_many == 1) {
1398 error << _("could not create a new audio track") << endmsg;
1399 } else {
1400 error << string_compose (_("could only create %1 of %2 new audio %3"),
1401 tracks.size(), how_many, (track ? _("tracks") : _("busses"))) << endmsg;
1405 } else {
1407 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template);
1409 if (routes.size() != how_many) {
1410 if (how_many == 1) {
1411 error << _("could not create a new audio track") << endmsg;
1412 } else {
1413 error << string_compose (_("could not create %1 new audio tracks"), how_many) << endmsg;
1419 catch (...) {
1420 MessageDialog msg (*editor,
1421 string_compose (_("There are insufficient JACK ports available\n\
1422 to create a new track or bus.\n\
1423 You should save %1, exit and\n\
1424 restart JACK with more ports."), PROGRAM_NAME));
1425 pop_back_splash ();
1426 msg.run ();
1430 void
1431 ARDOUR_UI::do_transport_locate (framepos_t new_position, bool with_roll)
1433 framecnt_t _preroll = 0;
1435 if (_session) {
1436 // XXX CONFIG_CHANGE FIX - requires AnyTime handling
1437 // _preroll = _session->convert_to_frames_at (new_position, Config->get_preroll());
1439 if (new_position > _preroll) {
1440 new_position -= _preroll;
1441 } else {
1442 new_position = 0;
1445 _session->request_locate (new_position, with_roll);
1449 void
1450 ARDOUR_UI::transport_goto_start ()
1452 if (_session) {
1453 _session->goto_start();
1455 /* force displayed area in editor to start no matter
1456 what "follow playhead" setting is.
1459 if (editor) {
1460 editor->center_screen (_session->current_start_frame ());
1465 void
1466 ARDOUR_UI::transport_goto_zero ()
1468 if (_session) {
1469 _session->request_locate (0);
1471 /* force displayed area in editor to start no matter
1472 what "follow playhead" setting is.
1475 if (editor) {
1476 editor->reset_x_origin (0);
1481 void
1482 ARDOUR_UI::transport_goto_wallclock ()
1484 if (_session && editor) {
1486 time_t now;
1487 struct tm tmnow;
1488 framepos_t frames;
1490 time (&now);
1491 localtime_r (&now, &tmnow);
1493 frames = tmnow.tm_hour * (60 * 60 * _session->frame_rate());
1494 frames += tmnow.tm_min * (60 * _session->frame_rate());
1495 frames += tmnow.tm_sec * _session->frame_rate();
1497 _session->request_locate (frames, _session->transport_rolling ());
1499 /* force displayed area in editor to start no matter
1500 what "follow playhead" setting is.
1503 if (editor) {
1504 editor->center_screen (frames);
1509 void
1510 ARDOUR_UI::transport_goto_end ()
1512 if (_session) {
1513 framepos_t const frame = _session->current_end_frame();
1514 _session->request_locate (frame);
1516 /* force displayed area in editor to start no matter
1517 what "follow playhead" setting is.
1520 if (editor) {
1521 editor->center_screen (frame);
1526 void
1527 ARDOUR_UI::transport_stop ()
1529 if (!_session) {
1530 return;
1533 if (_session->is_auditioning()) {
1534 _session->cancel_audition ();
1535 return;
1538 _session->request_stop (false, true);
1541 void
1542 ARDOUR_UI::transport_stop_and_forget_capture ()
1544 if (_session) {
1545 _session->request_stop (true, true);
1549 void
1550 ARDOUR_UI::remove_last_capture()
1552 if (editor) {
1553 editor->remove_last_capture();
1557 void
1558 ARDOUR_UI::transport_record (bool roll)
1561 if (_session) {
1562 switch (_session->record_status()) {
1563 case Session::Disabled:
1564 if (_session->ntracks() == 0) {
1565 MessageDialog msg (*editor, _("Please create 1 or more track\nbefore trying to record.\nCheck the Session menu."));
1566 msg.run ();
1567 return;
1569 _session->maybe_enable_record ();
1570 if (roll) {
1571 transport_roll ();
1573 break;
1574 case Session::Recording:
1575 if (roll) {
1576 _session->request_stop();
1577 } else {
1578 _session->disable_record (false, true);
1580 break;
1582 case Session::Enabled:
1583 _session->disable_record (false, true);
1586 //cerr << "ARDOUR_UI::transport_record () called roll = " << roll << " _session->record_status() = " << _session->record_status() << endl;
1589 void
1590 ARDOUR_UI::transport_roll ()
1592 if (!_session) {
1593 return;
1596 if (_session->is_auditioning()) {
1597 return;
1600 #if 0
1601 if (_session->config.get_external_sync()) {
1602 switch (_session->config.get_sync_source()) {
1603 case JACK:
1604 break;
1605 default:
1606 /* transport controlled by the master */
1607 return;
1610 #endif
1612 bool rolling = _session->transport_rolling();
1614 if (_session->get_play_loop()) {
1615 /* XXX it is not possible to just leave seamless loop and keep
1616 playing at present (nov 4th 2009)
1618 if (!Config->get_seamless_loop()) {
1619 _session->request_play_loop (false, true);
1621 } else if (_session->get_play_range () && !join_play_range_button.get_active()) {
1622 /* stop playing a range if we currently are */
1623 _session->request_play_range (0, true);
1626 if (join_play_range_button.get_active()) {
1627 _session->request_play_range (&editor->get_selection().time, true);
1630 if (!rolling) {
1631 _session->request_transport_speed (1.0f);
1635 void
1636 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
1639 if (!_session) {
1640 return;
1643 if (_session->is_auditioning()) {
1644 _session->cancel_audition ();
1645 return;
1648 if (_session->config.get_external_sync()) {
1649 switch (_session->config.get_sync_source()) {
1650 case JACK:
1651 break;
1652 default:
1653 /* transport controlled by the master */
1654 return;
1658 bool rolling = _session->transport_rolling();
1659 bool affect_transport = true;
1661 if (rolling && roll_out_of_bounded_mode) {
1662 /* drop out of loop/range playback but leave transport rolling */
1663 if (_session->get_play_loop()) {
1664 if (Config->get_seamless_loop()) {
1665 /* the disk buffers contain copies of the loop - we can't
1666 just keep playing, so stop the transport. the user
1667 can restart as they wish.
1669 affect_transport = true;
1670 } else {
1671 /* disk buffers are normal, so we can keep playing */
1672 affect_transport = false;
1674 _session->request_play_loop (false, true);
1675 } else if (_session->get_play_range ()) {
1676 affect_transport = false;
1677 _session->request_play_range (0, true);
1681 if (affect_transport) {
1682 if (rolling) {
1683 _session->request_stop (with_abort, true);
1684 } else {
1685 if (join_play_range_button.get_active()) {
1686 _session->request_play_range (&editor->get_selection().time, true);
1689 _session->request_transport_speed (1.0f);
1694 void
1695 ARDOUR_UI::toggle_session_auto_loop ()
1697 if (!_session) {
1698 return;
1701 if (_session->get_play_loop()) {
1703 if (_session->transport_rolling()) {
1705 Location * looploc = _session->locations()->auto_loop_location();
1707 if (looploc) {
1708 _session->request_locate (looploc->start(), true);
1709 _session->request_play_loop (false);
1712 } else {
1713 _session->request_play_loop (false);
1715 } else {
1717 Location * looploc = _session->locations()->auto_loop_location();
1719 if (looploc) {
1720 _session->request_play_loop (true);
1725 void
1726 ARDOUR_UI::transport_play_selection ()
1728 if (!_session) {
1729 return;
1732 editor->play_selection ();
1735 void
1736 ARDOUR_UI::transport_rewind (int option)
1738 float current_transport_speed;
1740 if (_session) {
1741 current_transport_speed = _session->transport_speed();
1743 if (current_transport_speed >= 0.0f) {
1744 switch (option) {
1745 case 0:
1746 _session->request_transport_speed (-1.0f);
1747 break;
1748 case 1:
1749 _session->request_transport_speed (-4.0f);
1750 break;
1751 case -1:
1752 _session->request_transport_speed (-0.5f);
1753 break;
1755 } else {
1756 /* speed up */
1757 _session->request_transport_speed (current_transport_speed * 1.5f);
1762 void
1763 ARDOUR_UI::transport_forward (int option)
1765 float current_transport_speed;
1767 if (_session) {
1768 current_transport_speed = _session->transport_speed();
1770 if (current_transport_speed <= 0.0f) {
1771 switch (option) {
1772 case 0:
1773 _session->request_transport_speed (1.0f);
1774 break;
1775 case 1:
1776 _session->request_transport_speed (4.0f);
1777 break;
1778 case -1:
1779 _session->request_transport_speed (0.5f);
1780 break;
1782 } else {
1783 /* speed up */
1784 _session->request_transport_speed (current_transport_speed * 1.5f);
1790 void
1791 ARDOUR_UI::toggle_record_enable (uint32_t rid)
1793 if (_session == 0) {
1794 return;
1797 boost::shared_ptr<Route> r;
1799 if ((r = _session->route_by_remote_id (rid)) != 0) {
1801 Track* t;
1803 if ((t = dynamic_cast<Track*>(r.get())) != 0) {
1804 t->set_record_enabled (!t->record_enabled(), this);
1807 if (_session == 0) {
1808 return;
1812 void
1813 ARDOUR_UI::map_transport_state ()
1815 if (!_session) {
1816 auto_loop_button.set_visual_state (0);
1817 play_selection_button.set_visual_state (0);
1818 roll_button.set_visual_state (0);
1819 stop_button.set_visual_state (1);
1820 return;
1823 shuttle_box->map_transport_state ();
1825 float sp = _session->transport_speed();
1827 if (sp != 0.0f) {
1829 /* we're rolling */
1831 if (_session->get_play_range()) {
1833 play_selection_button.set_visual_state (1);
1834 roll_button.set_visual_state (0);
1835 auto_loop_button.set_visual_state (0);
1837 } else if (_session->get_play_loop ()) {
1839 auto_loop_button.set_visual_state (1);
1840 play_selection_button.set_visual_state (0);
1841 roll_button.set_visual_state (0);
1843 } else {
1845 roll_button.set_visual_state (1);
1846 play_selection_button.set_visual_state (0);
1847 auto_loop_button.set_visual_state (0);
1850 if (join_play_range_button.get_active()) {
1851 /* light up both roll and play-selection if they are joined */
1852 roll_button.set_visual_state (1);
1853 play_selection_button.set_visual_state (1);
1856 stop_button.set_visual_state (0);
1858 } else {
1860 stop_button.set_visual_state (1);
1861 roll_button.set_visual_state (0);
1862 play_selection_button.set_visual_state (0);
1863 auto_loop_button.set_visual_state (0);
1864 update_disk_space ();
1868 void
1869 ARDOUR_UI::engine_stopped ()
1871 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
1872 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1873 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1876 void
1877 ARDOUR_UI::engine_running ()
1879 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
1880 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, true);
1881 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, false);
1883 Glib::RefPtr<Action> action;
1884 const char* action_name = 0;
1886 switch (engine->frames_per_cycle()) {
1887 case 32:
1888 action_name = X_("JACKLatency32");
1889 break;
1890 case 64:
1891 action_name = X_("JACKLatency64");
1892 break;
1893 case 128:
1894 action_name = X_("JACKLatency128");
1895 break;
1896 case 512:
1897 action_name = X_("JACKLatency512");
1898 break;
1899 case 1024:
1900 action_name = X_("JACKLatency1024");
1901 break;
1902 case 2048:
1903 action_name = X_("JACKLatency2048");
1904 break;
1905 case 4096:
1906 action_name = X_("JACKLatency4096");
1907 break;
1908 case 8192:
1909 action_name = X_("JACKLatency8192");
1910 break;
1911 default:
1912 /* XXX can we do anything useful ? */
1913 break;
1916 if (action_name) {
1918 action = ActionManager::get_action (X_("JACK"), action_name);
1920 if (action) {
1921 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (action);
1922 ract->set_active ();
1927 void
1928 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
1930 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
1931 /* we can't rely on the original string continuing to exist when we are called
1932 again in the GUI thread, so make a copy and note that we need to
1933 free it later.
1935 char *copy = strdup (reason);
1936 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
1937 return;
1940 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1941 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1943 update_sample_rate (0);
1945 string msgstr;
1947 /* if the reason is a non-empty string, it means that the backend was shutdown
1948 rather than just Ardour.
1951 if (strlen (reason)) {
1952 msgstr = string_compose (_("The audio backend (JACK) was shutdown because:\n\n%1"), reason);
1953 } else {
1954 msgstr = string_compose (_("\
1955 JACK has either been shutdown or it\n\
1956 disconnected %1 because %1\n\
1957 was not fast enough. Try to restart\n\
1958 JACK, reconnect and save the session."), PROGRAM_NAME);
1961 MessageDialog msg (*editor, msgstr);
1962 pop_back_splash ();
1963 msg.run ();
1965 if (free_reason) {
1966 free ((char*) reason);
1970 int32_t
1971 ARDOUR_UI::do_engine_start ()
1973 try {
1974 engine->start();
1977 catch (...) {
1978 engine->stop ();
1979 error << _("Unable to start the session running")
1980 << endmsg;
1981 unload_session ();
1982 return -2;
1985 return 0;
1988 void
1989 ARDOUR_UI::setup_theme ()
1991 theme_manager->setup_theme();
1994 void
1995 ARDOUR_UI::update_clocks ()
1997 if (!editor || !editor->dragging_playhead()) {
1998 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position()); /* EMIT_SIGNAL */
2002 void
2003 ARDOUR_UI::start_clocking ()
2005 clock_signal_connection = RapidScreenUpdate.connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2008 void
2009 ARDOUR_UI::stop_clocking ()
2011 clock_signal_connection.disconnect ();
2014 void
2015 ARDOUR_UI::toggle_clocking ()
2017 #if 0
2018 if (clock_button.get_active()) {
2019 start_clocking ();
2020 } else {
2021 stop_clocking ();
2023 #endif
2026 gint
2027 ARDOUR_UI::_blink (void *arg)
2030 ((ARDOUR_UI *) arg)->blink ();
2031 return TRUE;
2034 void
2035 ARDOUR_UI::blink ()
2037 Blink (blink_on = !blink_on); /* EMIT_SIGNAL */
2040 void
2041 ARDOUR_UI::start_blinking ()
2043 /* Start the blink signal. Everybody with a blinking widget
2044 uses Blink to drive the widget's state.
2047 if (blink_timeout_tag < 0) {
2048 blink_on = false;
2049 blink_timeout_tag = g_timeout_add (240, _blink, this);
2053 void
2054 ARDOUR_UI::stop_blinking ()
2056 if (blink_timeout_tag >= 0) {
2057 g_source_remove (blink_timeout_tag);
2058 blink_timeout_tag = -1;
2063 /** Ask the user for the name of a new shapshot and then take it.
2066 void
2067 ARDOUR_UI::snapshot_session (bool switch_to_it)
2069 ArdourPrompter prompter (true);
2070 string snapname;
2072 prompter.set_name ("Prompter");
2073 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2074 prompter.set_title (_("Take Snapshot"));
2075 prompter.set_title (_("Take Snapshot"));
2076 prompter.set_prompt (_("Name of new snapshot"));
2078 if (!switch_to_it) {
2079 char timebuf[128];
2080 time_t n;
2081 struct tm local_time;
2083 time (&n);
2084 localtime_r (&n, &local_time);
2085 strftime (timebuf, sizeof(timebuf), "%FT%T", &local_time);
2086 prompter.set_initial_text (timebuf);
2089 again:
2090 switch (prompter.run()) {
2091 case RESPONSE_ACCEPT:
2093 prompter.get_result (snapname);
2095 bool do_save = (snapname.length() != 0);
2097 if (do_save) {
2098 if (snapname.find ('/') != string::npos) {
2099 MessageDialog msg (_("To ensure compatibility with various systems\n"
2100 "snapshot names may not contain a '/' character"));
2101 msg.run ();
2102 goto again;
2104 if (snapname.find ('\\') != string::npos) {
2105 MessageDialog msg (_("To ensure compatibility with various systems\n"
2106 "snapshot names may not contain a '\\' character"));
2107 msg.run ();
2108 goto again;
2112 vector<sys::path> p;
2113 get_state_files_in_directory (_session->session_directory().root_path(), p);
2114 vector<string> n = get_file_names_no_extension (p);
2115 if (find (n.begin(), n.end(), snapname) != n.end()) {
2117 ArdourDialog confirm (_("Confirm Snapshot Overwrite"), true);
2118 Label m (_("A snapshot already exists with that name. Do you want to overwrite it?"));
2119 confirm.get_vbox()->pack_start (m, true, true);
2120 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2121 confirm.add_button (_("Overwrite"), Gtk::RESPONSE_ACCEPT);
2122 confirm.show_all ();
2123 switch (confirm.run()) {
2124 case RESPONSE_CANCEL:
2125 do_save = false;
2129 if (do_save) {
2130 save_state (snapname, switch_to_it);
2132 break;
2135 default:
2136 break;
2140 void
2141 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2143 XMLNode* node = new XMLNode (X_("UI"));
2145 for (list<WindowProxyBase*>::iterator i = _window_proxies.begin(); i != _window_proxies.end(); ++i) {
2146 if (!(*i)->rc_configured()) {
2147 node->add_child_nocopy (*((*i)->get_state ()));
2151 _session->add_extra_xml (*node);
2153 save_state_canfail (name, switch_to_it);
2157 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2159 if (_session) {
2160 int ret;
2162 if (name.length() == 0) {
2163 name = _session->snap_name();
2166 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2167 return ret;
2171 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2172 return 0;
2175 void
2176 ARDOUR_UI::primary_clock_value_changed ()
2178 if (_session) {
2179 _session->request_locate (primary_clock->current_time ());
2183 void
2184 ARDOUR_UI::big_clock_value_changed ()
2186 if (_session) {
2187 _session->request_locate (big_clock->current_time ());
2191 void
2192 ARDOUR_UI::secondary_clock_value_changed ()
2194 if (_session) {
2195 _session->request_locate (secondary_clock->current_time ());
2199 void
2200 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2202 if (_session == 0) {
2203 return;
2206 if (_session->step_editing()) {
2207 return;
2210 Session::RecordState const r = _session->record_status ();
2211 bool const h = _session->have_rec_enabled_track ();
2213 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2214 if (onoff) {
2215 rec_button.set_visual_state (2);
2216 } else {
2217 rec_button.set_visual_state (0);
2219 } else if (r == Session::Recording && h) {
2220 rec_button.set_visual_state (1);
2221 } else {
2222 rec_button.set_visual_state (0);
2226 void
2227 ARDOUR_UI::save_template ()
2229 ArdourPrompter prompter (true);
2230 string name;
2232 if (!check_audioengine()) {
2233 return;
2236 prompter.set_name (X_("Prompter"));
2237 prompter.set_title (_("Save Template"));
2238 prompter.set_prompt (_("Name for template:"));
2239 prompter.set_initial_text(_session->name() + _("-template"));
2240 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2242 switch (prompter.run()) {
2243 case RESPONSE_ACCEPT:
2244 prompter.get_result (name);
2246 if (name.length()) {
2247 _session->save_template (name);
2249 break;
2251 default:
2252 break;
2256 void
2257 ARDOUR_UI::edit_metadata ()
2259 SessionMetadataEditor dialog;
2260 dialog.set_session (_session);
2261 editor->ensure_float (dialog);
2262 dialog.run ();
2265 void
2266 ARDOUR_UI::import_metadata ()
2268 SessionMetadataImporter dialog;
2269 dialog.set_session (_session);
2270 editor->ensure_float (dialog);
2271 dialog.run ();
2274 bool
2275 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
2277 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2279 MessageDialog msg (str,
2280 false,
2281 Gtk::MESSAGE_WARNING,
2282 Gtk::BUTTONS_YES_NO,
2283 true);
2286 msg.set_name (X_("OpenExistingDialog"));
2287 msg.set_title (_("Open Existing Session"));
2288 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
2289 msg.set_position (Gtk::WIN_POS_MOUSE);
2290 pop_back_splash ();
2292 switch (msg.run()) {
2293 case RESPONSE_YES:
2294 return true;
2295 break;
2297 return false;
2301 ARDOUR_UI::build_session_from_nsd (const std::string& session_path, const std::string& session_name)
2303 BusProfile bus_profile;
2305 if (Profile->get_sae()) {
2307 bus_profile.master_out_channels = 2;
2308 bus_profile.input_ac = AutoConnectPhysical;
2309 bus_profile.output_ac = AutoConnectMaster;
2310 bus_profile.requested_physical_in = 0; // use all available
2311 bus_profile.requested_physical_out = 0; // use all available
2313 } else {
2315 /* get settings from advanced section of NSD */
2317 if (_startup->create_master_bus()) {
2318 bus_profile.master_out_channels = (uint32_t) _startup->master_channel_count();
2319 } else {
2320 bus_profile.master_out_channels = 0;
2323 if (_startup->connect_inputs()) {
2324 bus_profile.input_ac = AutoConnectPhysical;
2325 } else {
2326 bus_profile.input_ac = AutoConnectOption (0);
2329 /// @todo some minor tweaks.
2331 bus_profile.output_ac = AutoConnectOption (0);
2333 if (_startup->connect_outputs ()) {
2334 if (_startup->connect_outs_to_master()) {
2335 bus_profile.output_ac = AutoConnectMaster;
2336 } else if (_startup->connect_outs_to_physical()) {
2337 bus_profile.output_ac = AutoConnectPhysical;
2341 bus_profile.requested_physical_in = (uint32_t) _startup->input_limit_count();
2342 bus_profile.requested_physical_out = (uint32_t) _startup->output_limit_count();
2345 if (build_session (session_path, session_name, bus_profile)) {
2346 return -1;
2349 return 0;
2352 void
2353 ARDOUR_UI::idle_load (const std::string& path)
2355 if (_session) {
2356 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2357 /* /path/to/foo => /path/to/foo, foo */
2358 load_session (path, basename_nosuffix (path));
2359 } else {
2360 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2361 load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2363 } else {
2365 ARDOUR_COMMAND_LINE::session_name = path;
2368 * new_session_dialog doens't exist in A3
2369 * Try to remove all references to it to
2370 * see if it will compile. NOTE: this will
2371 * likely cause a runtime issue is my somewhat
2372 * uneducated guess.
2375 //if (new_session_dialog) {
2378 /* make it break out of Dialog::run() and
2379 start again.
2382 //new_session_dialog->response (1);
2387 void
2388 ARDOUR_UI::end_loading_messages ()
2390 // hide_splash ();
2393 void
2394 ARDOUR_UI::loading_message (const std::string& /*msg*/)
2396 // show_splash ();
2397 // splash->message (msg);
2398 flush_pending ();
2401 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
2403 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
2405 string session_name;
2406 string session_path;
2407 string template_name;
2408 int ret = -1;
2409 bool likely_new = false;
2411 if (!load_template.empty()) {
2412 should_be_new = true;
2413 template_name = load_template;
2416 while (ret != 0) {
2418 if (!should_be_new && !ARDOUR_COMMAND_LINE::session_name.empty()) {
2420 /* if they named a specific statefile, use it, otherwise they are
2421 just giving a session folder, and we want to use it as is
2422 to find the session.
2425 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
2427 if (suffix != string::npos) {
2428 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
2429 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
2430 session_name = Glib::path_get_basename (session_name);
2431 } else {
2432 session_path = ARDOUR_COMMAND_LINE::session_name;
2433 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
2436 } else {
2438 bool const apply = run_startup (should_be_new, load_template);
2440 if (!apply) {
2441 if (quit_on_cancel) {
2442 exit (1);
2443 } else {
2444 return ret;
2448 /* if we run the startup dialog again, offer more than just "new session" */
2450 should_be_new = false;
2452 session_name = _startup->session_name (likely_new);
2454 /* this shouldn't happen, but we catch it just in case it does */
2456 if (session_name.empty()) {
2457 continue;
2460 if (_startup->use_session_template()) {
2461 template_name = _startup->session_template_name();
2462 _session_is_new = true;
2465 if (session_name[0] == G_DIR_SEPARATOR ||
2466 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
2467 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)) {
2469 /* absolute path or cwd-relative path specified for session name: infer session folder
2470 from what was given.
2473 session_path = Glib::path_get_dirname (session_name);
2474 session_name = Glib::path_get_basename (session_name);
2476 } else {
2478 session_path = _startup->session_folder();
2480 if (session_name.find ('/') != string::npos) {
2481 MessageDialog msg (*_startup,
2482 _("To ensure compatibility with various systems\n"
2483 "session names may not contain a '/' character"));
2484 msg.run ();
2485 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2486 continue;
2489 if (session_name.find ('\\') != string::npos) {
2490 MessageDialog msg (*_startup,
2491 _("To ensure compatibility with various systems\n"
2492 "session names may not contain a '\\' character"));
2493 msg.run ();
2494 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2495 continue;
2500 if (create_engine ()) {
2501 break;
2504 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
2506 if (likely_new) {
2508 std::string existing = Glib::build_filename (session_path, session_name);
2510 if (!ask_about_loading_existing_session (existing)) {
2511 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2512 continue;
2516 _session_is_new = false;
2518 } else {
2520 if (!likely_new) {
2521 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
2522 msg.run ();
2523 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2524 continue;
2527 if (session_name.find ('/') != std::string::npos) {
2528 MessageDialog msg (*_startup,
2529 _("To ensure compatibility with various systems\n"
2530 "session names may not contain a '/' character"));
2531 msg.run ();
2532 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2533 continue;
2536 if (session_name.find ('\\') != std::string::npos) {
2537 MessageDialog msg (*_startup,
2538 _("To ensure compatibility with various systems\n"
2539 "session names may not contain a '\\' character"));
2540 msg.run ();
2541 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2542 continue;
2545 _session_is_new = true;
2548 if (likely_new && template_name.empty()) {
2550 ret = build_session_from_nsd (session_path, session_name);
2552 } else {
2554 ret = load_session (session_path, session_name, template_name);
2556 if (ret == -2) {
2557 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
2558 exit (1);
2561 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
2562 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
2563 exit (1);
2568 return ret;
2571 void
2572 ARDOUR_UI::close_session()
2574 if (!check_audioengine()) {
2575 return;
2578 if (unload_session (true)) {
2579 return;
2582 ARDOUR_COMMAND_LINE::session_name = "";
2584 if (get_session_parameters (true, false)) {
2585 exit (1);
2588 goto_editor_window ();
2591 /** @param snap_name Snapshot name (without .ardour suffix).
2592 * @return -2 if the load failed because we are not connected to the AudioEngine.
2595 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
2597 Session *new_session;
2598 int unload_status;
2599 int retval = -1;
2601 session_loaded = false;
2603 if (!check_audioengine()) {
2604 return -2;
2607 unload_status = unload_session ();
2609 if (unload_status < 0) {
2610 goto out;
2611 } else if (unload_status > 0) {
2612 retval = 0;
2613 goto out;
2616 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
2618 try {
2619 new_session = new Session (*engine, path, snap_name, 0, mix_template);
2622 /* this one is special */
2624 catch (AudioEngine::PortRegistrationFailure& err) {
2626 MessageDialog msg (err.what(),
2627 true,
2628 Gtk::MESSAGE_INFO,
2629 Gtk::BUTTONS_CLOSE);
2631 msg.set_title (_("Port Registration Error"));
2632 msg.set_secondary_text (_("Click the Close button to try again."));
2633 msg.set_position (Gtk::WIN_POS_CENTER);
2634 pop_back_splash ();
2635 msg.present ();
2637 int response = msg.run ();
2639 msg.hide ();
2641 switch (response) {
2642 case RESPONSE_CANCEL:
2643 exit (1);
2644 default:
2645 break;
2647 goto out;
2650 catch (...) {
2652 MessageDialog msg (string_compose(
2653 _("Session \"%1 (snapshot %2)\" did not load successfully"),
2654 path, snap_name),
2655 true,
2656 Gtk::MESSAGE_INFO,
2657 BUTTONS_OK);
2659 msg.set_title (_("Loading Error"));
2660 msg.set_secondary_text (_("Click the Refresh button to try again."));
2661 msg.add_button (Stock::REFRESH, 1);
2662 msg.set_position (Gtk::WIN_POS_CENTER);
2663 pop_back_splash ();
2664 msg.present ();
2666 int response = msg.run ();
2668 switch (response) {
2669 case 1:
2670 break;
2671 default:
2672 exit (1);
2675 msg.hide ();
2677 goto out;
2681 list<string> const u = new_session->unknown_processors ();
2682 if (!u.empty()) {
2683 MissingPluginDialog d (_session, u);
2684 d.run ();
2688 /* Now the session been created, add the transport controls */
2689 new_session->add_controllable(roll_controllable);
2690 new_session->add_controllable(stop_controllable);
2691 new_session->add_controllable(goto_start_controllable);
2692 new_session->add_controllable(goto_end_controllable);
2693 new_session->add_controllable(auto_loop_controllable);
2694 new_session->add_controllable(play_selection_controllable);
2695 new_session->add_controllable(rec_controllable);
2697 set_session (new_session);
2699 session_loaded = true;
2701 goto_editor_window ();
2703 if (_session) {
2704 _session->set_clean ();
2707 flush_pending ();
2708 retval = 0;
2710 out:
2711 return retval;
2715 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
2717 Session *new_session;
2718 int x;
2720 if (!check_audioengine()) {
2721 return -1;
2724 session_loaded = false;
2726 x = unload_session ();
2728 if (x < 0) {
2729 return -1;
2730 } else if (x > 0) {
2731 return 0;
2734 _session_is_new = true;
2736 try {
2737 new_session = new Session (*engine, path, snap_name, &bus_profile);
2740 catch (...) {
2742 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
2743 pop_back_splash ();
2744 msg.run ();
2745 return -1;
2748 /* Give the new session the default GUI state, if such things exist */
2750 XMLNode* n;
2751 n = Config->instant_xml (X_("Editor"));
2752 if (n) {
2753 new_session->add_instant_xml (*n, false);
2755 n = Config->instant_xml (X_("Mixer"));
2756 if (n) {
2757 new_session->add_instant_xml (*n, false);
2760 /* Put the playhead at 0 and scroll fully left */
2761 n = new_session->instant_xml (X_("Editor"));
2762 if (n) {
2763 n->add_property (X_("playhead"), X_("0"));
2764 n->add_property (X_("left-frame"), X_("0"));
2767 set_session (new_session);
2769 session_loaded = true;
2771 new_session->save_state(new_session->name());
2773 return 0;
2776 void
2777 ARDOUR_UI::launch_chat ()
2779 #ifdef __APPLE__
2780 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
2781 #else
2782 open_uri("http://webchat.freenode.net/?channels=ardour");
2783 #endif
2786 void
2787 ARDOUR_UI::show_about ()
2789 if (about == 0) {
2790 about = new About;
2791 about->signal_response().connect(sigc::mem_fun (*this, &ARDOUR_UI::about_signal_response) );
2794 about->set_transient_for(*editor);
2795 about->show_all ();
2798 void
2799 ARDOUR_UI::launch_manual ()
2801 PBD::open_uri("http://ardour.org/flossmanual");
2804 void
2805 ARDOUR_UI::launch_reference ()
2807 PBD::open_uri("http://ardour.org/refmanual");
2810 void
2811 ARDOUR_UI::hide_about ()
2813 if (about) {
2814 about->get_window()->set_cursor ();
2815 about->hide ();
2819 void
2820 ARDOUR_UI::about_signal_response (int /*response*/)
2822 hide_about();
2825 void
2826 ARDOUR_UI::show_splash ()
2828 if (splash == 0) {
2829 try {
2830 splash = new Splash;
2831 } catch (...) {
2832 return;
2836 splash->show ();
2837 splash->present ();
2838 splash->queue_draw ();
2839 splash->get_window()->process_updates (true);
2840 flush_pending ();
2843 void
2844 ARDOUR_UI::hide_splash ()
2846 if (splash) {
2847 splash->hide();
2851 void
2852 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title,
2853 const string& plural_msg, const string& singular_msg)
2855 size_t removed;
2857 removed = rep.paths.size();
2859 if (removed == 0) {
2860 MessageDialog msgd (*editor,
2861 _("No files were ready for clean-up"),
2862 true,
2863 Gtk::MESSAGE_INFO,
2864 (Gtk::ButtonsType)(Gtk::BUTTONS_OK) );
2865 msgd.set_title (_("Clean-up"));
2866 msgd.set_secondary_text (_("If this seems suprising, \n\
2867 check for any existing snapshots.\n\
2868 These may still include regions that\n\
2869 require some unused files to continue to exist."));
2871 msgd.run ();
2872 return;
2875 ArdourDialog results (_("Clean-up"), true, false);
2877 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
2878 CleanupResultsModelColumns() {
2879 add (visible_name);
2880 add (fullpath);
2882 Gtk::TreeModelColumn<std::string> visible_name;
2883 Gtk::TreeModelColumn<std::string> fullpath;
2887 CleanupResultsModelColumns results_columns;
2888 Glib::RefPtr<Gtk::ListStore> results_model;
2889 Gtk::TreeView results_display;
2891 results_model = ListStore::create (results_columns);
2892 results_display.set_model (results_model);
2893 results_display.append_column (list_title, results_columns.visible_name);
2895 results_display.set_name ("CleanupResultsList");
2896 results_display.set_headers_visible (true);
2897 results_display.set_headers_clickable (false);
2898 results_display.set_reorderable (false);
2900 Gtk::ScrolledWindow list_scroller;
2901 Gtk::Label txt;
2902 Gtk::VBox dvbox;
2903 Gtk::HBox dhbox; // the hbox for the image and text
2904 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
2905 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
2907 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
2909 const string dead_directory = _session->session_directory().dead_path().to_string();
2911 /* subst:
2912 %1 - number of files removed
2913 %2 - location of "dead"
2914 %3 - size of files affected
2915 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
2918 const char* bprefix;
2919 double space_adjusted = 0;
2921 if (rep.space < 1000) {
2922 bprefix = X_("");
2923 space_adjusted = rep.space;
2924 } else if (rep.space < 1000000) {
2925 bprefix = X_("kilo");
2926 space_adjusted = truncf((float)rep.space / 1000.0);
2927 } else if (rep.space < 1000000 * 1000) {
2928 bprefix = X_("mega");
2929 space_adjusted = truncf((float)rep.space / (1000.0 * 1000.0));
2930 } else {
2931 bprefix = X_("giga");
2932 space_adjusted = truncf((float)rep.space / (1000.0 * 1000 * 1000.0));
2935 if (removed > 1) {
2936 txt.set_text (string_compose (plural_msg, removed, dead_directory, space_adjusted, bprefix));
2937 } else {
2938 txt.set_text (string_compose (singular_msg, removed, dead_directory, space_adjusted, bprefix));
2941 dhbox.pack_start (*dimage, true, false, 5);
2942 dhbox.pack_start (txt, true, false, 5);
2944 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
2945 TreeModel::Row row = *(results_model->append());
2946 row[results_columns.visible_name] = *i;
2947 row[results_columns.fullpath] = *i;
2950 list_scroller.add (results_display);
2951 list_scroller.set_size_request (-1, 150);
2952 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
2954 dvbox.pack_start (dhbox, true, false, 5);
2955 dvbox.pack_start (list_scroller, true, false, 5);
2956 ddhbox.pack_start (dvbox, true, false, 5);
2958 results.get_vbox()->pack_start (ddhbox, true, false, 5);
2959 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
2960 results.set_default_response (RESPONSE_CLOSE);
2961 results.set_position (Gtk::WIN_POS_MOUSE);
2963 results_display.show();
2964 list_scroller.show();
2965 txt.show();
2966 dvbox.show();
2967 dhbox.show();
2968 ddhbox.show();
2969 dimage->show();
2971 //results.get_vbox()->show();
2972 results.set_resizable (false);
2974 results.run ();
2978 void
2979 ARDOUR_UI::cleanup ()
2981 if (_session == 0) {
2982 /* shouldn't happen: menu item is insensitive */
2983 return;
2987 MessageDialog checker (_("Are you sure you want to clean-up?"),
2988 true,
2989 Gtk::MESSAGE_QUESTION,
2990 (Gtk::ButtonsType)(Gtk::BUTTONS_NONE));
2992 checker.set_title (_("Clean-up"));
2994 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
2995 ALL undo/redo information will be lost if you clean-up.\n\
2996 Clean-up will move all unused files to a \"dead\" location."));
2998 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
2999 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
3000 checker.set_default_response (RESPONSE_CANCEL);
3002 checker.set_name (_("CleanupDialog"));
3003 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3004 checker.set_position (Gtk::WIN_POS_MOUSE);
3006 switch (checker.run()) {
3007 case RESPONSE_ACCEPT:
3008 break;
3009 default:
3010 return;
3013 ARDOUR::CleanupReport rep;
3015 editor->prepare_for_cleanup ();
3017 /* do not allow flush until a session is reloaded */
3019 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3020 if (act) {
3021 act->set_sensitive (false);
3024 if (_session->cleanup_sources (rep)) {
3025 editor->finish_cleanup ();
3026 return;
3029 editor->finish_cleanup ();
3031 checker.hide();
3032 display_cleanup_results (rep,
3033 _("Cleaned Files"),
3034 _("\
3035 The following %1 files were not in use and \n\
3036 have been moved to:\n\n\
3037 %2\n\n\
3038 After a restart of Ardour,\n\n\
3039 Session -> Clean-up -> Flush Wastebasket\n\n\
3040 will release an additional\n\
3041 %3 %4bytes of disk space.\n"),
3042 _("\
3043 The following file was not in use and \n\
3044 has been moved to:\n \
3045 %2\n\n\
3046 After a restart of Ardour,\n\n\
3047 Session -> Clean-up -> Flush Wastebasket\n\n\
3048 will release an additional\n\
3049 %3 %4bytes of disk space.\n"
3054 void
3055 ARDOUR_UI::flush_trash ()
3057 if (_session == 0) {
3058 /* shouldn't happen: menu item is insensitive */
3059 return;
3062 ARDOUR::CleanupReport rep;
3064 if (_session->cleanup_trash_sources (rep)) {
3065 return;
3068 display_cleanup_results (rep,
3069 _("deleted file"),
3070 _("The following %1 files were deleted from\n\
3071 %2,\n\
3072 releasing %3 %4bytes of disk space"),
3073 _("The following file was deleted from\n\
3074 %2,\n\
3075 releasing %3 %4bytes of disk space"));
3078 void
3079 ARDOUR_UI::add_route (Gtk::Window* float_window)
3081 int count;
3083 if (!_session) {
3084 return;
3087 if (add_route_dialog == 0) {
3088 add_route_dialog = new AddRouteDialog (_session);
3089 if (float_window) {
3090 add_route_dialog->set_transient_for (*float_window);
3094 if (add_route_dialog->is_visible()) {
3095 /* we're already doing this */
3096 return;
3099 ResponseType r = (ResponseType) add_route_dialog->run ();
3101 add_route_dialog->hide();
3103 switch (r) {
3104 case RESPONSE_ACCEPT:
3105 break;
3106 default:
3107 return;
3108 break;
3111 if ((count = add_route_dialog->count()) <= 0) {
3112 return;
3115 string template_path = add_route_dialog->track_template();
3117 if (!template_path.empty()) {
3118 _session->new_route_from_template (count, template_path);
3119 return;
3122 uint32_t input_chan = add_route_dialog->channels ();
3123 uint32_t output_chan;
3124 string name_template = add_route_dialog->name_template ();
3125 bool track = add_route_dialog->track ();
3126 RouteGroup* route_group = add_route_dialog->route_group ();
3128 AutoConnectOption oac = Config->get_output_auto_connect();
3130 if (oac & AutoConnectMaster) {
3131 output_chan = (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan);
3132 } else {
3133 output_chan = input_chan;
3136 /* XXX do something with name template */
3138 if (add_route_dialog->type() == ARDOUR::DataType::MIDI) {
3139 if (track) {
3140 session_add_midi_track (route_group, count, name_template);
3141 } else {
3142 MessageDialog msg (*editor,
3143 _("Sorry, MIDI Busses are not supported at this time."));
3144 msg.run ();
3145 //session_add_midi_bus();
3147 } else {
3148 if (track) {
3149 session_add_audio_track (input_chan, output_chan, add_route_dialog->mode(), route_group, count, name_template);
3150 } else {
3151 session_add_audio_bus (input_chan, output_chan, route_group, count, name_template);
3156 XMLNode*
3157 ARDOUR_UI::mixer_settings () const
3159 XMLNode* node = 0;
3161 if (_session) {
3162 node = _session->instant_xml(X_("Mixer"));
3163 } else {
3164 node = Config->instant_xml(X_("Mixer"));
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"));
3181 } else {
3182 node = Config->instant_xml(X_("Editor"));
3185 if (!node) {
3186 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
3187 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
3191 if (!node) {
3192 node = new XMLNode (X_("Editor"));
3195 return node;
3198 XMLNode*
3199 ARDOUR_UI::keyboard_settings () const
3201 XMLNode* node = 0;
3203 node = Config->extra_xml(X_("Keyboard"));
3205 if (!node) {
3206 node = new XMLNode (X_("Keyboard"));
3209 return node;
3212 void
3213 ARDOUR_UI::create_xrun_marker (framepos_t where)
3215 editor->mouse_add_new_marker (where, false, true);
3218 void
3219 ARDOUR_UI::halt_on_xrun_message ()
3221 MessageDialog msg (*editor,
3222 _("Recording was stopped because your system could not keep up."));
3223 msg.run ();
3226 void
3227 ARDOUR_UI::xrun_handler (framepos_t where)
3229 if (!_session) {
3230 return;
3233 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
3235 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
3236 create_xrun_marker(where);
3239 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
3240 halt_on_xrun_message ();
3244 void
3245 ARDOUR_UI::disk_overrun_handler ()
3247 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
3249 if (!have_disk_speed_dialog_displayed) {
3250 have_disk_speed_dialog_displayed = true;
3251 MessageDialog* msg = new MessageDialog (*editor, string_compose (_("\
3252 The disk system on your computer\n\
3253 was not able to keep up with %1.\n\
3255 Specifically, it failed to write data to disk\n\
3256 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
3257 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3258 msg->show ();
3262 void
3263 ARDOUR_UI::disk_underrun_handler ()
3265 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
3267 if (!have_disk_speed_dialog_displayed) {
3268 have_disk_speed_dialog_displayed = true;
3269 MessageDialog* msg = new MessageDialog (
3270 *editor, string_compose (_("The disk system on your computer\n\
3271 was not able to keep up with %1.\n\
3273 Specifically, it failed to read data from disk\n\
3274 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
3275 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3276 msg->show ();
3280 void
3281 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
3283 have_disk_speed_dialog_displayed = false;
3284 delete msg;
3287 void
3288 ARDOUR_UI::session_dialog (std::string msg)
3290 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
3292 MessageDialog* d;
3294 if (editor) {
3295 d = new MessageDialog (*editor, msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3296 } else {
3297 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3300 d->show_all ();
3301 d->run ();
3302 delete d;
3306 ARDOUR_UI::pending_state_dialog ()
3308 HBox* hbox = new HBox();
3309 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3310 ArdourDialog dialog (_("Crash Recovery"), true);
3311 Label message (_("\
3312 This session appears to have been in\n\
3313 middle of recording when ardour or\n\
3314 the computer was shutdown.\n\
3316 Ardour can recover any captured audio for\n\
3317 you, or it can ignore it. Please decide\n\
3318 what you would like to do.\n"));
3319 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3320 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3321 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3322 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3323 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
3324 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
3325 dialog.set_default_response (RESPONSE_ACCEPT);
3326 dialog.set_position (WIN_POS_CENTER);
3327 message.show();
3328 image->show();
3329 hbox->show();
3331 switch (dialog.run ()) {
3332 case RESPONSE_ACCEPT:
3333 return 1;
3334 default:
3335 return 0;
3340 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
3342 HBox* hbox = new HBox();
3343 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3344 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
3345 Label message (string_compose (_("\
3346 This session was created with a sample rate of %1 Hz\n\
3348 The audioengine is currently running at %2 Hz\n"), desired, actual));
3350 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3351 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3352 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3353 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3354 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
3355 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
3356 dialog.set_default_response (RESPONSE_ACCEPT);
3357 dialog.set_position (WIN_POS_CENTER);
3358 message.show();
3359 image->show();
3360 hbox->show();
3362 switch (dialog.run ()) {
3363 case RESPONSE_ACCEPT:
3364 return 0;
3365 default:
3366 return 1;
3371 void
3372 ARDOUR_UI::disconnect_from_jack ()
3374 if (engine) {
3375 if( engine->disconnect_from_jack ()) {
3376 MessageDialog msg (*editor, _("Could not disconnect from JACK"));
3377 msg.run ();
3380 update_sample_rate (0);
3384 void
3385 ARDOUR_UI::reconnect_to_jack ()
3387 if (engine) {
3388 if (engine->reconnect_to_jack ()) {
3389 MessageDialog msg (*editor, _("Could not reconnect to JACK"));
3390 msg.run ();
3393 update_sample_rate (0);
3397 void
3398 ARDOUR_UI::use_config ()
3400 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
3401 if (node) {
3402 set_transport_controllable_state (*node);
3406 void
3407 ARDOUR_UI::update_transport_clocks (framepos_t pos)
3409 if (Config->get_primary_clock_delta_edit_cursor()) {
3410 primary_clock->set (pos, false, editor->get_preferred_edit_position(), 1);
3411 } else {
3412 primary_clock->set (pos, 0, true);
3415 if (Config->get_secondary_clock_delta_edit_cursor()) {
3416 secondary_clock->set (pos, false, editor->get_preferred_edit_position(), 2);
3417 } else {
3418 secondary_clock->set (pos);
3421 if (big_clock_window->get()) {
3422 big_clock->set (pos);
3427 void
3428 ARDOUR_UI::step_edit_status_change (bool yn)
3430 // XXX should really store pre-step edit status of things
3431 // we make insensitive
3433 if (yn) {
3434 rec_button.set_visual_state (3);
3435 rec_button.set_sensitive (false);
3436 } else {
3437 rec_button.set_visual_state (0);
3438 rec_button.set_sensitive (true);
3442 void
3443 ARDOUR_UI::record_state_changed ()
3445 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
3447 if (!_session || !big_clock_window->get()) {
3448 /* why bother - the clock isn't visible */
3449 return;
3452 Session::RecordState const r = _session->record_status ();
3453 bool const h = _session->have_rec_enabled_track ();
3455 if (r == Session::Recording && h) {
3456 big_clock->set_widget_name ("BigClockRecording");
3457 } else {
3458 big_clock->set_widget_name ("BigClockNonRecording");
3462 bool
3463 ARDOUR_UI::first_idle ()
3465 if (_session) {
3466 _session->allow_auto_play (true);
3469 if (editor) {
3470 editor->first_idle();
3473 Keyboard::set_can_save_keybindings (true);
3474 return false;
3477 void
3478 ARDOUR_UI::store_clock_modes ()
3480 XMLNode* node = new XMLNode(X_("ClockModes"));
3482 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
3483 XMLNode* child = new XMLNode (X_("Clock"));
3485 child->add_property (X_("name"), (*x)->name());
3486 child->add_property (X_("mode"), enum_2_string ((*x)->mode()));
3487 child->add_property (X_("on"), ((*x)->off() ? X_("no") : X_("yes")));
3489 node->add_child_nocopy (*child);
3492 _session->add_extra_xml (*node);
3493 _session->set_dirty ();
3496 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
3497 : Controllable (name), ui (u), type(tp)
3502 void
3503 ARDOUR_UI::TransportControllable::set_value (double val)
3505 if (val < 0.5) {
3506 /* do nothing: these are radio-style actions */
3507 return;
3510 const char *action = 0;
3512 switch (type) {
3513 case Roll:
3514 action = X_("Roll");
3515 break;
3516 case Stop:
3517 action = X_("Stop");
3518 break;
3519 case GotoStart:
3520 action = X_("Goto Start");
3521 break;
3522 case GotoEnd:
3523 action = X_("Goto End");
3524 break;
3525 case AutoLoop:
3526 action = X_("Loop");
3527 break;
3528 case PlaySelection:
3529 action = X_("Play Selection");
3530 break;
3531 case RecordEnable:
3532 action = X_("Record");
3533 break;
3534 default:
3535 break;
3538 if (action == 0) {
3539 return;
3542 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
3544 if (act) {
3545 act->activate ();
3549 double
3550 ARDOUR_UI::TransportControllable::get_value (void) const
3552 float val = 0.0;
3554 switch (type) {
3555 case Roll:
3556 break;
3557 case Stop:
3558 break;
3559 case GotoStart:
3560 break;
3561 case GotoEnd:
3562 break;
3563 case AutoLoop:
3564 break;
3565 case PlaySelection:
3566 break;
3567 case RecordEnable:
3568 break;
3569 default:
3570 break;
3573 return val;
3576 void
3577 ARDOUR_UI::TransportControllable::set_id (const string& str)
3579 _id = str;
3582 void
3583 ARDOUR_UI::setup_profile ()
3585 if (gdk_screen_width() < 1200) {
3586 Profile->set_small_screen ();
3590 if (getenv ("ARDOUR_SAE")) {
3591 Profile->set_sae ();
3592 Profile->set_single_package ();
3596 void
3597 ARDOUR_UI::toggle_translations ()
3599 using namespace Glib;
3601 RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("EnableTranslation"));
3602 if (act) {
3603 RefPtr<ToggleAction> ract = RefPtr<ToggleAction>::cast_dynamic (act);
3604 if (ract) {
3606 string i18n_killer = ARDOUR::translation_kill_path();
3608 bool already_enabled = !ARDOUR::translations_are_disabled ();
3610 if (ract->get_active ()) {
3611 /* we don't care about errors */
3612 int fd = ::open (i18n_killer.c_str(), O_RDONLY|O_CREAT, 0644);
3613 close (fd);
3614 } else {
3615 /* we don't care about errors */
3616 unlink (i18n_killer.c_str());
3619 if (already_enabled != ract->get_active()) {
3620 MessageDialog win (already_enabled ? _("Translations disabled") : _("Translations enabled"),
3621 false,
3622 Gtk::MESSAGE_WARNING,
3623 Gtk::BUTTONS_OK);
3624 win.set_secondary_text (string_compose (_("You must restart %1 for this to take effect."), PROGRAM_NAME));
3625 win.set_position (Gtk::WIN_POS_CENTER);
3626 win.present ();
3627 win.run ();
3633 /** Add a window proxy to our list, so that its state will be saved.
3634 * This call also causes the window to be created and opened if its
3635 * state was saved as `visible'.
3637 void
3638 ARDOUR_UI::add_window_proxy (WindowProxyBase* p)
3640 _window_proxies.push_back (p);
3641 p->maybe_show ();
3644 /** Remove a window proxy from our list. Must be called if a WindowProxy
3645 * is deleted, to prevent hanging pointers.
3647 void
3648 ARDOUR_UI::remove_window_proxy (WindowProxyBase* p)
3650 _window_proxies.remove (p);
3654 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
3656 MissingFileDialog dialog (s, str, type);
3658 dialog.show ();
3659 dialog.present ();
3661 int result = dialog.run ();
3662 dialog.hide ();
3664 switch (result) {
3665 case RESPONSE_OK:
3666 break;
3667 default:
3668 return 1; // quit entire session load
3671 result = dialog.get_action ();
3673 return result;
3677 ARDOUR_UI::ambiguous_file (std::string file, std::string path, std::vector<std::string> hits)
3679 AmbiguousFileDialog dialog (file, hits);
3681 dialog.show ();
3682 dialog.present ();
3684 dialog.run ();
3685 return dialog.get_which ();