Fix a couple of minor typos.
[ardour2.git] / gtk2_ardour / ardour_ui.cc
blobc4c90a261f52564e4dd7762690e071265d1a5b80
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_object.h"
95 #include "gui_thread.h"
96 #include "keyboard.h"
97 #include "location_ui.h"
98 #include "missing_file_dialog.h"
99 #include "missing_plugin_dialog.h"
100 #include "mixer_ui.h"
101 #include "opts.h"
102 #include "processor_box.h"
103 #include "prompter.h"
104 #include "public_editor.h"
105 #include "route_time_axis.h"
106 #include "session_metadata_dialog.h"
107 #include "shuttle_control.h"
108 #include "speaker_dialog.h"
109 #include "splash.h"
110 #include "startup.h"
111 #include "theme_manager.h"
112 #include "time_axis_view_item.h"
113 #include "utils.h"
114 #include "window_proxy.h"
116 #include "i18n.h"
118 using namespace ARDOUR;
119 using namespace PBD;
120 using namespace Gtkmm2ext;
121 using namespace Gtk;
123 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
124 UIConfiguration *ARDOUR_UI::ui_config = 0;
126 sigc::signal<void,bool> ARDOUR_UI::Blink;
127 sigc::signal<void> ARDOUR_UI::RapidScreenUpdate;
128 sigc::signal<void> ARDOUR_UI::SuperRapidScreenUpdate;
129 sigc::signal<void, framepos_t, bool, framepos_t> ARDOUR_UI::Clock;
131 bool could_be_a_valid_path (const string& path);
133 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[])
135 : Gtkmm2ext::UI (PROGRAM_NAME, argcp, argvp)
137 , gui_object_state (new GUIObjectState)
138 , primary_clock (new AudioClock (X_("primary"), false, X_("TransportClockDisplay"), true, true, false, true))
139 , secondary_clock (new AudioClock (X_("secondary"), false, X_("SecondaryClockDisplay"), true, true, false, true))
140 , preroll_clock (new AudioClock (X_("preroll"), false, X_("PreRollClock"), true, false, true))
141 , postroll_clock (new AudioClock (X_("postroll"), false, X_("PostRollClock"), true, false, true))
143 /* preroll stuff */
145 , preroll_button (_("pre\nroll"))
146 , postroll_button (_("post\nroll"))
148 /* big clock */
150 , big_clock (new AudioClock (X_("bigclock"), false, "BigClockNonRecording", true, true, false, false))
152 /* transport */
154 , roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll))
155 , stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop))
156 , goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart))
157 , goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd))
158 , auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop))
159 , play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection))
160 , rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable))
162 , roll_button (roll_controllable)
163 , stop_button (stop_controllable)
164 , goto_start_button (goto_start_controllable)
165 , goto_end_button (goto_end_controllable)
166 , auto_loop_button (auto_loop_controllable)
167 , play_selection_button (play_selection_controllable)
168 , rec_button (rec_controllable)
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);
298 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
299 if (node) {
300 keyboard->set_state (*node, Stateful::loading_state_version);
303 /* we don't like certain modifiers */
304 Bindings::set_ignored_state (GDK_LOCK_MASK|GDK_MOD2_MASK|GDK_MOD3_MASK);
306 reset_dpi();
308 TimeAxisViewItem::set_constant_heights ();
310 /* The following must happen after ARDOUR::init() so that Config is set up */
312 location_ui = new ActionWindowProxy<LocationUIWindow> (X_("locations"), Config->extra_xml (X_("UI")), X_("ToggleLocations"));
313 big_clock_window = new ActionWindowProxy<Gtk::Window> (X_("bigclock"), Config->extra_xml (X_("UI")), X_("ToggleBigClock"));
314 speaker_config_window = new ActionWindowProxy<SpeakerDialog> (X_("speakerconf"), Config->extra_xml (X_("UI")), X_("toggle-speaker-config"));
316 for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) {
317 _global_port_matrix[*i] = new ActionWindowProxy<GlobalPortMatrixWindow> (
318 string_compose ("GlobalPortMatrix-%1", (*i).to_string()),
319 Config->extra_xml (X_("UI")),
320 string_compose ("toggle-%1-connection-manager", (*i).to_string())
324 setup_clock ();
326 SpeakerDialog* s = new SpeakerDialog ();
327 s->signal_unmap().connect (sigc::bind (sigc::ptr_fun (&ActionManager::uncheck_toggleaction), X_("<Actions>/Common/toggle-speaker-config")));
328 speaker_config_window->set (s);
330 starting.connect (sigc::mem_fun(*this, &ARDOUR_UI::startup));
331 stopping.connect (sigc::mem_fun(*this, &ARDOUR_UI::shutdown));
334 /** @return true if a session was chosen and `apply' clicked, otherwise false if `cancel' was clicked */
335 bool
336 ARDOUR_UI::run_startup (bool should_be_new, string load_template)
338 delete _startup;
339 _startup = new ArdourStartup ();
341 XMLNode* audio_setup = Config->extra_xml ("AudioSetup");
343 if (audio_setup && _startup->engine_control()) {
344 _startup->engine_control()->set_state (*audio_setup);
347 _startup->set_new_only (should_be_new);
348 if (!load_template.empty()) {
349 _startup->set_load_template( load_template );
351 _startup->present ();
353 main().run();
355 _startup->hide ();
357 switch (_startup->response()) {
358 case RESPONSE_OK:
359 return true;
360 default:
361 return false;
366 ARDOUR_UI::create_engine ()
368 // this gets called every time by new_session()
370 if (engine) {
371 return 0;
374 loading_message (_("Starting audio engine"));
376 try {
377 engine = new ARDOUR::AudioEngine (ARDOUR_COMMAND_LINE::jack_client_name, ARDOUR_COMMAND_LINE::jack_session_uuid);
379 } catch (...) {
381 return -1;
384 engine->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
385 engine->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
386 engine->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
388 engine->Halted.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
390 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
392 post_engine ();
394 return 0;
397 void
398 ARDOUR_UI::post_engine ()
400 /* Things to be done once we create the AudioEngine
403 ARDOUR::init_post_engine ();
405 ActionManager::init ();
406 _tooltips.enable();
408 if (setup_windows ()) {
409 throw failed_constructor ();
412 check_memory_locking();
414 /* this is the first point at which all the keybindings are available */
416 if (ARDOUR_COMMAND_LINE::show_key_actions) {
417 vector<string> names;
418 vector<string> paths;
419 vector<string> tooltips;
420 vector<string> keys;
421 vector<AccelKey> bindings;
423 ActionManager::get_all_actions (names, paths, tooltips, keys, bindings);
425 vector<string>::iterator n;
426 vector<string>::iterator k;
427 for (n = names.begin(), k = keys.begin(); n != names.end(); ++n, ++k) {
428 cerr << "Action: " << (*n) << " bound to " << (*k) << endl;
431 exit (0);
434 blink_timeout_tag = -1;
436 /* this being a GUI and all, we want peakfiles */
438 AudioFileSource::set_build_peakfiles (true);
439 AudioFileSource::set_build_missing_peakfiles (true);
441 /* set default clock modes */
443 if (Profile->get_sae()) {
444 primary_clock->set_mode (AudioClock::BBT);
445 secondary_clock->set_mode (AudioClock::MinSec);
446 } else {
447 primary_clock->set_mode (AudioClock::Timecode);
448 secondary_clock->set_mode (AudioClock::BBT);
451 /* start the time-of-day-clock */
453 #ifndef GTKOSX
454 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
455 update_wall_clock ();
456 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 60000);
457 #endif
459 update_disk_space ();
460 update_cpu_load ();
461 update_sample_rate (engine->frame_rate());
463 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
464 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
465 Config->map_parameters (pc);
467 /* now start and maybe save state */
469 if (do_engine_start () == 0) {
470 if (_session && _session_is_new) {
471 /* we need to retain initial visual
472 settings for a new session
474 _session->save_state ("");
479 ARDOUR_UI::~ARDOUR_UI ()
481 delete keyboard;
482 delete editor;
483 delete mixer;
484 delete add_route_dialog;
487 void
488 ARDOUR_UI::pop_back_splash ()
490 if (Splash::instance()) {
491 // Splash::instance()->pop_back();
492 Splash::instance()->hide ();
496 gint
497 ARDOUR_UI::configure_timeout ()
499 if (last_configure_time == 0) {
500 /* no configure events yet */
501 return true;
504 /* force a gap of 0.5 seconds since the last configure event
507 if (get_microseconds() - last_configure_time < 500000) {
508 return true;
509 } else {
510 have_configure_timeout = false;
511 cerr << "config event-driven save\n";
512 save_ardour_state ();
513 return false;
517 gboolean
518 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
520 if (have_configure_timeout) {
521 last_configure_time = get_microseconds();
522 } else {
523 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
524 have_configure_timeout = true;
527 return FALSE;
530 void
531 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
533 const XMLProperty* prop;
535 if ((prop = node.property ("roll")) != 0) {
536 roll_controllable->set_id (prop->value());
538 if ((prop = node.property ("stop")) != 0) {
539 stop_controllable->set_id (prop->value());
541 if ((prop = node.property ("goto-start")) != 0) {
542 goto_start_controllable->set_id (prop->value());
544 if ((prop = node.property ("goto-end")) != 0) {
545 goto_end_controllable->set_id (prop->value());
547 if ((prop = node.property ("auto-loop")) != 0) {
548 auto_loop_controllable->set_id (prop->value());
550 if ((prop = node.property ("play-selection")) != 0) {
551 play_selection_controllable->set_id (prop->value());
553 if ((prop = node.property ("rec")) != 0) {
554 rec_controllable->set_id (prop->value());
556 if ((prop = node.property ("shuttle")) != 0) {
557 shuttle_box->controllable()->set_id (prop->value());
562 XMLNode&
563 ARDOUR_UI::get_transport_controllable_state ()
565 XMLNode* node = new XMLNode(X_("TransportControllables"));
566 char buf[64];
568 roll_controllable->id().print (buf, sizeof (buf));
569 node->add_property (X_("roll"), buf);
570 stop_controllable->id().print (buf, sizeof (buf));
571 node->add_property (X_("stop"), buf);
572 goto_start_controllable->id().print (buf, sizeof (buf));
573 node->add_property (X_("goto_start"), buf);
574 goto_end_controllable->id().print (buf, sizeof (buf));
575 node->add_property (X_("goto_end"), buf);
576 auto_loop_controllable->id().print (buf, sizeof (buf));
577 node->add_property (X_("auto_loop"), buf);
578 play_selection_controllable->id().print (buf, sizeof (buf));
579 node->add_property (X_("play_selection"), buf);
580 rec_controllable->id().print (buf, sizeof (buf));
581 node->add_property (X_("rec"), buf);
582 shuttle_box->controllable()->id().print (buf, sizeof (buf));
583 node->add_property (X_("shuttle"), buf);
585 return *node;
589 gint
590 ARDOUR_UI::autosave_session ()
592 if (g_main_depth() > 1) {
593 /* inside a recursive main loop,
594 give up because we may not be able to
595 take a lock.
597 return 1;
600 if (!Config->get_periodic_safety_backups()) {
601 return 1;
604 if (_session) {
605 _session->maybe_write_autosave();
608 return 1;
611 void
612 ARDOUR_UI::update_autosave ()
614 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_autosave)
616 if (_session && _session->dirty()) {
617 if (_autosave_connection.connected()) {
618 _autosave_connection.disconnect();
621 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
622 Config->get_periodic_safety_backup_interval() * 1000);
624 } else {
625 if (_autosave_connection.connected()) {
626 _autosave_connection.disconnect();
631 void
632 ARDOUR_UI::backend_audio_error (bool we_set_params, Gtk::Window* toplevel)
634 string title;
635 if (we_set_params) {
636 title = string_compose (_("%1 could not start JACK"), PROGRAM_NAME);
637 } else {
638 title = string_compose (_("%1 could not connect to JACK."), PROGRAM_NAME);
641 MessageDialog win (title,
642 false,
643 Gtk::MESSAGE_INFO,
644 Gtk::BUTTONS_NONE);
646 if (we_set_params) {
647 win.set_secondary_text(_("There are several possible reasons:\n\
649 1) You requested audio parameters that are not supported..\n\
650 2) JACK is running as another user.\n\
652 Please consider the possibilities, and perhaps try different parameters."));
653 } else {
654 win.set_secondary_text(_("There are several possible reasons:\n\
656 1) JACK is not running.\n\
657 2) JACK is running as another user, perhaps root.\n\
658 3) There is already another client called \"ardour\".\n\
660 Please consider the possibilities, and perhaps (re)start JACK."));
663 if (toplevel) {
664 win.set_transient_for (*toplevel);
667 if (we_set_params) {
668 win.add_button (Stock::OK, RESPONSE_CLOSE);
669 } else {
670 win.add_button (Stock::QUIT, RESPONSE_CLOSE);
673 win.set_default_response (RESPONSE_CLOSE);
675 win.show_all ();
676 win.set_position (Gtk::WIN_POS_CENTER);
677 pop_back_splash ();
679 /* we just don't care about the result, but we want to block */
681 win.run ();
684 void
685 ARDOUR_UI::startup ()
687 Application* app = Application::instance ();
689 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
690 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::idle_load));
692 #ifdef PHONE_HOME
693 call_the_mothership (VERSIONSTRING);
694 #endif
696 app->ready ();
698 if (get_session_parameters (true, ARDOUR_COMMAND_LINE::new_session, ARDOUR_COMMAND_LINE::load_template)) {
699 exit (1);
702 use_config ();
704 goto_editor_window ();
706 /* Add the window proxies here; their addition may cause windows to be opened, and we want them
707 to be opened on top of the editor window that goto_editor_window() just opened.
709 add_window_proxy (location_ui);
710 add_window_proxy (big_clock_window);
711 for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) {
712 add_window_proxy (_global_port_matrix[*i]);
715 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
718 void
719 ARDOUR_UI::no_memory_warning ()
721 XMLNode node (X_("no-memory-warning"));
722 Config->add_instant_xml (node);
725 void
726 ARDOUR_UI::check_memory_locking ()
728 #ifdef __APPLE__
729 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
730 return;
731 #else // !__APPLE__
733 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
735 if (engine->is_realtime() && memory_warning_node == 0) {
737 struct rlimit limits;
738 int64_t ram;
739 long pages, page_size;
741 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0) {
742 ram = 0;
743 } else {
744 ram = (int64_t) pages * (int64_t) page_size;
747 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
748 return;
751 if (limits.rlim_cur != RLIM_INFINITY) {
753 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
755 MessageDialog msg (
756 string_compose (
757 _("WARNING: Your system has a limit for maximum amount of locked memory. "
758 "This might cause %1 to run out of memory before your system "
759 "runs out of memory. \n\n"
760 "You can view the memory limit with 'ulimit -l', "
761 "and it is normally controlled by /etc/security/limits.conf"),
762 PROGRAM_NAME).c_str());
764 VBox* vbox = msg.get_vbox();
765 HBox hbox;
766 CheckButton cb (_("Do not show this window again"));
768 cb.signal_toggled().connect (sigc::mem_fun (*this, &ARDOUR_UI::no_memory_warning));
770 hbox.pack_start (cb, true, false);
771 vbox->pack_start (hbox);
772 cb.show();
773 vbox->show();
774 hbox.show ();
776 pop_back_splash ();
778 editor->ensure_float (msg);
779 msg.run ();
783 #endif // !__APPLE__
787 void
788 ARDOUR_UI::queue_finish ()
790 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
793 bool
794 ARDOUR_UI::idle_finish ()
796 finish ();
797 return false; /* do not call again */
800 void
801 ARDOUR_UI::finish()
803 if (_session) {
804 int tries = 0;
806 if (_session->transport_rolling() && (++tries < 8)) {
807 _session->request_stop (false, true);
808 usleep (10000);
811 if (_session->dirty()) {
812 vector<string> actions;
813 actions.push_back (_("Don't quit"));
814 actions.push_back (_("Just quit"));
815 actions.push_back (_("Save and quit"));
816 switch (ask_about_saving_session(actions)) {
817 case -1:
818 return;
819 break;
820 case 1:
821 /* use the default name */
822 if (save_state_canfail ("")) {
823 /* failed - don't quit */
824 MessageDialog msg (*editor,
825 _("\
826 Ardour was unable to save your session.\n\n\
827 If you still wish to quit, please use the\n\n\
828 \"Just quit\" option."));
829 pop_back_splash();
830 msg.run ();
831 return;
833 break;
834 case 0:
835 break;
839 second_connection.disconnect ();
840 point_one_second_connection.disconnect ();
841 point_oh_five_second_connection.disconnect ();
842 point_zero_one_second_connection.disconnect();
845 /* Save state before deleting the session, as that causes some
846 windows to be destroyed before their visible state can be
847 saved.
849 save_ardour_state ();
851 if (_session) {
852 // _session->set_deletion_in_progress ();
853 _session->set_clean ();
854 _session->remove_pending_capture_state ();
855 delete _session;
856 _session = 0;
859 ArdourDialog::close_all_dialogs ();
860 engine->stop (true);
861 quit ();
865 ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
867 ArdourDialog window (_("Unsaved Session"));
868 Gtk::HBox dhbox; // the hbox for the image and text
869 Gtk::Label prompt_label;
870 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
872 string msg;
874 assert (actions.size() >= 3);
876 window.add_button (actions[0], RESPONSE_REJECT);
877 window.add_button (actions[1], RESPONSE_APPLY);
878 window.add_button (actions[2], RESPONSE_ACCEPT);
880 window.set_default_response (RESPONSE_ACCEPT);
882 Gtk::Button noquit_button (msg);
883 noquit_button.set_name ("EditorGTKButton");
885 string prompt;
887 if (_session->snap_name() == _session->name()) {
888 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?"),
889 _session->snap_name());
890 } else {
891 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?"),
892 _session->snap_name());
895 prompt_label.set_text (prompt);
896 prompt_label.set_name (X_("PrompterLabel"));
897 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
899 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
900 dhbox.set_homogeneous (false);
901 dhbox.pack_start (*dimage, false, false, 5);
902 dhbox.pack_start (prompt_label, true, false, 5);
903 window.get_vbox()->pack_start (dhbox);
905 window.set_name (_("Prompter"));
906 window.set_position (Gtk::WIN_POS_MOUSE);
907 window.set_modal (true);
908 window.set_resizable (false);
910 dhbox.show();
911 prompt_label.show();
912 dimage->show();
913 window.show();
914 window.set_keep_above (true);
915 window.present ();
917 ResponseType r = (ResponseType) window.run();
919 window.hide ();
921 switch (r) {
922 case RESPONSE_ACCEPT: // save and get out of here
923 return 1;
924 case RESPONSE_APPLY: // get out of here
925 return 0;
926 default:
927 break;
930 return -1;
933 gint
934 ARDOUR_UI::every_second ()
936 update_cpu_load ();
937 update_buffer_load ();
938 update_disk_space ();
939 return TRUE;
942 gint
943 ARDOUR_UI::every_point_one_seconds ()
945 shuttle_box->update_speed_display ();
946 RapidScreenUpdate(); /* EMIT_SIGNAL */
947 return TRUE;
950 gint
951 ARDOUR_UI::every_point_zero_one_seconds ()
953 // august 2007: actual update frequency: 40Hz, not 100Hz
955 SuperRapidScreenUpdate(); /* EMIT_SIGNAL */
956 return TRUE;
959 void
960 ARDOUR_UI::update_sample_rate (framecnt_t)
962 char buf[32];
964 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
966 if (!engine->connected()) {
968 snprintf (buf, sizeof (buf), _("disconnected"));
970 } else {
972 framecnt_t rate = engine->frame_rate();
974 if (fmod (rate, 1000.0) != 0.0) {
975 snprintf (buf, sizeof (buf), _("%.1f kHz / %4.1f ms"),
976 (float) rate/1000.0f,
977 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
978 } else {
979 snprintf (buf, sizeof (buf), _("%" PRId64 " kHz / %4.1f ms"),
980 rate/1000,
981 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
985 sample_rate_label.set_text (buf);
988 void
989 ARDOUR_UI::update_format ()
991 if (!_session) {
992 format_label.set_text ("");
993 return;
996 stringstream s;
998 switch (_session->config.get_native_file_header_format ()) {
999 case BWF:
1000 s << "BWF";
1001 break;
1002 case WAVE:
1003 s << "WAV";
1004 break;
1005 case WAVE64:
1006 s << "WAV64";
1007 break;
1008 case CAF:
1009 s << "CAF";
1010 break;
1011 case AIFF:
1012 s << "AIFF";
1013 break;
1014 case iXML:
1015 s << "iXML";
1016 break;
1017 case RF64:
1018 s << "RF64";
1019 break;
1022 s << " ";
1024 switch (_session->config.get_native_file_data_format ()) {
1025 case FormatFloat:
1026 s << "32-float";
1027 break;
1028 case FormatInt24:
1029 s << "24-int";
1030 break;
1031 case FormatInt16:
1032 s << "16-int";
1033 break;
1036 format_label.set_text (s.str ());
1039 void
1040 ARDOUR_UI::update_cpu_load ()
1042 char buf[32];
1043 snprintf (buf, sizeof (buf), _("DSP: %5.1f%%"), engine->get_cpu_load());
1044 cpu_load_label.set_text (buf);
1047 void
1048 ARDOUR_UI::update_buffer_load ()
1050 char buf[64];
1052 if (_session) {
1053 snprintf (buf, sizeof (buf), _("Buffers p:%" PRIu32 "%% c:%" PRIu32 "%%"),
1054 _session->playback_load(), _session->capture_load());
1055 buffer_load_label.set_text (buf);
1056 } else {
1057 buffer_load_label.set_text ("");
1061 void
1062 ARDOUR_UI::count_recenabled_streams (Route& route)
1064 Track* track = dynamic_cast<Track*>(&route);
1065 if (track && track->record_enabled()) {
1066 rec_enabled_streams += track->n_inputs().n_total();
1070 void
1071 ARDOUR_UI::update_disk_space()
1073 if (_session == 0) {
1074 return;
1077 framecnt_t frames = _session->available_capture_duration();
1078 char buf[64];
1079 framecnt_t fr = _session->frame_rate();
1081 if (frames == max_framecnt) {
1082 strcpy (buf, _("Disk: 24hrs+"));
1083 } else {
1084 rec_enabled_streams = 0;
1085 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams);
1087 if (rec_enabled_streams) {
1088 frames /= rec_enabled_streams;
1091 int hrs;
1092 int mins;
1093 int secs;
1095 hrs = frames / (fr * 3600);
1096 frames -= hrs * fr * 3600;
1097 mins = frames / (fr * 60);
1098 frames -= mins * fr * 60;
1099 secs = frames / fr;
1101 snprintf (buf, sizeof(buf), _("Disk: %02dh:%02dm:%02ds"), hrs, mins, secs);
1104 disk_space_label.set_text (buf);
1106 // An attempt to make the disk space label flash red when space has run out.
1108 if (frames < fr * 60 * 5) {
1109 /* disk_space_box.style ("disk_space_label_empty"); */
1110 } else {
1111 /* disk_space_box.style ("disk_space_label"); */
1116 gint
1117 ARDOUR_UI::update_wall_clock ()
1119 time_t now;
1120 struct tm *tm_now;
1121 char buf[16];
1123 time (&now);
1124 tm_now = localtime (&now);
1126 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1127 wall_clock_label.set_text (buf);
1129 return TRUE;
1132 gint
1133 ARDOUR_UI::session_menu (GdkEventButton */*ev*/)
1135 session_popup_menu->popup (0, 0);
1136 return TRUE;
1139 void
1140 ARDOUR_UI::redisplay_recent_sessions ()
1142 std::vector<sys::path> session_directories;
1143 RecentSessionsSorter cmp;
1145 recent_session_display.set_model (Glib::RefPtr<TreeModel>(0));
1146 recent_session_model->clear ();
1148 ARDOUR::RecentSessions rs;
1149 ARDOUR::read_recent_sessions (rs);
1151 if (rs.empty()) {
1152 recent_session_display.set_model (recent_session_model);
1153 return;
1156 // sort them alphabetically
1157 sort (rs.begin(), rs.end(), cmp);
1159 for (ARDOUR::RecentSessions::iterator i = rs.begin(); i != rs.end(); ++i) {
1160 session_directories.push_back ((*i).second);
1163 for (vector<sys::path>::const_iterator i = session_directories.begin();
1164 i != session_directories.end(); ++i)
1166 std::vector<sys::path> state_file_paths;
1168 // now get available states for this session
1170 get_state_files_in_directory (*i, state_file_paths);
1172 vector<string*>* states;
1173 vector<const gchar*> item;
1174 string fullpath = (*i).to_string();
1176 /* remove any trailing / */
1178 if (fullpath[fullpath.length()-1] == '/') {
1179 fullpath = fullpath.substr (0, fullpath.length()-1);
1182 /* check whether session still exists */
1183 if (!Glib::file_test(fullpath.c_str(), Glib::FILE_TEST_EXISTS)) {
1184 /* session doesn't exist */
1185 cerr << "skipping non-existent session " << fullpath << endl;
1186 continue;
1189 /* now get available states for this session */
1191 if ((states = Session::possible_states (fullpath)) == 0) {
1192 /* no state file? */
1193 continue;
1196 std::vector<string> state_file_names(get_file_names_no_extension (state_file_paths));
1198 Gtk::TreeModel::Row row = *(recent_session_model->append());
1200 row[recent_session_columns.visible_name] = Glib::path_get_basename (fullpath);
1201 row[recent_session_columns.fullpath] = fullpath;
1203 if (state_file_names.size() > 1) {
1205 // add the children
1207 for (std::vector<std::string>::iterator i2 = state_file_names.begin();
1208 i2 != state_file_names.end(); ++i2)
1211 Gtk::TreeModel::Row child_row = *(recent_session_model->append (row.children()));
1213 child_row[recent_session_columns.visible_name] = *i2;
1214 child_row[recent_session_columns.fullpath] = fullpath;
1219 recent_session_display.set_model (recent_session_model);
1222 void
1223 ARDOUR_UI::build_session_selector ()
1225 session_selector_window = new ArdourDialog (_("Recent Sessions"));
1227 Gtk::ScrolledWindow *scroller = manage (new Gtk::ScrolledWindow);
1229 session_selector_window->add_button (Stock::CANCEL, RESPONSE_CANCEL);
1230 session_selector_window->add_button (Stock::OPEN, RESPONSE_ACCEPT);
1231 session_selector_window->set_default_response (RESPONSE_ACCEPT);
1232 recent_session_model = TreeStore::create (recent_session_columns);
1233 recent_session_display.set_model (recent_session_model);
1234 recent_session_display.append_column (_("Recent Sessions"), recent_session_columns.visible_name);
1235 recent_session_display.set_headers_visible (false);
1236 recent_session_display.get_selection()->set_mode (SELECTION_BROWSE);
1237 recent_session_display.signal_row_activated().connect (sigc::mem_fun (*this, &ARDOUR_UI::recent_session_row_activated));
1239 scroller->add (recent_session_display);
1240 scroller->set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
1242 session_selector_window->set_name ("SessionSelectorWindow");
1243 session_selector_window->set_size_request (200, 400);
1244 session_selector_window->get_vbox()->pack_start (*scroller);
1246 recent_session_display.show();
1247 scroller->show();
1248 //session_selector_window->get_vbox()->show();
1251 void
1252 ARDOUR_UI::recent_session_row_activated (const TreePath& /*path*/, TreeViewColumn* /*col*/)
1254 session_selector_window->response (RESPONSE_ACCEPT);
1257 void
1258 ARDOUR_UI::open_recent_session ()
1260 bool can_return = (_session != 0);
1262 if (session_selector_window == 0) {
1263 build_session_selector ();
1266 redisplay_recent_sessions ();
1268 while (true) {
1270 session_selector_window->set_position (WIN_POS_MOUSE);
1272 ResponseType r = (ResponseType) session_selector_window->run ();
1274 switch (r) {
1275 case RESPONSE_ACCEPT:
1276 break;
1277 default:
1278 if (can_return) {
1279 session_selector_window->hide();
1280 return;
1281 } else {
1282 exit (1);
1286 if (recent_session_display.get_selection()->count_selected_rows() == 0) {
1287 continue;
1290 session_selector_window->hide();
1292 Gtk::TreeModel::iterator i = recent_session_display.get_selection()->get_selected();
1294 if (i == recent_session_model->children().end()) {
1295 return;
1298 std::string path = (*i)[recent_session_columns.fullpath];
1299 std::string state = (*i)[recent_session_columns.visible_name];
1301 _session_is_new = false;
1303 if (load_session (path, state) == 0) {
1304 break;
1307 can_return = false;
1311 bool
1312 ARDOUR_UI::check_audioengine ()
1314 if (engine) {
1315 if (!engine->connected()) {
1316 MessageDialog msg (string_compose (
1317 _("%1 is not connected to JACK\n"
1318 "You cannot open or close sessions in this condition"),
1319 PROGRAM_NAME));
1320 pop_back_splash ();
1321 msg.run ();
1322 return false;
1324 return true;
1325 } else {
1326 return false;
1330 void
1331 ARDOUR_UI::open_session ()
1333 if (!check_audioengine()) {
1334 return;
1338 /* popup selector window */
1340 if (open_session_selector == 0) {
1342 /* ardour sessions are folders */
1344 open_session_selector = new Gtk::FileChooserDialog (_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1345 open_session_selector->add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1346 open_session_selector->add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1347 open_session_selector->set_default_response(Gtk::RESPONSE_ACCEPT);
1349 FileFilter session_filter;
1350 session_filter.add_pattern ("*.ardour");
1351 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1352 open_session_selector->add_filter (session_filter);
1353 open_session_selector->set_filter (session_filter);
1356 int response = open_session_selector->run();
1357 open_session_selector->hide ();
1359 switch (response) {
1360 case RESPONSE_ACCEPT:
1361 break;
1362 default:
1363 open_session_selector->hide();
1364 return;
1367 open_session_selector->hide();
1368 string session_path = open_session_selector->get_filename();
1369 string path, name;
1370 bool isnew;
1372 if (session_path.length() > 0) {
1373 if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1374 _session_is_new = isnew;
1375 load_session (path, name);
1381 void
1382 ARDOUR_UI::session_add_midi_route (bool disk, RouteGroup* route_group, uint32_t how_many, string const & name_template)
1384 list<boost::shared_ptr<MidiTrack> > tracks;
1386 if (_session == 0) {
1387 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1388 return;
1391 try {
1392 if (disk) {
1394 tracks = _session->new_midi_track (ARDOUR::Normal, route_group, how_many, name_template);
1396 if (tracks.size() != how_many) {
1397 if (how_many == 1) {
1398 error << _("could not create a new midi track") << endmsg;
1399 } else {
1400 error << string_compose (_("could not create %1 new midi tracks"), how_many) << endmsg;
1403 } /*else {
1404 if ((route = _session->new_midi_route ()) == 0) {
1405 error << _("could not create new midi bus") << endmsg;
1410 catch (...) {
1411 MessageDialog msg (*editor,
1412 string_compose (_("There are insufficient JACK ports available\n\
1413 to create a new track or bus.\n\
1414 You should save %1, exit and\n\
1415 restart JACK with more ports."), PROGRAM_NAME));
1416 msg.run ();
1421 void
1422 ARDOUR_UI::session_add_audio_route (
1423 bool track,
1424 int32_t input_channels,
1425 int32_t output_channels,
1426 ARDOUR::TrackMode mode,
1427 RouteGroup* route_group,
1428 uint32_t how_many,
1429 string const & name_template
1432 list<boost::shared_ptr<AudioTrack> > tracks;
1433 RouteList routes;
1435 if (_session == 0) {
1436 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1437 return;
1440 try {
1441 if (track) {
1442 tracks = _session->new_audio_track (input_channels, output_channels, mode, route_group, how_many, name_template);
1444 if (tracks.size() != how_many) {
1445 if (how_many == 1) {
1446 error << _("could not create a new audio track") << endmsg;
1447 } else {
1448 error << string_compose (_("could only create %1 of %2 new audio %3"),
1449 tracks.size(), how_many, (track ? _("tracks") : _("busses"))) << endmsg;
1453 } else {
1455 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template);
1457 if (routes.size() != how_many) {
1458 if (how_many == 1) {
1459 error << _("could not create a new audio bus") << endmsg;
1460 } else {
1461 error << string_compose (_("could not create %1 new audio busses"), how_many) << endmsg;
1467 catch (...) {
1468 MessageDialog msg (*editor,
1469 string_compose (_("There are insufficient JACK ports available\n\
1470 to create a new track or bus.\n\
1471 You should save %1, exit and\n\
1472 restart JACK with more ports."), PROGRAM_NAME));
1473 pop_back_splash ();
1474 msg.run ();
1478 void
1479 ARDOUR_UI::do_transport_locate (framepos_t new_position, bool with_roll)
1481 framecnt_t _preroll = 0;
1483 if (_session) {
1484 // XXX CONFIG_CHANGE FIX - requires AnyTime handling
1485 // _preroll = _session->convert_to_frames_at (new_position, Config->get_preroll());
1487 if (new_position > _preroll) {
1488 new_position -= _preroll;
1489 } else {
1490 new_position = 0;
1493 _session->request_locate (new_position, with_roll);
1497 void
1498 ARDOUR_UI::transport_goto_start ()
1500 if (_session) {
1501 _session->goto_start();
1503 /* force displayed area in editor to start no matter
1504 what "follow playhead" setting is.
1507 if (editor) {
1508 editor->center_screen (_session->current_start_frame ());
1513 void
1514 ARDOUR_UI::transport_goto_zero ()
1516 if (_session) {
1517 _session->request_locate (0);
1519 /* force displayed area in editor to start no matter
1520 what "follow playhead" setting is.
1523 if (editor) {
1524 editor->reset_x_origin (0);
1529 void
1530 ARDOUR_UI::transport_goto_wallclock ()
1532 if (_session && editor) {
1534 time_t now;
1535 struct tm tmnow;
1536 framepos_t frames;
1538 time (&now);
1539 localtime_r (&now, &tmnow);
1541 frames = tmnow.tm_hour * (60 * 60 * _session->frame_rate());
1542 frames += tmnow.tm_min * (60 * _session->frame_rate());
1543 frames += tmnow.tm_sec * _session->frame_rate();
1545 _session->request_locate (frames, _session->transport_rolling ());
1547 /* force displayed area in editor to start no matter
1548 what "follow playhead" setting is.
1551 if (editor) {
1552 editor->center_screen (frames);
1557 void
1558 ARDOUR_UI::transport_goto_end ()
1560 if (_session) {
1561 framepos_t const frame = _session->current_end_frame();
1562 _session->request_locate (frame);
1564 /* force displayed area in editor to start no matter
1565 what "follow playhead" setting is.
1568 if (editor) {
1569 editor->center_screen (frame);
1574 void
1575 ARDOUR_UI::transport_stop ()
1577 if (!_session) {
1578 return;
1581 if (_session->is_auditioning()) {
1582 _session->cancel_audition ();
1583 return;
1586 _session->request_stop (false, true);
1589 void
1590 ARDOUR_UI::transport_stop_and_forget_capture ()
1592 if (_session) {
1593 _session->request_stop (true, true);
1597 void
1598 ARDOUR_UI::remove_last_capture()
1600 if (editor) {
1601 editor->remove_last_capture();
1605 void
1606 ARDOUR_UI::transport_record (bool roll)
1609 if (_session) {
1610 switch (_session->record_status()) {
1611 case Session::Disabled:
1612 if (_session->ntracks() == 0) {
1613 MessageDialog msg (*editor, _("Please create 1 or more track\nbefore trying to record.\nCheck the Session menu."));
1614 msg.run ();
1615 return;
1617 _session->maybe_enable_record ();
1618 if (roll) {
1619 transport_roll ();
1621 break;
1622 case Session::Recording:
1623 if (roll) {
1624 _session->request_stop();
1625 } else {
1626 _session->disable_record (false, true);
1628 break;
1630 case Session::Enabled:
1631 _session->disable_record (false, true);
1634 //cerr << "ARDOUR_UI::transport_record () called roll = " << roll << " _session->record_status() = " << _session->record_status() << endl;
1637 void
1638 ARDOUR_UI::transport_roll ()
1640 if (!_session) {
1641 return;
1644 if (_session->is_auditioning()) {
1645 return;
1648 #if 0
1649 if (_session->config.get_external_sync()) {
1650 switch (_session->config.get_sync_source()) {
1651 case JACK:
1652 break;
1653 default:
1654 /* transport controlled by the master */
1655 return;
1658 #endif
1660 bool rolling = _session->transport_rolling();
1662 if (_session->get_play_loop()) {
1663 /* XXX it is not possible to just leave seamless loop and keep
1664 playing at present (nov 4th 2009)
1666 if (!Config->get_seamless_loop()) {
1667 _session->request_play_loop (false, true);
1669 } else if (_session->get_play_range () && !join_play_range_button.get_active()) {
1670 /* stop playing a range if we currently are */
1671 _session->request_play_range (0, true);
1674 if (join_play_range_button.get_active()) {
1675 _session->request_play_range (&editor->get_selection().time, true);
1678 if (!rolling) {
1679 _session->request_transport_speed (1.0f);
1683 void
1684 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
1687 if (!_session) {
1688 return;
1691 if (_session->is_auditioning()) {
1692 _session->cancel_audition ();
1693 return;
1696 if (_session->config.get_external_sync()) {
1697 switch (_session->config.get_sync_source()) {
1698 case JACK:
1699 break;
1700 default:
1701 /* transport controlled by the master */
1702 return;
1706 bool rolling = _session->transport_rolling();
1707 bool affect_transport = true;
1709 if (rolling && roll_out_of_bounded_mode) {
1710 /* drop out of loop/range playback but leave transport rolling */
1711 if (_session->get_play_loop()) {
1712 if (Config->get_seamless_loop()) {
1713 /* the disk buffers contain copies of the loop - we can't
1714 just keep playing, so stop the transport. the user
1715 can restart as they wish.
1717 affect_transport = true;
1718 } else {
1719 /* disk buffers are normal, so we can keep playing */
1720 affect_transport = false;
1722 _session->request_play_loop (false, true);
1723 } else if (_session->get_play_range ()) {
1724 affect_transport = false;
1725 _session->request_play_range (0, true);
1729 if (affect_transport) {
1730 if (rolling) {
1731 _session->request_stop (with_abort, true);
1732 } else {
1733 if (join_play_range_button.get_active()) {
1734 _session->request_play_range (&editor->get_selection().time, true);
1737 _session->request_transport_speed (1.0f);
1742 void
1743 ARDOUR_UI::toggle_session_auto_loop ()
1745 if (!_session) {
1746 return;
1749 if (_session->get_play_loop()) {
1751 if (_session->transport_rolling()) {
1753 Location * looploc = _session->locations()->auto_loop_location();
1755 if (looploc) {
1756 _session->request_locate (looploc->start(), true);
1757 _session->request_play_loop (false);
1760 } else {
1761 _session->request_play_loop (false);
1763 } else {
1765 Location * looploc = _session->locations()->auto_loop_location();
1767 if (looploc) {
1768 _session->request_play_loop (true);
1773 void
1774 ARDOUR_UI::transport_play_selection ()
1776 if (!_session) {
1777 return;
1780 editor->play_selection ();
1783 void
1784 ARDOUR_UI::transport_rewind (int option)
1786 float current_transport_speed;
1788 if (_session) {
1789 current_transport_speed = _session->transport_speed();
1791 if (current_transport_speed >= 0.0f) {
1792 switch (option) {
1793 case 0:
1794 _session->request_transport_speed (-1.0f);
1795 break;
1796 case 1:
1797 _session->request_transport_speed (-4.0f);
1798 break;
1799 case -1:
1800 _session->request_transport_speed (-0.5f);
1801 break;
1803 } else {
1804 /* speed up */
1805 _session->request_transport_speed (current_transport_speed * 1.5f);
1810 void
1811 ARDOUR_UI::transport_forward (int option)
1813 float current_transport_speed;
1815 if (_session) {
1816 current_transport_speed = _session->transport_speed();
1818 if (current_transport_speed <= 0.0f) {
1819 switch (option) {
1820 case 0:
1821 _session->request_transport_speed (1.0f);
1822 break;
1823 case 1:
1824 _session->request_transport_speed (4.0f);
1825 break;
1826 case -1:
1827 _session->request_transport_speed (0.5f);
1828 break;
1830 } else {
1831 /* speed up */
1832 _session->request_transport_speed (current_transport_speed * 1.5f);
1838 void
1839 ARDOUR_UI::toggle_record_enable (uint32_t rid)
1841 if (_session == 0) {
1842 return;
1845 boost::shared_ptr<Route> r;
1847 if ((r = _session->route_by_remote_id (rid)) != 0) {
1849 Track* t;
1851 if ((t = dynamic_cast<Track*>(r.get())) != 0) {
1852 t->set_record_enabled (!t->record_enabled(), this);
1855 if (_session == 0) {
1856 return;
1860 void
1861 ARDOUR_UI::map_transport_state ()
1863 if (!_session) {
1864 auto_loop_button.set_visual_state (0);
1865 play_selection_button.set_visual_state (0);
1866 roll_button.set_visual_state (0);
1867 stop_button.set_visual_state (1);
1868 return;
1871 shuttle_box->map_transport_state ();
1873 float sp = _session->transport_speed();
1875 if (sp != 0.0f) {
1877 /* we're rolling */
1879 if (_session->get_play_range()) {
1881 play_selection_button.set_visual_state (1);
1882 roll_button.set_visual_state (0);
1883 auto_loop_button.set_visual_state (0);
1885 } else if (_session->get_play_loop ()) {
1887 auto_loop_button.set_visual_state (1);
1888 play_selection_button.set_visual_state (0);
1889 roll_button.set_visual_state (0);
1891 } else {
1893 roll_button.set_visual_state (1);
1894 play_selection_button.set_visual_state (0);
1895 auto_loop_button.set_visual_state (0);
1898 if (join_play_range_button.get_active()) {
1899 /* light up both roll and play-selection if they are joined */
1900 roll_button.set_visual_state (1);
1901 play_selection_button.set_visual_state (1);
1904 stop_button.set_visual_state (0);
1906 } else {
1908 stop_button.set_visual_state (1);
1909 roll_button.set_visual_state (0);
1910 play_selection_button.set_visual_state (0);
1911 auto_loop_button.set_visual_state (0);
1912 update_disk_space ();
1916 void
1917 ARDOUR_UI::engine_stopped ()
1919 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
1920 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1921 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1924 void
1925 ARDOUR_UI::engine_running ()
1927 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
1928 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, true);
1929 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, false);
1931 Glib::RefPtr<Action> action;
1932 const char* action_name = 0;
1934 switch (engine->frames_per_cycle()) {
1935 case 32:
1936 action_name = X_("JACKLatency32");
1937 break;
1938 case 64:
1939 action_name = X_("JACKLatency64");
1940 break;
1941 case 128:
1942 action_name = X_("JACKLatency128");
1943 break;
1944 case 512:
1945 action_name = X_("JACKLatency512");
1946 break;
1947 case 1024:
1948 action_name = X_("JACKLatency1024");
1949 break;
1950 case 2048:
1951 action_name = X_("JACKLatency2048");
1952 break;
1953 case 4096:
1954 action_name = X_("JACKLatency4096");
1955 break;
1956 case 8192:
1957 action_name = X_("JACKLatency8192");
1958 break;
1959 default:
1960 /* XXX can we do anything useful ? */
1961 break;
1964 if (action_name) {
1966 action = ActionManager::get_action (X_("JACK"), action_name);
1968 if (action) {
1969 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (action);
1970 ract->set_active ();
1975 void
1976 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
1978 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
1979 /* we can't rely on the original string continuing to exist when we are called
1980 again in the GUI thread, so make a copy and note that we need to
1981 free it later.
1983 char *copy = strdup (reason);
1984 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
1985 return;
1988 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1989 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1991 update_sample_rate (0);
1993 string msgstr;
1995 /* if the reason is a non-empty string, it means that the backend was shutdown
1996 rather than just Ardour.
1999 if (strlen (reason)) {
2000 msgstr = string_compose (_("The audio backend (JACK) was shutdown because:\n\n%1"), reason);
2001 } else {
2002 msgstr = string_compose (_("\
2003 JACK has either been shutdown or it\n\
2004 disconnected %1 because %1\n\
2005 was not fast enough. Try to restart\n\
2006 JACK, reconnect and save the session."), PROGRAM_NAME);
2009 MessageDialog msg (*editor, msgstr);
2010 pop_back_splash ();
2011 msg.run ();
2013 if (free_reason) {
2014 free ((char*) reason);
2018 int32_t
2019 ARDOUR_UI::do_engine_start ()
2021 try {
2022 engine->start();
2025 catch (...) {
2026 engine->stop ();
2027 error << _("Unable to start the session running")
2028 << endmsg;
2029 unload_session ();
2030 return -2;
2033 return 0;
2036 void
2037 ARDOUR_UI::setup_theme ()
2039 theme_manager->setup_theme();
2042 void
2043 ARDOUR_UI::update_clocks ()
2045 if (!editor || !editor->dragging_playhead()) {
2046 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position()); /* EMIT_SIGNAL */
2050 void
2051 ARDOUR_UI::start_clocking ()
2053 clock_signal_connection = RapidScreenUpdate.connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2056 void
2057 ARDOUR_UI::stop_clocking ()
2059 clock_signal_connection.disconnect ();
2062 void
2063 ARDOUR_UI::toggle_clocking ()
2065 #if 0
2066 if (clock_button.get_active()) {
2067 start_clocking ();
2068 } else {
2069 stop_clocking ();
2071 #endif
2074 gint
2075 ARDOUR_UI::_blink (void *arg)
2078 ((ARDOUR_UI *) arg)->blink ();
2079 return TRUE;
2082 void
2083 ARDOUR_UI::blink ()
2085 Blink (blink_on = !blink_on); /* EMIT_SIGNAL */
2088 void
2089 ARDOUR_UI::start_blinking ()
2091 /* Start the blink signal. Everybody with a blinking widget
2092 uses Blink to drive the widget's state.
2095 if (blink_timeout_tag < 0) {
2096 blink_on = false;
2097 blink_timeout_tag = g_timeout_add (240, _blink, this);
2101 void
2102 ARDOUR_UI::stop_blinking ()
2104 if (blink_timeout_tag >= 0) {
2105 g_source_remove (blink_timeout_tag);
2106 blink_timeout_tag = -1;
2111 /** Ask the user for the name of a new shapshot and then take it.
2114 void
2115 ARDOUR_UI::snapshot_session (bool switch_to_it)
2117 ArdourPrompter prompter (true);
2118 string snapname;
2120 prompter.set_name ("Prompter");
2121 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2122 prompter.set_title (_("Take Snapshot"));
2123 prompter.set_prompt (_("Name of new snapshot"));
2125 if (!switch_to_it) {
2126 char timebuf[128];
2127 time_t n;
2128 struct tm local_time;
2130 time (&n);
2131 localtime_r (&n, &local_time);
2132 strftime (timebuf, sizeof(timebuf), "%FT%T", &local_time);
2133 prompter.set_initial_text (timebuf);
2136 again:
2137 switch (prompter.run()) {
2138 case RESPONSE_ACCEPT:
2140 prompter.get_result (snapname);
2142 bool do_save = (snapname.length() != 0);
2144 if (do_save) {
2145 if (snapname.find ('/') != string::npos) {
2146 MessageDialog msg (_("To ensure compatibility with various systems\n"
2147 "snapshot names may not contain a '/' character"));
2148 msg.run ();
2149 goto again;
2151 if (snapname.find ('\\') != string::npos) {
2152 MessageDialog msg (_("To ensure compatibility with various systems\n"
2153 "snapshot names may not contain a '\\' character"));
2154 msg.run ();
2155 goto again;
2159 vector<sys::path> p;
2160 get_state_files_in_directory (_session->session_directory().root_path(), p);
2161 vector<string> n = get_file_names_no_extension (p);
2162 if (find (n.begin(), n.end(), snapname) != n.end()) {
2164 ArdourDialog confirm (_("Confirm Snapshot Overwrite"), true);
2165 Label m (_("A snapshot already exists with that name. Do you want to overwrite it?"));
2166 confirm.get_vbox()->pack_start (m, true, true);
2167 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2168 confirm.add_button (_("Overwrite"), Gtk::RESPONSE_ACCEPT);
2169 confirm.show_all ();
2170 switch (confirm.run()) {
2171 case RESPONSE_CANCEL:
2172 do_save = false;
2176 if (do_save) {
2177 save_state (snapname, switch_to_it);
2179 break;
2182 default:
2183 break;
2187 /** Ask the user for the name of a new shapshot and then take it.
2190 void
2191 ARDOUR_UI::rename_session ()
2193 if (!_session) {
2194 return;
2197 ArdourPrompter prompter (true);
2198 string name;
2200 prompter.set_name ("Prompter");
2201 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2202 prompter.set_title (_("Rename Session"));
2203 prompter.set_prompt (_("New session name"));
2205 again:
2206 switch (prompter.run()) {
2207 case RESPONSE_ACCEPT:
2209 prompter.get_result (name);
2211 bool do_rename = (name.length() != 0);
2213 if (do_rename) {
2214 if (name.find ('/') != string::npos) {
2215 MessageDialog msg (_("To ensure compatibility with various systems\n"
2216 "session names may not contain a '/' character"));
2217 msg.run ();
2218 goto again;
2220 if (name.find ('\\') != string::npos) {
2221 MessageDialog msg (_("To ensure compatibility with various systems\n"
2222 "session names may not contain a '\\' character"));
2223 msg.run ();
2224 goto again;
2227 switch (_session->rename (name)) {
2228 case -1: {
2229 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
2230 msg.set_position (WIN_POS_MOUSE);
2231 msg.run ();
2232 goto again;
2233 break;
2235 case 0:
2236 break;
2237 default: {
2238 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
2239 msg.set_position (WIN_POS_MOUSE);
2240 msg.run ();
2241 break;
2246 break;
2249 default:
2250 break;
2254 void
2255 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2257 XMLNode* node = new XMLNode (X_("UI"));
2259 for (list<WindowProxyBase*>::iterator i = _window_proxies.begin(); i != _window_proxies.end(); ++i) {
2260 if (!(*i)->rc_configured()) {
2261 node->add_child_nocopy (*((*i)->get_state ()));
2265 node->add_child_nocopy (gui_object_state->get_state());
2267 _session->add_extra_xml (*node);
2269 save_state_canfail (name, switch_to_it);
2273 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2275 if (_session) {
2276 int ret;
2278 if (name.length() == 0) {
2279 name = _session->snap_name();
2282 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2283 return ret;
2287 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2288 return 0;
2291 void
2292 ARDOUR_UI::primary_clock_value_changed ()
2294 if (_session) {
2295 _session->request_locate (primary_clock->current_time ());
2299 void
2300 ARDOUR_UI::big_clock_value_changed ()
2302 if (_session) {
2303 _session->request_locate (big_clock->current_time ());
2307 void
2308 ARDOUR_UI::secondary_clock_value_changed ()
2310 if (_session) {
2311 _session->request_locate (secondary_clock->current_time ());
2315 void
2316 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2318 if (_session == 0) {
2319 return;
2322 if (_session->step_editing()) {
2323 return;
2326 Session::RecordState const r = _session->record_status ();
2327 bool const h = _session->have_rec_enabled_track ();
2329 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2330 if (onoff) {
2331 rec_button.set_visual_state (2);
2332 } else {
2333 rec_button.set_visual_state (0);
2335 } else if (r == Session::Recording && h) {
2336 rec_button.set_visual_state (1);
2337 } else {
2338 rec_button.set_visual_state (0);
2342 void
2343 ARDOUR_UI::save_template ()
2345 ArdourPrompter prompter (true);
2346 string name;
2348 if (!check_audioengine()) {
2349 return;
2352 prompter.set_name (X_("Prompter"));
2353 prompter.set_title (_("Save Template"));
2354 prompter.set_prompt (_("Name for template:"));
2355 prompter.set_initial_text(_session->name() + _("-template"));
2356 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2358 switch (prompter.run()) {
2359 case RESPONSE_ACCEPT:
2360 prompter.get_result (name);
2362 if (name.length()) {
2363 _session->save_template (name);
2365 break;
2367 default:
2368 break;
2372 void
2373 ARDOUR_UI::edit_metadata ()
2375 SessionMetadataEditor dialog;
2376 dialog.set_session (_session);
2377 editor->ensure_float (dialog);
2378 dialog.run ();
2381 void
2382 ARDOUR_UI::import_metadata ()
2384 SessionMetadataImporter dialog;
2385 dialog.set_session (_session);
2386 editor->ensure_float (dialog);
2387 dialog.run ();
2390 bool
2391 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
2393 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2395 MessageDialog msg (str,
2396 false,
2397 Gtk::MESSAGE_WARNING,
2398 Gtk::BUTTONS_YES_NO,
2399 true);
2402 msg.set_name (X_("OpenExistingDialog"));
2403 msg.set_title (_("Open Existing Session"));
2404 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
2405 msg.set_position (Gtk::WIN_POS_MOUSE);
2406 pop_back_splash ();
2408 switch (msg.run()) {
2409 case RESPONSE_YES:
2410 return true;
2411 break;
2413 return false;
2417 ARDOUR_UI::build_session_from_nsd (const std::string& session_path, const std::string& session_name)
2419 BusProfile bus_profile;
2421 if (Profile->get_sae()) {
2423 bus_profile.master_out_channels = 2;
2424 bus_profile.input_ac = AutoConnectPhysical;
2425 bus_profile.output_ac = AutoConnectMaster;
2426 bus_profile.requested_physical_in = 0; // use all available
2427 bus_profile.requested_physical_out = 0; // use all available
2429 } else {
2431 /* get settings from advanced section of NSD */
2433 if (_startup->create_master_bus()) {
2434 bus_profile.master_out_channels = (uint32_t) _startup->master_channel_count();
2435 } else {
2436 bus_profile.master_out_channels = 0;
2439 if (_startup->connect_inputs()) {
2440 bus_profile.input_ac = AutoConnectPhysical;
2441 } else {
2442 bus_profile.input_ac = AutoConnectOption (0);
2445 /// @todo some minor tweaks.
2447 bus_profile.output_ac = AutoConnectOption (0);
2449 if (_startup->connect_outputs ()) {
2450 if (_startup->connect_outs_to_master()) {
2451 bus_profile.output_ac = AutoConnectMaster;
2452 } else if (_startup->connect_outs_to_physical()) {
2453 bus_profile.output_ac = AutoConnectPhysical;
2457 bus_profile.requested_physical_in = (uint32_t) _startup->input_limit_count();
2458 bus_profile.requested_physical_out = (uint32_t) _startup->output_limit_count();
2461 if (build_session (session_path, session_name, bus_profile)) {
2462 return -1;
2465 return 0;
2468 void
2469 ARDOUR_UI::idle_load (const std::string& path)
2471 if (_session) {
2472 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2473 /* /path/to/foo => /path/to/foo, foo */
2474 load_session (path, basename_nosuffix (path));
2475 } else {
2476 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2477 load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2479 } else {
2481 ARDOUR_COMMAND_LINE::session_name = path;
2484 * new_session_dialog doens't exist in A3
2485 * Try to remove all references to it to
2486 * see if it will compile. NOTE: this will
2487 * likely cause a runtime issue is my somewhat
2488 * uneducated guess.
2491 //if (new_session_dialog) {
2494 /* make it break out of Dialog::run() and
2495 start again.
2498 //new_session_dialog->response (1);
2503 void
2504 ARDOUR_UI::end_loading_messages ()
2506 // hide_splash ();
2509 void
2510 ARDOUR_UI::loading_message (const std::string& /*msg*/)
2512 // show_splash ();
2513 // splash->message (msg);
2514 flush_pending ();
2517 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
2519 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
2521 string session_name;
2522 string session_path;
2523 string template_name;
2524 int ret = -1;
2525 bool likely_new = false;
2527 if (!load_template.empty()) {
2528 should_be_new = true;
2529 template_name = load_template;
2532 while (ret != 0) {
2534 if (!should_be_new && !ARDOUR_COMMAND_LINE::session_name.empty()) {
2536 /* if they named a specific statefile, use it, otherwise they are
2537 just giving a session folder, and we want to use it as is
2538 to find the session.
2541 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
2543 if (suffix != string::npos) {
2544 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
2545 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
2546 session_name = Glib::path_get_basename (session_name);
2547 } else {
2548 session_path = ARDOUR_COMMAND_LINE::session_name;
2549 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
2552 } else {
2554 bool const apply = run_startup (should_be_new, load_template);
2556 if (!apply) {
2557 if (quit_on_cancel) {
2558 exit (1);
2559 } else {
2560 return ret;
2564 /* if we run the startup dialog again, offer more than just "new session" */
2566 should_be_new = false;
2568 session_name = _startup->session_name (likely_new);
2570 /* this shouldn't happen, but we catch it just in case it does */
2572 if (session_name.empty()) {
2573 continue;
2576 if (_startup->use_session_template()) {
2577 template_name = _startup->session_template_name();
2578 _session_is_new = true;
2581 if (session_name[0] == G_DIR_SEPARATOR ||
2582 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
2583 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)) {
2585 /* absolute path or cwd-relative path specified for session name: infer session folder
2586 from what was given.
2589 session_path = Glib::path_get_dirname (session_name);
2590 session_name = Glib::path_get_basename (session_name);
2592 } else {
2594 session_path = _startup->session_folder();
2596 if (session_name.find ('/') != string::npos) {
2597 MessageDialog msg (*_startup,
2598 _("To ensure compatibility with various systems\n"
2599 "session names may not contain a '/' character"));
2600 msg.run ();
2601 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2602 continue;
2605 if (session_name.find ('\\') != string::npos) {
2606 MessageDialog msg (*_startup,
2607 _("To ensure compatibility with various systems\n"
2608 "session names may not contain a '\\' character"));
2609 msg.run ();
2610 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2611 continue;
2616 if (create_engine ()) {
2617 break;
2620 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
2622 if (likely_new) {
2624 std::string existing = Glib::build_filename (session_path, session_name);
2626 if (!ask_about_loading_existing_session (existing)) {
2627 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2628 continue;
2632 _session_is_new = false;
2634 } else {
2636 if (!likely_new) {
2637 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
2638 msg.run ();
2639 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2640 continue;
2643 if (session_name.find ('/') != std::string::npos) {
2644 MessageDialog msg (*_startup,
2645 _("To ensure compatibility with various systems\n"
2646 "session names may not contain a '/' character"));
2647 msg.run ();
2648 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2649 continue;
2652 if (session_name.find ('\\') != std::string::npos) {
2653 MessageDialog msg (*_startup,
2654 _("To ensure compatibility with various systems\n"
2655 "session names may not contain a '\\' character"));
2656 msg.run ();
2657 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2658 continue;
2661 _session_is_new = true;
2664 if (likely_new && template_name.empty()) {
2666 ret = build_session_from_nsd (session_path, session_name);
2668 } else {
2670 ret = load_session (session_path, session_name, template_name);
2672 if (ret == -2) {
2673 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
2674 exit (1);
2677 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
2678 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
2679 exit (1);
2684 return ret;
2687 void
2688 ARDOUR_UI::close_session()
2690 if (!check_audioengine()) {
2691 return;
2694 if (unload_session (true)) {
2695 return;
2698 ARDOUR_COMMAND_LINE::session_name = "";
2700 if (get_session_parameters (true, false)) {
2701 exit (1);
2704 goto_editor_window ();
2707 /** @param snap_name Snapshot name (without .ardour suffix).
2708 * @return -2 if the load failed because we are not connected to the AudioEngine.
2711 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
2713 Session *new_session;
2714 int unload_status;
2715 int retval = -1;
2717 session_loaded = false;
2719 if (!check_audioengine()) {
2720 return -2;
2723 unload_status = unload_session ();
2725 if (unload_status < 0) {
2726 goto out;
2727 } else if (unload_status > 0) {
2728 retval = 0;
2729 goto out;
2732 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
2734 try {
2735 new_session = new Session (*engine, path, snap_name, 0, mix_template);
2738 /* this one is special */
2740 catch (AudioEngine::PortRegistrationFailure& err) {
2742 MessageDialog msg (err.what(),
2743 true,
2744 Gtk::MESSAGE_INFO,
2745 Gtk::BUTTONS_CLOSE);
2747 msg.set_title (_("Port Registration Error"));
2748 msg.set_secondary_text (_("Click the Close button to try again."));
2749 msg.set_position (Gtk::WIN_POS_CENTER);
2750 pop_back_splash ();
2751 msg.present ();
2753 int response = msg.run ();
2755 msg.hide ();
2757 switch (response) {
2758 case RESPONSE_CANCEL:
2759 exit (1);
2760 default:
2761 break;
2763 goto out;
2766 catch (...) {
2768 MessageDialog msg (string_compose(
2769 _("Session \"%1 (snapshot %2)\" did not load successfully"),
2770 path, snap_name),
2771 true,
2772 Gtk::MESSAGE_INFO,
2773 BUTTONS_OK);
2775 msg.set_title (_("Loading Error"));
2776 msg.set_secondary_text (_("Click the Refresh button to try again."));
2777 msg.add_button (Stock::REFRESH, 1);
2778 msg.set_position (Gtk::WIN_POS_CENTER);
2779 pop_back_splash ();
2780 msg.present ();
2782 int response = msg.run ();
2784 switch (response) {
2785 case 1:
2786 break;
2787 default:
2788 exit (1);
2791 msg.hide ();
2793 goto out;
2797 list<string> const u = new_session->unknown_processors ();
2798 if (!u.empty()) {
2799 MissingPluginDialog d (_session, u);
2800 d.run ();
2804 /* Now the session been created, add the transport controls */
2805 new_session->add_controllable(roll_controllable);
2806 new_session->add_controllable(stop_controllable);
2807 new_session->add_controllable(goto_start_controllable);
2808 new_session->add_controllable(goto_end_controllable);
2809 new_session->add_controllable(auto_loop_controllable);
2810 new_session->add_controllable(play_selection_controllable);
2811 new_session->add_controllable(rec_controllable);
2813 set_session (new_session);
2815 session_loaded = true;
2817 goto_editor_window ();
2819 if (_session) {
2820 _session->set_clean ();
2823 flush_pending ();
2824 retval = 0;
2826 out:
2827 return retval;
2831 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
2833 Session *new_session;
2834 int x;
2836 if (!check_audioengine()) {
2837 return -1;
2840 session_loaded = false;
2842 x = unload_session ();
2844 if (x < 0) {
2845 return -1;
2846 } else if (x > 0) {
2847 return 0;
2850 _session_is_new = true;
2852 try {
2853 new_session = new Session (*engine, path, snap_name, &bus_profile);
2856 catch (...) {
2858 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
2859 pop_back_splash ();
2860 msg.run ();
2861 return -1;
2864 /* Give the new session the default GUI state, if such things exist */
2866 XMLNode* n;
2867 n = Config->instant_xml (X_("Editor"));
2868 if (n) {
2869 new_session->add_instant_xml (*n, false);
2871 n = Config->instant_xml (X_("Mixer"));
2872 if (n) {
2873 new_session->add_instant_xml (*n, false);
2876 /* Put the playhead at 0 and scroll fully left */
2877 n = new_session->instant_xml (X_("Editor"));
2878 if (n) {
2879 n->add_property (X_("playhead"), X_("0"));
2880 n->add_property (X_("left-frame"), X_("0"));
2883 set_session (new_session);
2885 session_loaded = true;
2887 new_session->save_state(new_session->name());
2889 return 0;
2892 void
2893 ARDOUR_UI::launch_chat ()
2895 #ifdef __APPLE__
2896 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
2897 #else
2898 open_uri("http://webchat.freenode.net/?channels=ardour");
2899 #endif
2902 void
2903 ARDOUR_UI::show_about ()
2905 if (about == 0) {
2906 about = new About;
2907 about->signal_response().connect(sigc::mem_fun (*this, &ARDOUR_UI::about_signal_response) );
2910 about->set_transient_for(*editor);
2911 about->show_all ();
2914 void
2915 ARDOUR_UI::launch_manual ()
2917 PBD::open_uri("http://ardour.org/flossmanual");
2920 void
2921 ARDOUR_UI::launch_reference ()
2923 PBD::open_uri("http://ardour.org/refmanual");
2926 void
2927 ARDOUR_UI::hide_about ()
2929 if (about) {
2930 about->get_window()->set_cursor ();
2931 about->hide ();
2935 void
2936 ARDOUR_UI::about_signal_response (int /*response*/)
2938 hide_about();
2941 void
2942 ARDOUR_UI::show_splash ()
2944 if (splash == 0) {
2945 try {
2946 splash = new Splash;
2947 } catch (...) {
2948 return;
2952 splash->show ();
2953 splash->present ();
2954 splash->queue_draw ();
2955 splash->get_window()->process_updates (true);
2956 flush_pending ();
2959 void
2960 ARDOUR_UI::hide_splash ()
2962 if (splash) {
2963 splash->hide();
2967 void
2968 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title,
2969 const string& plural_msg, const string& singular_msg)
2971 size_t removed;
2973 removed = rep.paths.size();
2975 if (removed == 0) {
2976 MessageDialog msgd (*editor,
2977 _("No files were ready for clean-up"),
2978 true,
2979 Gtk::MESSAGE_INFO,
2980 (Gtk::ButtonsType)(Gtk::BUTTONS_OK) );
2981 msgd.set_title (_("Clean-up"));
2982 msgd.set_secondary_text (_("If this seems suprising, \n\
2983 check for any existing snapshots.\n\
2984 These may still include regions that\n\
2985 require some unused files to continue to exist."));
2987 msgd.run ();
2988 return;
2991 ArdourDialog results (_("Clean-up"), true, false);
2993 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
2994 CleanupResultsModelColumns() {
2995 add (visible_name);
2996 add (fullpath);
2998 Gtk::TreeModelColumn<std::string> visible_name;
2999 Gtk::TreeModelColumn<std::string> fullpath;
3003 CleanupResultsModelColumns results_columns;
3004 Glib::RefPtr<Gtk::ListStore> results_model;
3005 Gtk::TreeView results_display;
3007 results_model = ListStore::create (results_columns);
3008 results_display.set_model (results_model);
3009 results_display.append_column (list_title, results_columns.visible_name);
3011 results_display.set_name ("CleanupResultsList");
3012 results_display.set_headers_visible (true);
3013 results_display.set_headers_clickable (false);
3014 results_display.set_reorderable (false);
3016 Gtk::ScrolledWindow list_scroller;
3017 Gtk::Label txt;
3018 Gtk::VBox dvbox;
3019 Gtk::HBox dhbox; // the hbox for the image and text
3020 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
3021 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
3023 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
3025 const string dead_directory = _session->session_directory().dead_path().to_string();
3027 /* subst:
3028 %1 - number of files removed
3029 %2 - location of "dead"
3030 %3 - size of files affected
3031 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
3034 const char* bprefix;
3035 double space_adjusted = 0;
3037 if (rep.space < 1000) {
3038 bprefix = X_("");
3039 space_adjusted = rep.space;
3040 } else if (rep.space < 1000000) {
3041 bprefix = X_("kilo");
3042 space_adjusted = truncf((float)rep.space / 1000.0);
3043 } else if (rep.space < 1000000 * 1000) {
3044 bprefix = X_("mega");
3045 space_adjusted = truncf((float)rep.space / (1000.0 * 1000.0));
3046 } else {
3047 bprefix = X_("giga");
3048 space_adjusted = truncf((float)rep.space / (1000.0 * 1000 * 1000.0));
3051 if (removed > 1) {
3052 txt.set_text (string_compose (plural_msg, removed, dead_directory, space_adjusted, bprefix));
3053 } else {
3054 txt.set_text (string_compose (singular_msg, removed, dead_directory, space_adjusted, bprefix));
3057 dhbox.pack_start (*dimage, true, false, 5);
3058 dhbox.pack_start (txt, true, false, 5);
3060 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
3061 TreeModel::Row row = *(results_model->append());
3062 row[results_columns.visible_name] = *i;
3063 row[results_columns.fullpath] = *i;
3066 list_scroller.add (results_display);
3067 list_scroller.set_size_request (-1, 150);
3068 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
3070 dvbox.pack_start (dhbox, true, false, 5);
3071 dvbox.pack_start (list_scroller, true, false, 5);
3072 ddhbox.pack_start (dvbox, true, false, 5);
3074 results.get_vbox()->pack_start (ddhbox, true, false, 5);
3075 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
3076 results.set_default_response (RESPONSE_CLOSE);
3077 results.set_position (Gtk::WIN_POS_MOUSE);
3079 results_display.show();
3080 list_scroller.show();
3081 txt.show();
3082 dvbox.show();
3083 dhbox.show();
3084 ddhbox.show();
3085 dimage->show();
3087 //results.get_vbox()->show();
3088 results.set_resizable (false);
3090 results.run ();
3094 void
3095 ARDOUR_UI::cleanup ()
3097 if (_session == 0) {
3098 /* shouldn't happen: menu item is insensitive */
3099 return;
3103 MessageDialog checker (_("Are you sure you want to clean-up?"),
3104 true,
3105 Gtk::MESSAGE_QUESTION,
3106 (Gtk::ButtonsType)(Gtk::BUTTONS_NONE));
3108 checker.set_title (_("Clean-up"));
3110 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
3111 ALL undo/redo information will be lost if you clean-up.\n\
3112 Clean-up will move all unused files to a \"dead\" location."));
3114 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3115 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
3116 checker.set_default_response (RESPONSE_CANCEL);
3118 checker.set_name (_("CleanupDialog"));
3119 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3120 checker.set_position (Gtk::WIN_POS_MOUSE);
3122 switch (checker.run()) {
3123 case RESPONSE_ACCEPT:
3124 break;
3125 default:
3126 return;
3129 ARDOUR::CleanupReport rep;
3131 editor->prepare_for_cleanup ();
3133 /* do not allow flush until a session is reloaded */
3135 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3136 if (act) {
3137 act->set_sensitive (false);
3140 if (_session->cleanup_sources (rep)) {
3141 editor->finish_cleanup ();
3142 return;
3145 editor->finish_cleanup ();
3147 checker.hide();
3148 display_cleanup_results (rep,
3149 _("Cleaned Files"),
3150 _("\
3151 The following %1 files were not in use and \n\
3152 have been moved to:\n\n\
3153 %2\n\n\
3154 After a restart of Ardour,\n\n\
3155 Session -> Clean-up -> Flush Wastebasket\n\n\
3156 will release an additional\n\
3157 %3 %4bytes of disk space.\n"),
3158 _("\
3159 The following file was not in use and \n\
3160 has been moved to:\n \
3161 %2\n\n\
3162 After a restart of Ardour,\n\n\
3163 Session -> Clean-up -> Flush Wastebasket\n\n\
3164 will release an additional\n\
3165 %3 %4bytes of disk space.\n"
3170 void
3171 ARDOUR_UI::flush_trash ()
3173 if (_session == 0) {
3174 /* shouldn't happen: menu item is insensitive */
3175 return;
3178 ARDOUR::CleanupReport rep;
3180 if (_session->cleanup_trash_sources (rep)) {
3181 return;
3184 display_cleanup_results (rep,
3185 _("deleted file"),
3186 _("The following %1 files were deleted from\n\
3187 %2,\n\
3188 releasing %3 %4bytes of disk space"),
3189 _("The following file was deleted from\n\
3190 %2,\n\
3191 releasing %3 %4bytes of disk space"));
3194 void
3195 ARDOUR_UI::add_route (Gtk::Window* float_window)
3197 int count;
3199 if (!_session) {
3200 return;
3203 if (add_route_dialog == 0) {
3204 add_route_dialog = new AddRouteDialog (_session);
3205 if (float_window) {
3206 add_route_dialog->set_transient_for (*float_window);
3210 if (add_route_dialog->is_visible()) {
3211 /* we're already doing this */
3212 return;
3215 ResponseType r = (ResponseType) add_route_dialog->run ();
3217 add_route_dialog->hide();
3219 switch (r) {
3220 case RESPONSE_ACCEPT:
3221 break;
3222 default:
3223 return;
3224 break;
3227 if ((count = add_route_dialog->count()) <= 0) {
3228 return;
3231 string template_path = add_route_dialog->track_template();
3233 if (!template_path.empty()) {
3234 _session->new_route_from_template (count, template_path);
3235 return;
3238 uint32_t input_chan = add_route_dialog->channels ();
3239 uint32_t output_chan;
3240 string name_template = add_route_dialog->name_template ();
3241 bool track = add_route_dialog->track ();
3242 RouteGroup* route_group = add_route_dialog->route_group ();
3244 AutoConnectOption oac = Config->get_output_auto_connect();
3246 if (oac & AutoConnectMaster) {
3247 output_chan = (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan);
3248 } else {
3249 output_chan = input_chan;
3252 /* XXX do something with name template */
3254 if (add_route_dialog->type() == ARDOUR::DataType::MIDI) {
3255 if (track) {
3256 session_add_midi_track (route_group, count, name_template);
3257 } else {
3258 MessageDialog msg (*editor,
3259 _("Sorry, MIDI Busses are not supported at this time."));
3260 msg.run ();
3261 //session_add_midi_bus();
3263 } else {
3264 if (track) {
3265 session_add_audio_track (input_chan, output_chan, add_route_dialog->mode(), route_group, count, name_template);
3266 } else {
3267 session_add_audio_bus (input_chan, output_chan, route_group, count, name_template);
3272 XMLNode*
3273 ARDOUR_UI::mixer_settings () const
3275 XMLNode* node = 0;
3277 if (_session) {
3278 node = _session->instant_xml(X_("Mixer"));
3279 } else {
3280 node = Config->instant_xml(X_("Mixer"));
3283 if (!node) {
3284 node = new XMLNode (X_("Mixer"));
3287 return node;
3290 XMLNode*
3291 ARDOUR_UI::editor_settings () const
3293 XMLNode* node = 0;
3295 if (_session) {
3296 node = _session->instant_xml(X_("Editor"));
3297 } else {
3298 node = Config->instant_xml(X_("Editor"));
3301 if (!node) {
3302 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
3303 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
3307 if (!node) {
3308 node = new XMLNode (X_("Editor"));
3311 return node;
3314 XMLNode*
3315 ARDOUR_UI::keyboard_settings () const
3317 XMLNode* node = 0;
3319 node = Config->extra_xml(X_("Keyboard"));
3321 if (!node) {
3322 node = new XMLNode (X_("Keyboard"));
3325 return node;
3328 void
3329 ARDOUR_UI::create_xrun_marker (framepos_t where)
3331 editor->mouse_add_new_marker (where, false, true);
3334 void
3335 ARDOUR_UI::halt_on_xrun_message ()
3337 MessageDialog msg (*editor,
3338 _("Recording was stopped because your system could not keep up."));
3339 msg.run ();
3342 void
3343 ARDOUR_UI::xrun_handler (framepos_t where)
3345 if (!_session) {
3346 return;
3349 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
3351 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
3352 create_xrun_marker(where);
3355 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
3356 halt_on_xrun_message ();
3360 void
3361 ARDOUR_UI::disk_overrun_handler ()
3363 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
3365 if (!have_disk_speed_dialog_displayed) {
3366 have_disk_speed_dialog_displayed = true;
3367 MessageDialog* msg = new MessageDialog (*editor, string_compose (_("\
3368 The disk system on your computer\n\
3369 was not able to keep up with %1.\n\
3371 Specifically, it failed to write data to disk\n\
3372 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
3373 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3374 msg->show ();
3378 void
3379 ARDOUR_UI::disk_underrun_handler ()
3381 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
3383 if (!have_disk_speed_dialog_displayed) {
3384 have_disk_speed_dialog_displayed = true;
3385 MessageDialog* msg = new MessageDialog (
3386 *editor, string_compose (_("The disk system on your computer\n\
3387 was not able to keep up with %1.\n\
3389 Specifically, it failed to read data from disk\n\
3390 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
3391 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3392 msg->show ();
3396 void
3397 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
3399 have_disk_speed_dialog_displayed = false;
3400 delete msg;
3403 void
3404 ARDOUR_UI::session_dialog (std::string msg)
3406 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
3408 MessageDialog* d;
3410 if (editor) {
3411 d = new MessageDialog (*editor, msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3412 } else {
3413 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3416 d->show_all ();
3417 d->run ();
3418 delete d;
3422 ARDOUR_UI::pending_state_dialog ()
3424 HBox* hbox = new HBox();
3425 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3426 ArdourDialog dialog (_("Crash Recovery"), true);
3427 Label message (_("\
3428 This session appears to have been in\n\
3429 middle of recording when ardour or\n\
3430 the computer was shutdown.\n\
3432 Ardour can recover any captured audio for\n\
3433 you, or it can ignore it. Please decide\n\
3434 what you would like to do.\n"));
3435 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3436 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3437 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3438 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3439 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
3440 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
3441 dialog.set_default_response (RESPONSE_ACCEPT);
3442 dialog.set_position (WIN_POS_CENTER);
3443 message.show();
3444 image->show();
3445 hbox->show();
3447 switch (dialog.run ()) {
3448 case RESPONSE_ACCEPT:
3449 return 1;
3450 default:
3451 return 0;
3456 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
3458 HBox* hbox = new HBox();
3459 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3460 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
3461 Label message (string_compose (_("\
3462 This session was created with a sample rate of %1 Hz\n\
3464 The audioengine is currently running at %2 Hz\n"), desired, actual));
3466 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3467 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3468 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3469 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3470 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
3471 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
3472 dialog.set_default_response (RESPONSE_ACCEPT);
3473 dialog.set_position (WIN_POS_CENTER);
3474 message.show();
3475 image->show();
3476 hbox->show();
3478 switch (dialog.run ()) {
3479 case RESPONSE_ACCEPT:
3480 return 0;
3481 default:
3482 return 1;
3487 void
3488 ARDOUR_UI::disconnect_from_jack ()
3490 if (engine) {
3491 if( engine->disconnect_from_jack ()) {
3492 MessageDialog msg (*editor, _("Could not disconnect from JACK"));
3493 msg.run ();
3496 update_sample_rate (0);
3500 void
3501 ARDOUR_UI::reconnect_to_jack ()
3503 if (engine) {
3504 if (engine->reconnect_to_jack ()) {
3505 MessageDialog msg (*editor, _("Could not reconnect to JACK"));
3506 msg.run ();
3509 update_sample_rate (0);
3513 void
3514 ARDOUR_UI::use_config ()
3516 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
3517 if (node) {
3518 set_transport_controllable_state (*node);
3522 void
3523 ARDOUR_UI::update_transport_clocks (framepos_t pos)
3525 if (Config->get_primary_clock_delta_edit_cursor()) {
3526 primary_clock->set (pos, false, editor->get_preferred_edit_position(), 1);
3527 } else {
3528 primary_clock->set (pos, 0, true);
3531 if (Config->get_secondary_clock_delta_edit_cursor()) {
3532 secondary_clock->set (pos, false, editor->get_preferred_edit_position(), 2);
3533 } else {
3534 secondary_clock->set (pos);
3537 if (big_clock_window->get()) {
3538 big_clock->set (pos);
3543 void
3544 ARDOUR_UI::step_edit_status_change (bool yn)
3546 // XXX should really store pre-step edit status of things
3547 // we make insensitive
3549 if (yn) {
3550 rec_button.set_visual_state (3);
3551 rec_button.set_sensitive (false);
3552 } else {
3553 rec_button.set_visual_state (0);
3554 rec_button.set_sensitive (true);
3558 void
3559 ARDOUR_UI::record_state_changed ()
3561 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
3563 if (!_session || !big_clock_window->get()) {
3564 /* why bother - the clock isn't visible */
3565 return;
3568 Session::RecordState const r = _session->record_status ();
3569 bool const h = _session->have_rec_enabled_track ();
3571 if (r == Session::Recording && h) {
3572 big_clock->set_widget_name ("BigClockRecording");
3573 } else {
3574 big_clock->set_widget_name ("BigClockNonRecording");
3578 bool
3579 ARDOUR_UI::first_idle ()
3581 if (_session) {
3582 _session->allow_auto_play (true);
3585 if (editor) {
3586 editor->first_idle();
3589 Keyboard::set_can_save_keybindings (true);
3590 return false;
3593 void
3594 ARDOUR_UI::store_clock_modes ()
3596 XMLNode* node = new XMLNode(X_("ClockModes"));
3598 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
3599 XMLNode* child = new XMLNode (X_("Clock"));
3601 child->add_property (X_("name"), (*x)->name());
3602 child->add_property (X_("mode"), enum_2_string ((*x)->mode()));
3603 child->add_property (X_("on"), ((*x)->off() ? X_("no") : X_("yes")));
3605 node->add_child_nocopy (*child);
3608 _session->add_extra_xml (*node);
3609 _session->set_dirty ();
3612 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
3613 : Controllable (name), ui (u), type(tp)
3618 void
3619 ARDOUR_UI::TransportControllable::set_value (double val)
3621 if (val < 0.5) {
3622 /* do nothing: these are radio-style actions */
3623 return;
3626 const char *action = 0;
3628 switch (type) {
3629 case Roll:
3630 action = X_("Roll");
3631 break;
3632 case Stop:
3633 action = X_("Stop");
3634 break;
3635 case GotoStart:
3636 action = X_("Goto Start");
3637 break;
3638 case GotoEnd:
3639 action = X_("Goto End");
3640 break;
3641 case AutoLoop:
3642 action = X_("Loop");
3643 break;
3644 case PlaySelection:
3645 action = X_("Play Selection");
3646 break;
3647 case RecordEnable:
3648 action = X_("Record");
3649 break;
3650 default:
3651 break;
3654 if (action == 0) {
3655 return;
3658 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
3660 if (act) {
3661 act->activate ();
3665 double
3666 ARDOUR_UI::TransportControllable::get_value (void) const
3668 float val = 0.0;
3670 switch (type) {
3671 case Roll:
3672 break;
3673 case Stop:
3674 break;
3675 case GotoStart:
3676 break;
3677 case GotoEnd:
3678 break;
3679 case AutoLoop:
3680 break;
3681 case PlaySelection:
3682 break;
3683 case RecordEnable:
3684 break;
3685 default:
3686 break;
3689 return val;
3692 void
3693 ARDOUR_UI::TransportControllable::set_id (const string& str)
3695 _id = str;
3698 void
3699 ARDOUR_UI::setup_profile ()
3701 if (gdk_screen_width() < 1200) {
3702 Profile->set_small_screen ();
3706 if (getenv ("ARDOUR_SAE")) {
3707 Profile->set_sae ();
3708 Profile->set_single_package ();
3712 void
3713 ARDOUR_UI::toggle_translations ()
3715 using namespace Glib;
3717 RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("EnableTranslation"));
3718 if (act) {
3719 RefPtr<ToggleAction> ract = RefPtr<ToggleAction>::cast_dynamic (act);
3720 if (ract) {
3722 string i18n_killer = ARDOUR::translation_kill_path();
3724 bool already_enabled = !ARDOUR::translations_are_disabled ();
3726 if (ract->get_active ()) {
3727 /* we don't care about errors */
3728 int fd = ::open (i18n_killer.c_str(), O_RDONLY|O_CREAT, 0644);
3729 close (fd);
3730 } else {
3731 /* we don't care about errors */
3732 unlink (i18n_killer.c_str());
3735 if (already_enabled != ract->get_active()) {
3736 MessageDialog win (already_enabled ? _("Translations disabled") : _("Translations enabled"),
3737 false,
3738 Gtk::MESSAGE_WARNING,
3739 Gtk::BUTTONS_OK);
3740 win.set_secondary_text (string_compose (_("You must restart %1 for this to take effect."), PROGRAM_NAME));
3741 win.set_position (Gtk::WIN_POS_CENTER);
3742 win.present ();
3743 win.run ();
3749 /** Add a window proxy to our list, so that its state will be saved.
3750 * This call also causes the window to be created and opened if its
3751 * state was saved as `visible'.
3753 void
3754 ARDOUR_UI::add_window_proxy (WindowProxyBase* p)
3756 _window_proxies.push_back (p);
3757 p->maybe_show ();
3760 /** Remove a window proxy from our list. Must be called if a WindowProxy
3761 * is deleted, to prevent hanging pointers.
3763 void
3764 ARDOUR_UI::remove_window_proxy (WindowProxyBase* p)
3766 _window_proxies.remove (p);
3770 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
3772 MissingFileDialog dialog (s, str, type);
3774 dialog.show ();
3775 dialog.present ();
3777 int result = dialog.run ();
3778 dialog.hide ();
3780 switch (result) {
3781 case RESPONSE_OK:
3782 break;
3783 default:
3784 return 1; // quit entire session load
3787 result = dialog.get_action ();
3789 return result;
3793 ARDOUR_UI::ambiguous_file (std::string file, std::string path, std::vector<std::string> hits)
3795 AmbiguousFileDialog dialog (file, hits);
3797 dialog.show ();
3798 dialog.present ();
3800 dialog.run ();
3801 return dialog.get_which ();