fix rounding errors and bbox glitches that led to lines missing redraws, plus a few...
[ardour2.git] / gtk2_ardour / ardour_ui.cc
blob43fb42164f80f50c3ceb40cd1bb6cbb37e241b55
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/gtk_ui.h"
53 #include "gtkmm2ext/utils.h"
54 #include "gtkmm2ext/click_box.h"
55 #include "gtkmm2ext/fastmeter.h"
56 #include "gtkmm2ext/popup.h"
57 #include "gtkmm2ext/window_title.h"
59 #include "midi++/manager.h"
61 #include "ardour/ardour.h"
62 #include "ardour/callback.h"
63 #include "ardour/profile.h"
64 #include "ardour/session_directory.h"
65 #include "ardour/session_route.h"
66 #include "ardour/session_state_utils.h"
67 #include "ardour/session_utils.h"
68 #include "ardour/port.h"
69 #include "ardour/audioengine.h"
70 #include "ardour/playlist.h"
71 #include "ardour/utils.h"
72 #include "ardour/audio_diskstream.h"
73 #include "ardour/audiofilesource.h"
74 #include "ardour/recent_sessions.h"
75 #include "ardour/port.h"
76 #include "ardour/audio_track.h"
77 #include "ardour/midi_track.h"
78 #include "ardour/filesystem_paths.h"
79 #include "ardour/filename_extensions.h"
81 typedef uint64_t microseconds_t;
83 #include "actions.h"
84 #include "ardour_ui.h"
85 #include "public_editor.h"
86 #include "audio_clock.h"
87 #include "keyboard.h"
88 #include "mixer_ui.h"
89 #include "prompter.h"
90 #include "opts.h"
91 #include "add_route_dialog.h"
92 #include "about.h"
93 #include "splash.h"
94 #include "utils.h"
95 #include "gui_thread.h"
96 #include "theme_manager.h"
97 #include "bundle_manager.h"
98 #include "session_metadata_dialog.h"
99 #include "gain_meter.h"
100 #include "route_time_axis.h"
101 #include "startup.h"
102 #include "engine_dialog.h"
103 #include "processor_box.h"
104 #include "time_axis_view_item.h"
105 #include "window_proxy.h"
106 #include "global_port_matrix.h"
107 #include "location_ui.h"
108 #include "missing_file_dialog.h"
109 #include "missing_plugin_dialog.h"
110 #include "ambiguous_file_dialog.h"
112 #include "i18n.h"
114 using namespace ARDOUR;
115 using namespace PBD;
116 using namespace Gtkmm2ext;
117 using namespace Gtk;
119 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
120 UIConfiguration *ARDOUR_UI::ui_config = 0;
122 sigc::signal<void,bool> ARDOUR_UI::Blink;
123 sigc::signal<void> ARDOUR_UI::RapidScreenUpdate;
124 sigc::signal<void> ARDOUR_UI::SuperRapidScreenUpdate;
125 sigc::signal<void, framepos_t, bool, framepos_t> ARDOUR_UI::Clock;
127 bool could_be_a_valid_path (const string& path);
129 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[])
131 : Gtkmm2ext::UI (PROGRAM_NAME, argcp, argvp),
133 primary_clock (X_("primary"), false, X_("TransportClockDisplay"), true, true, false, true),
134 secondary_clock (X_("secondary"), false, X_("SecondaryClockDisplay"), true, true, false, true),
135 preroll_clock (X_("preroll"), false, X_("PreRollClock"), true, false, true),
136 postroll_clock (X_("postroll"), false, X_("PostRollClock"), true, false, true),
138 /* preroll stuff */
140 preroll_button (_("pre\nroll")),
141 postroll_button (_("post\nroll")),
143 /* big clock */
145 big_clock (X_("bigclock"), false, "BigClockNonRecording", true, true, false, false),
147 /* transport */
149 roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll)),
150 stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop)),
151 goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart)),
152 goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd)),
153 auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop)),
154 play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection)),
155 rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable)),
156 shuttle_controllable (new TransportControllable ("shuttle", *this, TransportControllable::ShuttleControl)),
157 shuttle_controller_binding_proxy (shuttle_controllable),
159 roll_button (roll_controllable),
160 stop_button (stop_controllable),
161 goto_start_button (goto_start_controllable),
162 goto_end_button (goto_end_controllable),
163 auto_loop_button (auto_loop_controllable),
164 play_selection_button (play_selection_controllable),
165 rec_button (rec_controllable),
167 shuttle_units_button (_("% ")),
169 punch_in_button (_("Punch In")),
170 punch_out_button (_("Punch Out")),
171 auto_return_button (_("Auto Return")),
172 auto_play_button (_("Auto Play")),
173 auto_input_button (_("Auto Input")),
174 click_button (_("Click")),
175 time_master_button (_("time\nmaster")),
177 auditioning_alert_button (_("AUDITION")),
178 solo_alert_button (_("SOLO")),
180 error_log_button (_("Errors"))
183 using namespace Gtk::Menu_Helpers;
185 Gtkmm2ext::init();
188 #ifdef TOP_MENUBAR
189 // _auto_display_errors = false;
191 * This was commented out as it wasn't defined
192 * in A3 IIRC. If this is not needed it should
193 * be completely removed.
195 #endif
197 about = 0;
198 splash = 0;
199 _startup = 0;
201 if (theArdourUI == 0) {
202 theArdourUI = this;
205 ui_config = new UIConfiguration();
206 theme_manager = new ThemeManager();
208 editor = 0;
209 mixer = 0;
210 editor = 0;
211 engine = 0;
212 _session_is_new = false;
213 big_clock_window = 0;
214 big_clock_height = 0;
215 big_clock_resize_in_progress = false;
216 session_selector_window = 0;
217 last_key_press_time = 0;
218 _will_create_new_session_automatically = false;
219 add_route_dialog = 0;
220 route_params = 0;
221 rc_option_editor = 0;
222 session_option_editor = 0;
223 location_ui = 0;
224 open_session_selector = 0;
225 have_configure_timeout = false;
226 have_disk_speed_dialog_displayed = false;
227 session_loaded = false;
228 last_speed_displayed = -1.0f;
229 ignore_dual_punch = false;
230 original_big_clock_width = -1;
231 original_big_clock_height = -1;
232 original_big_clock_font_size = 0;
234 roll_button.unset_flags (Gtk::CAN_FOCUS);
235 stop_button.unset_flags (Gtk::CAN_FOCUS);
236 goto_start_button.unset_flags (Gtk::CAN_FOCUS);
237 goto_end_button.unset_flags (Gtk::CAN_FOCUS);
238 auto_loop_button.unset_flags (Gtk::CAN_FOCUS);
239 play_selection_button.unset_flags (Gtk::CAN_FOCUS);
240 rec_button.unset_flags (Gtk::CAN_FOCUS);
242 last_configure_time= 0;
244 shuttle_grabbed = false;
245 shuttle_fract = 0.0;
246 shuttle_max_speed = 8.0f;
248 shuttle_style_menu = 0;
249 shuttle_unit_menu = 0;
251 // We do not have jack linked in yet so;
253 last_shuttle_request = last_peak_grab = 0; // get_microseconds();
255 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
256 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
258 /* handle dialog requests */
260 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
262 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
264 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
266 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
268 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
270 /* handle requests to quit (coming from JACK session) */
272 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::finish, this), gui_context ());
274 /* handle requests to deal with missing files */
276 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
278 /* and ambiguous files */
280 ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2, _3));
282 /* lets get this party started */
284 try {
285 if (ARDOUR::init (ARDOUR_COMMAND_LINE::use_vst, ARDOUR_COMMAND_LINE::try_hw_optimization)) {
286 throw failed_constructor ();
289 setup_gtk_ardour_enums ();
290 setup_profile ();
292 GainMeter::setup_slider_pix ();
293 RouteTimeAxisView::setup_slider_pix ();
294 SendProcessorEntry::setup_slider_pix ();
295 SessionEvent::create_per_thread_pool ("GUI", 512);
297 } catch (failed_constructor& err) {
298 error << string_compose (_("could not initialize %1."), PROGRAM_NAME) << endmsg;
299 // pass it on up
300 throw;
303 /* we like keyboards */
305 keyboard = new ArdourKeyboard(*this);
307 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
308 if (node) {
309 keyboard->set_state (*node, Stateful::loading_state_version);
312 reset_dpi();
314 TimeAxisViewItem::set_constant_heights ();
316 /* The following must happen after ARDOUR::init() so that Config is set up */
318 location_ui = new ActionWindowProxy<LocationUIWindow> (X_("locations"), Config->extra_xml (X_("UI")), X_("ToggleLocations"));
319 big_clock_window = new ActionWindowProxy<Gtk::Window> (X_("bigclock"), Config->extra_xml (X_("UI")), X_("ToggleBigClock"));
321 for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) {
322 _global_port_matrix[*i] = new ActionWindowProxy<GlobalPortMatrixWindow> (
323 string_compose ("GlobalPortMatrix-%1", (*i).to_string()),
324 Config->extra_xml (X_("UI")),
325 string_compose ("toggle-%1-connection-manager", (*i).to_string())
329 setup_clock ();
331 starting.connect (sigc::mem_fun(*this, &ARDOUR_UI::startup));
332 stopping.connect (sigc::mem_fun(*this, &ARDOUR_UI::shutdown));
334 platform_setup ();
337 /** @return true if a session was chosen and `apply' clicked, otherwise false if `cancel' was clicked */
338 bool
339 ARDOUR_UI::run_startup (bool should_be_new, string load_template)
341 delete _startup;
342 _startup = new ArdourStartup ();
344 XMLNode* audio_setup = Config->extra_xml ("AudioSetup");
346 if (audio_setup && _startup->engine_control()) {
347 _startup->engine_control()->set_state (*audio_setup);
350 _startup->set_new_only (should_be_new);
351 if (!load_template.empty()) {
352 _startup->set_load_template( load_template );
354 _startup->present ();
356 main().run();
358 _startup->hide ();
360 switch (_startup->response()) {
361 case RESPONSE_OK:
362 return true;
363 default:
364 return false;
369 ARDOUR_UI::create_engine ()
371 // this gets called every time by new_session()
373 if (engine) {
374 return 0;
377 loading_message (_("Starting audio engine"));
379 try {
380 engine = new ARDOUR::AudioEngine (ARDOUR_COMMAND_LINE::jack_client_name, ARDOUR_COMMAND_LINE::jack_session_uuid);
382 } catch (...) {
384 return -1;
387 engine->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
388 engine->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
389 engine->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
391 engine->Halted.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
393 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
395 post_engine ();
397 return 0;
400 void
401 ARDOUR_UI::post_engine ()
403 /* Things to be done once we create the AudioEngine
406 ARDOUR::init_post_engine ();
408 ActionManager::init ();
409 _tooltips.enable();
411 if (setup_windows ()) {
412 throw failed_constructor ();
415 check_memory_locking();
417 /* this is the first point at which all the keybindings are available */
419 if (ARDOUR_COMMAND_LINE::show_key_actions) {
420 vector<string> names;
421 vector<string> paths;
422 vector<string> keys;
423 vector<AccelKey> bindings;
425 ActionManager::get_all_actions (names, paths, keys, bindings);
427 vector<string>::iterator n;
428 vector<string>::iterator k;
429 for (n = names.begin(), k = keys.begin(); n != names.end(); ++n, ++k) {
430 cerr << "Action: " << (*n) << " bound to " << (*k) << endl;
433 exit (0);
436 blink_timeout_tag = -1;
438 /* this being a GUI and all, we want peakfiles */
440 AudioFileSource::set_build_peakfiles (true);
441 AudioFileSource::set_build_missing_peakfiles (true);
443 /* set default clock modes */
445 if (Profile->get_sae()) {
446 primary_clock.set_mode (AudioClock::BBT);
447 secondary_clock.set_mode (AudioClock::MinSec);
448 } else {
449 primary_clock.set_mode (AudioClock::Timecode);
450 secondary_clock.set_mode (AudioClock::BBT);
453 /* start the time-of-day-clock */
455 #ifndef GTKOSX
456 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
457 update_wall_clock ();
458 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 60000);
459 #endif
461 update_disk_space ();
462 update_cpu_load ();
463 update_sample_rate (engine->frame_rate());
465 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
466 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
467 Config->map_parameters (pc);
469 /* now start and maybe save state */
471 if (do_engine_start () == 0) {
472 if (_session && _session_is_new) {
473 /* we need to retain initial visual
474 settings for a new session
476 _session->save_state ("");
481 ARDOUR_UI::~ARDOUR_UI ()
483 delete keyboard;
484 delete editor;
485 delete mixer;
486 delete add_route_dialog;
489 void
490 ARDOUR_UI::pop_back_splash ()
492 if (Splash::instance()) {
493 // Splash::instance()->pop_back();
494 Splash::instance()->hide ();
498 gint
499 ARDOUR_UI::configure_timeout ()
501 if (last_configure_time == 0) {
502 /* no configure events yet */
503 return true;
506 /* force a gap of 0.5 seconds since the last configure event
509 if (get_microseconds() - last_configure_time < 500000) {
510 return true;
511 } else {
512 have_configure_timeout = false;
513 cerr << "config event-driven save\n";
514 save_ardour_state ();
515 return false;
519 gboolean
520 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
522 if (have_configure_timeout) {
523 last_configure_time = get_microseconds();
524 } else {
525 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
526 have_configure_timeout = true;
529 return FALSE;
532 void
533 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
535 const XMLProperty* prop;
537 if ((prop = node.property ("roll")) != 0) {
538 roll_controllable->set_id (prop->value());
540 if ((prop = node.property ("stop")) != 0) {
541 stop_controllable->set_id (prop->value());
543 if ((prop = node.property ("goto-start")) != 0) {
544 goto_start_controllable->set_id (prop->value());
546 if ((prop = node.property ("goto-end")) != 0) {
547 goto_end_controllable->set_id (prop->value());
549 if ((prop = node.property ("auto-loop")) != 0) {
550 auto_loop_controllable->set_id (prop->value());
552 if ((prop = node.property ("play-selection")) != 0) {
553 play_selection_controllable->set_id (prop->value());
555 if ((prop = node.property ("rec")) != 0) {
556 rec_controllable->set_id (prop->value());
558 if ((prop = node.property ("shuttle")) != 0) {
559 shuttle_controllable->set_id (prop->value());
563 XMLNode&
564 ARDOUR_UI::get_transport_controllable_state ()
566 XMLNode* node = new XMLNode(X_("TransportControllables"));
567 char buf[64];
569 roll_controllable->id().print (buf, sizeof (buf));
570 node->add_property (X_("roll"), buf);
571 stop_controllable->id().print (buf, sizeof (buf));
572 node->add_property (X_("stop"), buf);
573 goto_start_controllable->id().print (buf, sizeof (buf));
574 node->add_property (X_("goto_start"), buf);
575 goto_end_controllable->id().print (buf, sizeof (buf));
576 node->add_property (X_("goto_end"), buf);
577 auto_loop_controllable->id().print (buf, sizeof (buf));
578 node->add_property (X_("auto_loop"), buf);
579 play_selection_controllable->id().print (buf, sizeof (buf));
580 node->add_property (X_("play_selection"), buf);
581 rec_controllable->id().print (buf, sizeof (buf));
582 node->add_property (X_("rec"), buf);
583 shuttle_controllable->id().print (buf, sizeof (buf));
584 node->add_property (X_("shuttle"), buf);
586 return *node;
590 gint
591 ARDOUR_UI::autosave_session ()
593 if (g_main_depth() > 1) {
594 /* inside a recursive main loop,
595 give up because we may not be able to
596 take a lock.
598 return 1;
601 if (!Config->get_periodic_safety_backups()) {
602 return 1;
605 if (_session) {
606 _session->maybe_write_autosave();
609 return 1;
612 void
613 ARDOUR_UI::update_autosave ()
615 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_autosave)
617 if (_session && _session->dirty()) {
618 if (_autosave_connection.connected()) {
619 _autosave_connection.disconnect();
622 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
623 Config->get_periodic_safety_backup_interval() * 1000);
625 } else {
626 if (_autosave_connection.connected()) {
627 _autosave_connection.disconnect();
632 void
633 ARDOUR_UI::backend_audio_error (bool we_set_params, Gtk::Window* toplevel)
635 string title;
636 if (we_set_params) {
637 title = string_compose (_("%1 could not start JACK"), PROGRAM_NAME);
638 } else {
639 title = string_compose (_("%1 could not connect to JACK."), PROGRAM_NAME);
642 MessageDialog win (title,
643 false,
644 Gtk::MESSAGE_INFO,
645 Gtk::BUTTONS_NONE);
647 if (we_set_params) {
648 win.set_secondary_text(_("There are several possible reasons:\n\
650 1) You requested audio parameters that are not supported..\n\
651 2) JACK is running as another user.\n\
653 Please consider the possibilities, and perhaps try different parameters."));
654 } else {
655 win.set_secondary_text(_("There are several possible reasons:\n\
657 1) JACK is not running.\n\
658 2) JACK is running as another user, perhaps root.\n\
659 3) There is already another client called \"ardour\".\n\
661 Please consider the possibilities, and perhaps (re)start JACK."));
664 if (toplevel) {
665 win.set_transient_for (*toplevel);
668 if (we_set_params) {
669 win.add_button (Stock::OK, RESPONSE_CLOSE);
670 } else {
671 win.add_button (Stock::QUIT, RESPONSE_CLOSE);
674 win.set_default_response (RESPONSE_CLOSE);
676 win.show_all ();
677 win.set_position (Gtk::WIN_POS_CENTER);
678 pop_back_splash ();
680 /* we just don't care about the result, but we want to block */
682 win.run ();
685 void
686 ARDOUR_UI::startup ()
688 Application* app = Application::instance ();
690 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
691 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::idle_load));
693 #ifdef PHONE_HOME
694 call_the_mothership (VERSIONSTRING);
695 #endif
697 app->ready ();
699 if (get_session_parameters (true, ARDOUR_COMMAND_LINE::new_session, ARDOUR_COMMAND_LINE::load_template)) {
700 exit (1);
703 use_config ();
705 goto_editor_window ();
707 /* Add the window proxies here; their addition may cause windows to be opened, and we want them
708 to be opened on top of the editor window that goto_editor_window() just opened.
710 add_window_proxy (location_ui);
711 add_window_proxy (big_clock_window);
712 for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) {
713 add_window_proxy (_global_port_matrix[*i]);
716 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
719 void
720 ARDOUR_UI::no_memory_warning ()
722 XMLNode node (X_("no-memory-warning"));
723 Config->add_instant_xml (node);
726 void
727 ARDOUR_UI::check_memory_locking ()
729 #ifdef __APPLE__
730 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
731 return;
732 #else // !__APPLE__
734 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
736 if (engine->is_realtime() && memory_warning_node == 0) {
738 struct rlimit limits;
739 int64_t ram;
740 long pages, page_size;
742 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0) {
743 ram = 0;
744 } else {
745 ram = (int64_t) pages * (int64_t) page_size;
748 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
749 return;
752 if (limits.rlim_cur != RLIM_INFINITY) {
754 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
757 MessageDialog msg (
758 string_compose (_("WARNING: Your system has a limit for maximum amount of locked memory. "
759 "This might cause %1 to run out of memory before your system "
760 "runs out of memory. \n\n"
761 "You can view the memory limit with 'ulimit -l', "
762 "and it is normally controlled by /etc/security/limits.conf"),
763 PROGRAM_NAME).c_str());
765 VBox* vbox = msg.get_vbox();
766 HBox hbox;
767 CheckButton cb (_("Do not show this window again"));
769 cb.signal_toggled().connect (sigc::mem_fun (*this, &ARDOUR_UI::no_memory_warning));
771 hbox.pack_start (cb, true, false);
772 vbox->pack_start (hbox);
773 cb.show();
774 vbox->show();
775 hbox.show ();
777 pop_back_splash ();
779 editor->ensure_float (msg);
780 msg.run ();
784 #endif // !__APPLE__
788 void
789 ARDOUR_UI::queue_finish ()
791 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
794 bool
795 ARDOUR_UI::idle_finish ()
797 finish ();
798 return false; /* do not call again */
801 void
802 ARDOUR_UI::finish()
804 if (_session) {
805 int tries = 0;
807 if (_session->transport_rolling() && (++tries < 8)) {
808 _session->request_stop (false, true);
809 usleep (10000);
812 if (_session->dirty()) {
813 switch (ask_about_saving_session(_("quit"))) {
814 case -1:
815 return;
816 break;
817 case 1:
818 /* use the default name */
819 if (save_state_canfail ("")) {
820 /* failed - don't quit */
821 MessageDialog msg (*editor,
822 _("\
823 Ardour was unable to save your session.\n\n\
824 If you still wish to quit, please use the\n\n\
825 \"Just quit\" option."));
826 pop_back_splash();
827 msg.run ();
828 return;
830 break;
831 case 0:
832 break;
836 second_connection.disconnect ();
837 point_one_second_connection.disconnect ();
838 point_oh_five_second_connection.disconnect ();
839 point_zero_one_second_connection.disconnect();
842 /* Save state before deleting the session, as that causes some
843 windows to be destroyed before their visible state can be
844 saved.
846 save_ardour_state ();
848 if (_session) {
849 // _session->set_deletion_in_progress ();
850 _session->set_clean ();
851 _session->remove_pending_capture_state ();
852 delete _session;
853 _session = 0;
856 ArdourDialog::close_all_dialogs ();
857 engine->stop (true);
858 quit ();
862 ARDOUR_UI::ask_about_saving_session (const string & what)
864 ArdourDialog window (_("Unsaved Session"));
865 Gtk::HBox dhbox; // the hbox for the image and text
866 Gtk::Label prompt_label;
867 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
869 string msg;
871 msg = string_compose(_("Don't %1"), what);
872 window.add_button (msg, RESPONSE_REJECT);
873 msg = string_compose(_("Just %1"), what);
874 window.add_button (msg, RESPONSE_APPLY);
875 msg = string_compose(_("Save and %1"), what);
876 window.add_button (msg, RESPONSE_ACCEPT);
878 window.set_default_response (RESPONSE_ACCEPT);
880 Gtk::Button noquit_button (msg);
881 noquit_button.set_name ("EditorGTKButton");
883 string prompt;
884 string type;
886 if (_session->snap_name() == _session->name()) {
887 type = _("session");
888 } else {
889 type = _("snapshot");
891 prompt = string_compose(_("The %1 \"%2\"\nhas not been saved.\n\nAny changes made this time\nwill be lost unless you save it.\n\nWhat do you want to do?"),
892 type, _session->snap_name());
894 prompt_label.set_text (prompt);
895 prompt_label.set_name (X_("PrompterLabel"));
896 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
898 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
899 dhbox.set_homogeneous (false);
900 dhbox.pack_start (*dimage, false, false, 5);
901 dhbox.pack_start (prompt_label, true, false, 5);
902 window.get_vbox()->pack_start (dhbox);
904 window.set_name (_("Prompter"));
905 window.set_position (Gtk::WIN_POS_MOUSE);
906 window.set_modal (true);
907 window.set_resizable (false);
909 dhbox.show();
910 prompt_label.show();
911 dimage->show();
912 window.show();
913 window.set_keep_above (true);
914 window.present ();
916 ResponseType r = (ResponseType) window.run();
918 window.hide ();
920 switch (r) {
921 case RESPONSE_ACCEPT: // save and get out of here
922 return 1;
923 case RESPONSE_APPLY: // get out of here
924 return 0;
925 default:
926 break;
929 return -1;
932 gint
933 ARDOUR_UI::every_second ()
935 update_cpu_load ();
936 update_buffer_load ();
937 update_disk_space ();
938 return TRUE;
941 gint
942 ARDOUR_UI::every_point_one_seconds ()
944 update_speed_display ();
945 RapidScreenUpdate(); /* EMIT_SIGNAL */
946 return TRUE;
949 gint
950 ARDOUR_UI::every_point_zero_one_seconds ()
952 // august 2007: actual update frequency: 40Hz, not 100Hz
954 SuperRapidScreenUpdate(); /* EMIT_SIGNAL */
955 return TRUE;
958 void
959 ARDOUR_UI::update_sample_rate (framecnt_t)
961 char buf[32];
963 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
965 if (!engine->connected()) {
967 snprintf (buf, sizeof (buf), _("disconnected"));
969 } else {
971 framecnt_t rate = engine->frame_rate();
973 if (fmod (rate, 1000.0) != 0.0) {
974 snprintf (buf, sizeof (buf), _("%.1f kHz / %4.1f ms"),
975 (float) rate/1000.0f,
976 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
977 } else {
978 snprintf (buf, sizeof (buf), _("%" PRId64 " kHz / %4.1f ms"),
979 rate/1000,
980 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
984 sample_rate_label.set_text (buf);
987 void
988 ARDOUR_UI::update_cpu_load ()
990 char buf[32];
991 snprintf (buf, sizeof (buf), _("DSP: %5.1f%%"), engine->get_cpu_load());
992 cpu_load_label.set_text (buf);
995 void
996 ARDOUR_UI::update_buffer_load ()
998 char buf[64];
999 uint32_t c, p;
1001 if (_session) {
1002 c = _session->capture_load ();
1003 p = _session->playback_load ();
1005 snprintf (buf, sizeof (buf), _("Buffers p:%" PRIu32 "%% c:%" PRIu32 "%%"),
1006 _session->playback_load(), _session->capture_load());
1007 buffer_load_label.set_text (buf);
1008 } else {
1009 buffer_load_label.set_text ("");
1013 void
1014 ARDOUR_UI::count_recenabled_streams (Route& route)
1016 Track* track = dynamic_cast<Track*>(&route);
1017 if (track && track->record_enabled()) {
1018 rec_enabled_streams += track->n_inputs().n_total();
1022 void
1023 ARDOUR_UI::update_disk_space()
1025 if (_session == 0) {
1026 return;
1029 framecnt_t frames = _session->available_capture_duration();
1030 char buf[64];
1031 framecnt_t fr = _session->frame_rate();
1033 if (frames == max_framecnt) {
1034 strcpy (buf, _("Disk: 24hrs+"));
1035 } else {
1036 rec_enabled_streams = 0;
1037 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams);
1039 if (rec_enabled_streams) {
1040 frames /= rec_enabled_streams;
1043 int hrs;
1044 int mins;
1045 int secs;
1047 hrs = frames / (fr * 3600);
1048 frames -= hrs * fr * 3600;
1049 mins = frames / (fr * 60);
1050 frames -= mins * fr * 60;
1051 secs = frames / fr;
1053 snprintf (buf, sizeof(buf), _("Disk: %02dh:%02dm:%02ds"), hrs, mins, secs);
1056 disk_space_label.set_text (buf);
1058 // An attempt to make the disk space label flash red when space has run out.
1060 if (frames < fr * 60 * 5) {
1061 /* disk_space_box.style ("disk_space_label_empty"); */
1062 } else {
1063 /* disk_space_box.style ("disk_space_label"); */
1068 gint
1069 ARDOUR_UI::update_wall_clock ()
1071 time_t now;
1072 struct tm *tm_now;
1073 char buf[16];
1075 time (&now);
1076 tm_now = localtime (&now);
1078 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1079 wall_clock_label.set_text (buf);
1081 return TRUE;
1084 gint
1085 ARDOUR_UI::session_menu (GdkEventButton */*ev*/)
1087 session_popup_menu->popup (0, 0);
1088 return TRUE;
1091 void
1092 ARDOUR_UI::redisplay_recent_sessions ()
1094 std::vector<sys::path> session_directories;
1095 RecentSessionsSorter cmp;
1097 recent_session_display.set_model (Glib::RefPtr<TreeModel>(0));
1098 recent_session_model->clear ();
1100 ARDOUR::RecentSessions rs;
1101 ARDOUR::read_recent_sessions (rs);
1103 if (rs.empty()) {
1104 recent_session_display.set_model (recent_session_model);
1105 return;
1108 // sort them alphabetically
1109 sort (rs.begin(), rs.end(), cmp);
1111 for (ARDOUR::RecentSessions::iterator i = rs.begin(); i != rs.end(); ++i) {
1112 session_directories.push_back ((*i).second);
1115 for (vector<sys::path>::const_iterator i = session_directories.begin();
1116 i != session_directories.end(); ++i)
1118 std::vector<sys::path> state_file_paths;
1120 // now get available states for this session
1122 get_state_files_in_directory (*i, state_file_paths);
1124 vector<string*>* states;
1125 vector<const gchar*> item;
1126 string fullpath = (*i).to_string();
1128 /* remove any trailing / */
1130 if (fullpath[fullpath.length()-1] == '/') {
1131 fullpath = fullpath.substr (0, fullpath.length()-1);
1134 /* check whether session still exists */
1135 if (!Glib::file_test(fullpath.c_str(), Glib::FILE_TEST_EXISTS)) {
1136 /* session doesn't exist */
1137 cerr << "skipping non-existent session " << fullpath << endl;
1138 continue;
1141 /* now get available states for this session */
1143 if ((states = Session::possible_states (fullpath)) == 0) {
1144 /* no state file? */
1145 continue;
1148 std::vector<string> state_file_names(get_file_names_no_extension (state_file_paths));
1150 Gtk::TreeModel::Row row = *(recent_session_model->append());
1152 row[recent_session_columns.visible_name] = Glib::path_get_basename (fullpath);
1153 row[recent_session_columns.fullpath] = fullpath;
1155 if (state_file_names.size() > 1) {
1157 // add the children
1159 for (std::vector<std::string>::iterator i2 = state_file_names.begin();
1160 i2 != state_file_names.end(); ++i2)
1163 Gtk::TreeModel::Row child_row = *(recent_session_model->append (row.children()));
1165 child_row[recent_session_columns.visible_name] = *i2;
1166 child_row[recent_session_columns.fullpath] = fullpath;
1171 recent_session_display.set_model (recent_session_model);
1174 void
1175 ARDOUR_UI::build_session_selector ()
1177 session_selector_window = new ArdourDialog (_("Recent Sessions"));
1179 Gtk::ScrolledWindow *scroller = manage (new Gtk::ScrolledWindow);
1181 session_selector_window->add_button (Stock::CANCEL, RESPONSE_CANCEL);
1182 session_selector_window->add_button (Stock::OPEN, RESPONSE_ACCEPT);
1183 session_selector_window->set_default_response (RESPONSE_ACCEPT);
1184 recent_session_model = TreeStore::create (recent_session_columns);
1185 recent_session_display.set_model (recent_session_model);
1186 recent_session_display.append_column (_("Recent Sessions"), recent_session_columns.visible_name);
1187 recent_session_display.set_headers_visible (false);
1188 recent_session_display.get_selection()->set_mode (SELECTION_BROWSE);
1189 recent_session_display.signal_row_activated().connect (sigc::mem_fun (*this, &ARDOUR_UI::recent_session_row_activated));
1191 scroller->add (recent_session_display);
1192 scroller->set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
1194 session_selector_window->set_name ("SessionSelectorWindow");
1195 session_selector_window->set_size_request (200, 400);
1196 session_selector_window->get_vbox()->pack_start (*scroller);
1198 recent_session_display.show();
1199 scroller->show();
1200 //session_selector_window->get_vbox()->show();
1203 void
1204 ARDOUR_UI::recent_session_row_activated (const TreePath& /*path*/, TreeViewColumn* /*col*/)
1206 session_selector_window->response (RESPONSE_ACCEPT);
1209 void
1210 ARDOUR_UI::open_recent_session ()
1212 bool can_return = (_session != 0);
1214 if (session_selector_window == 0) {
1215 build_session_selector ();
1218 redisplay_recent_sessions ();
1220 while (true) {
1222 session_selector_window->set_position (WIN_POS_MOUSE);
1224 ResponseType r = (ResponseType) session_selector_window->run ();
1226 switch (r) {
1227 case RESPONSE_ACCEPT:
1228 break;
1229 default:
1230 if (can_return) {
1231 session_selector_window->hide();
1232 return;
1233 } else {
1234 exit (1);
1238 if (recent_session_display.get_selection()->count_selected_rows() == 0) {
1239 continue;
1242 session_selector_window->hide();
1244 Gtk::TreeModel::iterator i = recent_session_display.get_selection()->get_selected();
1246 if (i == recent_session_model->children().end()) {
1247 return;
1250 std::string path = (*i)[recent_session_columns.fullpath];
1251 std::string state = (*i)[recent_session_columns.visible_name];
1253 _session_is_new = false;
1255 if (load_session (path, state) == 0) {
1256 break;
1259 can_return = false;
1263 bool
1264 ARDOUR_UI::check_audioengine ()
1266 if (engine) {
1267 if (!engine->connected()) {
1268 MessageDialog msg (string_compose (_("%1 is not connected to JACK\n"
1269 "You cannot open or close sessions in this condition"),
1270 PROGRAM_NAME));
1271 pop_back_splash ();
1272 msg.run ();
1273 return false;
1275 return true;
1276 } else {
1277 return false;
1281 void
1282 ARDOUR_UI::open_session ()
1284 if (!check_audioengine()) {
1285 return;
1289 /* popup selector window */
1291 if (open_session_selector == 0) {
1293 /* ardour sessions are folders */
1295 open_session_selector = new Gtk::FileChooserDialog (_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1296 open_session_selector->add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1297 open_session_selector->add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1298 open_session_selector->set_default_response(Gtk::RESPONSE_ACCEPT);
1300 FileFilter session_filter;
1301 session_filter.add_pattern ("*.ardour");
1302 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1303 open_session_selector->add_filter (session_filter);
1304 open_session_selector->set_filter (session_filter);
1307 int response = open_session_selector->run();
1308 open_session_selector->hide ();
1310 switch (response) {
1311 case RESPONSE_ACCEPT:
1312 break;
1313 default:
1314 open_session_selector->hide();
1315 return;
1318 open_session_selector->hide();
1319 string session_path = open_session_selector->get_filename();
1320 string path, name;
1321 bool isnew;
1323 if (session_path.length() > 0) {
1324 if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1325 _session_is_new = isnew;
1326 load_session (path, name);
1332 void
1333 ARDOUR_UI::session_add_midi_route (bool disk, RouteGroup* route_group, uint32_t how_many)
1335 list<boost::shared_ptr<MidiTrack> > tracks;
1337 if (_session == 0) {
1338 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1339 return;
1342 try {
1343 if (disk) {
1345 tracks = _session->new_midi_track (ARDOUR::Normal, route_group, how_many);
1347 if (tracks.size() != how_many) {
1348 if (how_many == 1) {
1349 error << _("could not create a new midi track") << endmsg;
1350 } else {
1351 error << string_compose (_("could not create %1 new midi tracks"), how_many) << endmsg;
1354 } /*else {
1355 if ((route = _session->new_midi_route ()) == 0) {
1356 error << _("could not create new midi bus") << endmsg;
1361 catch (...) {
1362 MessageDialog msg (*editor,
1363 string_compose (_("There are insufficient JACK ports available\n\
1364 to create a new track or bus.\n\
1365 You should save %1, exit and\n\
1366 restart JACK with more ports."), PROGRAM_NAME));
1367 msg.run ();
1372 void
1373 ARDOUR_UI::session_add_audio_route (bool track, bool aux, int32_t input_channels, int32_t output_channels, ARDOUR::TrackMode mode, RouteGroup* route_group, uint32_t how_many)
1375 list<boost::shared_ptr<AudioTrack> > tracks;
1376 RouteList routes;
1378 if (_session == 0) {
1379 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1380 return;
1383 try {
1384 if (track) {
1385 tracks = _session->new_audio_track (input_channels, output_channels, mode, route_group, how_many);
1387 if (tracks.size() != how_many) {
1388 if (how_many == 1) {
1389 error << _("could not create a new audio track") << endmsg;
1390 } else {
1391 error << string_compose (_("could only create %1 of %2 new audio %3"),
1392 tracks.size(), how_many, (track ? _("tracks") : _("busses"))) << endmsg;
1396 } else {
1398 routes = _session->new_audio_route (aux, input_channels, output_channels, route_group, how_many);
1400 if (routes.size() != how_many) {
1401 if (how_many == 1) {
1402 error << _("could not create a new audio track") << endmsg;
1403 } else {
1404 error << string_compose (_("could not create %1 new audio tracks"), how_many) << 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 pop_back_splash ();
1417 msg.run ();
1421 void
1422 ARDOUR_UI::do_transport_locate (framepos_t new_position, bool with_roll)
1424 framecnt_t _preroll = 0;
1426 if (_session) {
1427 // XXX CONFIG_CHANGE FIX - requires AnyTime handling
1428 // _preroll = _session->convert_to_frames_at (new_position, Config->get_preroll());
1430 if (new_position > _preroll) {
1431 new_position -= _preroll;
1432 } else {
1433 new_position = 0;
1436 _session->request_locate (new_position, with_roll);
1440 void
1441 ARDOUR_UI::transport_goto_start ()
1443 if (_session) {
1444 _session->goto_start();
1446 /* force displayed area in editor to start no matter
1447 what "follow playhead" setting is.
1450 if (editor) {
1451 editor->center_screen (_session->current_start_frame ());
1456 void
1457 ARDOUR_UI::transport_goto_zero ()
1459 if (_session) {
1460 _session->request_locate (0);
1462 /* force displayed area in editor to start no matter
1463 what "follow playhead" setting is.
1466 if (editor) {
1467 editor->reset_x_origin (0);
1472 void
1473 ARDOUR_UI::transport_goto_wallclock ()
1475 if (_session && editor) {
1477 time_t now;
1478 struct tm tmnow;
1479 framepos_t frames;
1481 time (&now);
1482 localtime_r (&now, &tmnow);
1484 frames = tmnow.tm_hour * (60 * 60 * _session->frame_rate());
1485 frames += tmnow.tm_min * (60 * _session->frame_rate());
1486 frames += tmnow.tm_sec * _session->frame_rate();
1488 _session->request_locate (frames, _session->transport_rolling ());
1490 /* force displayed area in editor to start no matter
1491 what "follow playhead" setting is.
1494 if (editor) {
1495 editor->center_screen (frames);
1500 void
1501 ARDOUR_UI::transport_goto_end ()
1503 if (_session) {
1504 framepos_t const frame = _session->current_end_frame();
1505 _session->request_locate (frame);
1507 /* force displayed area in editor to start no matter
1508 what "follow playhead" setting is.
1511 if (editor) {
1512 editor->center_screen (frame);
1517 void
1518 ARDOUR_UI::transport_stop ()
1520 if (!_session) {
1521 return;
1524 if (_session->is_auditioning()) {
1525 _session->cancel_audition ();
1526 return;
1529 _session->request_stop (false, true);
1532 void
1533 ARDOUR_UI::transport_stop_and_forget_capture ()
1535 if (_session) {
1536 _session->request_stop (true, true);
1540 void
1541 ARDOUR_UI::remove_last_capture()
1543 if (editor) {
1544 editor->remove_last_capture();
1548 void
1549 ARDOUR_UI::transport_record (bool roll)
1552 if (_session) {
1553 switch (_session->record_status()) {
1554 case Session::Disabled:
1555 if (_session->ntracks() == 0) {
1556 MessageDialog msg (*editor, _("Please create 1 or more track\nbefore trying to record.\nCheck the Session menu."));
1557 msg.run ();
1558 return;
1560 _session->maybe_enable_record ();
1561 if (roll) {
1562 transport_roll ();
1564 break;
1565 case Session::Recording:
1566 if (roll) {
1567 _session->request_stop();
1568 } else {
1569 _session->disable_record (false, true);
1571 break;
1573 case Session::Enabled:
1574 _session->disable_record (false, true);
1577 //cerr << "ARDOUR_UI::transport_record () called roll = " << roll << " _session->record_status() = " << _session->record_status() << endl;
1580 void
1581 ARDOUR_UI::transport_roll ()
1583 if (!_session) {
1584 return;
1587 if (_session->is_auditioning()) {
1588 return;
1591 #if 0
1592 if (_session->config.get_external_sync()) {
1593 switch (_session->config.get_sync_source()) {
1594 case JACK:
1595 break;
1596 default:
1597 /* transport controlled by the master */
1598 return;
1601 #endif
1603 bool rolling = _session->transport_rolling();
1605 if (_session->get_play_loop()) {
1606 /* XXX it is not possible to just leave seamless loop and keep
1607 playing at present (nov 4th 2009)
1609 if (!Config->get_seamless_loop()) {
1610 _session->request_play_loop (false, true);
1612 } else if (_session->get_play_range () && !join_play_range_button.get_active()) {
1613 /* stop playing a range if we currently are */
1614 _session->request_play_range (0, true);
1617 if (join_play_range_button.get_active()) {
1618 _session->request_play_range (&editor->get_selection().time, true);
1621 if (!rolling) {
1622 _session->request_transport_speed (1.0f);
1626 void
1627 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
1630 if (!_session) {
1631 return;
1634 if (_session->is_auditioning()) {
1635 _session->cancel_audition ();
1636 return;
1639 #if 0
1640 if (_session->config.get_external_sync()) {
1641 switch (_session->config.get_sync_source()) {
1642 case JACK:
1643 break;
1644 default:
1645 /* transport controlled by the master */
1646 return;
1649 #endif
1651 bool rolling = _session->transport_rolling();
1652 bool affect_transport = true;
1654 if (rolling && roll_out_of_bounded_mode) {
1655 /* drop out of loop/range playback but leave transport rolling */
1656 if (_session->get_play_loop()) {
1657 if (Config->get_seamless_loop()) {
1658 /* the disk buffers contain copies of the loop - we can't
1659 just keep playing, so stop the transport. the user
1660 can restart as they wish.
1662 affect_transport = true;
1663 } else {
1664 /* disk buffers are normal, so we can keep playing */
1665 affect_transport = false;
1667 _session->request_play_loop (false, true);
1668 } else if (_session->get_play_range ()) {
1669 affect_transport = false;
1670 _session->request_play_range (0, true);
1674 if (affect_transport) {
1675 if (rolling) {
1676 _session->request_stop (with_abort, true);
1677 } else {
1678 if (join_play_range_button.get_active()) {
1679 _session->request_play_range (&editor->get_selection().time, true);
1682 _session->request_transport_speed (1.0f);
1687 void
1688 ARDOUR_UI::toggle_session_auto_loop ()
1690 if (_session) {
1691 if (_session->get_play_loop()) {
1692 if (_session->transport_rolling()) {
1693 Location * looploc = _session->locations()->auto_loop_location();
1694 if (looploc) {
1695 _session->request_locate (looploc->start(), true);
1697 } else {
1698 _session->request_play_loop (false);
1700 } else {
1701 Location * looploc = _session->locations()->auto_loop_location();
1702 if (looploc) {
1703 _session->request_play_loop (true);
1709 void
1710 ARDOUR_UI::transport_play_selection ()
1712 if (!_session) {
1713 return;
1716 editor->play_selection ();
1719 void
1720 ARDOUR_UI::transport_rewind (int option)
1722 float current_transport_speed;
1724 if (_session) {
1725 current_transport_speed = _session->transport_speed();
1727 if (current_transport_speed >= 0.0f) {
1728 switch (option) {
1729 case 0:
1730 _session->request_transport_speed (-1.0f);
1731 break;
1732 case 1:
1733 _session->request_transport_speed (-4.0f);
1734 break;
1735 case -1:
1736 _session->request_transport_speed (-0.5f);
1737 break;
1739 } else {
1740 /* speed up */
1741 _session->request_transport_speed (current_transport_speed * 1.5f);
1746 void
1747 ARDOUR_UI::transport_forward (int option)
1749 float current_transport_speed;
1751 if (_session) {
1752 current_transport_speed = _session->transport_speed();
1754 if (current_transport_speed <= 0.0f) {
1755 switch (option) {
1756 case 0:
1757 _session->request_transport_speed (1.0f);
1758 break;
1759 case 1:
1760 _session->request_transport_speed (4.0f);
1761 break;
1762 case -1:
1763 _session->request_transport_speed (0.5f);
1764 break;
1766 } else {
1767 /* speed up */
1768 _session->request_transport_speed (current_transport_speed * 1.5f);
1774 void
1775 ARDOUR_UI::toggle_record_enable (uint32_t rid)
1777 if (_session == 0) {
1778 return;
1781 boost::shared_ptr<Route> r;
1783 if ((r = _session->route_by_remote_id (rid)) != 0) {
1785 Track* t;
1787 if ((t = dynamic_cast<Track*>(r.get())) != 0) {
1788 t->set_record_enabled (!t->record_enabled(), this);
1791 if (_session == 0) {
1792 return;
1796 void
1797 ARDOUR_UI::map_transport_state ()
1799 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::map_transport_state)
1801 if (!_session) {
1802 auto_loop_button.set_visual_state (0);
1803 play_selection_button.set_visual_state (0);
1804 roll_button.set_visual_state (0);
1805 stop_button.set_visual_state (1);
1806 return;
1809 float sp = _session->transport_speed();
1811 if (sp == 1.0f) {
1812 shuttle_fract = SHUTTLE_FRACT_SPEED1; /* speed = 1.0, believe it or not */
1813 shuttle_box.queue_draw ();
1814 } else if (sp == 0.0f) {
1815 shuttle_fract = 0;
1816 shuttle_box.queue_draw ();
1817 update_disk_space ();
1820 if (sp != 0.0) {
1822 /* we're rolling */
1824 if (_session->get_play_range()) {
1826 play_selection_button.set_visual_state (1);
1827 roll_button.set_visual_state (0);
1828 auto_loop_button.set_visual_state (0);
1830 } else if (_session->get_play_loop ()) {
1832 auto_loop_button.set_visual_state (1);
1833 play_selection_button.set_visual_state (0);
1834 roll_button.set_visual_state (0);
1836 } else {
1838 roll_button.set_visual_state (1);
1839 play_selection_button.set_visual_state (0);
1840 auto_loop_button.set_visual_state (0);
1843 if (join_play_range_button.get_active()) {
1844 /* light up both roll and play-selection if they are joined */
1845 roll_button.set_visual_state (1);
1846 play_selection_button.set_visual_state (1);
1849 stop_button.set_visual_state (0);
1851 } else {
1853 stop_button.set_visual_state (1);
1854 roll_button.set_visual_state (0);
1855 play_selection_button.set_visual_state (0);
1856 auto_loop_button.set_visual_state (0);
1860 void
1861 ARDOUR_UI::engine_stopped ()
1863 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
1864 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1865 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1868 void
1869 ARDOUR_UI::engine_running ()
1871 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
1872 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, true);
1873 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, false);
1875 Glib::RefPtr<Action> action;
1876 const char* action_name = 0;
1878 switch (engine->frames_per_cycle()) {
1879 case 32:
1880 action_name = X_("JACKLatency32");
1881 break;
1882 case 64:
1883 action_name = X_("JACKLatency64");
1884 break;
1885 case 128:
1886 action_name = X_("JACKLatency128");
1887 break;
1888 case 512:
1889 action_name = X_("JACKLatency512");
1890 break;
1891 case 1024:
1892 action_name = X_("JACKLatency1024");
1893 break;
1894 case 2048:
1895 action_name = X_("JACKLatency2048");
1896 break;
1897 case 4096:
1898 action_name = X_("JACKLatency4096");
1899 break;
1900 case 8192:
1901 action_name = X_("JACKLatency8192");
1902 break;
1903 default:
1904 /* XXX can we do anything useful ? */
1905 break;
1908 if (action_name) {
1910 action = ActionManager::get_action (X_("JACK"), action_name);
1912 if (action) {
1913 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (action);
1914 ract->set_active ();
1919 void
1920 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
1922 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
1923 /* we can't rely on the original string continuing to exist when we are called
1924 again in the GUI thread, so make a copy and note that we need to
1925 free it later.
1927 char *copy = strdup (reason);
1928 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
1929 return;
1932 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1933 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1935 update_sample_rate (0);
1937 string msgstr;
1939 /* if the reason is a non-empty string, it means that the backend was shutdown
1940 rather than just Ardour.
1943 if (strlen (reason)) {
1944 msgstr = string_compose (_("The audio backend (JACK) was shutdown because:\n\n%1"), reason);
1945 } else {
1946 msgstr = string_compose (_("\
1947 JACK has either been shutdown or it\n\
1948 disconnected %1 because %1\n\
1949 was not fast enough. Try to restart\n\
1950 JACK, reconnect and save the session."), PROGRAM_NAME);
1953 MessageDialog msg (*editor, msgstr);
1954 pop_back_splash ();
1955 msg.run ();
1957 if (free_reason) {
1958 free ((char*) reason);
1962 int32_t
1963 ARDOUR_UI::do_engine_start ()
1965 try {
1966 engine->start();
1969 catch (...) {
1970 engine->stop ();
1971 error << _("Unable to start the session running")
1972 << endmsg;
1973 unload_session ();
1974 return -2;
1977 return 0;
1980 void
1981 ARDOUR_UI::setup_theme ()
1983 theme_manager->setup_theme();
1986 void
1987 ARDOUR_UI::update_clocks ()
1989 if (!editor || !editor->dragging_playhead()) {
1990 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position()); /* EMIT_SIGNAL */
1994 void
1995 ARDOUR_UI::start_clocking ()
1997 clock_signal_connection = RapidScreenUpdate.connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2000 void
2001 ARDOUR_UI::stop_clocking ()
2003 clock_signal_connection.disconnect ();
2006 void
2007 ARDOUR_UI::toggle_clocking ()
2009 #if 0
2010 if (clock_button.get_active()) {
2011 start_clocking ();
2012 } else {
2013 stop_clocking ();
2015 #endif
2018 gint
2019 ARDOUR_UI::_blink (void *arg)
2022 ((ARDOUR_UI *) arg)->blink ();
2023 return TRUE;
2026 void
2027 ARDOUR_UI::blink ()
2029 Blink (blink_on = !blink_on); /* EMIT_SIGNAL */
2032 void
2033 ARDOUR_UI::start_blinking ()
2035 /* Start the blink signal. Everybody with a blinking widget
2036 uses Blink to drive the widget's state.
2039 if (blink_timeout_tag < 0) {
2040 blink_on = false;
2041 blink_timeout_tag = g_timeout_add (240, _blink, this);
2045 void
2046 ARDOUR_UI::stop_blinking ()
2048 if (blink_timeout_tag >= 0) {
2049 g_source_remove (blink_timeout_tag);
2050 blink_timeout_tag = -1;
2055 /** Ask the user for the name of a new shapshot and then take it.
2058 void
2059 ARDOUR_UI::snapshot_session (bool switch_to_it)
2061 ArdourPrompter prompter (true);
2062 string snapname;
2064 prompter.set_name ("Prompter");
2065 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2066 prompter.set_title (_("Take Snapshot"));
2067 prompter.set_title (_("Take Snapshot"));
2068 prompter.set_prompt (_("Name of new snapshot"));
2070 if (!switch_to_it) {
2071 char timebuf[128];
2072 time_t n;
2073 struct tm local_time;
2075 time (&n);
2076 localtime_r (&n, &local_time);
2077 strftime (timebuf, sizeof(timebuf), "%FT%T", &local_time);
2078 prompter.set_initial_text (timebuf);
2081 again:
2082 switch (prompter.run()) {
2083 case RESPONSE_ACCEPT:
2085 prompter.get_result (snapname);
2087 bool do_save = (snapname.length() != 0);
2089 if (do_save) {
2090 if (snapname.find ('/') != string::npos) {
2091 MessageDialog msg (_("To ensure compatibility with various systems\n"
2092 "snapshot names may not contain a '/' character"));
2093 msg.run ();
2094 goto again;
2096 if (snapname.find ('\\') != string::npos) {
2097 MessageDialog msg (_("To ensure compatibility with various systems\n"
2098 "snapshot names may not contain a '\\' character"));
2099 msg.run ();
2100 goto again;
2104 vector<sys::path> p;
2105 get_state_files_in_directory (_session->session_directory().root_path(), p);
2106 vector<string> n = get_file_names_no_extension (p);
2107 if (find (n.begin(), n.end(), snapname) != n.end()) {
2109 ArdourDialog confirm (_("Confirm Snapshot Overwrite"), true);
2110 Label m (_("A snapshot already exists with that name. Do you want to overwrite it?"));
2111 confirm.get_vbox()->pack_start (m, true, true);
2112 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2113 confirm.add_button (_("Overwrite"), Gtk::RESPONSE_ACCEPT);
2114 confirm.show_all ();
2115 switch (confirm.run()) {
2116 case RESPONSE_CANCEL:
2117 do_save = false;
2121 if (do_save) {
2122 save_state (snapname, switch_to_it);
2124 break;
2127 default:
2128 break;
2132 void
2133 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2135 XMLNode* node = new XMLNode (X_("UI"));
2137 for (list<WindowProxyBase*>::iterator i = _window_proxies.begin(); i != _window_proxies.end(); ++i) {
2138 if (!(*i)->rc_configured()) {
2139 node->add_child_nocopy (*((*i)->get_state ()));
2143 _session->add_extra_xml (*node);
2145 save_state_canfail (name, switch_to_it);
2149 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2151 if (_session) {
2152 int ret;
2154 if (name.length() == 0) {
2155 name = _session->snap_name();
2158 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2159 return ret;
2162 cerr << "SS canfail\n";
2163 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2164 return 0;
2167 void
2168 ARDOUR_UI::primary_clock_value_changed ()
2170 if (_session) {
2171 _session->request_locate (primary_clock.current_time ());
2175 void
2176 ARDOUR_UI::big_clock_value_changed ()
2178 if (_session) {
2179 _session->request_locate (big_clock.current_time ());
2183 void
2184 ARDOUR_UI::secondary_clock_value_changed ()
2186 if (_session) {
2187 _session->request_locate (secondary_clock.current_time ());
2191 void
2192 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2194 if (_session == 0) {
2195 return;
2198 if (_session->step_editing()) {
2199 return;
2202 Session::RecordState const r = _session->record_status ();
2203 bool const h = _session->have_rec_enabled_track ();
2205 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2206 if (onoff) {
2207 rec_button.set_visual_state (2);
2208 } else {
2209 rec_button.set_visual_state (0);
2211 } else if (r == Session::Recording && h) {
2212 rec_button.set_visual_state (1);
2213 } else {
2214 rec_button.set_visual_state (0);
2218 void
2219 ARDOUR_UI::save_template ()
2221 ArdourPrompter prompter (true);
2222 string name;
2224 if (!check_audioengine()) {
2225 return;
2228 prompter.set_name (X_("Prompter"));
2229 prompter.set_title (_("Save Mix Template"));
2230 prompter.set_prompt (_("Name for mix template:"));
2231 prompter.set_initial_text(_session->name() + _("-template"));
2232 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2234 switch (prompter.run()) {
2235 case RESPONSE_ACCEPT:
2236 prompter.get_result (name);
2238 if (name.length()) {
2239 _session->save_template (name);
2241 break;
2243 default:
2244 break;
2248 void
2249 ARDOUR_UI::edit_metadata ()
2251 SessionMetadataEditor dialog;
2252 dialog.set_session (_session);
2253 editor->ensure_float (dialog);
2254 dialog.run ();
2257 void
2258 ARDOUR_UI::import_metadata ()
2260 SessionMetadataImporter dialog;
2261 dialog.set_session (_session);
2262 editor->ensure_float (dialog);
2263 dialog.run ();
2266 void
2267 ARDOUR_UI::fontconfig_dialog ()
2269 #ifdef GTKOSX
2270 /* X11 users will always have fontconfig info around, but new GTK-OSX users
2271 may not and it can take a while to build it. Warn them.
2274 std::string fontconfig = Glib::build_filename (Glib::get_home_dir(), ".fontconfig");
2276 if (!Glib::file_test (fontconfig, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_DIR)) {
2277 MessageDialog msg (*_startup,
2278 string_compose (_("Welcome to %1.\n\n"
2279 "The program will take a bit longer to start up\n"
2280 "while the system fonts are checked.\n\n"
2281 "This will only be done once, and you will\n"
2282 "not see this message again\n"), PROGRAM_NAME),
2283 true,
2284 Gtk::MESSAGE_INFO,
2285 Gtk::BUTTONS_OK);
2286 pop_back_splash ();
2287 msg.show_all ();
2288 msg.present ();
2289 msg.run ();
2291 #endif
2294 void
2295 ARDOUR_UI::parse_cmdline_path (const std::string& cmdline_path, std::string& session_name, std::string& session_path, bool& existing_session)
2297 existing_session = false;
2299 if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_DIR)) {
2300 session_path = cmdline_path;
2301 existing_session = true;
2302 } else if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_REGULAR)) {
2303 session_path = Glib::path_get_dirname (string (cmdline_path));
2304 existing_session = true;
2305 } else {
2306 /* it doesn't exist, assume the best */
2307 session_path = Glib::path_get_dirname (string (cmdline_path));
2310 session_name = basename_nosuffix (string (cmdline_path));
2314 ARDOUR_UI::load_cmdline_session (const std::string& session_name, const std::string& session_path, bool& existing_session)
2316 /* when this is called, the backend audio system must be running */
2318 /* the main idea here is to deal with the fact that a cmdline argument for the session
2319 can be interpreted in different ways - it could be a directory or a file, and before
2320 we load, we need to know both the session directory and the snapshot (statefile) within it
2321 that we are supposed to use.
2324 if (session_name.length() == 0 || session_path.length() == 0) {
2325 return false;
2328 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_DIR)) {
2330 std::string predicted_session_file;
2332 predicted_session_file = session_path;
2333 predicted_session_file += '/';
2334 predicted_session_file += session_name;
2335 predicted_session_file += ARDOUR::statefile_suffix;
2337 if (Glib::file_test (predicted_session_file, Glib::FILE_TEST_EXISTS)) {
2338 existing_session = true;
2341 } else if (Glib::file_test (session_path, Glib::FILE_TEST_EXISTS)) {
2343 if (session_path.find (ARDOUR::statefile_suffix) == session_path.length() - 7) {
2344 /* existing .ardour file */
2345 existing_session = true;
2348 } else {
2349 existing_session = false;
2352 /* lets just try to load it */
2354 if (create_engine ()) {
2355 backend_audio_error (false, _startup);
2356 return -1;
2359 return load_session (session_path, session_name);
2362 bool
2363 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
2365 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2367 MessageDialog msg (str,
2368 false,
2369 Gtk::MESSAGE_WARNING,
2370 Gtk::BUTTONS_YES_NO,
2371 true);
2374 msg.set_name (X_("OpenExistingDialog"));
2375 msg.set_title (_("Open Existing Session"));
2376 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
2377 msg.set_position (Gtk::WIN_POS_MOUSE);
2378 pop_back_splash ();
2380 switch (msg.run()) {
2381 case RESPONSE_YES:
2382 return true;
2383 break;
2385 return false;
2389 ARDOUR_UI::build_session_from_nsd (const std::string& session_path, const std::string& session_name)
2391 BusProfile bus_profile;
2393 if (Profile->get_sae()) {
2395 bus_profile.master_out_channels = 2;
2396 bus_profile.input_ac = AutoConnectPhysical;
2397 bus_profile.output_ac = AutoConnectMaster;
2398 bus_profile.requested_physical_in = 0; // use all available
2399 bus_profile.requested_physical_out = 0; // use all available
2401 } else {
2403 /* get settings from advanced section of NSD */
2405 if (_startup->create_master_bus()) {
2406 bus_profile.master_out_channels = (uint32_t) _startup->master_channel_count();
2407 } else {
2408 bus_profile.master_out_channels = 0;
2411 if (_startup->connect_inputs()) {
2412 bus_profile.input_ac = AutoConnectPhysical;
2413 } else {
2414 bus_profile.input_ac = AutoConnectOption (0);
2417 /// @todo some minor tweaks.
2419 bus_profile.output_ac = AutoConnectOption (0);
2421 if (_startup->connect_outputs ()) {
2422 if (_startup->connect_outs_to_master()) {
2423 bus_profile.output_ac = AutoConnectMaster;
2424 } else if (_startup->connect_outs_to_physical()) {
2425 bus_profile.output_ac = AutoConnectPhysical;
2429 bus_profile.requested_physical_in = (uint32_t) _startup->input_limit_count();
2430 bus_profile.requested_physical_out = (uint32_t) _startup->output_limit_count();
2433 if (build_session (session_path, session_name, bus_profile)) {
2434 return -1;
2437 return 0;
2440 void
2441 ARDOUR_UI::idle_load (const std::string& path)
2443 if (_session) {
2444 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2445 /* /path/to/foo => /path/to/foo, foo */
2446 load_session (path, basename_nosuffix (path));
2447 } else {
2448 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2449 load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2451 } else {
2453 ARDOUR_COMMAND_LINE::session_name = path;
2456 * new_session_dialog doens't exist in A3
2457 * Try to remove all references to it to
2458 * see if it will compile. NOTE: this will
2459 * likely cause a runtime issue is my somewhat
2460 * uneducated guess.
2463 //if (new_session_dialog) {
2466 /* make it break out of Dialog::run() and
2467 start again.
2470 //new_session_dialog->response (1);
2475 void
2476 ARDOUR_UI::end_loading_messages ()
2478 // hide_splash ();
2481 void
2482 ARDOUR_UI::loading_message (const std::string& /*msg*/)
2484 // show_splash ();
2485 // splash->message (msg);
2486 flush_pending ();
2489 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
2491 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
2493 string session_name;
2494 string session_path;
2495 string template_name;
2496 int ret = -1;
2497 bool likely_new = false;
2499 if (! load_template.empty()) {
2500 should_be_new = true;
2501 template_name = load_template;
2504 while (ret != 0) {
2506 if (!should_be_new && !ARDOUR_COMMAND_LINE::session_name.empty()) {
2508 /* if they named a specific statefile, use it, otherwise they are
2509 just giving a session folder, and we want to use it as is
2510 to find the session.
2513 if (ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix) != string::npos) {
2514 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
2515 } else {
2516 session_path = ARDOUR_COMMAND_LINE::session_name;
2519 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
2521 } else {
2523 bool const apply = run_startup (should_be_new, load_template);
2525 if (!apply) {
2526 if (quit_on_cancel) {
2527 exit (1);
2528 } else {
2529 return ret;
2533 /* if we run the startup dialog again, offer more than just "new session" */
2535 should_be_new = false;
2537 session_name = _startup->session_name (likely_new);
2539 /* this shouldn't happen, but we catch it just in case it does */
2541 if (session_name.empty()) {
2542 continue;
2545 if (_startup->use_session_template()) {
2546 template_name = _startup->session_template_name();
2547 _session_is_new = true;
2550 if (session_name[0] == G_DIR_SEPARATOR ||
2551 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
2552 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)) {
2554 /* absolute path or cwd-relative path specified for session name: infer session folder
2555 from what was given.
2558 session_path = Glib::path_get_dirname (session_name);
2559 session_name = Glib::path_get_basename (session_name);
2561 } else {
2563 session_path = _startup->session_folder();
2565 if (session_name.find ('/') != string::npos) {
2566 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2567 "session names may not contain a '/' character"));
2568 msg.run ();
2569 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2570 continue;
2573 if (session_name.find ('\\') != string::npos) {
2574 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2575 "session names may not contain a '\\' character"));
2576 msg.run ();
2577 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2578 continue;
2583 if (create_engine ()) {
2584 break;
2587 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
2589 if (likely_new) {
2591 std::string existing = Glib::build_filename (session_path, session_name);
2593 if (!ask_about_loading_existing_session (existing)) {
2594 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2595 continue;
2599 _session_is_new = false;
2601 } else {
2603 if (!likely_new) {
2604 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
2605 msg.run ();
2606 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2607 continue;
2610 if (session_name.find ('/') != std::string::npos) {
2611 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2612 "session names may not contain a '/' character"));
2613 msg.run ();
2614 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2615 continue;
2618 if (session_name.find ('\\') != std::string::npos) {
2619 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2620 "session names may not contain a '\\' character"));
2621 msg.run ();
2622 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2623 continue;
2626 _session_is_new = true;
2629 if (likely_new && template_name.empty()) {
2631 ret = build_session_from_nsd (session_path, session_name);
2633 } else {
2635 ret = load_session (session_path, session_name, template_name);
2636 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
2637 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
2638 exit (1);
2643 return ret;
2646 void
2647 ARDOUR_UI::close_session()
2649 if (!check_audioengine()) {
2650 return;
2653 if (unload_session (true)) {
2654 return;
2657 ARDOUR_COMMAND_LINE::session_name = "";
2659 if (get_session_parameters (true, false)) {
2660 exit (1);
2663 goto_editor_window ();
2667 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
2669 Session *new_session;
2670 int unload_status;
2671 int retval = -1;
2673 session_loaded = false;
2675 if (!check_audioengine()) {
2676 return -1;
2679 unload_status = unload_session ();
2681 if (unload_status < 0) {
2682 goto out;
2683 } else if (unload_status > 0) {
2684 retval = 0;
2685 goto out;
2688 loading_message (string_compose (_("Please wait while %1loads your session"), PROGRAM_NAME));
2690 try {
2691 new_session = new Session (*engine, path, snap_name, 0, mix_template);
2694 /* this one is special */
2696 catch (AudioEngine::PortRegistrationFailure& err) {
2698 MessageDialog msg (err.what(),
2699 true,
2700 Gtk::MESSAGE_INFO,
2701 Gtk::BUTTONS_CLOSE);
2703 msg.set_title (_("Port Registration Error"));
2704 msg.set_secondary_text (_("Click the Close button to try again."));
2705 msg.set_position (Gtk::WIN_POS_CENTER);
2706 pop_back_splash ();
2707 msg.present ();
2709 int response = msg.run ();
2711 msg.hide ();
2713 switch (response) {
2714 case RESPONSE_CANCEL:
2715 exit (1);
2716 default:
2717 break;
2719 goto out;
2722 catch (...) {
2724 MessageDialog msg (string_compose(_("Session \"%1 (snapshot %2)\" did not load successfully"),path, snap_name),
2725 true,
2726 Gtk::MESSAGE_INFO,
2727 BUTTONS_OK);
2729 msg.set_title (_("Loading Error"));
2730 msg.set_secondary_text (_("Click the Refresh button to try again."));
2731 msg.add_button (Stock::REFRESH, 1);
2732 msg.set_position (Gtk::WIN_POS_CENTER);
2733 pop_back_splash ();
2734 msg.present ();
2736 int response = msg.run ();
2738 switch (response) {
2739 case 1:
2740 break;
2741 default:
2742 exit (1);
2745 msg.hide ();
2747 goto out;
2751 list<string> const u = new_session->unknown_processors ();
2752 if (!u.empty()) {
2753 MissingPluginDialog d (_session, u);
2754 d.run ();
2758 /* Now the session been created, add the transport controls */
2759 new_session->add_controllable(roll_controllable);
2760 new_session->add_controllable(stop_controllable);
2761 new_session->add_controllable(goto_start_controllable);
2762 new_session->add_controllable(goto_end_controllable);
2763 new_session->add_controllable(auto_loop_controllable);
2764 new_session->add_controllable(play_selection_controllable);
2765 new_session->add_controllable(rec_controllable);
2767 set_session (new_session);
2769 session_loaded = true;
2771 goto_editor_window ();
2773 if (_session) {
2774 _session->set_clean ();
2777 flush_pending ();
2778 retval = 0;
2780 out:
2781 return retval;
2785 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
2787 Session *new_session;
2788 int x;
2790 if (!check_audioengine()) {
2791 return -1;
2794 session_loaded = false;
2796 x = unload_session ();
2798 if (x < 0) {
2799 return -1;
2800 } else if (x > 0) {
2801 return 0;
2804 _session_is_new = true;
2806 try {
2807 new_session = new Session (*engine, path, snap_name, &bus_profile);
2810 catch (...) {
2812 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
2813 pop_back_splash ();
2814 msg.run ();
2815 return -1;
2818 /* Give the new session the default GUI state, if such things exist */
2820 XMLNode* n;
2821 n = Config->instant_xml (X_("Editor"));
2822 if (n) {
2823 new_session->add_instant_xml (*n, false);
2825 n = Config->instant_xml (X_("Mixer"));
2826 if (n) {
2827 new_session->add_instant_xml (*n, false);
2830 set_session (new_session);
2832 session_loaded = true;
2834 new_session->save_state(new_session->name());
2836 return 0;
2839 void
2840 ARDOUR_UI::launch_chat ()
2842 #ifdef __APPLE__
2843 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
2844 #else
2845 open_uri("http://webchat.freenode.net/?channels=ardour");
2846 #endif
2849 void
2850 ARDOUR_UI::show_about ()
2852 if (about == 0) {
2853 about = new About;
2854 about->signal_response().connect(sigc::mem_fun (*this, &ARDOUR_UI::about_signal_response) );
2857 about->set_transient_for(*editor);
2858 about->show_all ();
2861 void
2862 ARDOUR_UI::launch_manual ()
2864 PBD::open_uri("http://ardour.org/flossmanual");
2867 void
2868 ARDOUR_UI::launch_reference ()
2870 PBD::open_uri("http://ardour.org/refmanual");
2873 void
2874 ARDOUR_UI::hide_about ()
2876 if (about) {
2877 about->get_window()->set_cursor ();
2878 about->hide ();
2882 void
2883 ARDOUR_UI::about_signal_response (int /*response*/)
2885 hide_about();
2888 void
2889 ARDOUR_UI::show_splash ()
2891 if (splash == 0) {
2892 try {
2893 splash = new Splash;
2894 } catch (...) {
2895 return;
2899 splash->show ();
2900 splash->present ();
2901 splash->queue_draw ();
2902 splash->get_window()->process_updates (true);
2903 flush_pending ();
2906 void
2907 ARDOUR_UI::hide_splash ()
2909 if (splash) {
2910 splash->hide();
2914 void
2915 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title,
2916 const string& plural_msg, const string& singular_msg)
2918 size_t removed;
2920 removed = rep.paths.size();
2922 if (removed == 0) {
2923 MessageDialog msgd (*editor,
2924 _("No audio files were ready for cleanup"),
2925 true,
2926 Gtk::MESSAGE_INFO,
2927 (Gtk::ButtonsType)(Gtk::BUTTONS_OK) );
2928 msgd.set_secondary_text (_("If this seems suprising, \n\
2929 check for any existing snapshots.\n\
2930 These may still include regions that\n\
2931 require some unused files to continue to exist."));
2933 msgd.run ();
2934 return;
2937 ArdourDialog results (_("Clean-up"), true, false);
2939 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
2940 CleanupResultsModelColumns() {
2941 add (visible_name);
2942 add (fullpath);
2944 Gtk::TreeModelColumn<std::string> visible_name;
2945 Gtk::TreeModelColumn<std::string> fullpath;
2949 CleanupResultsModelColumns results_columns;
2950 Glib::RefPtr<Gtk::ListStore> results_model;
2951 Gtk::TreeView results_display;
2953 results_model = ListStore::create (results_columns);
2954 results_display.set_model (results_model);
2955 results_display.append_column (list_title, results_columns.visible_name);
2957 results_display.set_name ("CleanupResultsList");
2958 results_display.set_headers_visible (true);
2959 results_display.set_headers_clickable (false);
2960 results_display.set_reorderable (false);
2962 Gtk::ScrolledWindow list_scroller;
2963 Gtk::Label txt;
2964 Gtk::VBox dvbox;
2965 Gtk::HBox dhbox; // the hbox for the image and text
2966 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
2967 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
2969 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
2971 const string dead_sound_directory = _session->session_directory().dead_sound_path().to_string();
2973 /* subst:
2974 %1 - number of files removed
2975 %2 - location of "dead_sounds"
2976 %3 - size of files affected
2977 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
2980 const char* bprefix;
2981 double space_adjusted = 0;
2983 if (rep.space < 100000.0f) {
2984 bprefix = X_("kilo");
2985 } else if (rep.space < 1000000.0f * 1000) {
2986 bprefix = X_("mega");
2987 space_adjusted = truncf((float)rep.space / 1000.0);
2988 } else {
2989 bprefix = X_("giga");
2990 space_adjusted = truncf((float)rep.space / (1000000.0 * 1000));
2993 if (removed > 1) {
2994 txt.set_text (string_compose (plural_msg, removed, _session->path() + "dead_sounds", space_adjusted, bprefix));
2995 } else {
2996 txt.set_text (string_compose (singular_msg, removed, _session->path() + "dead_sounds", space_adjusted, bprefix));
2999 dhbox.pack_start (*dimage, true, false, 5);
3000 dhbox.pack_start (txt, true, false, 5);
3002 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
3003 TreeModel::Row row = *(results_model->append());
3004 row[results_columns.visible_name] = *i;
3005 row[results_columns.fullpath] = *i;
3008 list_scroller.add (results_display);
3009 list_scroller.set_size_request (-1, 150);
3010 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
3012 dvbox.pack_start (dhbox, true, false, 5);
3013 dvbox.pack_start (list_scroller, true, false, 5);
3014 ddhbox.pack_start (dvbox, true, false, 5);
3016 results.get_vbox()->pack_start (ddhbox, true, false, 5);
3017 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
3018 results.set_default_response (RESPONSE_CLOSE);
3019 results.set_position (Gtk::WIN_POS_MOUSE);
3021 results_display.show();
3022 list_scroller.show();
3023 txt.show();
3024 dvbox.show();
3025 dhbox.show();
3026 ddhbox.show();
3027 dimage->show();
3029 //results.get_vbox()->show();
3030 results.set_resizable (false);
3032 results.run ();
3036 void
3037 ARDOUR_UI::cleanup ()
3039 if (_session == 0) {
3040 /* shouldn't happen: menu item is insensitive */
3041 return;
3045 MessageDialog checker (_("Are you sure you want to cleanup?"),
3046 true,
3047 Gtk::MESSAGE_QUESTION,
3048 (Gtk::ButtonsType)(Gtk::BUTTONS_NONE));
3050 checker.set_secondary_text(_("Cleanup is a destructive operation.\n\
3051 ALL undo/redo information will be lost if you cleanup.\n\
3052 After cleanup, unused audio files will be moved to a \
3053 \"dead sounds\" location."));
3055 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3056 checker.add_button (_("Clean Up"), RESPONSE_ACCEPT);
3057 checker.set_default_response (RESPONSE_CANCEL);
3059 checker.set_name (_("CleanupDialog"));
3060 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3061 checker.set_position (Gtk::WIN_POS_MOUSE);
3063 switch (checker.run()) {
3064 case RESPONSE_ACCEPT:
3065 break;
3066 default:
3067 return;
3070 ARDOUR::CleanupReport rep;
3072 editor->prepare_for_cleanup ();
3074 /* do not allow flush until a session is reloaded */
3076 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3077 if (act) {
3078 act->set_sensitive (false);
3081 if (_session->cleanup_sources (rep)) {
3082 editor->finish_cleanup ();
3083 return;
3086 editor->finish_cleanup ();
3088 checker.hide();
3089 display_cleanup_results (rep,
3090 _("cleaned files"),
3091 _("\
3092 The following %1 files were not in use and \n\
3093 have been moved to:\n\
3094 %2. \n\n\
3095 Flushing the wastebasket will \n\
3096 release an additional\n\
3097 %3 %4bytes of disk space.\n"),
3098 _("\
3099 The following file was not in use and \n \
3100 has been moved to:\n \
3101 %2. \n\n\
3102 Flushing the wastebasket will \n\
3103 release an additional\n\
3104 %3 %4bytes of disk space.\n"
3109 void
3110 ARDOUR_UI::flush_trash ()
3112 if (_session == 0) {
3113 /* shouldn't happen: menu item is insensitive */
3114 return;
3117 ARDOUR::CleanupReport rep;
3119 if (_session->cleanup_trash_sources (rep)) {
3120 return;
3123 display_cleanup_results (rep,
3124 _("deleted file"),
3125 _("The following %1 files were deleted from\n\
3126 %2,\n\
3127 releasing %3 %4bytes of disk space"),
3128 _("The following file was deleted from\n\
3129 %2,\n\
3130 releasing %3 %4bytes of disk space"));
3133 void
3134 ARDOUR_UI::add_route (Gtk::Window* float_window)
3136 int count;
3138 if (!_session) {
3139 return;
3142 if (add_route_dialog == 0) {
3143 add_route_dialog = new AddRouteDialog (_session);
3144 if (float_window) {
3145 add_route_dialog->set_transient_for (*float_window);
3149 if (add_route_dialog->is_visible()) {
3150 /* we're already doing this */
3151 return;
3154 ResponseType r = (ResponseType) add_route_dialog->run ();
3156 add_route_dialog->hide();
3158 switch (r) {
3159 case RESPONSE_ACCEPT:
3160 break;
3161 default:
3162 return;
3163 break;
3166 if ((count = add_route_dialog->count()) <= 0) {
3167 return;
3170 string template_path = add_route_dialog->track_template();
3172 if (!template_path.empty()) {
3173 _session->new_route_from_template (count, template_path);
3174 return;
3177 uint32_t input_chan = add_route_dialog->channels ();
3178 uint32_t output_chan;
3179 string name_template = add_route_dialog->name_template ();
3180 bool track = add_route_dialog->track ();
3181 bool aux = !track && add_route_dialog->aux();
3182 RouteGroup* route_group = add_route_dialog->route_group ();
3184 AutoConnectOption oac = Config->get_output_auto_connect();
3186 if (oac & AutoConnectMaster) {
3187 output_chan = (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan);
3188 } else {
3189 output_chan = input_chan;
3192 /* XXX do something with name template */
3194 if (add_route_dialog->type() == ARDOUR::DataType::MIDI) {
3195 if (track) {
3196 session_add_midi_track (route_group, count);
3197 } else {
3198 MessageDialog msg (*editor,
3199 _("Sorry, MIDI Busses are not supported at this time."));
3200 msg.run ();
3201 //session_add_midi_bus();
3203 } else {
3204 if (track) {
3205 session_add_audio_track (input_chan, output_chan, add_route_dialog->mode(), route_group, count);
3206 } else {
3207 session_add_audio_bus (aux, input_chan, output_chan, route_group, count);
3212 XMLNode*
3213 ARDOUR_UI::mixer_settings () const
3215 XMLNode* node = 0;
3217 if (_session) {
3218 node = _session->instant_xml(X_("Mixer"));
3219 } else {
3220 node = Config->instant_xml(X_("Mixer"));
3223 if (!node) {
3224 node = new XMLNode (X_("Mixer"));
3227 return node;
3230 XMLNode*
3231 ARDOUR_UI::editor_settings () const
3233 XMLNode* node = 0;
3235 if (_session) {
3236 node = _session->instant_xml(X_("Editor"));
3237 } else {
3238 node = Config->instant_xml(X_("Editor"));
3241 if (!node) {
3242 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
3243 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
3247 if (!node) {
3248 node = new XMLNode (X_("Editor"));
3251 return node;
3254 XMLNode*
3255 ARDOUR_UI::keyboard_settings () const
3257 XMLNode* node = 0;
3259 node = Config->extra_xml(X_("Keyboard"));
3261 if (!node) {
3262 node = new XMLNode (X_("Keyboard"));
3264 return node;
3267 void
3268 ARDOUR_UI::create_xrun_marker (framepos_t where)
3270 editor->mouse_add_new_marker (where, false, true);
3273 void
3274 ARDOUR_UI::halt_on_xrun_message ()
3276 MessageDialog msg (*editor,
3277 _("Recording was stopped because your system could not keep up."));
3278 msg.run ();
3281 void
3282 ARDOUR_UI::xrun_handler (framepos_t where)
3284 if (!_session) {
3285 return;
3288 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
3290 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
3291 create_xrun_marker(where);
3294 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
3295 halt_on_xrun_message ();
3299 void
3300 ARDOUR_UI::disk_overrun_handler ()
3302 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
3304 if (!have_disk_speed_dialog_displayed) {
3305 have_disk_speed_dialog_displayed = true;
3306 MessageDialog* msg = new MessageDialog (*editor, string_compose (_("\
3307 The disk system on your computer\n\
3308 was not able to keep up with %1.\n\
3310 Specifically, it failed to write data to disk\n\
3311 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
3312 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3313 msg->show ();
3317 void
3318 ARDOUR_UI::disk_underrun_handler ()
3320 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
3322 if (!have_disk_speed_dialog_displayed) {
3323 have_disk_speed_dialog_displayed = true;
3324 MessageDialog* msg = new MessageDialog (*editor,
3325 string_compose (_("The disk system on your computer\n\
3326 was not able to keep up with %1.\n\
3328 Specifically, it failed to read data from disk\n\
3329 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
3330 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3331 msg->show ();
3335 void
3336 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
3338 have_disk_speed_dialog_displayed = false;
3339 delete msg;
3342 void
3343 ARDOUR_UI::session_dialog (std::string msg)
3345 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
3347 MessageDialog* d;
3349 if (editor) {
3350 d = new MessageDialog (*editor, msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3351 } else {
3352 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3355 d->show_all ();
3356 d->run ();
3357 delete d;
3361 ARDOUR_UI::pending_state_dialog ()
3363 HBox* hbox = new HBox();
3364 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3365 ArdourDialog dialog (_("Crash Recovery"), true);
3366 Label message (_("\
3367 This session appears to have been in\n\
3368 middle of recording when ardour or\n\
3369 the computer was shutdown.\n\
3371 Ardour can recover any captured audio for\n\
3372 you, or it can ignore it. Please decide\n\
3373 what you would like to do.\n"));
3374 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3375 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3376 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3377 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3378 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
3379 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
3380 dialog.set_default_response (RESPONSE_ACCEPT);
3381 dialog.set_position (WIN_POS_CENTER);
3382 message.show();
3383 image->show();
3384 hbox->show();
3386 switch (dialog.run ()) {
3387 case RESPONSE_ACCEPT:
3388 return 1;
3389 default:
3390 return 0;
3395 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
3397 HBox* hbox = new HBox();
3398 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3399 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
3400 Label message (string_compose (_("\
3401 This session was created with a sample rate of %1 Hz\n\
3403 The audioengine is currently running at %2 Hz\n"), desired, actual));
3405 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3406 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3407 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3408 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3409 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
3410 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
3411 dialog.set_default_response (RESPONSE_ACCEPT);
3412 dialog.set_position (WIN_POS_CENTER);
3413 message.show();
3414 image->show();
3415 hbox->show();
3417 switch (dialog.run ()) {
3418 case RESPONSE_ACCEPT:
3419 return 0;
3420 default:
3421 return 1;
3426 void
3427 ARDOUR_UI::disconnect_from_jack ()
3429 if (engine) {
3430 if( engine->disconnect_from_jack ()) {
3431 MessageDialog msg (*editor, _("Could not disconnect from JACK"));
3432 msg.run ();
3435 update_sample_rate (0);
3439 void
3440 ARDOUR_UI::reconnect_to_jack ()
3442 if (engine) {
3443 if (engine->reconnect_to_jack ()) {
3444 MessageDialog msg (*editor, _("Could not reconnect to JACK"));
3445 msg.run ();
3448 update_sample_rate (0);
3452 void
3453 ARDOUR_UI::use_config ()
3455 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
3456 if (node) {
3457 set_transport_controllable_state (*node);
3461 void
3462 ARDOUR_UI::update_transport_clocks (framepos_t pos)
3464 if (Config->get_primary_clock_delta_edit_cursor()) {
3465 primary_clock.set (pos, false, editor->get_preferred_edit_position(), 1);
3466 } else {
3467 primary_clock.set (pos, 0, true);
3470 if (Config->get_secondary_clock_delta_edit_cursor()) {
3471 secondary_clock.set (pos, false, editor->get_preferred_edit_position(), 2);
3472 } else {
3473 secondary_clock.set (pos);
3476 if (big_clock_window->get()) {
3477 big_clock.set (pos);
3482 void
3483 ARDOUR_UI::step_edit_status_change (bool yn)
3485 // XXX should really store pre-step edit status of things
3486 // we make insensitive
3488 if (yn) {
3489 rec_button.set_visual_state (3);
3490 rec_button.set_sensitive (false);
3491 } else {
3492 rec_button.set_visual_state (0);
3493 rec_button.set_sensitive (true);
3497 void
3498 ARDOUR_UI::record_state_changed ()
3500 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
3502 if (!_session || !big_clock_window->get()) {
3503 /* why bother - the clock isn't visible */
3504 return;
3507 Session::RecordState const r = _session->record_status ();
3508 bool const h = _session->have_rec_enabled_track ();
3510 if (r == Session::Recording && h) {
3511 big_clock.set_widget_name ("BigClockRecording");
3512 } else {
3513 big_clock.set_widget_name ("BigClockNonRecording");
3517 bool
3518 ARDOUR_UI::first_idle ()
3520 if (_session) {
3521 _session->allow_auto_play (true);
3524 if (editor) {
3525 editor->first_idle();
3528 Keyboard::set_can_save_keybindings (true);
3529 return false;
3532 void
3533 ARDOUR_UI::store_clock_modes ()
3535 XMLNode* node = new XMLNode(X_("ClockModes"));
3537 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
3538 node->add_property ((*x)->name().c_str(), enum_2_string ((*x)->mode()));
3541 _session->add_extra_xml (*node);
3542 _session->set_dirty ();
3547 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
3548 : Controllable (name), ui (u), type(tp)
3553 void
3554 ARDOUR_UI::TransportControllable::set_value (double val)
3556 if (type == ShuttleControl) {
3557 double fract;
3559 if (val == 0.5) {
3560 fract = 0.0;
3561 } else {
3562 if (val < 0.5) {
3563 fract = -((0.5 - val)/0.5);
3564 } else {
3565 fract = ((val - 0.5)/0.5);
3569 ui.set_shuttle_fract (fract);
3570 return;
3573 if (val < 0.5) {
3574 /* do nothing: these are radio-style actions */
3575 return;
3578 const char *action = 0;
3580 switch (type) {
3581 case Roll:
3582 action = X_("Roll");
3583 break;
3584 case Stop:
3585 action = X_("Stop");
3586 break;
3587 case GotoStart:
3588 action = X_("Goto Start");
3589 break;
3590 case GotoEnd:
3591 action = X_("Goto End");
3592 break;
3593 case AutoLoop:
3594 action = X_("Loop");
3595 break;
3596 case PlaySelection:
3597 action = X_("Play Selection");
3598 break;
3599 case RecordEnable:
3600 action = X_("Record");
3601 break;
3602 default:
3603 break;
3606 if (action == 0) {
3607 return;
3610 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
3612 if (act) {
3613 act->activate ();
3617 double
3618 ARDOUR_UI::TransportControllable::get_value (void) const
3620 float val = 0.0;
3622 switch (type) {
3623 case Roll:
3624 break;
3625 case Stop:
3626 break;
3627 case GotoStart:
3628 break;
3629 case GotoEnd:
3630 break;
3631 case AutoLoop:
3632 break;
3633 case PlaySelection:
3634 break;
3635 case RecordEnable:
3636 break;
3637 case ShuttleControl:
3638 break;
3639 default:
3640 break;
3643 return val;
3646 void
3647 ARDOUR_UI::TransportControllable::set_id (const string& str)
3649 _id = str;
3652 void
3653 ARDOUR_UI::setup_profile ()
3655 if (gdk_screen_width() < 1200) {
3656 Profile->set_small_screen ();
3660 if (getenv ("ARDOUR_SAE")) {
3661 Profile->set_sae ();
3662 Profile->set_single_package ();
3666 void
3667 ARDOUR_UI::toggle_translations ()
3669 using namespace Glib;
3671 RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("EnableTranslation"));
3672 if (act) {
3673 RefPtr<ToggleAction> ract = RefPtr<ToggleAction>::cast_dynamic (act);
3674 if (ract) {
3676 string i18n_killer = ARDOUR::translation_kill_path();
3678 bool already_enabled = !ARDOUR::translations_are_disabled ();
3680 if (ract->get_active ()) {
3681 /* we don't care about errors */
3682 int fd = ::open (i18n_killer.c_str(), O_RDONLY|O_CREAT, 0644);
3683 close (fd);
3684 } else {
3685 /* we don't care about errors */
3686 unlink (i18n_killer.c_str());
3689 if (already_enabled != ract->get_active()) {
3690 MessageDialog win (already_enabled ? _("Translations disabled") : _("Translations enabled"),
3691 false,
3692 Gtk::MESSAGE_WARNING,
3693 Gtk::BUTTONS_OK);
3694 win.set_secondary_text (string_compose (_("You must restart %1 for this to take effect."), PROGRAM_NAME));
3695 win.set_position (Gtk::WIN_POS_CENTER);
3696 win.present ();
3697 win.run ();
3703 /** Add a window proxy to our list, so that its state will be saved.
3704 * This call also causes the window to be created and opened if its
3705 * state was saved as `visible'.
3707 void
3708 ARDOUR_UI::add_window_proxy (WindowProxyBase* p)
3710 _window_proxies.push_back (p);
3711 p->maybe_show ();
3714 /** Remove a window proxy from our list. Must be called if a WindowProxy
3715 * is deleted, to prevent hanging pointers.
3717 void
3718 ARDOUR_UI::remove_window_proxy (WindowProxyBase* p)
3720 _window_proxies.remove (p);
3724 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
3726 MissingFileDialog dialog (s, str, type);
3728 dialog.show ();
3729 dialog.present ();
3731 int result = dialog.run ();
3732 dialog.hide ();
3734 switch (result) {
3735 case RESPONSE_OK:
3736 break;
3737 default:
3738 return 1; // quit entire session load
3741 result = dialog.get_action ();
3743 return result;
3747 ARDOUR_UI::ambiguous_file (std::string file, std::string path, std::vector<std::string> hits)
3749 AmbiguousFileDialog dialog (file, hits);
3751 dialog.show ();
3752 dialog.present ();
3754 dialog.run ();
3755 return dialog.get_which ();