somewhat illogical and temporary workaround to the problems with consolidate & bounce...
[ardour2.git] / gtk2_ardour / ardour_ui.cc
blobd53e441fd27b402d12692e637b92b1e3a3010193
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 (X_("primary"), false, X_("TransportClockDisplay"), true, true, false, true),
137 secondary_clock (X_("secondary"), false, X_("SecondaryClockDisplay"), true, true, false, true),
138 preroll_clock (X_("preroll"), false, X_("PreRollClock"), true, false, true),
139 postroll_clock (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 (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 punch_in_button (_("Punch In")),
169 punch_out_button (_("Punch Out")),
170 auto_return_button (_("Auto Return")),
171 auto_play_button (_("Auto Play")),
172 auto_input_button (_("Auto Input")),
173 click_button (_("Click")),
174 time_master_button (_("time\nmaster")),
176 auditioning_alert_button (_("AUDITION")),
177 solo_alert_button (_("SOLO")),
179 error_log_button (_("Errors"))
182 using namespace Gtk::Menu_Helpers;
184 Gtkmm2ext::init();
187 #ifdef TOP_MENUBAR
188 // _auto_display_errors = false;
190 * This was commented out as it wasn't defined
191 * in A3 IIRC. If this is not needed it should
192 * be completely removed.
194 #endif
196 about = 0;
197 splash = 0;
198 _startup = 0;
200 if (theArdourUI == 0) {
201 theArdourUI = this;
204 ui_config = new UIConfiguration();
205 theme_manager = new ThemeManager();
207 key_editor = 0;
209 editor = 0;
210 mixer = 0;
211 editor = 0;
212 engine = 0;
213 _session_is_new = false;
214 big_clock_window = 0;
215 big_clock_height = 0;
216 big_clock_resize_in_progress = false;
217 session_selector_window = 0;
218 last_key_press_time = 0;
219 _will_create_new_session_automatically = false;
220 add_route_dialog = 0;
221 route_params = 0;
222 bundle_manager = 0;
223 rc_option_editor = 0;
224 session_option_editor = 0;
225 location_ui = 0;
226 open_session_selector = 0;
227 have_configure_timeout = false;
228 have_disk_speed_dialog_displayed = false;
229 session_loaded = false;
230 ignore_dual_punch = false;
231 original_big_clock_width = -1;
232 original_big_clock_height = -1;
233 original_big_clock_font_size = 0;
235 roll_button.unset_flags (Gtk::CAN_FOCUS);
236 stop_button.unset_flags (Gtk::CAN_FOCUS);
237 goto_start_button.unset_flags (Gtk::CAN_FOCUS);
238 goto_end_button.unset_flags (Gtk::CAN_FOCUS);
239 auto_loop_button.unset_flags (Gtk::CAN_FOCUS);
240 play_selection_button.unset_flags (Gtk::CAN_FOCUS);
241 rec_button.unset_flags (Gtk::CAN_FOCUS);
242 join_play_range_button.unset_flags (Gtk::CAN_FOCUS);
243 last_configure_time= 0;
244 last_peak_grab = 0;
246 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
247 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
249 /* handle dialog requests */
251 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
253 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
255 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
257 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
259 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
261 /* handle requests to quit (coming from JACK session) */
263 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::finish, this), gui_context ());
265 /* handle requests to deal with missing files */
267 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
269 /* and ambiguous files */
271 ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2, _3));
273 /* lets get this party started */
275 try {
276 if (ARDOUR::init (ARDOUR_COMMAND_LINE::use_vst, ARDOUR_COMMAND_LINE::try_hw_optimization)) {
277 throw failed_constructor ();
280 setup_gtk_ardour_enums ();
281 setup_profile ();
283 GainMeter::setup_slider_pix ();
284 RouteTimeAxisView::setup_slider_pix ();
285 SendProcessorEntry::setup_slider_pix ();
286 SessionEvent::create_per_thread_pool ("GUI", 512);
288 } catch (failed_constructor& err) {
289 error << string_compose (_("could not initialize %1."), PROGRAM_NAME) << endmsg;
290 // pass it on up
291 throw;
294 /* we like keyboards */
296 keyboard = new ArdourKeyboard(*this);
299 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
300 if (node) {
301 keyboard->set_state (*node, Stateful::loading_state_version);
304 /* we don't like certain modifiers */
305 Bindings::set_ignored_state (GDK_LOCK_MASK|GDK_MOD2_MASK|GDK_MOD3_MASK);
307 reset_dpi();
309 TimeAxisViewItem::set_constant_heights ();
311 /* The following must happen after ARDOUR::init() so that Config is set up */
313 location_ui = new ActionWindowProxy<LocationUIWindow> (X_("locations"), Config->extra_xml (X_("UI")), X_("ToggleLocations"));
314 big_clock_window = new ActionWindowProxy<Gtk::Window> (X_("bigclock"), Config->extra_xml (X_("UI")), X_("ToggleBigClock"));
315 speaker_config_window = new ActionWindowProxy<SpeakerDialog> (X_("speakerconf"), Config->extra_xml (X_("UI")), X_("toggle-speaker-config"));
317 for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) {
318 _global_port_matrix[*i] = new ActionWindowProxy<GlobalPortMatrixWindow> (
319 string_compose ("GlobalPortMatrix-%1", (*i).to_string()),
320 Config->extra_xml (X_("UI")),
321 string_compose ("toggle-%1-connection-manager", (*i).to_string())
325 setup_clock ();
327 SpeakerDialog* s = new SpeakerDialog ();
328 s->signal_unmap().connect (sigc::bind (sigc::ptr_fun (&ActionManager::uncheck_toggleaction), X_("<Actions>/Common/toggle-speaker-config")));
329 speaker_config_window->set (s);
331 starting.connect (sigc::mem_fun(*this, &ARDOUR_UI::startup));
332 stopping.connect (sigc::mem_fun(*this, &ARDOUR_UI::shutdown));
335 /** @return true if a session was chosen and `apply' clicked, otherwise false if `cancel' was clicked */
336 bool
337 ARDOUR_UI::run_startup (bool should_be_new, string load_template)
339 delete _startup;
340 _startup = new ArdourStartup ();
342 XMLNode* audio_setup = Config->extra_xml ("AudioSetup");
344 if (audio_setup && _startup->engine_control()) {
345 _startup->engine_control()->set_state (*audio_setup);
348 _startup->set_new_only (should_be_new);
349 if (!load_template.empty()) {
350 _startup->set_load_template( load_template );
352 _startup->present ();
354 main().run();
356 _startup->hide ();
358 switch (_startup->response()) {
359 case RESPONSE_OK:
360 return true;
361 default:
362 return false;
367 ARDOUR_UI::create_engine ()
369 // this gets called every time by new_session()
371 if (engine) {
372 return 0;
375 loading_message (_("Starting audio engine"));
377 try {
378 engine = new ARDOUR::AudioEngine (ARDOUR_COMMAND_LINE::jack_client_name, ARDOUR_COMMAND_LINE::jack_session_uuid);
380 } catch (...) {
382 return -1;
385 engine->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
386 engine->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
387 engine->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
389 engine->Halted.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
391 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
393 post_engine ();
395 return 0;
398 void
399 ARDOUR_UI::post_engine ()
401 /* Things to be done once we create the AudioEngine
404 ARDOUR::init_post_engine ();
406 ActionManager::init ();
407 _tooltips.enable();
409 if (setup_windows ()) {
410 throw failed_constructor ();
413 check_memory_locking();
415 /* this is the first point at which all the keybindings are available */
417 if (ARDOUR_COMMAND_LINE::show_key_actions) {
418 vector<string> names;
419 vector<string> paths;
420 vector<string> tooltips;
421 vector<string> keys;
422 vector<AccelKey> bindings;
424 ActionManager::get_all_actions (names, paths, tooltips, keys, bindings);
426 vector<string>::iterator n;
427 vector<string>::iterator k;
428 for (n = names.begin(), k = keys.begin(); n != names.end(); ++n, ++k) {
429 cerr << "Action: " << (*n) << " bound to " << (*k) << endl;
432 exit (0);
435 blink_timeout_tag = -1;
437 /* this being a GUI and all, we want peakfiles */
439 AudioFileSource::set_build_peakfiles (true);
440 AudioFileSource::set_build_missing_peakfiles (true);
442 /* set default clock modes */
444 if (Profile->get_sae()) {
445 primary_clock.set_mode (AudioClock::BBT);
446 secondary_clock.set_mode (AudioClock::MinSec);
447 } else {
448 primary_clock.set_mode (AudioClock::Timecode);
449 secondary_clock.set_mode (AudioClock::BBT);
452 /* start the time-of-day-clock */
454 #ifndef GTKOSX
455 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
456 update_wall_clock ();
457 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 60000);
458 #endif
460 update_disk_space ();
461 update_cpu_load ();
462 update_sample_rate (engine->frame_rate());
464 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
465 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
466 Config->map_parameters (pc);
468 /* now start and maybe save state */
470 if (do_engine_start () == 0) {
471 if (_session && _session_is_new) {
472 /* we need to retain initial visual
473 settings for a new session
475 _session->save_state ("");
480 ARDOUR_UI::~ARDOUR_UI ()
482 delete keyboard;
483 delete editor;
484 delete mixer;
485 delete add_route_dialog;
488 void
489 ARDOUR_UI::pop_back_splash ()
491 if (Splash::instance()) {
492 // Splash::instance()->pop_back();
493 Splash::instance()->hide ();
497 gint
498 ARDOUR_UI::configure_timeout ()
500 if (last_configure_time == 0) {
501 /* no configure events yet */
502 return true;
505 /* force a gap of 0.5 seconds since the last configure event
508 if (get_microseconds() - last_configure_time < 500000) {
509 return true;
510 } else {
511 have_configure_timeout = false;
512 cerr << "config event-driven save\n";
513 save_ardour_state ();
514 return false;
518 gboolean
519 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
521 if (have_configure_timeout) {
522 last_configure_time = get_microseconds();
523 } else {
524 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
525 have_configure_timeout = true;
528 return FALSE;
531 void
532 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
534 const XMLProperty* prop;
536 if ((prop = node.property ("roll")) != 0) {
537 roll_controllable->set_id (prop->value());
539 if ((prop = node.property ("stop")) != 0) {
540 stop_controllable->set_id (prop->value());
542 if ((prop = node.property ("goto-start")) != 0) {
543 goto_start_controllable->set_id (prop->value());
545 if ((prop = node.property ("goto-end")) != 0) {
546 goto_end_controllable->set_id (prop->value());
548 if ((prop = node.property ("auto-loop")) != 0) {
549 auto_loop_controllable->set_id (prop->value());
551 if ((prop = node.property ("play-selection")) != 0) {
552 play_selection_controllable->set_id (prop->value());
554 if ((prop = node.property ("rec")) != 0) {
555 rec_controllable->set_id (prop->value());
557 if ((prop = node.property ("shuttle")) != 0) {
558 shuttle_box->controllable()->set_id (prop->value());
563 XMLNode&
564 ARDOUR_UI::get_transport_controllable_state ()
566 XMLNode* node = new XMLNode(X_("TransportControllables"));
567 char buf[64];
569 roll_controllable->id().print (buf, sizeof (buf));
570 node->add_property (X_("roll"), buf);
571 stop_controllable->id().print (buf, sizeof (buf));
572 node->add_property (X_("stop"), buf);
573 goto_start_controllable->id().print (buf, sizeof (buf));
574 node->add_property (X_("goto_start"), buf);
575 goto_end_controllable->id().print (buf, sizeof (buf));
576 node->add_property (X_("goto_end"), buf);
577 auto_loop_controllable->id().print (buf, sizeof (buf));
578 node->add_property (X_("auto_loop"), buf);
579 play_selection_controllable->id().print (buf, sizeof (buf));
580 node->add_property (X_("play_selection"), buf);
581 rec_controllable->id().print (buf, sizeof (buf));
582 node->add_property (X_("rec"), buf);
583 shuttle_box->controllable()->id().print (buf, sizeof (buf));
584 node->add_property (X_("shuttle"), buf);
586 return *node;
590 gint
591 ARDOUR_UI::autosave_session ()
593 if (g_main_depth() > 1) {
594 /* inside a recursive main loop,
595 give up because we may not be able to
596 take a lock.
598 return 1;
601 if (!Config->get_periodic_safety_backups()) {
602 return 1;
605 if (_session) {
606 _session->maybe_write_autosave();
609 return 1;
612 void
613 ARDOUR_UI::update_autosave ()
615 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_autosave)
617 if (_session && _session->dirty()) {
618 if (_autosave_connection.connected()) {
619 _autosave_connection.disconnect();
622 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
623 Config->get_periodic_safety_backup_interval() * 1000);
625 } else {
626 if (_autosave_connection.connected()) {
627 _autosave_connection.disconnect();
632 void
633 ARDOUR_UI::backend_audio_error (bool we_set_params, Gtk::Window* toplevel)
635 string title;
636 if (we_set_params) {
637 title = string_compose (_("%1 could not start JACK"), PROGRAM_NAME);
638 } else {
639 title = string_compose (_("%1 could not connect to JACK."), PROGRAM_NAME);
642 MessageDialog win (title,
643 false,
644 Gtk::MESSAGE_INFO,
645 Gtk::BUTTONS_NONE);
647 if (we_set_params) {
648 win.set_secondary_text(_("There are several possible reasons:\n\
650 1) You requested audio parameters that are not supported..\n\
651 2) JACK is running as another user.\n\
653 Please consider the possibilities, and perhaps try different parameters."));
654 } else {
655 win.set_secondary_text(_("There are several possible reasons:\n\
657 1) JACK is not running.\n\
658 2) JACK is running as another user, perhaps root.\n\
659 3) There is already another client called \"ardour\".\n\
661 Please consider the possibilities, and perhaps (re)start JACK."));
664 if (toplevel) {
665 win.set_transient_for (*toplevel);
668 if (we_set_params) {
669 win.add_button (Stock::OK, RESPONSE_CLOSE);
670 } else {
671 win.add_button (Stock::QUIT, RESPONSE_CLOSE);
674 win.set_default_response (RESPONSE_CLOSE);
676 win.show_all ();
677 win.set_position (Gtk::WIN_POS_CENTER);
678 pop_back_splash ();
680 /* we just don't care about the result, but we want to block */
682 win.run ();
685 void
686 ARDOUR_UI::startup ()
688 Application* app = Application::instance ();
690 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
691 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::idle_load));
693 #ifdef PHONE_HOME
694 call_the_mothership (VERSIONSTRING);
695 #endif
697 app->ready ();
699 if (get_session_parameters (true, ARDOUR_COMMAND_LINE::new_session, ARDOUR_COMMAND_LINE::load_template)) {
700 exit (1);
703 use_config ();
705 goto_editor_window ();
707 /* Add the window proxies here; their addition may cause windows to be opened, and we want them
708 to be opened on top of the editor window that goto_editor_window() just opened.
710 add_window_proxy (location_ui);
711 add_window_proxy (big_clock_window);
712 for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) {
713 add_window_proxy (_global_port_matrix[*i]);
716 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
719 void
720 ARDOUR_UI::no_memory_warning ()
722 XMLNode node (X_("no-memory-warning"));
723 Config->add_instant_xml (node);
726 void
727 ARDOUR_UI::check_memory_locking ()
729 #ifdef __APPLE__
730 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
731 return;
732 #else // !__APPLE__
734 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
736 if (engine->is_realtime() && memory_warning_node == 0) {
738 struct rlimit limits;
739 int64_t ram;
740 long pages, page_size;
742 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0) {
743 ram = 0;
744 } else {
745 ram = (int64_t) pages * (int64_t) page_size;
748 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
749 return;
752 if (limits.rlim_cur != RLIM_INFINITY) {
754 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
756 MessageDialog msg (
757 string_compose (
758 _("WARNING: Your system has a limit for maximum amount of locked memory. "
759 "This might cause %1 to run out of memory before your system "
760 "runs out of memory. \n\n"
761 "You can view the memory limit with 'ulimit -l', "
762 "and it is normally controlled by /etc/security/limits.conf"),
763 PROGRAM_NAME).c_str());
765 VBox* vbox = msg.get_vbox();
766 HBox hbox;
767 CheckButton cb (_("Do not show this window again"));
769 cb.signal_toggled().connect (sigc::mem_fun (*this, &ARDOUR_UI::no_memory_warning));
771 hbox.pack_start (cb, true, false);
772 vbox->pack_start (hbox);
773 cb.show();
774 vbox->show();
775 hbox.show ();
777 pop_back_splash ();
779 editor->ensure_float (msg);
780 msg.run ();
784 #endif // !__APPLE__
788 void
789 ARDOUR_UI::queue_finish ()
791 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
794 bool
795 ARDOUR_UI::idle_finish ()
797 finish ();
798 return false; /* do not call again */
801 void
802 ARDOUR_UI::finish()
804 if (_session) {
805 int tries = 0;
807 if (_session->transport_rolling() && (++tries < 8)) {
808 _session->request_stop (false, true);
809 usleep (10000);
812 if (_session->dirty()) {
813 vector<string> actions;
814 actions.push_back (_("Don't quit"));
815 actions.push_back (_("Just quit"));
816 actions.push_back (_("Save and quit"));
817 switch (ask_about_saving_session(actions)) {
818 case -1:
819 return;
820 break;
821 case 1:
822 /* use the default name */
823 if (save_state_canfail ("")) {
824 /* failed - don't quit */
825 MessageDialog msg (*editor,
826 _("\
827 Ardour was unable to save your session.\n\n\
828 If you still wish to quit, please use the\n\n\
829 \"Just quit\" option."));
830 pop_back_splash();
831 msg.run ();
832 return;
834 break;
835 case 0:
836 break;
840 second_connection.disconnect ();
841 point_one_second_connection.disconnect ();
842 point_oh_five_second_connection.disconnect ();
843 point_zero_one_second_connection.disconnect();
846 /* Save state before deleting the session, as that causes some
847 windows to be destroyed before their visible state can be
848 saved.
850 save_ardour_state ();
852 if (_session) {
853 // _session->set_deletion_in_progress ();
854 _session->set_clean ();
855 _session->remove_pending_capture_state ();
856 delete _session;
857 _session = 0;
860 ArdourDialog::close_all_dialogs ();
861 engine->stop (true);
862 quit ();
866 ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
868 ArdourDialog window (_("Unsaved Session"));
869 Gtk::HBox dhbox; // the hbox for the image and text
870 Gtk::Label prompt_label;
871 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
873 string msg;
875 assert (actions.size() >= 3);
877 window.add_button (actions[0], RESPONSE_REJECT);
878 window.add_button (actions[1], RESPONSE_APPLY);
879 window.add_button (actions[2], RESPONSE_ACCEPT);
881 window.set_default_response (RESPONSE_ACCEPT);
883 Gtk::Button noquit_button (msg);
884 noquit_button.set_name ("EditorGTKButton");
886 string prompt;
888 if (_session->snap_name() == _session->name()) {
889 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?"),
890 _session->snap_name());
891 } else {
892 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?"),
893 _session->snap_name());
896 prompt_label.set_text (prompt);
897 prompt_label.set_name (X_("PrompterLabel"));
898 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
900 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
901 dhbox.set_homogeneous (false);
902 dhbox.pack_start (*dimage, false, false, 5);
903 dhbox.pack_start (prompt_label, true, false, 5);
904 window.get_vbox()->pack_start (dhbox);
906 window.set_name (_("Prompter"));
907 window.set_position (Gtk::WIN_POS_MOUSE);
908 window.set_modal (true);
909 window.set_resizable (false);
911 dhbox.show();
912 prompt_label.show();
913 dimage->show();
914 window.show();
915 window.set_keep_above (true);
916 window.present ();
918 ResponseType r = (ResponseType) window.run();
920 window.hide ();
922 switch (r) {
923 case RESPONSE_ACCEPT: // save and get out of here
924 return 1;
925 case RESPONSE_APPLY: // get out of here
926 return 0;
927 default:
928 break;
931 return -1;
934 gint
935 ARDOUR_UI::every_second ()
937 update_cpu_load ();
938 update_buffer_load ();
939 update_disk_space ();
940 return TRUE;
943 gint
944 ARDOUR_UI::every_point_one_seconds ()
946 shuttle_box->update_speed_display ();
947 RapidScreenUpdate(); /* EMIT_SIGNAL */
948 return TRUE;
951 gint
952 ARDOUR_UI::every_point_zero_one_seconds ()
954 // august 2007: actual update frequency: 40Hz, not 100Hz
956 SuperRapidScreenUpdate(); /* EMIT_SIGNAL */
957 return TRUE;
960 void
961 ARDOUR_UI::update_sample_rate (framecnt_t)
963 char buf[32];
965 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
967 if (!engine->connected()) {
969 snprintf (buf, sizeof (buf), _("disconnected"));
971 } else {
973 framecnt_t rate = engine->frame_rate();
975 if (fmod (rate, 1000.0) != 0.0) {
976 snprintf (buf, sizeof (buf), _("%.1f kHz / %4.1f ms"),
977 (float) rate/1000.0f,
978 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
979 } else {
980 snprintf (buf, sizeof (buf), _("%" PRId64 " kHz / %4.1f ms"),
981 rate/1000,
982 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
986 sample_rate_label.set_text (buf);
989 void
990 ARDOUR_UI::update_cpu_load ()
992 char buf[32];
993 snprintf (buf, sizeof (buf), _("DSP: %5.1f%%"), engine->get_cpu_load());
994 cpu_load_label.set_text (buf);
997 void
998 ARDOUR_UI::update_buffer_load ()
1000 char buf[64];
1001 uint32_t c, p;
1003 if (_session) {
1004 c = _session->capture_load ();
1005 p = _session->playback_load ();
1007 snprintf (buf, sizeof (buf), _("Buffers p:%" PRIu32 "%% c:%" PRIu32 "%%"),
1008 _session->playback_load(), _session->capture_load());
1009 buffer_load_label.set_text (buf);
1010 } else {
1011 buffer_load_label.set_text ("");
1015 void
1016 ARDOUR_UI::count_recenabled_streams (Route& route)
1018 Track* track = dynamic_cast<Track*>(&route);
1019 if (track && track->record_enabled()) {
1020 rec_enabled_streams += track->n_inputs().n_total();
1024 void
1025 ARDOUR_UI::update_disk_space()
1027 if (_session == 0) {
1028 return;
1031 framecnt_t frames = _session->available_capture_duration();
1032 char buf[64];
1033 framecnt_t fr = _session->frame_rate();
1035 if (frames == max_framecnt) {
1036 strcpy (buf, _("Disk: 24hrs+"));
1037 } else {
1038 rec_enabled_streams = 0;
1039 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams);
1041 if (rec_enabled_streams) {
1042 frames /= rec_enabled_streams;
1045 int hrs;
1046 int mins;
1047 int secs;
1049 hrs = frames / (fr * 3600);
1050 frames -= hrs * fr * 3600;
1051 mins = frames / (fr * 60);
1052 frames -= mins * fr * 60;
1053 secs = frames / fr;
1055 snprintf (buf, sizeof(buf), _("Disk: %02dh:%02dm:%02ds"), hrs, mins, secs);
1058 disk_space_label.set_text (buf);
1060 // An attempt to make the disk space label flash red when space has run out.
1062 if (frames < fr * 60 * 5) {
1063 /* disk_space_box.style ("disk_space_label_empty"); */
1064 } else {
1065 /* disk_space_box.style ("disk_space_label"); */
1070 gint
1071 ARDOUR_UI::update_wall_clock ()
1073 time_t now;
1074 struct tm *tm_now;
1075 char buf[16];
1077 time (&now);
1078 tm_now = localtime (&now);
1080 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1081 wall_clock_label.set_text (buf);
1083 return TRUE;
1086 gint
1087 ARDOUR_UI::session_menu (GdkEventButton */*ev*/)
1089 session_popup_menu->popup (0, 0);
1090 return TRUE;
1093 void
1094 ARDOUR_UI::redisplay_recent_sessions ()
1096 std::vector<sys::path> session_directories;
1097 RecentSessionsSorter cmp;
1099 recent_session_display.set_model (Glib::RefPtr<TreeModel>(0));
1100 recent_session_model->clear ();
1102 ARDOUR::RecentSessions rs;
1103 ARDOUR::read_recent_sessions (rs);
1105 if (rs.empty()) {
1106 recent_session_display.set_model (recent_session_model);
1107 return;
1110 // sort them alphabetically
1111 sort (rs.begin(), rs.end(), cmp);
1113 for (ARDOUR::RecentSessions::iterator i = rs.begin(); i != rs.end(); ++i) {
1114 session_directories.push_back ((*i).second);
1117 for (vector<sys::path>::const_iterator i = session_directories.begin();
1118 i != session_directories.end(); ++i)
1120 std::vector<sys::path> state_file_paths;
1122 // now get available states for this session
1124 get_state_files_in_directory (*i, state_file_paths);
1126 vector<string*>* states;
1127 vector<const gchar*> item;
1128 string fullpath = (*i).to_string();
1130 /* remove any trailing / */
1132 if (fullpath[fullpath.length()-1] == '/') {
1133 fullpath = fullpath.substr (0, fullpath.length()-1);
1136 /* check whether session still exists */
1137 if (!Glib::file_test(fullpath.c_str(), Glib::FILE_TEST_EXISTS)) {
1138 /* session doesn't exist */
1139 cerr << "skipping non-existent session " << fullpath << endl;
1140 continue;
1143 /* now get available states for this session */
1145 if ((states = Session::possible_states (fullpath)) == 0) {
1146 /* no state file? */
1147 continue;
1150 std::vector<string> state_file_names(get_file_names_no_extension (state_file_paths));
1152 Gtk::TreeModel::Row row = *(recent_session_model->append());
1154 row[recent_session_columns.visible_name] = Glib::path_get_basename (fullpath);
1155 row[recent_session_columns.fullpath] = fullpath;
1157 if (state_file_names.size() > 1) {
1159 // add the children
1161 for (std::vector<std::string>::iterator i2 = state_file_names.begin();
1162 i2 != state_file_names.end(); ++i2)
1165 Gtk::TreeModel::Row child_row = *(recent_session_model->append (row.children()));
1167 child_row[recent_session_columns.visible_name] = *i2;
1168 child_row[recent_session_columns.fullpath] = fullpath;
1173 recent_session_display.set_model (recent_session_model);
1176 void
1177 ARDOUR_UI::build_session_selector ()
1179 session_selector_window = new ArdourDialog (_("Recent Sessions"));
1181 Gtk::ScrolledWindow *scroller = manage (new Gtk::ScrolledWindow);
1183 session_selector_window->add_button (Stock::CANCEL, RESPONSE_CANCEL);
1184 session_selector_window->add_button (Stock::OPEN, RESPONSE_ACCEPT);
1185 session_selector_window->set_default_response (RESPONSE_ACCEPT);
1186 recent_session_model = TreeStore::create (recent_session_columns);
1187 recent_session_display.set_model (recent_session_model);
1188 recent_session_display.append_column (_("Recent Sessions"), recent_session_columns.visible_name);
1189 recent_session_display.set_headers_visible (false);
1190 recent_session_display.get_selection()->set_mode (SELECTION_BROWSE);
1191 recent_session_display.signal_row_activated().connect (sigc::mem_fun (*this, &ARDOUR_UI::recent_session_row_activated));
1193 scroller->add (recent_session_display);
1194 scroller->set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
1196 session_selector_window->set_name ("SessionSelectorWindow");
1197 session_selector_window->set_size_request (200, 400);
1198 session_selector_window->get_vbox()->pack_start (*scroller);
1200 recent_session_display.show();
1201 scroller->show();
1202 //session_selector_window->get_vbox()->show();
1205 void
1206 ARDOUR_UI::recent_session_row_activated (const TreePath& /*path*/, TreeViewColumn* /*col*/)
1208 session_selector_window->response (RESPONSE_ACCEPT);
1211 void
1212 ARDOUR_UI::open_recent_session ()
1214 bool can_return = (_session != 0);
1216 if (session_selector_window == 0) {
1217 build_session_selector ();
1220 redisplay_recent_sessions ();
1222 while (true) {
1224 session_selector_window->set_position (WIN_POS_MOUSE);
1226 ResponseType r = (ResponseType) session_selector_window->run ();
1228 switch (r) {
1229 case RESPONSE_ACCEPT:
1230 break;
1231 default:
1232 if (can_return) {
1233 session_selector_window->hide();
1234 return;
1235 } else {
1236 exit (1);
1240 if (recent_session_display.get_selection()->count_selected_rows() == 0) {
1241 continue;
1244 session_selector_window->hide();
1246 Gtk::TreeModel::iterator i = recent_session_display.get_selection()->get_selected();
1248 if (i == recent_session_model->children().end()) {
1249 return;
1252 std::string path = (*i)[recent_session_columns.fullpath];
1253 std::string state = (*i)[recent_session_columns.visible_name];
1255 _session_is_new = false;
1257 if (load_session (path, state) == 0) {
1258 break;
1261 can_return = false;
1265 bool
1266 ARDOUR_UI::check_audioengine ()
1268 if (engine) {
1269 if (!engine->connected()) {
1270 MessageDialog msg (string_compose (
1271 _("%1 is not connected to JACK\n"
1272 "You cannot open or close sessions in this condition"),
1273 PROGRAM_NAME));
1274 pop_back_splash ();
1275 msg.run ();
1276 return false;
1278 return true;
1279 } else {
1280 return false;
1284 void
1285 ARDOUR_UI::open_session ()
1287 if (!check_audioengine()) {
1288 return;
1292 /* popup selector window */
1294 if (open_session_selector == 0) {
1296 /* ardour sessions are folders */
1298 open_session_selector = new Gtk::FileChooserDialog (_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1299 open_session_selector->add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1300 open_session_selector->add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1301 open_session_selector->set_default_response(Gtk::RESPONSE_ACCEPT);
1303 FileFilter session_filter;
1304 session_filter.add_pattern ("*.ardour");
1305 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1306 open_session_selector->add_filter (session_filter);
1307 open_session_selector->set_filter (session_filter);
1310 int response = open_session_selector->run();
1311 open_session_selector->hide ();
1313 switch (response) {
1314 case RESPONSE_ACCEPT:
1315 break;
1316 default:
1317 open_session_selector->hide();
1318 return;
1321 open_session_selector->hide();
1322 string session_path = open_session_selector->get_filename();
1323 string path, name;
1324 bool isnew;
1326 if (session_path.length() > 0) {
1327 if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1328 _session_is_new = isnew;
1329 load_session (path, name);
1335 void
1336 ARDOUR_UI::session_add_midi_route (bool disk, RouteGroup* route_group, uint32_t how_many, string const & name_template)
1338 list<boost::shared_ptr<MidiTrack> > tracks;
1340 if (_session == 0) {
1341 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1342 return;
1345 try {
1346 if (disk) {
1348 tracks = _session->new_midi_track (ARDOUR::Normal, route_group, how_many, name_template);
1350 if (tracks.size() != how_many) {
1351 if (how_many == 1) {
1352 error << _("could not create a new midi track") << endmsg;
1353 } else {
1354 error << string_compose (_("could not create %1 new midi tracks"), how_many) << endmsg;
1357 } /*else {
1358 if ((route = _session->new_midi_route ()) == 0) {
1359 error << _("could not create new midi bus") << endmsg;
1364 catch (...) {
1365 MessageDialog msg (*editor,
1366 string_compose (_("There are insufficient JACK ports available\n\
1367 to create a new track or bus.\n\
1368 You should save %1, exit and\n\
1369 restart JACK with more ports."), PROGRAM_NAME));
1370 msg.run ();
1375 void
1376 ARDOUR_UI::session_add_audio_route (
1377 bool track,
1378 int32_t input_channels,
1379 int32_t output_channels,
1380 ARDOUR::TrackMode mode,
1381 RouteGroup* route_group,
1382 uint32_t how_many,
1383 string const & name_template
1386 list<boost::shared_ptr<AudioTrack> > tracks;
1387 RouteList routes;
1389 if (_session == 0) {
1390 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1391 return;
1394 try {
1395 if (track) {
1396 tracks = _session->new_audio_track (input_channels, output_channels, mode, route_group, how_many, name_template);
1398 if (tracks.size() != how_many) {
1399 if (how_many == 1) {
1400 error << _("could not create a new audio track") << endmsg;
1401 } else {
1402 error << string_compose (_("could only create %1 of %2 new audio %3"),
1403 tracks.size(), how_many, (track ? _("tracks") : _("busses"))) << endmsg;
1407 } else {
1409 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template);
1411 if (routes.size() != how_many) {
1412 if (how_many == 1) {
1413 error << _("could not create a new audio track") << endmsg;
1414 } else {
1415 error << string_compose (_("could not create %1 new audio tracks"), how_many) << endmsg;
1421 catch (...) {
1422 MessageDialog msg (*editor,
1423 string_compose (_("There are insufficient JACK ports available\n\
1424 to create a new track or bus.\n\
1425 You should save %1, exit and\n\
1426 restart JACK with more ports."), PROGRAM_NAME));
1427 pop_back_splash ();
1428 msg.run ();
1432 void
1433 ARDOUR_UI::do_transport_locate (framepos_t new_position, bool with_roll)
1435 framecnt_t _preroll = 0;
1437 if (_session) {
1438 // XXX CONFIG_CHANGE FIX - requires AnyTime handling
1439 // _preroll = _session->convert_to_frames_at (new_position, Config->get_preroll());
1441 if (new_position > _preroll) {
1442 new_position -= _preroll;
1443 } else {
1444 new_position = 0;
1447 _session->request_locate (new_position, with_roll);
1451 void
1452 ARDOUR_UI::transport_goto_start ()
1454 if (_session) {
1455 _session->goto_start();
1457 /* force displayed area in editor to start no matter
1458 what "follow playhead" setting is.
1461 if (editor) {
1462 editor->center_screen (_session->current_start_frame ());
1467 void
1468 ARDOUR_UI::transport_goto_zero ()
1470 if (_session) {
1471 _session->request_locate (0);
1473 /* force displayed area in editor to start no matter
1474 what "follow playhead" setting is.
1477 if (editor) {
1478 editor->reset_x_origin (0);
1483 void
1484 ARDOUR_UI::transport_goto_wallclock ()
1486 if (_session && editor) {
1488 time_t now;
1489 struct tm tmnow;
1490 framepos_t frames;
1492 time (&now);
1493 localtime_r (&now, &tmnow);
1495 frames = tmnow.tm_hour * (60 * 60 * _session->frame_rate());
1496 frames += tmnow.tm_min * (60 * _session->frame_rate());
1497 frames += tmnow.tm_sec * _session->frame_rate();
1499 _session->request_locate (frames, _session->transport_rolling ());
1501 /* force displayed area in editor to start no matter
1502 what "follow playhead" setting is.
1505 if (editor) {
1506 editor->center_screen (frames);
1511 void
1512 ARDOUR_UI::transport_goto_end ()
1514 if (_session) {
1515 framepos_t const frame = _session->current_end_frame();
1516 _session->request_locate (frame);
1518 /* force displayed area in editor to start no matter
1519 what "follow playhead" setting is.
1522 if (editor) {
1523 editor->center_screen (frame);
1528 void
1529 ARDOUR_UI::transport_stop ()
1531 if (!_session) {
1532 return;
1535 if (_session->is_auditioning()) {
1536 _session->cancel_audition ();
1537 return;
1540 _session->request_stop (false, true);
1543 void
1544 ARDOUR_UI::transport_stop_and_forget_capture ()
1546 if (_session) {
1547 _session->request_stop (true, true);
1551 void
1552 ARDOUR_UI::remove_last_capture()
1554 if (editor) {
1555 editor->remove_last_capture();
1559 void
1560 ARDOUR_UI::transport_record (bool roll)
1563 if (_session) {
1564 switch (_session->record_status()) {
1565 case Session::Disabled:
1566 if (_session->ntracks() == 0) {
1567 MessageDialog msg (*editor, _("Please create 1 or more track\nbefore trying to record.\nCheck the Session menu."));
1568 msg.run ();
1569 return;
1571 _session->maybe_enable_record ();
1572 if (roll) {
1573 transport_roll ();
1575 break;
1576 case Session::Recording:
1577 if (roll) {
1578 _session->request_stop();
1579 } else {
1580 _session->disable_record (false, true);
1582 break;
1584 case Session::Enabled:
1585 _session->disable_record (false, true);
1588 //cerr << "ARDOUR_UI::transport_record () called roll = " << roll << " _session->record_status() = " << _session->record_status() << endl;
1591 void
1592 ARDOUR_UI::transport_roll ()
1594 if (!_session) {
1595 return;
1598 if (_session->is_auditioning()) {
1599 return;
1602 #if 0
1603 if (_session->config.get_external_sync()) {
1604 switch (_session->config.get_sync_source()) {
1605 case JACK:
1606 break;
1607 default:
1608 /* transport controlled by the master */
1609 return;
1612 #endif
1614 bool rolling = _session->transport_rolling();
1616 if (_session->get_play_loop()) {
1617 /* XXX it is not possible to just leave seamless loop and keep
1618 playing at present (nov 4th 2009)
1620 if (!Config->get_seamless_loop()) {
1621 _session->request_play_loop (false, true);
1623 } else if (_session->get_play_range () && !join_play_range_button.get_active()) {
1624 /* stop playing a range if we currently are */
1625 _session->request_play_range (0, true);
1628 if (join_play_range_button.get_active()) {
1629 _session->request_play_range (&editor->get_selection().time, true);
1632 if (!rolling) {
1633 _session->request_transport_speed (1.0f);
1637 void
1638 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
1641 if (!_session) {
1642 return;
1645 if (_session->is_auditioning()) {
1646 _session->cancel_audition ();
1647 return;
1650 if (_session->config.get_external_sync()) {
1651 switch (_session->config.get_sync_source()) {
1652 case JACK:
1653 break;
1654 default:
1655 /* transport controlled by the master */
1656 return;
1660 bool rolling = _session->transport_rolling();
1661 bool affect_transport = true;
1663 if (rolling && roll_out_of_bounded_mode) {
1664 /* drop out of loop/range playback but leave transport rolling */
1665 if (_session->get_play_loop()) {
1666 if (Config->get_seamless_loop()) {
1667 /* the disk buffers contain copies of the loop - we can't
1668 just keep playing, so stop the transport. the user
1669 can restart as they wish.
1671 affect_transport = true;
1672 } else {
1673 /* disk buffers are normal, so we can keep playing */
1674 affect_transport = false;
1676 _session->request_play_loop (false, true);
1677 } else if (_session->get_play_range ()) {
1678 affect_transport = false;
1679 _session->request_play_range (0, true);
1683 if (affect_transport) {
1684 if (rolling) {
1685 _session->request_stop (with_abort, true);
1686 } else {
1687 if (join_play_range_button.get_active()) {
1688 _session->request_play_range (&editor->get_selection().time, true);
1691 _session->request_transport_speed (1.0f);
1696 void
1697 ARDOUR_UI::toggle_session_auto_loop ()
1699 if (!_session) {
1700 return;
1703 if (_session->get_play_loop()) {
1705 if (_session->transport_rolling()) {
1707 Location * looploc = _session->locations()->auto_loop_location();
1709 if (looploc) {
1710 _session->request_locate (looploc->start(), true);
1711 _session->request_play_loop (false);
1714 } else {
1715 _session->request_play_loop (false);
1717 } else {
1719 Location * looploc = _session->locations()->auto_loop_location();
1721 if (looploc) {
1722 _session->request_play_loop (true);
1727 void
1728 ARDOUR_UI::transport_play_selection ()
1730 if (!_session) {
1731 return;
1734 editor->play_selection ();
1737 void
1738 ARDOUR_UI::transport_rewind (int option)
1740 float current_transport_speed;
1742 if (_session) {
1743 current_transport_speed = _session->transport_speed();
1745 if (current_transport_speed >= 0.0f) {
1746 switch (option) {
1747 case 0:
1748 _session->request_transport_speed (-1.0f);
1749 break;
1750 case 1:
1751 _session->request_transport_speed (-4.0f);
1752 break;
1753 case -1:
1754 _session->request_transport_speed (-0.5f);
1755 break;
1757 } else {
1758 /* speed up */
1759 _session->request_transport_speed (current_transport_speed * 1.5f);
1764 void
1765 ARDOUR_UI::transport_forward (int option)
1767 float current_transport_speed;
1769 if (_session) {
1770 current_transport_speed = _session->transport_speed();
1772 if (current_transport_speed <= 0.0f) {
1773 switch (option) {
1774 case 0:
1775 _session->request_transport_speed (1.0f);
1776 break;
1777 case 1:
1778 _session->request_transport_speed (4.0f);
1779 break;
1780 case -1:
1781 _session->request_transport_speed (0.5f);
1782 break;
1784 } else {
1785 /* speed up */
1786 _session->request_transport_speed (current_transport_speed * 1.5f);
1792 void
1793 ARDOUR_UI::toggle_record_enable (uint32_t rid)
1795 if (_session == 0) {
1796 return;
1799 boost::shared_ptr<Route> r;
1801 if ((r = _session->route_by_remote_id (rid)) != 0) {
1803 Track* t;
1805 if ((t = dynamic_cast<Track*>(r.get())) != 0) {
1806 t->set_record_enabled (!t->record_enabled(), this);
1809 if (_session == 0) {
1810 return;
1814 void
1815 ARDOUR_UI::map_transport_state ()
1817 if (!_session) {
1818 auto_loop_button.set_visual_state (0);
1819 play_selection_button.set_visual_state (0);
1820 roll_button.set_visual_state (0);
1821 stop_button.set_visual_state (1);
1822 return;
1825 shuttle_box->map_transport_state ();
1827 float sp = _session->transport_speed();
1829 if (sp != 0.0f) {
1831 /* we're rolling */
1833 if (_session->get_play_range()) {
1835 play_selection_button.set_visual_state (1);
1836 roll_button.set_visual_state (0);
1837 auto_loop_button.set_visual_state (0);
1839 } else if (_session->get_play_loop ()) {
1841 auto_loop_button.set_visual_state (1);
1842 play_selection_button.set_visual_state (0);
1843 roll_button.set_visual_state (0);
1845 } else {
1847 roll_button.set_visual_state (1);
1848 play_selection_button.set_visual_state (0);
1849 auto_loop_button.set_visual_state (0);
1852 if (join_play_range_button.get_active()) {
1853 /* light up both roll and play-selection if they are joined */
1854 roll_button.set_visual_state (1);
1855 play_selection_button.set_visual_state (1);
1858 stop_button.set_visual_state (0);
1860 } else {
1862 stop_button.set_visual_state (1);
1863 roll_button.set_visual_state (0);
1864 play_selection_button.set_visual_state (0);
1865 auto_loop_button.set_visual_state (0);
1866 update_disk_space ();
1870 void
1871 ARDOUR_UI::engine_stopped ()
1873 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
1874 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1875 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1878 void
1879 ARDOUR_UI::engine_running ()
1881 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
1882 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, true);
1883 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, false);
1885 Glib::RefPtr<Action> action;
1886 const char* action_name = 0;
1888 switch (engine->frames_per_cycle()) {
1889 case 32:
1890 action_name = X_("JACKLatency32");
1891 break;
1892 case 64:
1893 action_name = X_("JACKLatency64");
1894 break;
1895 case 128:
1896 action_name = X_("JACKLatency128");
1897 break;
1898 case 512:
1899 action_name = X_("JACKLatency512");
1900 break;
1901 case 1024:
1902 action_name = X_("JACKLatency1024");
1903 break;
1904 case 2048:
1905 action_name = X_("JACKLatency2048");
1906 break;
1907 case 4096:
1908 action_name = X_("JACKLatency4096");
1909 break;
1910 case 8192:
1911 action_name = X_("JACKLatency8192");
1912 break;
1913 default:
1914 /* XXX can we do anything useful ? */
1915 break;
1918 if (action_name) {
1920 action = ActionManager::get_action (X_("JACK"), action_name);
1922 if (action) {
1923 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (action);
1924 ract->set_active ();
1929 void
1930 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
1932 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
1933 /* we can't rely on the original string continuing to exist when we are called
1934 again in the GUI thread, so make a copy and note that we need to
1935 free it later.
1937 char *copy = strdup (reason);
1938 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
1939 return;
1942 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1943 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1945 update_sample_rate (0);
1947 string msgstr;
1949 /* if the reason is a non-empty string, it means that the backend was shutdown
1950 rather than just Ardour.
1953 if (strlen (reason)) {
1954 msgstr = string_compose (_("The audio backend (JACK) was shutdown because:\n\n%1"), reason);
1955 } else {
1956 msgstr = string_compose (_("\
1957 JACK has either been shutdown or it\n\
1958 disconnected %1 because %1\n\
1959 was not fast enough. Try to restart\n\
1960 JACK, reconnect and save the session."), PROGRAM_NAME);
1963 MessageDialog msg (*editor, msgstr);
1964 pop_back_splash ();
1965 msg.run ();
1967 if (free_reason) {
1968 free ((char*) reason);
1972 int32_t
1973 ARDOUR_UI::do_engine_start ()
1975 try {
1976 engine->start();
1979 catch (...) {
1980 engine->stop ();
1981 error << _("Unable to start the session running")
1982 << endmsg;
1983 unload_session ();
1984 return -2;
1987 return 0;
1990 void
1991 ARDOUR_UI::setup_theme ()
1993 theme_manager->setup_theme();
1996 void
1997 ARDOUR_UI::update_clocks ()
1999 if (!editor || !editor->dragging_playhead()) {
2000 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position()); /* EMIT_SIGNAL */
2004 void
2005 ARDOUR_UI::start_clocking ()
2007 clock_signal_connection = RapidScreenUpdate.connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2010 void
2011 ARDOUR_UI::stop_clocking ()
2013 clock_signal_connection.disconnect ();
2016 void
2017 ARDOUR_UI::toggle_clocking ()
2019 #if 0
2020 if (clock_button.get_active()) {
2021 start_clocking ();
2022 } else {
2023 stop_clocking ();
2025 #endif
2028 gint
2029 ARDOUR_UI::_blink (void *arg)
2032 ((ARDOUR_UI *) arg)->blink ();
2033 return TRUE;
2036 void
2037 ARDOUR_UI::blink ()
2039 Blink (blink_on = !blink_on); /* EMIT_SIGNAL */
2042 void
2043 ARDOUR_UI::start_blinking ()
2045 /* Start the blink signal. Everybody with a blinking widget
2046 uses Blink to drive the widget's state.
2049 if (blink_timeout_tag < 0) {
2050 blink_on = false;
2051 blink_timeout_tag = g_timeout_add (240, _blink, this);
2055 void
2056 ARDOUR_UI::stop_blinking ()
2058 if (blink_timeout_tag >= 0) {
2059 g_source_remove (blink_timeout_tag);
2060 blink_timeout_tag = -1;
2065 /** Ask the user for the name of a new shapshot and then take it.
2068 void
2069 ARDOUR_UI::snapshot_session (bool switch_to_it)
2071 ArdourPrompter prompter (true);
2072 string snapname;
2074 prompter.set_name ("Prompter");
2075 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2076 prompter.set_title (_("Take Snapshot"));
2077 prompter.set_title (_("Take Snapshot"));
2078 prompter.set_prompt (_("Name of new snapshot"));
2080 if (!switch_to_it) {
2081 char timebuf[128];
2082 time_t n;
2083 struct tm local_time;
2085 time (&n);
2086 localtime_r (&n, &local_time);
2087 strftime (timebuf, sizeof(timebuf), "%FT%T", &local_time);
2088 prompter.set_initial_text (timebuf);
2091 again:
2092 switch (prompter.run()) {
2093 case RESPONSE_ACCEPT:
2095 prompter.get_result (snapname);
2097 bool do_save = (snapname.length() != 0);
2099 if (do_save) {
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;
2106 if (snapname.find ('\\') != string::npos) {
2107 MessageDialog msg (_("To ensure compatibility with various systems\n"
2108 "snapshot names may not contain a '\\' character"));
2109 msg.run ();
2110 goto again;
2114 vector<sys::path> p;
2115 get_state_files_in_directory (_session->session_directory().root_path(), p);
2116 vector<string> n = get_file_names_no_extension (p);
2117 if (find (n.begin(), n.end(), snapname) != n.end()) {
2119 ArdourDialog confirm (_("Confirm Snapshot Overwrite"), true);
2120 Label m (_("A snapshot already exists with that name. Do you want to overwrite it?"));
2121 confirm.get_vbox()->pack_start (m, true, true);
2122 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2123 confirm.add_button (_("Overwrite"), Gtk::RESPONSE_ACCEPT);
2124 confirm.show_all ();
2125 switch (confirm.run()) {
2126 case RESPONSE_CANCEL:
2127 do_save = false;
2131 if (do_save) {
2132 save_state (snapname, switch_to_it);
2134 break;
2137 default:
2138 break;
2142 void
2143 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2145 XMLNode* node = new XMLNode (X_("UI"));
2147 for (list<WindowProxyBase*>::iterator i = _window_proxies.begin(); i != _window_proxies.end(); ++i) {
2148 if (!(*i)->rc_configured()) {
2149 node->add_child_nocopy (*((*i)->get_state ()));
2153 _session->add_extra_xml (*node);
2155 save_state_canfail (name, switch_to_it);
2159 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2161 if (_session) {
2162 int ret;
2164 if (name.length() == 0) {
2165 name = _session->snap_name();
2168 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2169 return ret;
2173 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2174 return 0;
2177 void
2178 ARDOUR_UI::primary_clock_value_changed ()
2180 if (_session) {
2181 _session->request_locate (primary_clock.current_time ());
2185 void
2186 ARDOUR_UI::big_clock_value_changed ()
2188 if (_session) {
2189 _session->request_locate (big_clock.current_time ());
2193 void
2194 ARDOUR_UI::secondary_clock_value_changed ()
2196 if (_session) {
2197 _session->request_locate (secondary_clock.current_time ());
2201 void
2202 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2204 if (_session == 0) {
2205 return;
2208 if (_session->step_editing()) {
2209 return;
2212 Session::RecordState const r = _session->record_status ();
2213 bool const h = _session->have_rec_enabled_track ();
2215 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2216 if (onoff) {
2217 rec_button.set_visual_state (2);
2218 } else {
2219 rec_button.set_visual_state (0);
2221 } else if (r == Session::Recording && h) {
2222 rec_button.set_visual_state (1);
2223 } else {
2224 rec_button.set_visual_state (0);
2228 void
2229 ARDOUR_UI::save_template ()
2231 ArdourPrompter prompter (true);
2232 string name;
2234 if (!check_audioengine()) {
2235 return;
2238 prompter.set_name (X_("Prompter"));
2239 prompter.set_title (_("Save Template"));
2240 prompter.set_prompt (_("Name for template:"));
2241 prompter.set_initial_text(_session->name() + _("-template"));
2242 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2244 switch (prompter.run()) {
2245 case RESPONSE_ACCEPT:
2246 prompter.get_result (name);
2248 if (name.length()) {
2249 _session->save_template (name);
2251 break;
2253 default:
2254 break;
2258 void
2259 ARDOUR_UI::edit_metadata ()
2261 SessionMetadataEditor dialog;
2262 dialog.set_session (_session);
2263 editor->ensure_float (dialog);
2264 dialog.run ();
2267 void
2268 ARDOUR_UI::import_metadata ()
2270 SessionMetadataImporter dialog;
2271 dialog.set_session (_session);
2272 editor->ensure_float (dialog);
2273 dialog.run ();
2276 bool
2277 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
2279 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2281 MessageDialog msg (str,
2282 false,
2283 Gtk::MESSAGE_WARNING,
2284 Gtk::BUTTONS_YES_NO,
2285 true);
2288 msg.set_name (X_("OpenExistingDialog"));
2289 msg.set_title (_("Open Existing Session"));
2290 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
2291 msg.set_position (Gtk::WIN_POS_MOUSE);
2292 pop_back_splash ();
2294 switch (msg.run()) {
2295 case RESPONSE_YES:
2296 return true;
2297 break;
2299 return false;
2303 ARDOUR_UI::build_session_from_nsd (const std::string& session_path, const std::string& session_name)
2305 BusProfile bus_profile;
2307 if (Profile->get_sae()) {
2309 bus_profile.master_out_channels = 2;
2310 bus_profile.input_ac = AutoConnectPhysical;
2311 bus_profile.output_ac = AutoConnectMaster;
2312 bus_profile.requested_physical_in = 0; // use all available
2313 bus_profile.requested_physical_out = 0; // use all available
2315 } else {
2317 /* get settings from advanced section of NSD */
2319 if (_startup->create_master_bus()) {
2320 bus_profile.master_out_channels = (uint32_t) _startup->master_channel_count();
2321 } else {
2322 bus_profile.master_out_channels = 0;
2325 if (_startup->connect_inputs()) {
2326 bus_profile.input_ac = AutoConnectPhysical;
2327 } else {
2328 bus_profile.input_ac = AutoConnectOption (0);
2331 /// @todo some minor tweaks.
2333 bus_profile.output_ac = AutoConnectOption (0);
2335 if (_startup->connect_outputs ()) {
2336 if (_startup->connect_outs_to_master()) {
2337 bus_profile.output_ac = AutoConnectMaster;
2338 } else if (_startup->connect_outs_to_physical()) {
2339 bus_profile.output_ac = AutoConnectPhysical;
2343 bus_profile.requested_physical_in = (uint32_t) _startup->input_limit_count();
2344 bus_profile.requested_physical_out = (uint32_t) _startup->output_limit_count();
2347 if (build_session (session_path, session_name, bus_profile)) {
2348 return -1;
2351 return 0;
2354 void
2355 ARDOUR_UI::idle_load (const std::string& path)
2357 if (_session) {
2358 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2359 /* /path/to/foo => /path/to/foo, foo */
2360 load_session (path, basename_nosuffix (path));
2361 } else {
2362 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2363 load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2365 } else {
2367 ARDOUR_COMMAND_LINE::session_name = path;
2370 * new_session_dialog doens't exist in A3
2371 * Try to remove all references to it to
2372 * see if it will compile. NOTE: this will
2373 * likely cause a runtime issue is my somewhat
2374 * uneducated guess.
2377 //if (new_session_dialog) {
2380 /* make it break out of Dialog::run() and
2381 start again.
2384 //new_session_dialog->response (1);
2389 void
2390 ARDOUR_UI::end_loading_messages ()
2392 // hide_splash ();
2395 void
2396 ARDOUR_UI::loading_message (const std::string& /*msg*/)
2398 // show_splash ();
2399 // splash->message (msg);
2400 flush_pending ();
2403 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
2405 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
2407 string session_name;
2408 string session_path;
2409 string template_name;
2410 int ret = -1;
2411 bool likely_new = false;
2413 if (!load_template.empty()) {
2414 should_be_new = true;
2415 template_name = load_template;
2418 while (ret != 0) {
2420 if (!should_be_new && !ARDOUR_COMMAND_LINE::session_name.empty()) {
2422 /* if they named a specific statefile, use it, otherwise they are
2423 just giving a session folder, and we want to use it as is
2424 to find the session.
2427 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
2429 if (suffix != string::npos) {
2430 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
2431 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
2432 session_name = Glib::path_get_basename (session_name);
2433 } else {
2434 session_path = ARDOUR_COMMAND_LINE::session_name;
2435 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
2438 } else {
2440 bool const apply = run_startup (should_be_new, load_template);
2442 if (!apply) {
2443 if (quit_on_cancel) {
2444 exit (1);
2445 } else {
2446 return ret;
2450 /* if we run the startup dialog again, offer more than just "new session" */
2452 should_be_new = false;
2454 session_name = _startup->session_name (likely_new);
2456 /* this shouldn't happen, but we catch it just in case it does */
2458 if (session_name.empty()) {
2459 continue;
2462 if (_startup->use_session_template()) {
2463 template_name = _startup->session_template_name();
2464 _session_is_new = true;
2467 if (session_name[0] == G_DIR_SEPARATOR ||
2468 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
2469 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)) {
2471 /* absolute path or cwd-relative path specified for session name: infer session folder
2472 from what was given.
2475 session_path = Glib::path_get_dirname (session_name);
2476 session_name = Glib::path_get_basename (session_name);
2478 } else {
2480 session_path = _startup->session_folder();
2482 if (session_name.find ('/') != string::npos) {
2483 MessageDialog msg (*_startup,
2484 _("To ensure compatibility with various systems\n"
2485 "session names may not contain a '/' character"));
2486 msg.run ();
2487 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2488 continue;
2491 if (session_name.find ('\\') != string::npos) {
2492 MessageDialog msg (*_startup,
2493 _("To ensure compatibility with various systems\n"
2494 "session names may not contain a '\\' character"));
2495 msg.run ();
2496 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2497 continue;
2502 if (create_engine ()) {
2503 break;
2506 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
2508 if (likely_new) {
2510 std::string existing = Glib::build_filename (session_path, session_name);
2512 if (!ask_about_loading_existing_session (existing)) {
2513 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2514 continue;
2518 _session_is_new = false;
2520 } else {
2522 if (!likely_new) {
2523 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
2524 msg.run ();
2525 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2526 continue;
2529 if (session_name.find ('/') != std::string::npos) {
2530 MessageDialog msg (*_startup,
2531 _("To ensure compatibility with various systems\n"
2532 "session names may not contain a '/' character"));
2533 msg.run ();
2534 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2535 continue;
2538 if (session_name.find ('\\') != std::string::npos) {
2539 MessageDialog msg (*_startup,
2540 _("To ensure compatibility with various systems\n"
2541 "session names may not contain a '\\' character"));
2542 msg.run ();
2543 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2544 continue;
2547 _session_is_new = true;
2550 if (likely_new && template_name.empty()) {
2552 ret = build_session_from_nsd (session_path, session_name);
2554 } else {
2556 ret = load_session (session_path, session_name, template_name);
2558 if (ret == -2) {
2559 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
2560 exit (1);
2563 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
2564 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
2565 exit (1);
2570 return ret;
2573 void
2574 ARDOUR_UI::close_session()
2576 if (!check_audioengine()) {
2577 return;
2580 if (unload_session (true)) {
2581 return;
2584 ARDOUR_COMMAND_LINE::session_name = "";
2586 if (get_session_parameters (true, false)) {
2587 exit (1);
2590 goto_editor_window ();
2593 /** @param snap_name Snapshot name (without .ardour suffix).
2594 * @return -2 if the load failed because we are not connected to the AudioEngine.
2597 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
2599 Session *new_session;
2600 int unload_status;
2601 int retval = -1;
2603 session_loaded = false;
2605 if (!check_audioengine()) {
2606 return -2;
2609 unload_status = unload_session ();
2611 if (unload_status < 0) {
2612 goto out;
2613 } else if (unload_status > 0) {
2614 retval = 0;
2615 goto out;
2618 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
2620 try {
2621 new_session = new Session (*engine, path, snap_name, 0, mix_template);
2624 /* this one is special */
2626 catch (AudioEngine::PortRegistrationFailure& err) {
2628 MessageDialog msg (err.what(),
2629 true,
2630 Gtk::MESSAGE_INFO,
2631 Gtk::BUTTONS_CLOSE);
2633 msg.set_title (_("Port Registration Error"));
2634 msg.set_secondary_text (_("Click the Close button to try again."));
2635 msg.set_position (Gtk::WIN_POS_CENTER);
2636 pop_back_splash ();
2637 msg.present ();
2639 int response = msg.run ();
2641 msg.hide ();
2643 switch (response) {
2644 case RESPONSE_CANCEL:
2645 exit (1);
2646 default:
2647 break;
2649 goto out;
2652 catch (...) {
2654 MessageDialog msg (string_compose(
2655 _("Session \"%1 (snapshot %2)\" did not load successfully"),
2656 path, snap_name),
2657 true,
2658 Gtk::MESSAGE_INFO,
2659 BUTTONS_OK);
2661 msg.set_title (_("Loading Error"));
2662 msg.set_secondary_text (_("Click the Refresh button to try again."));
2663 msg.add_button (Stock::REFRESH, 1);
2664 msg.set_position (Gtk::WIN_POS_CENTER);
2665 pop_back_splash ();
2666 msg.present ();
2668 int response = msg.run ();
2670 switch (response) {
2671 case 1:
2672 break;
2673 default:
2674 exit (1);
2677 msg.hide ();
2679 goto out;
2683 list<string> const u = new_session->unknown_processors ();
2684 if (!u.empty()) {
2685 MissingPluginDialog d (_session, u);
2686 d.run ();
2690 /* Now the session been created, add the transport controls */
2691 new_session->add_controllable(roll_controllable);
2692 new_session->add_controllable(stop_controllable);
2693 new_session->add_controllable(goto_start_controllable);
2694 new_session->add_controllable(goto_end_controllable);
2695 new_session->add_controllable(auto_loop_controllable);
2696 new_session->add_controllable(play_selection_controllable);
2697 new_session->add_controllable(rec_controllable);
2699 set_session (new_session);
2701 session_loaded = true;
2703 goto_editor_window ();
2705 if (_session) {
2706 _session->set_clean ();
2709 flush_pending ();
2710 retval = 0;
2712 out:
2713 return retval;
2717 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
2719 Session *new_session;
2720 int x;
2722 if (!check_audioengine()) {
2723 return -1;
2726 session_loaded = false;
2728 x = unload_session ();
2730 if (x < 0) {
2731 return -1;
2732 } else if (x > 0) {
2733 return 0;
2736 _session_is_new = true;
2738 try {
2739 new_session = new Session (*engine, path, snap_name, &bus_profile);
2742 catch (...) {
2744 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
2745 pop_back_splash ();
2746 msg.run ();
2747 return -1;
2750 /* Give the new session the default GUI state, if such things exist */
2752 XMLNode* n;
2753 n = Config->instant_xml (X_("Editor"));
2754 if (n) {
2755 new_session->add_instant_xml (*n, false);
2757 n = Config->instant_xml (X_("Mixer"));
2758 if (n) {
2759 new_session->add_instant_xml (*n, false);
2762 /* Put the playhead at 0 and scroll fully left */
2763 n = new_session->instant_xml (X_("Editor"));
2764 if (n) {
2765 n->add_property (X_("playhead"), X_("0"));
2766 n->add_property (X_("left-frame"), X_("0"));
2769 set_session (new_session);
2771 session_loaded = true;
2773 new_session->save_state(new_session->name());
2775 return 0;
2778 void
2779 ARDOUR_UI::launch_chat ()
2781 #ifdef __APPLE__
2782 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
2783 #else
2784 open_uri("http://webchat.freenode.net/?channels=ardour");
2785 #endif
2788 void
2789 ARDOUR_UI::show_about ()
2791 if (about == 0) {
2792 about = new About;
2793 about->signal_response().connect(sigc::mem_fun (*this, &ARDOUR_UI::about_signal_response) );
2796 about->set_transient_for(*editor);
2797 about->show_all ();
2800 void
2801 ARDOUR_UI::launch_manual ()
2803 PBD::open_uri("http://ardour.org/flossmanual");
2806 void
2807 ARDOUR_UI::launch_reference ()
2809 PBD::open_uri("http://ardour.org/refmanual");
2812 void
2813 ARDOUR_UI::hide_about ()
2815 if (about) {
2816 about->get_window()->set_cursor ();
2817 about->hide ();
2821 void
2822 ARDOUR_UI::about_signal_response (int /*response*/)
2824 hide_about();
2827 void
2828 ARDOUR_UI::show_splash ()
2830 if (splash == 0) {
2831 try {
2832 splash = new Splash;
2833 } catch (...) {
2834 return;
2838 splash->show ();
2839 splash->present ();
2840 splash->queue_draw ();
2841 splash->get_window()->process_updates (true);
2842 flush_pending ();
2845 void
2846 ARDOUR_UI::hide_splash ()
2848 if (splash) {
2849 splash->hide();
2853 void
2854 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title,
2855 const string& plural_msg, const string& singular_msg)
2857 size_t removed;
2859 removed = rep.paths.size();
2861 if (removed == 0) {
2862 MessageDialog msgd (*editor,
2863 _("No files were ready for clean-up"),
2864 true,
2865 Gtk::MESSAGE_INFO,
2866 (Gtk::ButtonsType)(Gtk::BUTTONS_OK) );
2867 msgd.set_title (_("Clean-up"));
2868 msgd.set_secondary_text (_("If this seems suprising, \n\
2869 check for any existing snapshots.\n\
2870 These may still include regions that\n\
2871 require some unused files to continue to exist."));
2873 msgd.run ();
2874 return;
2877 ArdourDialog results (_("Clean-up"), true, false);
2879 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
2880 CleanupResultsModelColumns() {
2881 add (visible_name);
2882 add (fullpath);
2884 Gtk::TreeModelColumn<std::string> visible_name;
2885 Gtk::TreeModelColumn<std::string> fullpath;
2889 CleanupResultsModelColumns results_columns;
2890 Glib::RefPtr<Gtk::ListStore> results_model;
2891 Gtk::TreeView results_display;
2893 results_model = ListStore::create (results_columns);
2894 results_display.set_model (results_model);
2895 results_display.append_column (list_title, results_columns.visible_name);
2897 results_display.set_name ("CleanupResultsList");
2898 results_display.set_headers_visible (true);
2899 results_display.set_headers_clickable (false);
2900 results_display.set_reorderable (false);
2902 Gtk::ScrolledWindow list_scroller;
2903 Gtk::Label txt;
2904 Gtk::VBox dvbox;
2905 Gtk::HBox dhbox; // the hbox for the image and text
2906 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
2907 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
2909 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
2911 const string dead_directory = _session->session_directory().dead_path().to_string();
2913 /* subst:
2914 %1 - number of files removed
2915 %2 - location of "dead"
2916 %3 - size of files affected
2917 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
2920 const char* bprefix;
2921 double space_adjusted = 0;
2923 if (rep.space < 1000) {
2924 bprefix = X_("");
2925 space_adjusted = rep.space;
2926 } else if (rep.space < 1000000) {
2927 bprefix = X_("kilo");
2928 space_adjusted = truncf((float)rep.space / 1000.0);
2929 } else if (rep.space < 1000000 * 1000) {
2930 bprefix = X_("mega");
2931 space_adjusted = truncf((float)rep.space / (1000.0 * 1000.0));
2932 } else {
2933 bprefix = X_("giga");
2934 space_adjusted = truncf((float)rep.space / (1000.0 * 1000 * 1000.0));
2937 if (removed > 1) {
2938 txt.set_text (string_compose (plural_msg, removed, dead_directory, space_adjusted, bprefix));
2939 } else {
2940 txt.set_text (string_compose (singular_msg, removed, dead_directory, space_adjusted, bprefix));
2943 dhbox.pack_start (*dimage, true, false, 5);
2944 dhbox.pack_start (txt, true, false, 5);
2946 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
2947 TreeModel::Row row = *(results_model->append());
2948 row[results_columns.visible_name] = *i;
2949 row[results_columns.fullpath] = *i;
2952 list_scroller.add (results_display);
2953 list_scroller.set_size_request (-1, 150);
2954 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
2956 dvbox.pack_start (dhbox, true, false, 5);
2957 dvbox.pack_start (list_scroller, true, false, 5);
2958 ddhbox.pack_start (dvbox, true, false, 5);
2960 results.get_vbox()->pack_start (ddhbox, true, false, 5);
2961 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
2962 results.set_default_response (RESPONSE_CLOSE);
2963 results.set_position (Gtk::WIN_POS_MOUSE);
2965 results_display.show();
2966 list_scroller.show();
2967 txt.show();
2968 dvbox.show();
2969 dhbox.show();
2970 ddhbox.show();
2971 dimage->show();
2973 //results.get_vbox()->show();
2974 results.set_resizable (false);
2976 results.run ();
2980 void
2981 ARDOUR_UI::cleanup ()
2983 if (_session == 0) {
2984 /* shouldn't happen: menu item is insensitive */
2985 return;
2989 MessageDialog checker (_("Are you sure you want to clean-up?"),
2990 true,
2991 Gtk::MESSAGE_QUESTION,
2992 (Gtk::ButtonsType)(Gtk::BUTTONS_NONE));
2994 checker.set_title (_("Clean-up"));
2996 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
2997 ALL undo/redo information will be lost if you clean-up.\n\
2998 Clean-up will move all unused files to a \"dead\" location."));
3000 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3001 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
3002 checker.set_default_response (RESPONSE_CANCEL);
3004 checker.set_name (_("CleanupDialog"));
3005 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3006 checker.set_position (Gtk::WIN_POS_MOUSE);
3008 switch (checker.run()) {
3009 case RESPONSE_ACCEPT:
3010 break;
3011 default:
3012 return;
3015 ARDOUR::CleanupReport rep;
3017 editor->prepare_for_cleanup ();
3019 /* do not allow flush until a session is reloaded */
3021 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3022 if (act) {
3023 act->set_sensitive (false);
3026 if (_session->cleanup_sources (rep)) {
3027 editor->finish_cleanup ();
3028 return;
3031 editor->finish_cleanup ();
3033 checker.hide();
3034 display_cleanup_results (rep,
3035 _("Cleaned Files"),
3036 _("\
3037 The following %1 files were not in use and \n\
3038 have been moved to:\n\n\
3039 %2\n\n\
3040 After a restart of Ardour,\n\n\
3041 Session -> Clean-up -> Flush Wastebasket\n\n\
3042 will release an additional\n\
3043 %3 %4bytes of disk space.\n"),
3044 _("\
3045 The following file was not in use and \n\
3046 has been moved to:\n \
3047 %2\n\n\
3048 After a restart of Ardour,\n\n\
3049 Session -> Clean-up -> Flush Wastebasket\n\n\
3050 will release an additional\n\
3051 %3 %4bytes of disk space.\n"
3056 void
3057 ARDOUR_UI::flush_trash ()
3059 if (_session == 0) {
3060 /* shouldn't happen: menu item is insensitive */
3061 return;
3064 ARDOUR::CleanupReport rep;
3066 if (_session->cleanup_trash_sources (rep)) {
3067 return;
3070 display_cleanup_results (rep,
3071 _("deleted file"),
3072 _("The following %1 files were deleted from\n\
3073 %2,\n\
3074 releasing %3 %4bytes of disk space"),
3075 _("The following file was deleted from\n\
3076 %2,\n\
3077 releasing %3 %4bytes of disk space"));
3080 void
3081 ARDOUR_UI::add_route (Gtk::Window* float_window)
3083 int count;
3085 if (!_session) {
3086 return;
3089 if (add_route_dialog == 0) {
3090 add_route_dialog = new AddRouteDialog (_session);
3091 if (float_window) {
3092 add_route_dialog->set_transient_for (*float_window);
3096 if (add_route_dialog->is_visible()) {
3097 /* we're already doing this */
3098 return;
3101 ResponseType r = (ResponseType) add_route_dialog->run ();
3103 add_route_dialog->hide();
3105 switch (r) {
3106 case RESPONSE_ACCEPT:
3107 break;
3108 default:
3109 return;
3110 break;
3113 if ((count = add_route_dialog->count()) <= 0) {
3114 return;
3117 string template_path = add_route_dialog->track_template();
3119 if (!template_path.empty()) {
3120 _session->new_route_from_template (count, template_path);
3121 return;
3124 uint32_t input_chan = add_route_dialog->channels ();
3125 uint32_t output_chan;
3126 string name_template = add_route_dialog->name_template ();
3127 bool track = add_route_dialog->track ();
3128 RouteGroup* route_group = add_route_dialog->route_group ();
3130 AutoConnectOption oac = Config->get_output_auto_connect();
3132 if (oac & AutoConnectMaster) {
3133 output_chan = (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan);
3134 } else {
3135 output_chan = input_chan;
3138 /* XXX do something with name template */
3140 if (add_route_dialog->type() == ARDOUR::DataType::MIDI) {
3141 if (track) {
3142 session_add_midi_track (route_group, count, name_template);
3143 } else {
3144 MessageDialog msg (*editor,
3145 _("Sorry, MIDI Busses are not supported at this time."));
3146 msg.run ();
3147 //session_add_midi_bus();
3149 } else {
3150 if (track) {
3151 session_add_audio_track (input_chan, output_chan, add_route_dialog->mode(), route_group, count, name_template);
3152 } else {
3153 session_add_audio_bus (input_chan, output_chan, route_group, count, name_template);
3158 XMLNode*
3159 ARDOUR_UI::mixer_settings () const
3161 XMLNode* node = 0;
3163 if (_session) {
3164 node = _session->instant_xml(X_("Mixer"));
3165 } else {
3166 node = Config->instant_xml(X_("Mixer"));
3169 if (!node) {
3170 node = new XMLNode (X_("Mixer"));
3173 return node;
3176 XMLNode*
3177 ARDOUR_UI::editor_settings () const
3179 XMLNode* node = 0;
3181 if (_session) {
3182 node = _session->instant_xml(X_("Editor"));
3183 } else {
3184 node = Config->instant_xml(X_("Editor"));
3187 if (!node) {
3188 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
3189 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
3193 if (!node) {
3194 node = new XMLNode (X_("Editor"));
3197 return node;
3200 XMLNode*
3201 ARDOUR_UI::keyboard_settings () const
3203 XMLNode* node = 0;
3205 node = Config->extra_xml(X_("Keyboard"));
3207 if (!node) {
3208 node = new XMLNode (X_("Keyboard"));
3211 return node;
3214 void
3215 ARDOUR_UI::create_xrun_marker (framepos_t where)
3217 editor->mouse_add_new_marker (where, false, true);
3220 void
3221 ARDOUR_UI::halt_on_xrun_message ()
3223 MessageDialog msg (*editor,
3224 _("Recording was stopped because your system could not keep up."));
3225 msg.run ();
3228 void
3229 ARDOUR_UI::xrun_handler (framepos_t where)
3231 if (!_session) {
3232 return;
3235 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
3237 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
3238 create_xrun_marker(where);
3241 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
3242 halt_on_xrun_message ();
3246 void
3247 ARDOUR_UI::disk_overrun_handler ()
3249 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
3251 if (!have_disk_speed_dialog_displayed) {
3252 have_disk_speed_dialog_displayed = true;
3253 MessageDialog* msg = new MessageDialog (*editor, string_compose (_("\
3254 The disk system on your computer\n\
3255 was not able to keep up with %1.\n\
3257 Specifically, it failed to write data to disk\n\
3258 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
3259 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3260 msg->show ();
3264 void
3265 ARDOUR_UI::disk_underrun_handler ()
3267 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
3269 if (!have_disk_speed_dialog_displayed) {
3270 have_disk_speed_dialog_displayed = true;
3271 MessageDialog* msg = new MessageDialog (
3272 *editor, string_compose (_("The disk system on your computer\n\
3273 was not able to keep up with %1.\n\
3275 Specifically, it failed to read data from disk\n\
3276 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
3277 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3278 msg->show ();
3282 void
3283 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
3285 have_disk_speed_dialog_displayed = false;
3286 delete msg;
3289 void
3290 ARDOUR_UI::session_dialog (std::string msg)
3292 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
3294 MessageDialog* d;
3296 if (editor) {
3297 d = new MessageDialog (*editor, msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3298 } else {
3299 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3302 d->show_all ();
3303 d->run ();
3304 delete d;
3308 ARDOUR_UI::pending_state_dialog ()
3310 HBox* hbox = new HBox();
3311 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3312 ArdourDialog dialog (_("Crash Recovery"), true);
3313 Label message (_("\
3314 This session appears to have been in\n\
3315 middle of recording when ardour or\n\
3316 the computer was shutdown.\n\
3318 Ardour can recover any captured audio for\n\
3319 you, or it can ignore it. Please decide\n\
3320 what you would like to do.\n"));
3321 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3322 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3323 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3324 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3325 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
3326 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
3327 dialog.set_default_response (RESPONSE_ACCEPT);
3328 dialog.set_position (WIN_POS_CENTER);
3329 message.show();
3330 image->show();
3331 hbox->show();
3333 switch (dialog.run ()) {
3334 case RESPONSE_ACCEPT:
3335 return 1;
3336 default:
3337 return 0;
3342 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
3344 HBox* hbox = new HBox();
3345 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3346 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
3347 Label message (string_compose (_("\
3348 This session was created with a sample rate of %1 Hz\n\
3350 The audioengine is currently running at %2 Hz\n"), desired, actual));
3352 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3353 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3354 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3355 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3356 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
3357 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
3358 dialog.set_default_response (RESPONSE_ACCEPT);
3359 dialog.set_position (WIN_POS_CENTER);
3360 message.show();
3361 image->show();
3362 hbox->show();
3364 switch (dialog.run ()) {
3365 case RESPONSE_ACCEPT:
3366 return 0;
3367 default:
3368 return 1;
3373 void
3374 ARDOUR_UI::disconnect_from_jack ()
3376 if (engine) {
3377 if( engine->disconnect_from_jack ()) {
3378 MessageDialog msg (*editor, _("Could not disconnect from JACK"));
3379 msg.run ();
3382 update_sample_rate (0);
3386 void
3387 ARDOUR_UI::reconnect_to_jack ()
3389 if (engine) {
3390 if (engine->reconnect_to_jack ()) {
3391 MessageDialog msg (*editor, _("Could not reconnect to JACK"));
3392 msg.run ();
3395 update_sample_rate (0);
3399 void
3400 ARDOUR_UI::use_config ()
3402 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
3403 if (node) {
3404 set_transport_controllable_state (*node);
3408 void
3409 ARDOUR_UI::update_transport_clocks (framepos_t pos)
3411 if (Config->get_primary_clock_delta_edit_cursor()) {
3412 primary_clock.set (pos, false, editor->get_preferred_edit_position(), 1);
3413 } else {
3414 primary_clock.set (pos, 0, true);
3417 if (Config->get_secondary_clock_delta_edit_cursor()) {
3418 secondary_clock.set (pos, false, editor->get_preferred_edit_position(), 2);
3419 } else {
3420 secondary_clock.set (pos);
3423 if (big_clock_window->get()) {
3424 big_clock.set (pos);
3429 void
3430 ARDOUR_UI::step_edit_status_change (bool yn)
3432 // XXX should really store pre-step edit status of things
3433 // we make insensitive
3435 if (yn) {
3436 rec_button.set_visual_state (3);
3437 rec_button.set_sensitive (false);
3438 } else {
3439 rec_button.set_visual_state (0);
3440 rec_button.set_sensitive (true);
3444 void
3445 ARDOUR_UI::record_state_changed ()
3447 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
3449 if (!_session || !big_clock_window->get()) {
3450 /* why bother - the clock isn't visible */
3451 return;
3454 Session::RecordState const r = _session->record_status ();
3455 bool const h = _session->have_rec_enabled_track ();
3457 if (r == Session::Recording && h) {
3458 big_clock.set_widget_name ("BigClockRecording");
3459 } else {
3460 big_clock.set_widget_name ("BigClockNonRecording");
3464 bool
3465 ARDOUR_UI::first_idle ()
3467 if (_session) {
3468 _session->allow_auto_play (true);
3471 if (editor) {
3472 editor->first_idle();
3475 Keyboard::set_can_save_keybindings (true);
3476 return false;
3479 void
3480 ARDOUR_UI::store_clock_modes ()
3482 XMLNode* node = new XMLNode(X_("ClockModes"));
3484 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
3485 node->add_property ((*x)->name().c_str(), enum_2_string ((*x)->mode()));
3488 _session->add_extra_xml (*node);
3489 _session->set_dirty ();
3494 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
3495 : Controllable (name), ui (u), type(tp)
3500 void
3501 ARDOUR_UI::TransportControllable::set_value (double val)
3503 if (val < 0.5) {
3504 /* do nothing: these are radio-style actions */
3505 return;
3508 const char *action = 0;
3510 switch (type) {
3511 case Roll:
3512 action = X_("Roll");
3513 break;
3514 case Stop:
3515 action = X_("Stop");
3516 break;
3517 case GotoStart:
3518 action = X_("Goto Start");
3519 break;
3520 case GotoEnd:
3521 action = X_("Goto End");
3522 break;
3523 case AutoLoop:
3524 action = X_("Loop");
3525 break;
3526 case PlaySelection:
3527 action = X_("Play Selection");
3528 break;
3529 case RecordEnable:
3530 action = X_("Record");
3531 break;
3532 default:
3533 break;
3536 if (action == 0) {
3537 return;
3540 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
3542 if (act) {
3543 act->activate ();
3547 double
3548 ARDOUR_UI::TransportControllable::get_value (void) const
3550 float val = 0.0;
3552 switch (type) {
3553 case Roll:
3554 break;
3555 case Stop:
3556 break;
3557 case GotoStart:
3558 break;
3559 case GotoEnd:
3560 break;
3561 case AutoLoop:
3562 break;
3563 case PlaySelection:
3564 break;
3565 case RecordEnable:
3566 break;
3567 default:
3568 break;
3571 return val;
3574 void
3575 ARDOUR_UI::TransportControllable::set_id (const string& str)
3577 _id = str;
3580 void
3581 ARDOUR_UI::setup_profile ()
3583 if (gdk_screen_width() < 1200) {
3584 Profile->set_small_screen ();
3588 if (getenv ("ARDOUR_SAE")) {
3589 Profile->set_sae ();
3590 Profile->set_single_package ();
3594 void
3595 ARDOUR_UI::toggle_translations ()
3597 using namespace Glib;
3599 RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("EnableTranslation"));
3600 if (act) {
3601 RefPtr<ToggleAction> ract = RefPtr<ToggleAction>::cast_dynamic (act);
3602 if (ract) {
3604 string i18n_killer = ARDOUR::translation_kill_path();
3606 bool already_enabled = !ARDOUR::translations_are_disabled ();
3608 if (ract->get_active ()) {
3609 /* we don't care about errors */
3610 int fd = ::open (i18n_killer.c_str(), O_RDONLY|O_CREAT, 0644);
3611 close (fd);
3612 } else {
3613 /* we don't care about errors */
3614 unlink (i18n_killer.c_str());
3617 if (already_enabled != ract->get_active()) {
3618 MessageDialog win (already_enabled ? _("Translations disabled") : _("Translations enabled"),
3619 false,
3620 Gtk::MESSAGE_WARNING,
3621 Gtk::BUTTONS_OK);
3622 win.set_secondary_text (string_compose (_("You must restart %1 for this to take effect."), PROGRAM_NAME));
3623 win.set_position (Gtk::WIN_POS_CENTER);
3624 win.present ();
3625 win.run ();
3631 /** Add a window proxy to our list, so that its state will be saved.
3632 * This call also causes the window to be created and opened if its
3633 * state was saved as `visible'.
3635 void
3636 ARDOUR_UI::add_window_proxy (WindowProxyBase* p)
3638 _window_proxies.push_back (p);
3639 p->maybe_show ();
3642 /** Remove a window proxy from our list. Must be called if a WindowProxy
3643 * is deleted, to prevent hanging pointers.
3645 void
3646 ARDOUR_UI::remove_window_proxy (WindowProxyBase* p)
3648 _window_proxies.remove (p);
3652 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
3654 MissingFileDialog dialog (s, str, type);
3656 dialog.show ();
3657 dialog.present ();
3659 int result = dialog.run ();
3660 dialog.hide ();
3662 switch (result) {
3663 case RESPONSE_OK:
3664 break;
3665 default:
3666 return 1; // quit entire session load
3669 result = dialog.get_action ();
3671 return result;
3675 ARDOUR_UI::ambiguous_file (std::string file, std::string path, std::vector<std::string> hits)
3677 AmbiguousFileDialog dialog (file, hits);
3679 dialog.show ();
3680 dialog.present ();
3682 dialog.run ();
3683 return dialog.get_which ();