Remove erroneous assert which I added earlier.
[ardour2.git] / gtk2_ardour / ardour_ui.cc
blob71768c699cd59ef2d22eb8db4118549523834a38
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];
1000 if (_session) {
1001 snprintf (buf, sizeof (buf), _("Buffers p:%" PRIu32 "%% c:%" PRIu32 "%%"),
1002 _session->playback_load(), _session->capture_load());
1003 buffer_load_label.set_text (buf);
1004 } else {
1005 buffer_load_label.set_text ("");
1009 void
1010 ARDOUR_UI::count_recenabled_streams (Route& route)
1012 Track* track = dynamic_cast<Track*>(&route);
1013 if (track && track->record_enabled()) {
1014 rec_enabled_streams += track->n_inputs().n_total();
1018 void
1019 ARDOUR_UI::update_disk_space()
1021 if (_session == 0) {
1022 return;
1025 framecnt_t frames = _session->available_capture_duration();
1026 char buf[64];
1027 framecnt_t fr = _session->frame_rate();
1029 if (frames == max_framecnt) {
1030 strcpy (buf, _("Disk: 24hrs+"));
1031 } else {
1032 rec_enabled_streams = 0;
1033 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams);
1035 if (rec_enabled_streams) {
1036 frames /= rec_enabled_streams;
1039 int hrs;
1040 int mins;
1041 int secs;
1043 hrs = frames / (fr * 3600);
1044 frames -= hrs * fr * 3600;
1045 mins = frames / (fr * 60);
1046 frames -= mins * fr * 60;
1047 secs = frames / fr;
1049 snprintf (buf, sizeof(buf), _("Disk: %02dh:%02dm:%02ds"), hrs, mins, secs);
1052 disk_space_label.set_text (buf);
1054 // An attempt to make the disk space label flash red when space has run out.
1056 if (frames < fr * 60 * 5) {
1057 /* disk_space_box.style ("disk_space_label_empty"); */
1058 } else {
1059 /* disk_space_box.style ("disk_space_label"); */
1064 gint
1065 ARDOUR_UI::update_wall_clock ()
1067 time_t now;
1068 struct tm *tm_now;
1069 char buf[16];
1071 time (&now);
1072 tm_now = localtime (&now);
1074 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1075 wall_clock_label.set_text (buf);
1077 return TRUE;
1080 gint
1081 ARDOUR_UI::session_menu (GdkEventButton */*ev*/)
1083 session_popup_menu->popup (0, 0);
1084 return TRUE;
1087 void
1088 ARDOUR_UI::redisplay_recent_sessions ()
1090 std::vector<sys::path> session_directories;
1091 RecentSessionsSorter cmp;
1093 recent_session_display.set_model (Glib::RefPtr<TreeModel>(0));
1094 recent_session_model->clear ();
1096 ARDOUR::RecentSessions rs;
1097 ARDOUR::read_recent_sessions (rs);
1099 if (rs.empty()) {
1100 recent_session_display.set_model (recent_session_model);
1101 return;
1104 // sort them alphabetically
1105 sort (rs.begin(), rs.end(), cmp);
1107 for (ARDOUR::RecentSessions::iterator i = rs.begin(); i != rs.end(); ++i) {
1108 session_directories.push_back ((*i).second);
1111 for (vector<sys::path>::const_iterator i = session_directories.begin();
1112 i != session_directories.end(); ++i)
1114 std::vector<sys::path> state_file_paths;
1116 // now get available states for this session
1118 get_state_files_in_directory (*i, state_file_paths);
1120 vector<string*>* states;
1121 vector<const gchar*> item;
1122 string fullpath = (*i).to_string();
1124 /* remove any trailing / */
1126 if (fullpath[fullpath.length()-1] == '/') {
1127 fullpath = fullpath.substr (0, fullpath.length()-1);
1130 /* check whether session still exists */
1131 if (!Glib::file_test(fullpath.c_str(), Glib::FILE_TEST_EXISTS)) {
1132 /* session doesn't exist */
1133 cerr << "skipping non-existent session " << fullpath << endl;
1134 continue;
1137 /* now get available states for this session */
1139 if ((states = Session::possible_states (fullpath)) == 0) {
1140 /* no state file? */
1141 continue;
1144 std::vector<string> state_file_names(get_file_names_no_extension (state_file_paths));
1146 Gtk::TreeModel::Row row = *(recent_session_model->append());
1148 row[recent_session_columns.visible_name] = Glib::path_get_basename (fullpath);
1149 row[recent_session_columns.fullpath] = fullpath;
1151 if (state_file_names.size() > 1) {
1153 // add the children
1155 for (std::vector<std::string>::iterator i2 = state_file_names.begin();
1156 i2 != state_file_names.end(); ++i2)
1159 Gtk::TreeModel::Row child_row = *(recent_session_model->append (row.children()));
1161 child_row[recent_session_columns.visible_name] = *i2;
1162 child_row[recent_session_columns.fullpath] = fullpath;
1167 recent_session_display.set_model (recent_session_model);
1170 void
1171 ARDOUR_UI::build_session_selector ()
1173 session_selector_window = new ArdourDialog (_("Recent Sessions"));
1175 Gtk::ScrolledWindow *scroller = manage (new Gtk::ScrolledWindow);
1177 session_selector_window->add_button (Stock::CANCEL, RESPONSE_CANCEL);
1178 session_selector_window->add_button (Stock::OPEN, RESPONSE_ACCEPT);
1179 session_selector_window->set_default_response (RESPONSE_ACCEPT);
1180 recent_session_model = TreeStore::create (recent_session_columns);
1181 recent_session_display.set_model (recent_session_model);
1182 recent_session_display.append_column (_("Recent Sessions"), recent_session_columns.visible_name);
1183 recent_session_display.set_headers_visible (false);
1184 recent_session_display.get_selection()->set_mode (SELECTION_BROWSE);
1185 recent_session_display.signal_row_activated().connect (sigc::mem_fun (*this, &ARDOUR_UI::recent_session_row_activated));
1187 scroller->add (recent_session_display);
1188 scroller->set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
1190 session_selector_window->set_name ("SessionSelectorWindow");
1191 session_selector_window->set_size_request (200, 400);
1192 session_selector_window->get_vbox()->pack_start (*scroller);
1194 recent_session_display.show();
1195 scroller->show();
1196 //session_selector_window->get_vbox()->show();
1199 void
1200 ARDOUR_UI::recent_session_row_activated (const TreePath& /*path*/, TreeViewColumn* /*col*/)
1202 session_selector_window->response (RESPONSE_ACCEPT);
1205 void
1206 ARDOUR_UI::open_recent_session ()
1208 bool can_return = (_session != 0);
1210 if (session_selector_window == 0) {
1211 build_session_selector ();
1214 redisplay_recent_sessions ();
1216 while (true) {
1218 session_selector_window->set_position (WIN_POS_MOUSE);
1220 ResponseType r = (ResponseType) session_selector_window->run ();
1222 switch (r) {
1223 case RESPONSE_ACCEPT:
1224 break;
1225 default:
1226 if (can_return) {
1227 session_selector_window->hide();
1228 return;
1229 } else {
1230 exit (1);
1234 if (recent_session_display.get_selection()->count_selected_rows() == 0) {
1235 continue;
1238 session_selector_window->hide();
1240 Gtk::TreeModel::iterator i = recent_session_display.get_selection()->get_selected();
1242 if (i == recent_session_model->children().end()) {
1243 return;
1246 std::string path = (*i)[recent_session_columns.fullpath];
1247 std::string state = (*i)[recent_session_columns.visible_name];
1249 _session_is_new = false;
1251 if (load_session (path, state) == 0) {
1252 break;
1255 can_return = false;
1259 bool
1260 ARDOUR_UI::check_audioengine ()
1262 if (engine) {
1263 if (!engine->connected()) {
1264 MessageDialog msg (string_compose (
1265 _("%1 is not connected to JACK\n"
1266 "You cannot open or close sessions in this condition"),
1267 PROGRAM_NAME));
1268 pop_back_splash ();
1269 msg.run ();
1270 return false;
1272 return true;
1273 } else {
1274 return false;
1278 void
1279 ARDOUR_UI::open_session ()
1281 if (!check_audioengine()) {
1282 return;
1286 /* popup selector window */
1288 if (open_session_selector == 0) {
1290 /* ardour sessions are folders */
1292 open_session_selector = new Gtk::FileChooserDialog (_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1293 open_session_selector->add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1294 open_session_selector->add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1295 open_session_selector->set_default_response(Gtk::RESPONSE_ACCEPT);
1297 FileFilter session_filter;
1298 session_filter.add_pattern ("*.ardour");
1299 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1300 open_session_selector->add_filter (session_filter);
1301 open_session_selector->set_filter (session_filter);
1304 int response = open_session_selector->run();
1305 open_session_selector->hide ();
1307 switch (response) {
1308 case RESPONSE_ACCEPT:
1309 break;
1310 default:
1311 open_session_selector->hide();
1312 return;
1315 open_session_selector->hide();
1316 string session_path = open_session_selector->get_filename();
1317 string path, name;
1318 bool isnew;
1320 if (session_path.length() > 0) {
1321 if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1322 _session_is_new = isnew;
1323 load_session (path, name);
1329 void
1330 ARDOUR_UI::session_add_midi_route (bool disk, RouteGroup* route_group, uint32_t how_many, string const & name_template)
1332 list<boost::shared_ptr<MidiTrack> > tracks;
1334 if (_session == 0) {
1335 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1336 return;
1339 try {
1340 if (disk) {
1342 tracks = _session->new_midi_track (ARDOUR::Normal, route_group, how_many, name_template);
1344 if (tracks.size() != how_many) {
1345 if (how_many == 1) {
1346 error << _("could not create a new midi track") << endmsg;
1347 } else {
1348 error << string_compose (_("could not create %1 new midi tracks"), how_many) << endmsg;
1351 } /*else {
1352 if ((route = _session->new_midi_route ()) == 0) {
1353 error << _("could not create new midi bus") << endmsg;
1358 catch (...) {
1359 MessageDialog msg (*editor,
1360 string_compose (_("There are insufficient JACK ports available\n\
1361 to create a new track or bus.\n\
1362 You should save %1, exit and\n\
1363 restart JACK with more ports."), PROGRAM_NAME));
1364 msg.run ();
1369 void
1370 ARDOUR_UI::session_add_audio_route (
1371 bool track,
1372 int32_t input_channels,
1373 int32_t output_channels,
1374 ARDOUR::TrackMode mode,
1375 RouteGroup* route_group,
1376 uint32_t how_many,
1377 string const & name_template
1380 list<boost::shared_ptr<AudioTrack> > tracks;
1381 RouteList routes;
1383 if (_session == 0) {
1384 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1385 return;
1388 try {
1389 if (track) {
1390 tracks = _session->new_audio_track (input_channels, output_channels, mode, route_group, how_many, name_template);
1392 if (tracks.size() != how_many) {
1393 if (how_many == 1) {
1394 error << _("could not create a new audio track") << endmsg;
1395 } else {
1396 error << string_compose (_("could only create %1 of %2 new audio %3"),
1397 tracks.size(), how_many, (track ? _("tracks") : _("busses"))) << endmsg;
1401 } else {
1403 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template);
1405 if (routes.size() != how_many) {
1406 if (how_many == 1) {
1407 error << _("could not create a new audio track") << endmsg;
1408 } else {
1409 error << string_compose (_("could not create %1 new audio tracks"), how_many) << endmsg;
1415 catch (...) {
1416 MessageDialog msg (*editor,
1417 string_compose (_("There are insufficient JACK ports available\n\
1418 to create a new track or bus.\n\
1419 You should save %1, exit and\n\
1420 restart JACK with more ports."), PROGRAM_NAME));
1421 pop_back_splash ();
1422 msg.run ();
1426 void
1427 ARDOUR_UI::do_transport_locate (framepos_t new_position, bool with_roll)
1429 framecnt_t _preroll = 0;
1431 if (_session) {
1432 // XXX CONFIG_CHANGE FIX - requires AnyTime handling
1433 // _preroll = _session->convert_to_frames_at (new_position, Config->get_preroll());
1435 if (new_position > _preroll) {
1436 new_position -= _preroll;
1437 } else {
1438 new_position = 0;
1441 _session->request_locate (new_position, with_roll);
1445 void
1446 ARDOUR_UI::transport_goto_start ()
1448 if (_session) {
1449 _session->goto_start();
1451 /* force displayed area in editor to start no matter
1452 what "follow playhead" setting is.
1455 if (editor) {
1456 editor->center_screen (_session->current_start_frame ());
1461 void
1462 ARDOUR_UI::transport_goto_zero ()
1464 if (_session) {
1465 _session->request_locate (0);
1467 /* force displayed area in editor to start no matter
1468 what "follow playhead" setting is.
1471 if (editor) {
1472 editor->reset_x_origin (0);
1477 void
1478 ARDOUR_UI::transport_goto_wallclock ()
1480 if (_session && editor) {
1482 time_t now;
1483 struct tm tmnow;
1484 framepos_t frames;
1486 time (&now);
1487 localtime_r (&now, &tmnow);
1489 frames = tmnow.tm_hour * (60 * 60 * _session->frame_rate());
1490 frames += tmnow.tm_min * (60 * _session->frame_rate());
1491 frames += tmnow.tm_sec * _session->frame_rate();
1493 _session->request_locate (frames, _session->transport_rolling ());
1495 /* force displayed area in editor to start no matter
1496 what "follow playhead" setting is.
1499 if (editor) {
1500 editor->center_screen (frames);
1505 void
1506 ARDOUR_UI::transport_goto_end ()
1508 if (_session) {
1509 framepos_t const frame = _session->current_end_frame();
1510 _session->request_locate (frame);
1512 /* force displayed area in editor to start no matter
1513 what "follow playhead" setting is.
1516 if (editor) {
1517 editor->center_screen (frame);
1522 void
1523 ARDOUR_UI::transport_stop ()
1525 if (!_session) {
1526 return;
1529 if (_session->is_auditioning()) {
1530 _session->cancel_audition ();
1531 return;
1534 _session->request_stop (false, true);
1537 void
1538 ARDOUR_UI::transport_stop_and_forget_capture ()
1540 if (_session) {
1541 _session->request_stop (true, true);
1545 void
1546 ARDOUR_UI::remove_last_capture()
1548 if (editor) {
1549 editor->remove_last_capture();
1553 void
1554 ARDOUR_UI::transport_record (bool roll)
1557 if (_session) {
1558 switch (_session->record_status()) {
1559 case Session::Disabled:
1560 if (_session->ntracks() == 0) {
1561 MessageDialog msg (*editor, _("Please create 1 or more track\nbefore trying to record.\nCheck the Session menu."));
1562 msg.run ();
1563 return;
1565 _session->maybe_enable_record ();
1566 if (roll) {
1567 transport_roll ();
1569 break;
1570 case Session::Recording:
1571 if (roll) {
1572 _session->request_stop();
1573 } else {
1574 _session->disable_record (false, true);
1576 break;
1578 case Session::Enabled:
1579 _session->disable_record (false, true);
1582 //cerr << "ARDOUR_UI::transport_record () called roll = " << roll << " _session->record_status() = " << _session->record_status() << endl;
1585 void
1586 ARDOUR_UI::transport_roll ()
1588 if (!_session) {
1589 return;
1592 if (_session->is_auditioning()) {
1593 return;
1596 #if 0
1597 if (_session->config.get_external_sync()) {
1598 switch (_session->config.get_sync_source()) {
1599 case JACK:
1600 break;
1601 default:
1602 /* transport controlled by the master */
1603 return;
1606 #endif
1608 bool rolling = _session->transport_rolling();
1610 if (_session->get_play_loop()) {
1611 /* XXX it is not possible to just leave seamless loop and keep
1612 playing at present (nov 4th 2009)
1614 if (!Config->get_seamless_loop()) {
1615 _session->request_play_loop (false, true);
1617 } else if (_session->get_play_range () && !join_play_range_button.get_active()) {
1618 /* stop playing a range if we currently are */
1619 _session->request_play_range (0, true);
1622 if (join_play_range_button.get_active()) {
1623 _session->request_play_range (&editor->get_selection().time, true);
1626 if (!rolling) {
1627 _session->request_transport_speed (1.0f);
1631 void
1632 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
1635 if (!_session) {
1636 return;
1639 if (_session->is_auditioning()) {
1640 _session->cancel_audition ();
1641 return;
1644 if (_session->config.get_external_sync()) {
1645 switch (_session->config.get_sync_source()) {
1646 case JACK:
1647 break;
1648 default:
1649 /* transport controlled by the master */
1650 return;
1654 bool rolling = _session->transport_rolling();
1655 bool affect_transport = true;
1657 if (rolling && roll_out_of_bounded_mode) {
1658 /* drop out of loop/range playback but leave transport rolling */
1659 if (_session->get_play_loop()) {
1660 if (Config->get_seamless_loop()) {
1661 /* the disk buffers contain copies of the loop - we can't
1662 just keep playing, so stop the transport. the user
1663 can restart as they wish.
1665 affect_transport = true;
1666 } else {
1667 /* disk buffers are normal, so we can keep playing */
1668 affect_transport = false;
1670 _session->request_play_loop (false, true);
1671 } else if (_session->get_play_range ()) {
1672 affect_transport = false;
1673 _session->request_play_range (0, true);
1677 if (affect_transport) {
1678 if (rolling) {
1679 _session->request_stop (with_abort, true);
1680 } else {
1681 if (join_play_range_button.get_active()) {
1682 _session->request_play_range (&editor->get_selection().time, true);
1685 _session->request_transport_speed (1.0f);
1690 void
1691 ARDOUR_UI::toggle_session_auto_loop ()
1693 if (!_session) {
1694 return;
1697 if (_session->get_play_loop()) {
1699 if (_session->transport_rolling()) {
1701 Location * looploc = _session->locations()->auto_loop_location();
1703 if (looploc) {
1704 _session->request_locate (looploc->start(), true);
1705 _session->request_play_loop (false);
1708 } else {
1709 _session->request_play_loop (false);
1711 } else {
1713 Location * looploc = _session->locations()->auto_loop_location();
1715 if (looploc) {
1716 _session->request_play_loop (true);
1721 void
1722 ARDOUR_UI::transport_play_selection ()
1724 if (!_session) {
1725 return;
1728 editor->play_selection ();
1731 void
1732 ARDOUR_UI::transport_rewind (int option)
1734 float current_transport_speed;
1736 if (_session) {
1737 current_transport_speed = _session->transport_speed();
1739 if (current_transport_speed >= 0.0f) {
1740 switch (option) {
1741 case 0:
1742 _session->request_transport_speed (-1.0f);
1743 break;
1744 case 1:
1745 _session->request_transport_speed (-4.0f);
1746 break;
1747 case -1:
1748 _session->request_transport_speed (-0.5f);
1749 break;
1751 } else {
1752 /* speed up */
1753 _session->request_transport_speed (current_transport_speed * 1.5f);
1758 void
1759 ARDOUR_UI::transport_forward (int option)
1761 float current_transport_speed;
1763 if (_session) {
1764 current_transport_speed = _session->transport_speed();
1766 if (current_transport_speed <= 0.0f) {
1767 switch (option) {
1768 case 0:
1769 _session->request_transport_speed (1.0f);
1770 break;
1771 case 1:
1772 _session->request_transport_speed (4.0f);
1773 break;
1774 case -1:
1775 _session->request_transport_speed (0.5f);
1776 break;
1778 } else {
1779 /* speed up */
1780 _session->request_transport_speed (current_transport_speed * 1.5f);
1786 void
1787 ARDOUR_UI::toggle_record_enable (uint32_t rid)
1789 if (_session == 0) {
1790 return;
1793 boost::shared_ptr<Route> r;
1795 if ((r = _session->route_by_remote_id (rid)) != 0) {
1797 Track* t;
1799 if ((t = dynamic_cast<Track*>(r.get())) != 0) {
1800 t->set_record_enabled (!t->record_enabled(), this);
1803 if (_session == 0) {
1804 return;
1808 void
1809 ARDOUR_UI::map_transport_state ()
1811 if (!_session) {
1812 auto_loop_button.set_visual_state (0);
1813 play_selection_button.set_visual_state (0);
1814 roll_button.set_visual_state (0);
1815 stop_button.set_visual_state (1);
1816 return;
1819 shuttle_box->map_transport_state ();
1821 float sp = _session->transport_speed();
1823 if (sp != 0.0f) {
1825 /* we're rolling */
1827 if (_session->get_play_range()) {
1829 play_selection_button.set_visual_state (1);
1830 roll_button.set_visual_state (0);
1831 auto_loop_button.set_visual_state (0);
1833 } else if (_session->get_play_loop ()) {
1835 auto_loop_button.set_visual_state (1);
1836 play_selection_button.set_visual_state (0);
1837 roll_button.set_visual_state (0);
1839 } else {
1841 roll_button.set_visual_state (1);
1842 play_selection_button.set_visual_state (0);
1843 auto_loop_button.set_visual_state (0);
1846 if (join_play_range_button.get_active()) {
1847 /* light up both roll and play-selection if they are joined */
1848 roll_button.set_visual_state (1);
1849 play_selection_button.set_visual_state (1);
1852 stop_button.set_visual_state (0);
1854 } else {
1856 stop_button.set_visual_state (1);
1857 roll_button.set_visual_state (0);
1858 play_selection_button.set_visual_state (0);
1859 auto_loop_button.set_visual_state (0);
1860 update_disk_space ();
1864 void
1865 ARDOUR_UI::engine_stopped ()
1867 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
1868 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1869 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1872 void
1873 ARDOUR_UI::engine_running ()
1875 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
1876 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, true);
1877 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, false);
1879 Glib::RefPtr<Action> action;
1880 const char* action_name = 0;
1882 switch (engine->frames_per_cycle()) {
1883 case 32:
1884 action_name = X_("JACKLatency32");
1885 break;
1886 case 64:
1887 action_name = X_("JACKLatency64");
1888 break;
1889 case 128:
1890 action_name = X_("JACKLatency128");
1891 break;
1892 case 512:
1893 action_name = X_("JACKLatency512");
1894 break;
1895 case 1024:
1896 action_name = X_("JACKLatency1024");
1897 break;
1898 case 2048:
1899 action_name = X_("JACKLatency2048");
1900 break;
1901 case 4096:
1902 action_name = X_("JACKLatency4096");
1903 break;
1904 case 8192:
1905 action_name = X_("JACKLatency8192");
1906 break;
1907 default:
1908 /* XXX can we do anything useful ? */
1909 break;
1912 if (action_name) {
1914 action = ActionManager::get_action (X_("JACK"), action_name);
1916 if (action) {
1917 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (action);
1918 ract->set_active ();
1923 void
1924 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
1926 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
1927 /* we can't rely on the original string continuing to exist when we are called
1928 again in the GUI thread, so make a copy and note that we need to
1929 free it later.
1931 char *copy = strdup (reason);
1932 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
1933 return;
1936 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1937 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1939 update_sample_rate (0);
1941 string msgstr;
1943 /* if the reason is a non-empty string, it means that the backend was shutdown
1944 rather than just Ardour.
1947 if (strlen (reason)) {
1948 msgstr = string_compose (_("The audio backend (JACK) was shutdown because:\n\n%1"), reason);
1949 } else {
1950 msgstr = string_compose (_("\
1951 JACK has either been shutdown or it\n\
1952 disconnected %1 because %1\n\
1953 was not fast enough. Try to restart\n\
1954 JACK, reconnect and save the session."), PROGRAM_NAME);
1957 MessageDialog msg (*editor, msgstr);
1958 pop_back_splash ();
1959 msg.run ();
1961 if (free_reason) {
1962 free ((char*) reason);
1966 int32_t
1967 ARDOUR_UI::do_engine_start ()
1969 try {
1970 engine->start();
1973 catch (...) {
1974 engine->stop ();
1975 error << _("Unable to start the session running")
1976 << endmsg;
1977 unload_session ();
1978 return -2;
1981 return 0;
1984 void
1985 ARDOUR_UI::setup_theme ()
1987 theme_manager->setup_theme();
1990 void
1991 ARDOUR_UI::update_clocks ()
1993 if (!editor || !editor->dragging_playhead()) {
1994 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position()); /* EMIT_SIGNAL */
1998 void
1999 ARDOUR_UI::start_clocking ()
2001 clock_signal_connection = RapidScreenUpdate.connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2004 void
2005 ARDOUR_UI::stop_clocking ()
2007 clock_signal_connection.disconnect ();
2010 void
2011 ARDOUR_UI::toggle_clocking ()
2013 #if 0
2014 if (clock_button.get_active()) {
2015 start_clocking ();
2016 } else {
2017 stop_clocking ();
2019 #endif
2022 gint
2023 ARDOUR_UI::_blink (void *arg)
2026 ((ARDOUR_UI *) arg)->blink ();
2027 return TRUE;
2030 void
2031 ARDOUR_UI::blink ()
2033 Blink (blink_on = !blink_on); /* EMIT_SIGNAL */
2036 void
2037 ARDOUR_UI::start_blinking ()
2039 /* Start the blink signal. Everybody with a blinking widget
2040 uses Blink to drive the widget's state.
2043 if (blink_timeout_tag < 0) {
2044 blink_on = false;
2045 blink_timeout_tag = g_timeout_add (240, _blink, this);
2049 void
2050 ARDOUR_UI::stop_blinking ()
2052 if (blink_timeout_tag >= 0) {
2053 g_source_remove (blink_timeout_tag);
2054 blink_timeout_tag = -1;
2059 /** Ask the user for the name of a new shapshot and then take it.
2062 void
2063 ARDOUR_UI::snapshot_session (bool switch_to_it)
2065 ArdourPrompter prompter (true);
2066 string snapname;
2068 prompter.set_name ("Prompter");
2069 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2070 prompter.set_title (_("Take Snapshot"));
2071 prompter.set_title (_("Take Snapshot"));
2072 prompter.set_prompt (_("Name of new snapshot"));
2074 if (!switch_to_it) {
2075 char timebuf[128];
2076 time_t n;
2077 struct tm local_time;
2079 time (&n);
2080 localtime_r (&n, &local_time);
2081 strftime (timebuf, sizeof(timebuf), "%FT%T", &local_time);
2082 prompter.set_initial_text (timebuf);
2085 again:
2086 switch (prompter.run()) {
2087 case RESPONSE_ACCEPT:
2089 prompter.get_result (snapname);
2091 bool do_save = (snapname.length() != 0);
2093 if (do_save) {
2094 if (snapname.find ('/') != string::npos) {
2095 MessageDialog msg (_("To ensure compatibility with various systems\n"
2096 "snapshot names may not contain a '/' character"));
2097 msg.run ();
2098 goto again;
2100 if (snapname.find ('\\') != string::npos) {
2101 MessageDialog msg (_("To ensure compatibility with various systems\n"
2102 "snapshot names may not contain a '\\' character"));
2103 msg.run ();
2104 goto again;
2108 vector<sys::path> p;
2109 get_state_files_in_directory (_session->session_directory().root_path(), p);
2110 vector<string> n = get_file_names_no_extension (p);
2111 if (find (n.begin(), n.end(), snapname) != n.end()) {
2113 ArdourDialog confirm (_("Confirm Snapshot Overwrite"), true);
2114 Label m (_("A snapshot already exists with that name. Do you want to overwrite it?"));
2115 confirm.get_vbox()->pack_start (m, true, true);
2116 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2117 confirm.add_button (_("Overwrite"), Gtk::RESPONSE_ACCEPT);
2118 confirm.show_all ();
2119 switch (confirm.run()) {
2120 case RESPONSE_CANCEL:
2121 do_save = false;
2125 if (do_save) {
2126 save_state (snapname, switch_to_it);
2128 break;
2131 default:
2132 break;
2136 void
2137 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2139 XMLNode* node = new XMLNode (X_("UI"));
2141 for (list<WindowProxyBase*>::iterator i = _window_proxies.begin(); i != _window_proxies.end(); ++i) {
2142 if (!(*i)->rc_configured()) {
2143 node->add_child_nocopy (*((*i)->get_state ()));
2147 _session->add_extra_xml (*node);
2149 save_state_canfail (name, switch_to_it);
2153 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2155 if (_session) {
2156 int ret;
2158 if (name.length() == 0) {
2159 name = _session->snap_name();
2162 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2163 return ret;
2167 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2168 return 0;
2171 void
2172 ARDOUR_UI::primary_clock_value_changed ()
2174 if (_session) {
2175 _session->request_locate (primary_clock->current_time ());
2179 void
2180 ARDOUR_UI::big_clock_value_changed ()
2182 if (_session) {
2183 _session->request_locate (big_clock->current_time ());
2187 void
2188 ARDOUR_UI::secondary_clock_value_changed ()
2190 if (_session) {
2191 _session->request_locate (secondary_clock->current_time ());
2195 void
2196 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2198 if (_session == 0) {
2199 return;
2202 if (_session->step_editing()) {
2203 return;
2206 Session::RecordState const r = _session->record_status ();
2207 bool const h = _session->have_rec_enabled_track ();
2209 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2210 if (onoff) {
2211 rec_button.set_visual_state (2);
2212 } else {
2213 rec_button.set_visual_state (0);
2215 } else if (r == Session::Recording && h) {
2216 rec_button.set_visual_state (1);
2217 } else {
2218 rec_button.set_visual_state (0);
2222 void
2223 ARDOUR_UI::save_template ()
2225 ArdourPrompter prompter (true);
2226 string name;
2228 if (!check_audioengine()) {
2229 return;
2232 prompter.set_name (X_("Prompter"));
2233 prompter.set_title (_("Save Template"));
2234 prompter.set_prompt (_("Name for template:"));
2235 prompter.set_initial_text(_session->name() + _("-template"));
2236 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2238 switch (prompter.run()) {
2239 case RESPONSE_ACCEPT:
2240 prompter.get_result (name);
2242 if (name.length()) {
2243 _session->save_template (name);
2245 break;
2247 default:
2248 break;
2252 void
2253 ARDOUR_UI::edit_metadata ()
2255 SessionMetadataEditor dialog;
2256 dialog.set_session (_session);
2257 editor->ensure_float (dialog);
2258 dialog.run ();
2261 void
2262 ARDOUR_UI::import_metadata ()
2264 SessionMetadataImporter dialog;
2265 dialog.set_session (_session);
2266 editor->ensure_float (dialog);
2267 dialog.run ();
2270 bool
2271 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
2273 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2275 MessageDialog msg (str,
2276 false,
2277 Gtk::MESSAGE_WARNING,
2278 Gtk::BUTTONS_YES_NO,
2279 true);
2282 msg.set_name (X_("OpenExistingDialog"));
2283 msg.set_title (_("Open Existing Session"));
2284 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
2285 msg.set_position (Gtk::WIN_POS_MOUSE);
2286 pop_back_splash ();
2288 switch (msg.run()) {
2289 case RESPONSE_YES:
2290 return true;
2291 break;
2293 return false;
2297 ARDOUR_UI::build_session_from_nsd (const std::string& session_path, const std::string& session_name)
2299 BusProfile bus_profile;
2301 if (Profile->get_sae()) {
2303 bus_profile.master_out_channels = 2;
2304 bus_profile.input_ac = AutoConnectPhysical;
2305 bus_profile.output_ac = AutoConnectMaster;
2306 bus_profile.requested_physical_in = 0; // use all available
2307 bus_profile.requested_physical_out = 0; // use all available
2309 } else {
2311 /* get settings from advanced section of NSD */
2313 if (_startup->create_master_bus()) {
2314 bus_profile.master_out_channels = (uint32_t) _startup->master_channel_count();
2315 } else {
2316 bus_profile.master_out_channels = 0;
2319 if (_startup->connect_inputs()) {
2320 bus_profile.input_ac = AutoConnectPhysical;
2321 } else {
2322 bus_profile.input_ac = AutoConnectOption (0);
2325 /// @todo some minor tweaks.
2327 bus_profile.output_ac = AutoConnectOption (0);
2329 if (_startup->connect_outputs ()) {
2330 if (_startup->connect_outs_to_master()) {
2331 bus_profile.output_ac = AutoConnectMaster;
2332 } else if (_startup->connect_outs_to_physical()) {
2333 bus_profile.output_ac = AutoConnectPhysical;
2337 bus_profile.requested_physical_in = (uint32_t) _startup->input_limit_count();
2338 bus_profile.requested_physical_out = (uint32_t) _startup->output_limit_count();
2341 if (build_session (session_path, session_name, bus_profile)) {
2342 return -1;
2345 return 0;
2348 void
2349 ARDOUR_UI::idle_load (const std::string& path)
2351 if (_session) {
2352 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2353 /* /path/to/foo => /path/to/foo, foo */
2354 load_session (path, basename_nosuffix (path));
2355 } else {
2356 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2357 load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2359 } else {
2361 ARDOUR_COMMAND_LINE::session_name = path;
2364 * new_session_dialog doens't exist in A3
2365 * Try to remove all references to it to
2366 * see if it will compile. NOTE: this will
2367 * likely cause a runtime issue is my somewhat
2368 * uneducated guess.
2371 //if (new_session_dialog) {
2374 /* make it break out of Dialog::run() and
2375 start again.
2378 //new_session_dialog->response (1);
2383 void
2384 ARDOUR_UI::end_loading_messages ()
2386 // hide_splash ();
2389 void
2390 ARDOUR_UI::loading_message (const std::string& /*msg*/)
2392 // show_splash ();
2393 // splash->message (msg);
2394 flush_pending ();
2397 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
2399 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
2401 string session_name;
2402 string session_path;
2403 string template_name;
2404 int ret = -1;
2405 bool likely_new = false;
2407 if (!load_template.empty()) {
2408 should_be_new = true;
2409 template_name = load_template;
2412 while (ret != 0) {
2414 if (!should_be_new && !ARDOUR_COMMAND_LINE::session_name.empty()) {
2416 /* if they named a specific statefile, use it, otherwise they are
2417 just giving a session folder, and we want to use it as is
2418 to find the session.
2421 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
2423 if (suffix != string::npos) {
2424 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
2425 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
2426 session_name = Glib::path_get_basename (session_name);
2427 } else {
2428 session_path = ARDOUR_COMMAND_LINE::session_name;
2429 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
2432 } else {
2434 bool const apply = run_startup (should_be_new, load_template);
2436 if (!apply) {
2437 if (quit_on_cancel) {
2438 exit (1);
2439 } else {
2440 return ret;
2444 /* if we run the startup dialog again, offer more than just "new session" */
2446 should_be_new = false;
2448 session_name = _startup->session_name (likely_new);
2450 /* this shouldn't happen, but we catch it just in case it does */
2452 if (session_name.empty()) {
2453 continue;
2456 if (_startup->use_session_template()) {
2457 template_name = _startup->session_template_name();
2458 _session_is_new = true;
2461 if (session_name[0] == G_DIR_SEPARATOR ||
2462 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
2463 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)) {
2465 /* absolute path or cwd-relative path specified for session name: infer session folder
2466 from what was given.
2469 session_path = Glib::path_get_dirname (session_name);
2470 session_name = Glib::path_get_basename (session_name);
2472 } else {
2474 session_path = _startup->session_folder();
2476 if (session_name.find ('/') != string::npos) {
2477 MessageDialog msg (*_startup,
2478 _("To ensure compatibility with various systems\n"
2479 "session names may not contain a '/' character"));
2480 msg.run ();
2481 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2482 continue;
2485 if (session_name.find ('\\') != string::npos) {
2486 MessageDialog msg (*_startup,
2487 _("To ensure compatibility with various systems\n"
2488 "session names may not contain a '\\' character"));
2489 msg.run ();
2490 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2491 continue;
2496 if (create_engine ()) {
2497 break;
2500 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
2502 if (likely_new) {
2504 std::string existing = Glib::build_filename (session_path, session_name);
2506 if (!ask_about_loading_existing_session (existing)) {
2507 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2508 continue;
2512 _session_is_new = false;
2514 } else {
2516 if (!likely_new) {
2517 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
2518 msg.run ();
2519 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2520 continue;
2523 if (session_name.find ('/') != std::string::npos) {
2524 MessageDialog msg (*_startup,
2525 _("To ensure compatibility with various systems\n"
2526 "session names may not contain a '/' character"));
2527 msg.run ();
2528 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2529 continue;
2532 if (session_name.find ('\\') != std::string::npos) {
2533 MessageDialog msg (*_startup,
2534 _("To ensure compatibility with various systems\n"
2535 "session names may not contain a '\\' character"));
2536 msg.run ();
2537 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2538 continue;
2541 _session_is_new = true;
2544 if (likely_new && template_name.empty()) {
2546 ret = build_session_from_nsd (session_path, session_name);
2548 } else {
2550 ret = load_session (session_path, session_name, template_name);
2552 if (ret == -2) {
2553 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
2554 exit (1);
2557 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
2558 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
2559 exit (1);
2564 return ret;
2567 void
2568 ARDOUR_UI::close_session()
2570 if (!check_audioengine()) {
2571 return;
2574 if (unload_session (true)) {
2575 return;
2578 ARDOUR_COMMAND_LINE::session_name = "";
2580 if (get_session_parameters (true, false)) {
2581 exit (1);
2584 goto_editor_window ();
2587 /** @param snap_name Snapshot name (without .ardour suffix).
2588 * @return -2 if the load failed because we are not connected to the AudioEngine.
2591 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
2593 Session *new_session;
2594 int unload_status;
2595 int retval = -1;
2597 session_loaded = false;
2599 if (!check_audioengine()) {
2600 return -2;
2603 unload_status = unload_session ();
2605 if (unload_status < 0) {
2606 goto out;
2607 } else if (unload_status > 0) {
2608 retval = 0;
2609 goto out;
2612 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
2614 try {
2615 new_session = new Session (*engine, path, snap_name, 0, mix_template);
2618 /* this one is special */
2620 catch (AudioEngine::PortRegistrationFailure& err) {
2622 MessageDialog msg (err.what(),
2623 true,
2624 Gtk::MESSAGE_INFO,
2625 Gtk::BUTTONS_CLOSE);
2627 msg.set_title (_("Port Registration Error"));
2628 msg.set_secondary_text (_("Click the Close button to try again."));
2629 msg.set_position (Gtk::WIN_POS_CENTER);
2630 pop_back_splash ();
2631 msg.present ();
2633 int response = msg.run ();
2635 msg.hide ();
2637 switch (response) {
2638 case RESPONSE_CANCEL:
2639 exit (1);
2640 default:
2641 break;
2643 goto out;
2646 catch (...) {
2648 MessageDialog msg (string_compose(
2649 _("Session \"%1 (snapshot %2)\" did not load successfully"),
2650 path, snap_name),
2651 true,
2652 Gtk::MESSAGE_INFO,
2653 BUTTONS_OK);
2655 msg.set_title (_("Loading Error"));
2656 msg.set_secondary_text (_("Click the Refresh button to try again."));
2657 msg.add_button (Stock::REFRESH, 1);
2658 msg.set_position (Gtk::WIN_POS_CENTER);
2659 pop_back_splash ();
2660 msg.present ();
2662 int response = msg.run ();
2664 switch (response) {
2665 case 1:
2666 break;
2667 default:
2668 exit (1);
2671 msg.hide ();
2673 goto out;
2677 list<string> const u = new_session->unknown_processors ();
2678 if (!u.empty()) {
2679 MissingPluginDialog d (_session, u);
2680 d.run ();
2684 /* Now the session been created, add the transport controls */
2685 new_session->add_controllable(roll_controllable);
2686 new_session->add_controllable(stop_controllable);
2687 new_session->add_controllable(goto_start_controllable);
2688 new_session->add_controllable(goto_end_controllable);
2689 new_session->add_controllable(auto_loop_controllable);
2690 new_session->add_controllable(play_selection_controllable);
2691 new_session->add_controllable(rec_controllable);
2693 set_session (new_session);
2695 session_loaded = true;
2697 goto_editor_window ();
2699 if (_session) {
2700 _session->set_clean ();
2703 flush_pending ();
2704 retval = 0;
2706 out:
2707 return retval;
2711 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
2713 Session *new_session;
2714 int x;
2716 if (!check_audioengine()) {
2717 return -1;
2720 session_loaded = false;
2722 x = unload_session ();
2724 if (x < 0) {
2725 return -1;
2726 } else if (x > 0) {
2727 return 0;
2730 _session_is_new = true;
2732 try {
2733 new_session = new Session (*engine, path, snap_name, &bus_profile);
2736 catch (...) {
2738 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
2739 pop_back_splash ();
2740 msg.run ();
2741 return -1;
2744 /* Give the new session the default GUI state, if such things exist */
2746 XMLNode* n;
2747 n = Config->instant_xml (X_("Editor"));
2748 if (n) {
2749 new_session->add_instant_xml (*n, false);
2751 n = Config->instant_xml (X_("Mixer"));
2752 if (n) {
2753 new_session->add_instant_xml (*n, false);
2756 /* Put the playhead at 0 and scroll fully left */
2757 n = new_session->instant_xml (X_("Editor"));
2758 if (n) {
2759 n->add_property (X_("playhead"), X_("0"));
2760 n->add_property (X_("left-frame"), X_("0"));
2763 set_session (new_session);
2765 session_loaded = true;
2767 new_session->save_state(new_session->name());
2769 return 0;
2772 void
2773 ARDOUR_UI::launch_chat ()
2775 #ifdef __APPLE__
2776 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
2777 #else
2778 open_uri("http://webchat.freenode.net/?channels=ardour");
2779 #endif
2782 void
2783 ARDOUR_UI::show_about ()
2785 if (about == 0) {
2786 about = new About;
2787 about->signal_response().connect(sigc::mem_fun (*this, &ARDOUR_UI::about_signal_response) );
2790 about->set_transient_for(*editor);
2791 about->show_all ();
2794 void
2795 ARDOUR_UI::launch_manual ()
2797 PBD::open_uri("http://ardour.org/flossmanual");
2800 void
2801 ARDOUR_UI::launch_reference ()
2803 PBD::open_uri("http://ardour.org/refmanual");
2806 void
2807 ARDOUR_UI::hide_about ()
2809 if (about) {
2810 about->get_window()->set_cursor ();
2811 about->hide ();
2815 void
2816 ARDOUR_UI::about_signal_response (int /*response*/)
2818 hide_about();
2821 void
2822 ARDOUR_UI::show_splash ()
2824 if (splash == 0) {
2825 try {
2826 splash = new Splash;
2827 } catch (...) {
2828 return;
2832 splash->show ();
2833 splash->present ();
2834 splash->queue_draw ();
2835 splash->get_window()->process_updates (true);
2836 flush_pending ();
2839 void
2840 ARDOUR_UI::hide_splash ()
2842 if (splash) {
2843 splash->hide();
2847 void
2848 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title,
2849 const string& plural_msg, const string& singular_msg)
2851 size_t removed;
2853 removed = rep.paths.size();
2855 if (removed == 0) {
2856 MessageDialog msgd (*editor,
2857 _("No files were ready for clean-up"),
2858 true,
2859 Gtk::MESSAGE_INFO,
2860 (Gtk::ButtonsType)(Gtk::BUTTONS_OK) );
2861 msgd.set_title (_("Clean-up"));
2862 msgd.set_secondary_text (_("If this seems suprising, \n\
2863 check for any existing snapshots.\n\
2864 These may still include regions that\n\
2865 require some unused files to continue to exist."));
2867 msgd.run ();
2868 return;
2871 ArdourDialog results (_("Clean-up"), true, false);
2873 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
2874 CleanupResultsModelColumns() {
2875 add (visible_name);
2876 add (fullpath);
2878 Gtk::TreeModelColumn<std::string> visible_name;
2879 Gtk::TreeModelColumn<std::string> fullpath;
2883 CleanupResultsModelColumns results_columns;
2884 Glib::RefPtr<Gtk::ListStore> results_model;
2885 Gtk::TreeView results_display;
2887 results_model = ListStore::create (results_columns);
2888 results_display.set_model (results_model);
2889 results_display.append_column (list_title, results_columns.visible_name);
2891 results_display.set_name ("CleanupResultsList");
2892 results_display.set_headers_visible (true);
2893 results_display.set_headers_clickable (false);
2894 results_display.set_reorderable (false);
2896 Gtk::ScrolledWindow list_scroller;
2897 Gtk::Label txt;
2898 Gtk::VBox dvbox;
2899 Gtk::HBox dhbox; // the hbox for the image and text
2900 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
2901 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
2903 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
2905 const string dead_directory = _session->session_directory().dead_path().to_string();
2907 /* subst:
2908 %1 - number of files removed
2909 %2 - location of "dead"
2910 %3 - size of files affected
2911 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
2914 const char* bprefix;
2915 double space_adjusted = 0;
2917 if (rep.space < 1000) {
2918 bprefix = X_("");
2919 space_adjusted = rep.space;
2920 } else if (rep.space < 1000000) {
2921 bprefix = X_("kilo");
2922 space_adjusted = truncf((float)rep.space / 1000.0);
2923 } else if (rep.space < 1000000 * 1000) {
2924 bprefix = X_("mega");
2925 space_adjusted = truncf((float)rep.space / (1000.0 * 1000.0));
2926 } else {
2927 bprefix = X_("giga");
2928 space_adjusted = truncf((float)rep.space / (1000.0 * 1000 * 1000.0));
2931 if (removed > 1) {
2932 txt.set_text (string_compose (plural_msg, removed, dead_directory, space_adjusted, bprefix));
2933 } else {
2934 txt.set_text (string_compose (singular_msg, removed, dead_directory, space_adjusted, bprefix));
2937 dhbox.pack_start (*dimage, true, false, 5);
2938 dhbox.pack_start (txt, true, false, 5);
2940 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
2941 TreeModel::Row row = *(results_model->append());
2942 row[results_columns.visible_name] = *i;
2943 row[results_columns.fullpath] = *i;
2946 list_scroller.add (results_display);
2947 list_scroller.set_size_request (-1, 150);
2948 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
2950 dvbox.pack_start (dhbox, true, false, 5);
2951 dvbox.pack_start (list_scroller, true, false, 5);
2952 ddhbox.pack_start (dvbox, true, false, 5);
2954 results.get_vbox()->pack_start (ddhbox, true, false, 5);
2955 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
2956 results.set_default_response (RESPONSE_CLOSE);
2957 results.set_position (Gtk::WIN_POS_MOUSE);
2959 results_display.show();
2960 list_scroller.show();
2961 txt.show();
2962 dvbox.show();
2963 dhbox.show();
2964 ddhbox.show();
2965 dimage->show();
2967 //results.get_vbox()->show();
2968 results.set_resizable (false);
2970 results.run ();
2974 void
2975 ARDOUR_UI::cleanup ()
2977 if (_session == 0) {
2978 /* shouldn't happen: menu item is insensitive */
2979 return;
2983 MessageDialog checker (_("Are you sure you want to clean-up?"),
2984 true,
2985 Gtk::MESSAGE_QUESTION,
2986 (Gtk::ButtonsType)(Gtk::BUTTONS_NONE));
2988 checker.set_title (_("Clean-up"));
2990 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
2991 ALL undo/redo information will be lost if you clean-up.\n\
2992 Clean-up will move all unused files to a \"dead\" location."));
2994 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
2995 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
2996 checker.set_default_response (RESPONSE_CANCEL);
2998 checker.set_name (_("CleanupDialog"));
2999 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3000 checker.set_position (Gtk::WIN_POS_MOUSE);
3002 switch (checker.run()) {
3003 case RESPONSE_ACCEPT:
3004 break;
3005 default:
3006 return;
3009 ARDOUR::CleanupReport rep;
3011 editor->prepare_for_cleanup ();
3013 /* do not allow flush until a session is reloaded */
3015 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3016 if (act) {
3017 act->set_sensitive (false);
3020 if (_session->cleanup_sources (rep)) {
3021 editor->finish_cleanup ();
3022 return;
3025 editor->finish_cleanup ();
3027 checker.hide();
3028 display_cleanup_results (rep,
3029 _("Cleaned Files"),
3030 _("\
3031 The following %1 files were not in use and \n\
3032 have been moved to:\n\n\
3033 %2\n\n\
3034 After a restart of Ardour,\n\n\
3035 Session -> Clean-up -> Flush Wastebasket\n\n\
3036 will release an additional\n\
3037 %3 %4bytes of disk space.\n"),
3038 _("\
3039 The following file was not in use and \n\
3040 has been moved to:\n \
3041 %2\n\n\
3042 After a restart of Ardour,\n\n\
3043 Session -> Clean-up -> Flush Wastebasket\n\n\
3044 will release an additional\n\
3045 %3 %4bytes of disk space.\n"
3050 void
3051 ARDOUR_UI::flush_trash ()
3053 if (_session == 0) {
3054 /* shouldn't happen: menu item is insensitive */
3055 return;
3058 ARDOUR::CleanupReport rep;
3060 if (_session->cleanup_trash_sources (rep)) {
3061 return;
3064 display_cleanup_results (rep,
3065 _("deleted file"),
3066 _("The following %1 files were deleted from\n\
3067 %2,\n\
3068 releasing %3 %4bytes of disk space"),
3069 _("The following file was deleted from\n\
3070 %2,\n\
3071 releasing %3 %4bytes of disk space"));
3074 void
3075 ARDOUR_UI::add_route (Gtk::Window* float_window)
3077 int count;
3079 if (!_session) {
3080 return;
3083 if (add_route_dialog == 0) {
3084 add_route_dialog = new AddRouteDialog (_session);
3085 if (float_window) {
3086 add_route_dialog->set_transient_for (*float_window);
3090 if (add_route_dialog->is_visible()) {
3091 /* we're already doing this */
3092 return;
3095 ResponseType r = (ResponseType) add_route_dialog->run ();
3097 add_route_dialog->hide();
3099 switch (r) {
3100 case RESPONSE_ACCEPT:
3101 break;
3102 default:
3103 return;
3104 break;
3107 if ((count = add_route_dialog->count()) <= 0) {
3108 return;
3111 string template_path = add_route_dialog->track_template();
3113 if (!template_path.empty()) {
3114 _session->new_route_from_template (count, template_path);
3115 return;
3118 uint32_t input_chan = add_route_dialog->channels ();
3119 uint32_t output_chan;
3120 string name_template = add_route_dialog->name_template ();
3121 bool track = add_route_dialog->track ();
3122 RouteGroup* route_group = add_route_dialog->route_group ();
3124 AutoConnectOption oac = Config->get_output_auto_connect();
3126 if (oac & AutoConnectMaster) {
3127 output_chan = (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan);
3128 } else {
3129 output_chan = input_chan;
3132 /* XXX do something with name template */
3134 if (add_route_dialog->type() == ARDOUR::DataType::MIDI) {
3135 if (track) {
3136 session_add_midi_track (route_group, count, name_template);
3137 } else {
3138 MessageDialog msg (*editor,
3139 _("Sorry, MIDI Busses are not supported at this time."));
3140 msg.run ();
3141 //session_add_midi_bus();
3143 } else {
3144 if (track) {
3145 session_add_audio_track (input_chan, output_chan, add_route_dialog->mode(), route_group, count, name_template);
3146 } else {
3147 session_add_audio_bus (input_chan, output_chan, route_group, count, name_template);
3152 XMLNode*
3153 ARDOUR_UI::mixer_settings () const
3155 XMLNode* node = 0;
3157 if (_session) {
3158 node = _session->instant_xml(X_("Mixer"));
3159 } else {
3160 node = Config->instant_xml(X_("Mixer"));
3163 if (!node) {
3164 node = new XMLNode (X_("Mixer"));
3167 return node;
3170 XMLNode*
3171 ARDOUR_UI::editor_settings () const
3173 XMLNode* node = 0;
3175 if (_session) {
3176 node = _session->instant_xml(X_("Editor"));
3177 } else {
3178 node = Config->instant_xml(X_("Editor"));
3181 if (!node) {
3182 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
3183 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
3187 if (!node) {
3188 node = new XMLNode (X_("Editor"));
3191 return node;
3194 XMLNode*
3195 ARDOUR_UI::keyboard_settings () const
3197 XMLNode* node = 0;
3199 node = Config->extra_xml(X_("Keyboard"));
3201 if (!node) {
3202 node = new XMLNode (X_("Keyboard"));
3205 return node;
3208 void
3209 ARDOUR_UI::create_xrun_marker (framepos_t where)
3211 editor->mouse_add_new_marker (where, false, true);
3214 void
3215 ARDOUR_UI::halt_on_xrun_message ()
3217 MessageDialog msg (*editor,
3218 _("Recording was stopped because your system could not keep up."));
3219 msg.run ();
3222 void
3223 ARDOUR_UI::xrun_handler (framepos_t where)
3225 if (!_session) {
3226 return;
3229 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
3231 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
3232 create_xrun_marker(where);
3235 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
3236 halt_on_xrun_message ();
3240 void
3241 ARDOUR_UI::disk_overrun_handler ()
3243 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
3245 if (!have_disk_speed_dialog_displayed) {
3246 have_disk_speed_dialog_displayed = true;
3247 MessageDialog* msg = new MessageDialog (*editor, string_compose (_("\
3248 The disk system on your computer\n\
3249 was not able to keep up with %1.\n\
3251 Specifically, it failed to write data to disk\n\
3252 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
3253 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3254 msg->show ();
3258 void
3259 ARDOUR_UI::disk_underrun_handler ()
3261 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
3263 if (!have_disk_speed_dialog_displayed) {
3264 have_disk_speed_dialog_displayed = true;
3265 MessageDialog* msg = new MessageDialog (
3266 *editor, string_compose (_("The disk system on your computer\n\
3267 was not able to keep up with %1.\n\
3269 Specifically, it failed to read data from disk\n\
3270 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
3271 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3272 msg->show ();
3276 void
3277 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
3279 have_disk_speed_dialog_displayed = false;
3280 delete msg;
3283 void
3284 ARDOUR_UI::session_dialog (std::string msg)
3286 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
3288 MessageDialog* d;
3290 if (editor) {
3291 d = new MessageDialog (*editor, msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3292 } else {
3293 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3296 d->show_all ();
3297 d->run ();
3298 delete d;
3302 ARDOUR_UI::pending_state_dialog ()
3304 HBox* hbox = new HBox();
3305 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3306 ArdourDialog dialog (_("Crash Recovery"), true);
3307 Label message (_("\
3308 This session appears to have been in\n\
3309 middle of recording when ardour or\n\
3310 the computer was shutdown.\n\
3312 Ardour can recover any captured audio for\n\
3313 you, or it can ignore it. Please decide\n\
3314 what you would like to do.\n"));
3315 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3316 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3317 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3318 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3319 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
3320 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
3321 dialog.set_default_response (RESPONSE_ACCEPT);
3322 dialog.set_position (WIN_POS_CENTER);
3323 message.show();
3324 image->show();
3325 hbox->show();
3327 switch (dialog.run ()) {
3328 case RESPONSE_ACCEPT:
3329 return 1;
3330 default:
3331 return 0;
3336 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
3338 HBox* hbox = new HBox();
3339 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3340 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
3341 Label message (string_compose (_("\
3342 This session was created with a sample rate of %1 Hz\n\
3344 The audioengine is currently running at %2 Hz\n"), desired, actual));
3346 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3347 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3348 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3349 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3350 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
3351 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
3352 dialog.set_default_response (RESPONSE_ACCEPT);
3353 dialog.set_position (WIN_POS_CENTER);
3354 message.show();
3355 image->show();
3356 hbox->show();
3358 switch (dialog.run ()) {
3359 case RESPONSE_ACCEPT:
3360 return 0;
3361 default:
3362 return 1;
3367 void
3368 ARDOUR_UI::disconnect_from_jack ()
3370 if (engine) {
3371 if( engine->disconnect_from_jack ()) {
3372 MessageDialog msg (*editor, _("Could not disconnect from JACK"));
3373 msg.run ();
3376 update_sample_rate (0);
3380 void
3381 ARDOUR_UI::reconnect_to_jack ()
3383 if (engine) {
3384 if (engine->reconnect_to_jack ()) {
3385 MessageDialog msg (*editor, _("Could not reconnect to JACK"));
3386 msg.run ();
3389 update_sample_rate (0);
3393 void
3394 ARDOUR_UI::use_config ()
3396 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
3397 if (node) {
3398 set_transport_controllable_state (*node);
3402 void
3403 ARDOUR_UI::update_transport_clocks (framepos_t pos)
3405 if (Config->get_primary_clock_delta_edit_cursor()) {
3406 primary_clock->set (pos, false, editor->get_preferred_edit_position(), 1);
3407 } else {
3408 primary_clock->set (pos, 0, true);
3411 if (Config->get_secondary_clock_delta_edit_cursor()) {
3412 secondary_clock->set (pos, false, editor->get_preferred_edit_position(), 2);
3413 } else {
3414 secondary_clock->set (pos);
3417 if (big_clock_window->get()) {
3418 big_clock->set (pos);
3423 void
3424 ARDOUR_UI::step_edit_status_change (bool yn)
3426 // XXX should really store pre-step edit status of things
3427 // we make insensitive
3429 if (yn) {
3430 rec_button.set_visual_state (3);
3431 rec_button.set_sensitive (false);
3432 } else {
3433 rec_button.set_visual_state (0);
3434 rec_button.set_sensitive (true);
3438 void
3439 ARDOUR_UI::record_state_changed ()
3441 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
3443 if (!_session || !big_clock_window->get()) {
3444 /* why bother - the clock isn't visible */
3445 return;
3448 Session::RecordState const r = _session->record_status ();
3449 bool const h = _session->have_rec_enabled_track ();
3451 if (r == Session::Recording && h) {
3452 big_clock->set_widget_name ("BigClockRecording");
3453 } else {
3454 big_clock->set_widget_name ("BigClockNonRecording");
3458 bool
3459 ARDOUR_UI::first_idle ()
3461 if (_session) {
3462 _session->allow_auto_play (true);
3465 if (editor) {
3466 editor->first_idle();
3469 Keyboard::set_can_save_keybindings (true);
3470 return false;
3473 void
3474 ARDOUR_UI::store_clock_modes ()
3476 XMLNode* node = new XMLNode(X_("ClockModes"));
3478 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
3479 XMLNode* child = new XMLNode (X_("Clock"));
3481 child->add_property (X_("name"), (*x)->name());
3482 child->add_property (X_("mode"), enum_2_string ((*x)->mode()));
3483 child->add_property (X_("on"), ((*x)->off() ? X_("no") : X_("yes")));
3485 node->add_child_nocopy (*child);
3488 _session->add_extra_xml (*node);
3489 _session->set_dirty ();
3492 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
3493 : Controllable (name), ui (u), type(tp)
3498 void
3499 ARDOUR_UI::TransportControllable::set_value (double val)
3501 if (val < 0.5) {
3502 /* do nothing: these are radio-style actions */
3503 return;
3506 const char *action = 0;
3508 switch (type) {
3509 case Roll:
3510 action = X_("Roll");
3511 break;
3512 case Stop:
3513 action = X_("Stop");
3514 break;
3515 case GotoStart:
3516 action = X_("Goto Start");
3517 break;
3518 case GotoEnd:
3519 action = X_("Goto End");
3520 break;
3521 case AutoLoop:
3522 action = X_("Loop");
3523 break;
3524 case PlaySelection:
3525 action = X_("Play Selection");
3526 break;
3527 case RecordEnable:
3528 action = X_("Record");
3529 break;
3530 default:
3531 break;
3534 if (action == 0) {
3535 return;
3538 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
3540 if (act) {
3541 act->activate ();
3545 double
3546 ARDOUR_UI::TransportControllable::get_value (void) const
3548 float val = 0.0;
3550 switch (type) {
3551 case Roll:
3552 break;
3553 case Stop:
3554 break;
3555 case GotoStart:
3556 break;
3557 case GotoEnd:
3558 break;
3559 case AutoLoop:
3560 break;
3561 case PlaySelection:
3562 break;
3563 case RecordEnable:
3564 break;
3565 default:
3566 break;
3569 return val;
3572 void
3573 ARDOUR_UI::TransportControllable::set_id (const string& str)
3575 _id = str;
3578 void
3579 ARDOUR_UI::setup_profile ()
3581 if (gdk_screen_width() < 1200) {
3582 Profile->set_small_screen ();
3586 if (getenv ("ARDOUR_SAE")) {
3587 Profile->set_sae ();
3588 Profile->set_single_package ();
3592 void
3593 ARDOUR_UI::toggle_translations ()
3595 using namespace Glib;
3597 RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("EnableTranslation"));
3598 if (act) {
3599 RefPtr<ToggleAction> ract = RefPtr<ToggleAction>::cast_dynamic (act);
3600 if (ract) {
3602 string i18n_killer = ARDOUR::translation_kill_path();
3604 bool already_enabled = !ARDOUR::translations_are_disabled ();
3606 if (ract->get_active ()) {
3607 /* we don't care about errors */
3608 int fd = ::open (i18n_killer.c_str(), O_RDONLY|O_CREAT, 0644);
3609 close (fd);
3610 } else {
3611 /* we don't care about errors */
3612 unlink (i18n_killer.c_str());
3615 if (already_enabled != ract->get_active()) {
3616 MessageDialog win (already_enabled ? _("Translations disabled") : _("Translations enabled"),
3617 false,
3618 Gtk::MESSAGE_WARNING,
3619 Gtk::BUTTONS_OK);
3620 win.set_secondary_text (string_compose (_("You must restart %1 for this to take effect."), PROGRAM_NAME));
3621 win.set_position (Gtk::WIN_POS_CENTER);
3622 win.present ();
3623 win.run ();
3629 /** Add a window proxy to our list, so that its state will be saved.
3630 * This call also causes the window to be created and opened if its
3631 * state was saved as `visible'.
3633 void
3634 ARDOUR_UI::add_window_proxy (WindowProxyBase* p)
3636 _window_proxies.push_back (p);
3637 p->maybe_show ();
3640 /** Remove a window proxy from our list. Must be called if a WindowProxy
3641 * is deleted, to prevent hanging pointers.
3643 void
3644 ARDOUR_UI::remove_window_proxy (WindowProxyBase* p)
3646 _window_proxies.remove (p);
3650 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
3652 MissingFileDialog dialog (s, str, type);
3654 dialog.show ();
3655 dialog.present ();
3657 int result = dialog.run ();
3658 dialog.hide ();
3660 switch (result) {
3661 case RESPONSE_OK:
3662 break;
3663 default:
3664 return 1; // quit entire session load
3667 result = dialog.get_action ();
3669 return result;
3673 ARDOUR_UI::ambiguous_file (std::string file, std::string path, std::vector<std::string> hits)
3675 AmbiguousFileDialog dialog (file, hits);
3677 dialog.show ();
3678 dialog.present ();
3680 dialog.run ();
3681 return dialog.get_which ();