prettification of vbap/2d panner GUI. lots of details still to fix. also signal place...
[ardour2.git] / gtk2_ardour / ardour_ui.cc
blob883071e725b3f5eb04c60dcb15bf3df44f26ece1
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 "about.h"
84 #include "actions.h"
85 #include "add_route_dialog.h"
86 #include "ambiguous_file_dialog.h"
87 #include "ardour_ui.h"
88 #include "audio_clock.h"
89 #include "bundle_manager.h"
90 #include "engine_dialog.h"
91 #include "gain_meter.h"
92 #include "global_port_matrix.h"
93 #include "gui_thread.h"
94 #include "keyboard.h"
95 #include "location_ui.h"
96 #include "missing_file_dialog.h"
97 #include "missing_plugin_dialog.h"
98 #include "mixer_ui.h"
99 #include "opts.h"
100 #include "processor_box.h"
101 #include "prompter.h"
102 #include "public_editor.h"
103 #include "route_time_axis.h"
104 #include "session_metadata_dialog.h"
105 #include "speaker_dialog.h"
106 #include "splash.h"
107 #include "startup.h"
108 #include "theme_manager.h"
109 #include "time_axis_view_item.h"
110 #include "utils.h"
111 #include "window_proxy.h"
113 #include "i18n.h"
115 using namespace ARDOUR;
116 using namespace PBD;
117 using namespace Gtkmm2ext;
118 using namespace Gtk;
120 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
121 UIConfiguration *ARDOUR_UI::ui_config = 0;
123 sigc::signal<void,bool> ARDOUR_UI::Blink;
124 sigc::signal<void> ARDOUR_UI::RapidScreenUpdate;
125 sigc::signal<void> ARDOUR_UI::SuperRapidScreenUpdate;
126 sigc::signal<void, framepos_t, bool, framepos_t> ARDOUR_UI::Clock;
128 bool could_be_a_valid_path (const string& path);
130 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[])
132 : Gtkmm2ext::UI (PROGRAM_NAME, argcp, argvp),
134 primary_clock (X_("primary"), false, X_("TransportClockDisplay"), true, true, false, true),
135 secondary_clock (X_("secondary"), false, X_("SecondaryClockDisplay"), true, true, false, true),
136 preroll_clock (X_("preroll"), false, X_("PreRollClock"), true, false, true),
137 postroll_clock (X_("postroll"), false, X_("PostRollClock"), true, false, true),
139 /* preroll stuff */
141 preroll_button (_("pre\nroll")),
142 postroll_button (_("post\nroll")),
144 /* big clock */
146 big_clock (X_("bigclock"), false, "BigClockNonRecording", true, true, false, false),
148 /* transport */
150 roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll)),
151 stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop)),
152 goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart)),
153 goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd)),
154 auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop)),
155 play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection)),
156 rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable)),
157 shuttle_controllable (new TransportControllable ("shuttle", *this, TransportControllable::ShuttleControl)),
158 shuttle_controller_binding_proxy (shuttle_controllable),
160 roll_button (roll_controllable),
161 stop_button (stop_controllable),
162 goto_start_button (goto_start_controllable),
163 goto_end_button (goto_end_controllable),
164 auto_loop_button (auto_loop_controllable),
165 play_selection_button (play_selection_controllable),
166 rec_button (rec_controllable),
168 shuttle_units_button (_("% ")),
170 punch_in_button (_("Punch In")),
171 punch_out_button (_("Punch Out")),
172 auto_return_button (_("Auto Return")),
173 auto_play_button (_("Auto Play")),
174 auto_input_button (_("Auto Input")),
175 click_button (_("Click")),
176 time_master_button (_("time\nmaster")),
178 auditioning_alert_button (_("AUDITION")),
179 solo_alert_button (_("SOLO")),
181 error_log_button (_("Errors"))
184 using namespace Gtk::Menu_Helpers;
186 Gtkmm2ext::init();
189 #ifdef TOP_MENUBAR
190 // _auto_display_errors = false;
192 * This was commented out as it wasn't defined
193 * in A3 IIRC. If this is not needed it should
194 * be completely removed.
196 #endif
198 about = 0;
199 splash = 0;
200 _startup = 0;
202 if (theArdourUI == 0) {
203 theArdourUI = this;
206 ui_config = new UIConfiguration();
207 theme_manager = new ThemeManager();
209 editor = 0;
210 mixer = 0;
211 editor = 0;
212 engine = 0;
213 _session_is_new = false;
214 big_clock_window = 0;
215 big_clock_height = 0;
216 big_clock_resize_in_progress = false;
217 session_selector_window = 0;
218 last_key_press_time = 0;
219 _will_create_new_session_automatically = false;
220 add_route_dialog = 0;
221 route_params = 0;
222 rc_option_editor = 0;
223 session_option_editor = 0;
224 location_ui = 0;
225 open_session_selector = 0;
226 have_configure_timeout = false;
227 have_disk_speed_dialog_displayed = false;
228 session_loaded = false;
229 last_speed_displayed = -1.0f;
230 ignore_dual_punch = false;
231 original_big_clock_width = -1;
232 original_big_clock_height = -1;
233 original_big_clock_font_size = 0;
235 roll_button.unset_flags (Gtk::CAN_FOCUS);
236 stop_button.unset_flags (Gtk::CAN_FOCUS);
237 goto_start_button.unset_flags (Gtk::CAN_FOCUS);
238 goto_end_button.unset_flags (Gtk::CAN_FOCUS);
239 auto_loop_button.unset_flags (Gtk::CAN_FOCUS);
240 play_selection_button.unset_flags (Gtk::CAN_FOCUS);
241 rec_button.unset_flags (Gtk::CAN_FOCUS);
243 last_configure_time= 0;
245 shuttle_grabbed = false;
246 shuttle_fract = 0.0;
247 shuttle_max_speed = 8.0f;
249 shuttle_style_menu = 0;
250 shuttle_unit_menu = 0;
252 // We do not have jack linked in yet so;
254 last_shuttle_request = last_peak_grab = 0; // get_microseconds();
256 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
257 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
259 /* handle dialog requests */
261 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
263 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
265 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
267 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
269 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
271 /* handle requests to quit (coming from JACK session) */
273 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::finish, this), gui_context ());
275 /* handle requests to deal with missing files */
277 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
279 /* and ambiguous files */
281 ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2, _3));
283 /* lets get this party started */
285 try {
286 if (ARDOUR::init (ARDOUR_COMMAND_LINE::use_vst, ARDOUR_COMMAND_LINE::try_hw_optimization)) {
287 throw failed_constructor ();
290 setup_gtk_ardour_enums ();
291 setup_profile ();
293 GainMeter::setup_slider_pix ();
294 RouteTimeAxisView::setup_slider_pix ();
295 SendProcessorEntry::setup_slider_pix ();
296 SessionEvent::create_per_thread_pool ("GUI", 512);
298 } catch (failed_constructor& err) {
299 error << string_compose (_("could not initialize %1."), PROGRAM_NAME) << endmsg;
300 // pass it on up
301 throw;
304 /* we like keyboards */
306 keyboard = new ArdourKeyboard(*this);
308 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
309 if (node) {
310 keyboard->set_state (*node, Stateful::loading_state_version);
313 reset_dpi();
315 TimeAxisViewItem::set_constant_heights ();
317 /* The following must happen after ARDOUR::init() so that Config is set up */
319 location_ui = new ActionWindowProxy<LocationUIWindow> (X_("locations"), Config->extra_xml (X_("UI")), X_("ToggleLocations"));
320 big_clock_window = new ActionWindowProxy<Gtk::Window> (X_("bigclock"), Config->extra_xml (X_("UI")), X_("ToggleBigClock"));
321 speaker_config_window = new ActionWindowProxy<SpeakerDialog> (X_("speakerconf"), Config->extra_xml (X_("UI")), X_("toggle-speaker-config"));
323 for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) {
324 _global_port_matrix[*i] = new ActionWindowProxy<GlobalPortMatrixWindow> (
325 string_compose ("GlobalPortMatrix-%1", (*i).to_string()),
326 Config->extra_xml (X_("UI")),
327 string_compose ("toggle-%1-connection-manager", (*i).to_string())
331 setup_clock ();
332 speaker_config_window->set (new SpeakerDialog);
334 starting.connect (sigc::mem_fun(*this, &ARDOUR_UI::startup));
335 stopping.connect (sigc::mem_fun(*this, &ARDOUR_UI::shutdown));
337 platform_setup ();
340 /** @return true if a session was chosen and `apply' clicked, otherwise false if `cancel' was clicked */
341 bool
342 ARDOUR_UI::run_startup (bool should_be_new, string load_template)
344 delete _startup;
345 _startup = new ArdourStartup ();
347 XMLNode* audio_setup = Config->extra_xml ("AudioSetup");
349 if (audio_setup && _startup->engine_control()) {
350 _startup->engine_control()->set_state (*audio_setup);
353 _startup->set_new_only (should_be_new);
354 if (!load_template.empty()) {
355 _startup->set_load_template( load_template );
357 _startup->present ();
359 main().run();
361 _startup->hide ();
363 switch (_startup->response()) {
364 case RESPONSE_OK:
365 return true;
366 default:
367 return false;
372 ARDOUR_UI::create_engine ()
374 // this gets called every time by new_session()
376 if (engine) {
377 return 0;
380 loading_message (_("Starting audio engine"));
382 try {
383 engine = new ARDOUR::AudioEngine (ARDOUR_COMMAND_LINE::jack_client_name, ARDOUR_COMMAND_LINE::jack_session_uuid);
385 } catch (...) {
387 return -1;
390 engine->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
391 engine->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
392 engine->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
394 engine->Halted.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
396 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
398 post_engine ();
400 return 0;
403 void
404 ARDOUR_UI::post_engine ()
406 /* Things to be done once we create the AudioEngine
409 ARDOUR::init_post_engine ();
411 ActionManager::init ();
412 _tooltips.enable();
414 if (setup_windows ()) {
415 throw failed_constructor ();
418 check_memory_locking();
420 /* this is the first point at which all the keybindings are available */
422 if (ARDOUR_COMMAND_LINE::show_key_actions) {
423 vector<string> names;
424 vector<string> paths;
425 vector<string> tooltips;
426 vector<string> keys;
427 vector<AccelKey> bindings;
429 ActionManager::get_all_actions (names, paths, tooltips, keys, bindings);
431 vector<string>::iterator n;
432 vector<string>::iterator k;
433 for (n = names.begin(), k = keys.begin(); n != names.end(); ++n, ++k) {
434 cerr << "Action: " << (*n) << " bound to " << (*k) << endl;
437 exit (0);
440 blink_timeout_tag = -1;
442 /* this being a GUI and all, we want peakfiles */
444 AudioFileSource::set_build_peakfiles (true);
445 AudioFileSource::set_build_missing_peakfiles (true);
447 /* set default clock modes */
449 if (Profile->get_sae()) {
450 primary_clock.set_mode (AudioClock::BBT);
451 secondary_clock.set_mode (AudioClock::MinSec);
452 } else {
453 primary_clock.set_mode (AudioClock::Timecode);
454 secondary_clock.set_mode (AudioClock::BBT);
457 /* start the time-of-day-clock */
459 #ifndef GTKOSX
460 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
461 update_wall_clock ();
462 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 60000);
463 #endif
465 update_disk_space ();
466 update_cpu_load ();
467 update_sample_rate (engine->frame_rate());
469 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
470 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
471 Config->map_parameters (pc);
473 /* now start and maybe save state */
475 if (do_engine_start () == 0) {
476 if (_session && _session_is_new) {
477 /* we need to retain initial visual
478 settings for a new session
480 _session->save_state ("");
485 ARDOUR_UI::~ARDOUR_UI ()
487 delete keyboard;
488 delete editor;
489 delete mixer;
490 delete add_route_dialog;
493 void
494 ARDOUR_UI::pop_back_splash ()
496 if (Splash::instance()) {
497 // Splash::instance()->pop_back();
498 Splash::instance()->hide ();
502 gint
503 ARDOUR_UI::configure_timeout ()
505 if (last_configure_time == 0) {
506 /* no configure events yet */
507 return true;
510 /* force a gap of 0.5 seconds since the last configure event
513 if (get_microseconds() - last_configure_time < 500000) {
514 return true;
515 } else {
516 have_configure_timeout = false;
517 cerr << "config event-driven save\n";
518 save_ardour_state ();
519 return false;
523 gboolean
524 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
526 if (have_configure_timeout) {
527 last_configure_time = get_microseconds();
528 } else {
529 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
530 have_configure_timeout = true;
533 return FALSE;
536 void
537 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
539 const XMLProperty* prop;
541 if ((prop = node.property ("roll")) != 0) {
542 roll_controllable->set_id (prop->value());
544 if ((prop = node.property ("stop")) != 0) {
545 stop_controllable->set_id (prop->value());
547 if ((prop = node.property ("goto-start")) != 0) {
548 goto_start_controllable->set_id (prop->value());
550 if ((prop = node.property ("goto-end")) != 0) {
551 goto_end_controllable->set_id (prop->value());
553 if ((prop = node.property ("auto-loop")) != 0) {
554 auto_loop_controllable->set_id (prop->value());
556 if ((prop = node.property ("play-selection")) != 0) {
557 play_selection_controllable->set_id (prop->value());
559 if ((prop = node.property ("rec")) != 0) {
560 rec_controllable->set_id (prop->value());
562 if ((prop = node.property ("shuttle")) != 0) {
563 shuttle_controllable->set_id (prop->value());
567 XMLNode&
568 ARDOUR_UI::get_transport_controllable_state ()
570 XMLNode* node = new XMLNode(X_("TransportControllables"));
571 char buf[64];
573 roll_controllable->id().print (buf, sizeof (buf));
574 node->add_property (X_("roll"), buf);
575 stop_controllable->id().print (buf, sizeof (buf));
576 node->add_property (X_("stop"), buf);
577 goto_start_controllable->id().print (buf, sizeof (buf));
578 node->add_property (X_("goto_start"), buf);
579 goto_end_controllable->id().print (buf, sizeof (buf));
580 node->add_property (X_("goto_end"), buf);
581 auto_loop_controllable->id().print (buf, sizeof (buf));
582 node->add_property (X_("auto_loop"), buf);
583 play_selection_controllable->id().print (buf, sizeof (buf));
584 node->add_property (X_("play_selection"), buf);
585 rec_controllable->id().print (buf, sizeof (buf));
586 node->add_property (X_("rec"), buf);
587 shuttle_controllable->id().print (buf, sizeof (buf));
588 node->add_property (X_("shuttle"), buf);
590 return *node;
594 gint
595 ARDOUR_UI::autosave_session ()
597 if (g_main_depth() > 1) {
598 /* inside a recursive main loop,
599 give up because we may not be able to
600 take a lock.
602 return 1;
605 if (!Config->get_periodic_safety_backups()) {
606 return 1;
609 if (_session) {
610 _session->maybe_write_autosave();
613 return 1;
616 void
617 ARDOUR_UI::update_autosave ()
619 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_autosave)
621 if (_session && _session->dirty()) {
622 if (_autosave_connection.connected()) {
623 _autosave_connection.disconnect();
626 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
627 Config->get_periodic_safety_backup_interval() * 1000);
629 } else {
630 if (_autosave_connection.connected()) {
631 _autosave_connection.disconnect();
636 void
637 ARDOUR_UI::backend_audio_error (bool we_set_params, Gtk::Window* toplevel)
639 string title;
640 if (we_set_params) {
641 title = string_compose (_("%1 could not start JACK"), PROGRAM_NAME);
642 } else {
643 title = string_compose (_("%1 could not connect to JACK."), PROGRAM_NAME);
646 MessageDialog win (title,
647 false,
648 Gtk::MESSAGE_INFO,
649 Gtk::BUTTONS_NONE);
651 if (we_set_params) {
652 win.set_secondary_text(_("There are several possible reasons:\n\
654 1) You requested audio parameters that are not supported..\n\
655 2) JACK is running as another user.\n\
657 Please consider the possibilities, and perhaps try different parameters."));
658 } else {
659 win.set_secondary_text(_("There are several possible reasons:\n\
661 1) JACK is not running.\n\
662 2) JACK is running as another user, perhaps root.\n\
663 3) There is already another client called \"ardour\".\n\
665 Please consider the possibilities, and perhaps (re)start JACK."));
668 if (toplevel) {
669 win.set_transient_for (*toplevel);
672 if (we_set_params) {
673 win.add_button (Stock::OK, RESPONSE_CLOSE);
674 } else {
675 win.add_button (Stock::QUIT, RESPONSE_CLOSE);
678 win.set_default_response (RESPONSE_CLOSE);
680 win.show_all ();
681 win.set_position (Gtk::WIN_POS_CENTER);
682 pop_back_splash ();
684 /* we just don't care about the result, but we want to block */
686 win.run ();
689 void
690 ARDOUR_UI::startup ()
692 Application* app = Application::instance ();
694 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
695 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::idle_load));
697 #ifdef PHONE_HOME
698 call_the_mothership (VERSIONSTRING);
699 #endif
701 app->ready ();
703 if (get_session_parameters (true, ARDOUR_COMMAND_LINE::new_session, ARDOUR_COMMAND_LINE::load_template)) {
704 exit (1);
707 use_config ();
709 goto_editor_window ();
711 /* Add the window proxies here; their addition may cause windows to be opened, and we want them
712 to be opened on top of the editor window that goto_editor_window() just opened.
714 add_window_proxy (location_ui);
715 add_window_proxy (big_clock_window);
716 for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) {
717 add_window_proxy (_global_port_matrix[*i]);
720 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
723 void
724 ARDOUR_UI::no_memory_warning ()
726 XMLNode node (X_("no-memory-warning"));
727 Config->add_instant_xml (node);
730 void
731 ARDOUR_UI::check_memory_locking ()
733 #ifdef __APPLE__
734 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
735 return;
736 #else // !__APPLE__
738 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
740 if (engine->is_realtime() && memory_warning_node == 0) {
742 struct rlimit limits;
743 int64_t ram;
744 long pages, page_size;
746 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0) {
747 ram = 0;
748 } else {
749 ram = (int64_t) pages * (int64_t) page_size;
752 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
753 return;
756 if (limits.rlim_cur != RLIM_INFINITY) {
758 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
761 MessageDialog msg (
762 string_compose (_("WARNING: Your system has a limit for maximum amount of locked memory. "
763 "This might cause %1 to run out of memory before your system "
764 "runs out of memory. \n\n"
765 "You can view the memory limit with 'ulimit -l', "
766 "and it is normally controlled by /etc/security/limits.conf"),
767 PROGRAM_NAME).c_str());
769 VBox* vbox = msg.get_vbox();
770 HBox hbox;
771 CheckButton cb (_("Do not show this window again"));
773 cb.signal_toggled().connect (sigc::mem_fun (*this, &ARDOUR_UI::no_memory_warning));
775 hbox.pack_start (cb, true, false);
776 vbox->pack_start (hbox);
777 cb.show();
778 vbox->show();
779 hbox.show ();
781 pop_back_splash ();
783 editor->ensure_float (msg);
784 msg.run ();
788 #endif // !__APPLE__
792 void
793 ARDOUR_UI::queue_finish ()
795 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
798 bool
799 ARDOUR_UI::idle_finish ()
801 finish ();
802 return false; /* do not call again */
805 void
806 ARDOUR_UI::finish()
808 if (_session) {
809 int tries = 0;
811 if (_session->transport_rolling() && (++tries < 8)) {
812 _session->request_stop (false, true);
813 usleep (10000);
816 if (_session->dirty()) {
817 switch (ask_about_saving_session(_("quit"))) {
818 case -1:
819 return;
820 break;
821 case 1:
822 /* use the default name */
823 if (save_state_canfail ("")) {
824 /* failed - don't quit */
825 MessageDialog msg (*editor,
826 _("\
827 Ardour was unable to save your session.\n\n\
828 If you still wish to quit, please use the\n\n\
829 \"Just quit\" option."));
830 pop_back_splash();
831 msg.run ();
832 return;
834 break;
835 case 0:
836 break;
840 second_connection.disconnect ();
841 point_one_second_connection.disconnect ();
842 point_oh_five_second_connection.disconnect ();
843 point_zero_one_second_connection.disconnect();
846 /* Save state before deleting the session, as that causes some
847 windows to be destroyed before their visible state can be
848 saved.
850 save_ardour_state ();
852 if (_session) {
853 // _session->set_deletion_in_progress ();
854 _session->set_clean ();
855 _session->remove_pending_capture_state ();
856 delete _session;
857 _session = 0;
860 ArdourDialog::close_all_dialogs ();
861 engine->stop (true);
862 quit ();
866 ARDOUR_UI::ask_about_saving_session (const string & what)
868 ArdourDialog window (_("Unsaved Session"));
869 Gtk::HBox dhbox; // the hbox for the image and text
870 Gtk::Label prompt_label;
871 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
873 string msg;
875 msg = string_compose(_("Don't %1"), what);
876 window.add_button (msg, RESPONSE_REJECT);
877 msg = string_compose(_("Just %1"), what);
878 window.add_button (msg, RESPONSE_APPLY);
879 msg = string_compose(_("Save and %1"), what);
880 window.add_button (msg, RESPONSE_ACCEPT);
882 window.set_default_response (RESPONSE_ACCEPT);
884 Gtk::Button noquit_button (msg);
885 noquit_button.set_name ("EditorGTKButton");
887 string prompt;
888 string type;
890 if (_session->snap_name() == _session->name()) {
891 type = _("session");
892 } else {
893 type = _("snapshot");
895 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?"),
896 type, _session->snap_name());
898 prompt_label.set_text (prompt);
899 prompt_label.set_name (X_("PrompterLabel"));
900 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
902 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
903 dhbox.set_homogeneous (false);
904 dhbox.pack_start (*dimage, false, false, 5);
905 dhbox.pack_start (prompt_label, true, false, 5);
906 window.get_vbox()->pack_start (dhbox);
908 window.set_name (_("Prompter"));
909 window.set_position (Gtk::WIN_POS_MOUSE);
910 window.set_modal (true);
911 window.set_resizable (false);
913 dhbox.show();
914 prompt_label.show();
915 dimage->show();
916 window.show();
917 window.set_keep_above (true);
918 window.present ();
920 ResponseType r = (ResponseType) window.run();
922 window.hide ();
924 switch (r) {
925 case RESPONSE_ACCEPT: // save and get out of here
926 return 1;
927 case RESPONSE_APPLY: // get out of here
928 return 0;
929 default:
930 break;
933 return -1;
936 gint
937 ARDOUR_UI::every_second ()
939 update_cpu_load ();
940 update_buffer_load ();
941 update_disk_space ();
942 return TRUE;
945 gint
946 ARDOUR_UI::every_point_one_seconds ()
948 update_speed_display ();
949 RapidScreenUpdate(); /* EMIT_SIGNAL */
950 return TRUE;
953 gint
954 ARDOUR_UI::every_point_zero_one_seconds ()
956 // august 2007: actual update frequency: 40Hz, not 100Hz
958 SuperRapidScreenUpdate(); /* EMIT_SIGNAL */
959 return TRUE;
962 void
963 ARDOUR_UI::update_sample_rate (framecnt_t)
965 char buf[32];
967 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
969 if (!engine->connected()) {
971 snprintf (buf, sizeof (buf), _("disconnected"));
973 } else {
975 framecnt_t rate = engine->frame_rate();
977 if (fmod (rate, 1000.0) != 0.0) {
978 snprintf (buf, sizeof (buf), _("%.1f kHz / %4.1f ms"),
979 (float) rate/1000.0f,
980 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
981 } else {
982 snprintf (buf, sizeof (buf), _("%" PRId64 " kHz / %4.1f ms"),
983 rate/1000,
984 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
988 sample_rate_label.set_text (buf);
991 void
992 ARDOUR_UI::update_cpu_load ()
994 char buf[32];
995 snprintf (buf, sizeof (buf), _("DSP: %5.1f%%"), engine->get_cpu_load());
996 cpu_load_label.set_text (buf);
999 void
1000 ARDOUR_UI::update_buffer_load ()
1002 char buf[64];
1003 uint32_t c, p;
1005 if (_session) {
1006 c = _session->capture_load ();
1007 p = _session->playback_load ();
1009 snprintf (buf, sizeof (buf), _("Buffers p:%" PRIu32 "%% c:%" PRIu32 "%%"),
1010 _session->playback_load(), _session->capture_load());
1011 buffer_load_label.set_text (buf);
1012 } else {
1013 buffer_load_label.set_text ("");
1017 void
1018 ARDOUR_UI::count_recenabled_streams (Route& route)
1020 Track* track = dynamic_cast<Track*>(&route);
1021 if (track && track->record_enabled()) {
1022 rec_enabled_streams += track->n_inputs().n_total();
1026 void
1027 ARDOUR_UI::update_disk_space()
1029 if (_session == 0) {
1030 return;
1033 framecnt_t frames = _session->available_capture_duration();
1034 char buf[64];
1035 framecnt_t fr = _session->frame_rate();
1037 if (frames == max_framecnt) {
1038 strcpy (buf, _("Disk: 24hrs+"));
1039 } else {
1040 rec_enabled_streams = 0;
1041 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams);
1043 if (rec_enabled_streams) {
1044 frames /= rec_enabled_streams;
1047 int hrs;
1048 int mins;
1049 int secs;
1051 hrs = frames / (fr * 3600);
1052 frames -= hrs * fr * 3600;
1053 mins = frames / (fr * 60);
1054 frames -= mins * fr * 60;
1055 secs = frames / fr;
1057 snprintf (buf, sizeof(buf), _("Disk: %02dh:%02dm:%02ds"), hrs, mins, secs);
1060 disk_space_label.set_text (buf);
1062 // An attempt to make the disk space label flash red when space has run out.
1064 if (frames < fr * 60 * 5) {
1065 /* disk_space_box.style ("disk_space_label_empty"); */
1066 } else {
1067 /* disk_space_box.style ("disk_space_label"); */
1072 gint
1073 ARDOUR_UI::update_wall_clock ()
1075 time_t now;
1076 struct tm *tm_now;
1077 char buf[16];
1079 time (&now);
1080 tm_now = localtime (&now);
1082 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1083 wall_clock_label.set_text (buf);
1085 return TRUE;
1088 gint
1089 ARDOUR_UI::session_menu (GdkEventButton */*ev*/)
1091 session_popup_menu->popup (0, 0);
1092 return TRUE;
1095 void
1096 ARDOUR_UI::redisplay_recent_sessions ()
1098 std::vector<sys::path> session_directories;
1099 RecentSessionsSorter cmp;
1101 recent_session_display.set_model (Glib::RefPtr<TreeModel>(0));
1102 recent_session_model->clear ();
1104 ARDOUR::RecentSessions rs;
1105 ARDOUR::read_recent_sessions (rs);
1107 if (rs.empty()) {
1108 recent_session_display.set_model (recent_session_model);
1109 return;
1112 // sort them alphabetically
1113 sort (rs.begin(), rs.end(), cmp);
1115 for (ARDOUR::RecentSessions::iterator i = rs.begin(); i != rs.end(); ++i) {
1116 session_directories.push_back ((*i).second);
1119 for (vector<sys::path>::const_iterator i = session_directories.begin();
1120 i != session_directories.end(); ++i)
1122 std::vector<sys::path> state_file_paths;
1124 // now get available states for this session
1126 get_state_files_in_directory (*i, state_file_paths);
1128 vector<string*>* states;
1129 vector<const gchar*> item;
1130 string fullpath = (*i).to_string();
1132 /* remove any trailing / */
1134 if (fullpath[fullpath.length()-1] == '/') {
1135 fullpath = fullpath.substr (0, fullpath.length()-1);
1138 /* check whether session still exists */
1139 if (!Glib::file_test(fullpath.c_str(), Glib::FILE_TEST_EXISTS)) {
1140 /* session doesn't exist */
1141 cerr << "skipping non-existent session " << fullpath << endl;
1142 continue;
1145 /* now get available states for this session */
1147 if ((states = Session::possible_states (fullpath)) == 0) {
1148 /* no state file? */
1149 continue;
1152 std::vector<string> state_file_names(get_file_names_no_extension (state_file_paths));
1154 Gtk::TreeModel::Row row = *(recent_session_model->append());
1156 row[recent_session_columns.visible_name] = Glib::path_get_basename (fullpath);
1157 row[recent_session_columns.fullpath] = fullpath;
1159 if (state_file_names.size() > 1) {
1161 // add the children
1163 for (std::vector<std::string>::iterator i2 = state_file_names.begin();
1164 i2 != state_file_names.end(); ++i2)
1167 Gtk::TreeModel::Row child_row = *(recent_session_model->append (row.children()));
1169 child_row[recent_session_columns.visible_name] = *i2;
1170 child_row[recent_session_columns.fullpath] = fullpath;
1175 recent_session_display.set_model (recent_session_model);
1178 void
1179 ARDOUR_UI::build_session_selector ()
1181 session_selector_window = new ArdourDialog (_("Recent Sessions"));
1183 Gtk::ScrolledWindow *scroller = manage (new Gtk::ScrolledWindow);
1185 session_selector_window->add_button (Stock::CANCEL, RESPONSE_CANCEL);
1186 session_selector_window->add_button (Stock::OPEN, RESPONSE_ACCEPT);
1187 session_selector_window->set_default_response (RESPONSE_ACCEPT);
1188 recent_session_model = TreeStore::create (recent_session_columns);
1189 recent_session_display.set_model (recent_session_model);
1190 recent_session_display.append_column (_("Recent Sessions"), recent_session_columns.visible_name);
1191 recent_session_display.set_headers_visible (false);
1192 recent_session_display.get_selection()->set_mode (SELECTION_BROWSE);
1193 recent_session_display.signal_row_activated().connect (sigc::mem_fun (*this, &ARDOUR_UI::recent_session_row_activated));
1195 scroller->add (recent_session_display);
1196 scroller->set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
1198 session_selector_window->set_name ("SessionSelectorWindow");
1199 session_selector_window->set_size_request (200, 400);
1200 session_selector_window->get_vbox()->pack_start (*scroller);
1202 recent_session_display.show();
1203 scroller->show();
1204 //session_selector_window->get_vbox()->show();
1207 void
1208 ARDOUR_UI::recent_session_row_activated (const TreePath& /*path*/, TreeViewColumn* /*col*/)
1210 session_selector_window->response (RESPONSE_ACCEPT);
1213 void
1214 ARDOUR_UI::open_recent_session ()
1216 bool can_return = (_session != 0);
1218 if (session_selector_window == 0) {
1219 build_session_selector ();
1222 redisplay_recent_sessions ();
1224 while (true) {
1226 session_selector_window->set_position (WIN_POS_MOUSE);
1228 ResponseType r = (ResponseType) session_selector_window->run ();
1230 switch (r) {
1231 case RESPONSE_ACCEPT:
1232 break;
1233 default:
1234 if (can_return) {
1235 session_selector_window->hide();
1236 return;
1237 } else {
1238 exit (1);
1242 if (recent_session_display.get_selection()->count_selected_rows() == 0) {
1243 continue;
1246 session_selector_window->hide();
1248 Gtk::TreeModel::iterator i = recent_session_display.get_selection()->get_selected();
1250 if (i == recent_session_model->children().end()) {
1251 return;
1254 std::string path = (*i)[recent_session_columns.fullpath];
1255 std::string state = (*i)[recent_session_columns.visible_name];
1257 _session_is_new = false;
1259 if (load_session (path, state) == 0) {
1260 break;
1263 can_return = false;
1267 bool
1268 ARDOUR_UI::check_audioengine ()
1270 if (engine) {
1271 if (!engine->connected()) {
1272 MessageDialog msg (string_compose (_("%1 is not connected to JACK\n"
1273 "You cannot open or close sessions in this condition"),
1274 PROGRAM_NAME));
1275 pop_back_splash ();
1276 msg.run ();
1277 return false;
1279 return true;
1280 } else {
1281 return false;
1285 void
1286 ARDOUR_UI::open_session ()
1288 if (!check_audioengine()) {
1289 return;
1293 /* popup selector window */
1295 if (open_session_selector == 0) {
1297 /* ardour sessions are folders */
1299 open_session_selector = new Gtk::FileChooserDialog (_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1300 open_session_selector->add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1301 open_session_selector->add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1302 open_session_selector->set_default_response(Gtk::RESPONSE_ACCEPT);
1304 FileFilter session_filter;
1305 session_filter.add_pattern ("*.ardour");
1306 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1307 open_session_selector->add_filter (session_filter);
1308 open_session_selector->set_filter (session_filter);
1311 int response = open_session_selector->run();
1312 open_session_selector->hide ();
1314 switch (response) {
1315 case RESPONSE_ACCEPT:
1316 break;
1317 default:
1318 open_session_selector->hide();
1319 return;
1322 open_session_selector->hide();
1323 string session_path = open_session_selector->get_filename();
1324 string path, name;
1325 bool isnew;
1327 if (session_path.length() > 0) {
1328 if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1329 _session_is_new = isnew;
1330 load_session (path, name);
1336 void
1337 ARDOUR_UI::session_add_midi_route (bool disk, RouteGroup* route_group, uint32_t how_many)
1339 list<boost::shared_ptr<MidiTrack> > tracks;
1341 if (_session == 0) {
1342 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1343 return;
1346 try {
1347 if (disk) {
1349 tracks = _session->new_midi_track (ARDOUR::Normal, route_group, how_many);
1351 if (tracks.size() != how_many) {
1352 if (how_many == 1) {
1353 error << _("could not create a new midi track") << endmsg;
1354 } else {
1355 error << string_compose (_("could not create %1 new midi tracks"), how_many) << endmsg;
1358 } /*else {
1359 if ((route = _session->new_midi_route ()) == 0) {
1360 error << _("could not create new midi bus") << endmsg;
1365 catch (...) {
1366 MessageDialog msg (*editor,
1367 string_compose (_("There are insufficient JACK ports available\n\
1368 to create a new track or bus.\n\
1369 You should save %1, exit and\n\
1370 restart JACK with more ports."), PROGRAM_NAME));
1371 msg.run ();
1376 void
1377 ARDOUR_UI::session_add_audio_route (bool track, int32_t input_channels, int32_t output_channels, ARDOUR::TrackMode mode, RouteGroup* route_group, uint32_t how_many)
1379 list<boost::shared_ptr<AudioTrack> > tracks;
1380 RouteList routes;
1382 if (_session == 0) {
1383 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1384 return;
1387 try {
1388 if (track) {
1389 tracks = _session->new_audio_track (input_channels, output_channels, mode, route_group, how_many);
1391 if (tracks.size() != how_many) {
1392 if (how_many == 1) {
1393 error << _("could not create a new audio track") << endmsg;
1394 } else {
1395 error << string_compose (_("could only create %1 of %2 new audio %3"),
1396 tracks.size(), how_many, (track ? _("tracks") : _("busses"))) << endmsg;
1400 } else {
1402 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many);
1404 if (routes.size() != how_many) {
1405 if (how_many == 1) {
1406 error << _("could not create a new audio track") << endmsg;
1407 } else {
1408 error << string_compose (_("could not create %1 new audio tracks"), how_many) << endmsg;
1414 catch (...) {
1415 MessageDialog msg (*editor,
1416 string_compose (_("There are insufficient JACK ports available\n\
1417 to create a new track or bus.\n\
1418 You should save %1, exit and\n\
1419 restart JACK with more ports."), PROGRAM_NAME));
1420 pop_back_splash ();
1421 msg.run ();
1425 void
1426 ARDOUR_UI::do_transport_locate (framepos_t new_position, bool with_roll)
1428 framecnt_t _preroll = 0;
1430 if (_session) {
1431 // XXX CONFIG_CHANGE FIX - requires AnyTime handling
1432 // _preroll = _session->convert_to_frames_at (new_position, Config->get_preroll());
1434 if (new_position > _preroll) {
1435 new_position -= _preroll;
1436 } else {
1437 new_position = 0;
1440 _session->request_locate (new_position, with_roll);
1444 void
1445 ARDOUR_UI::transport_goto_start ()
1447 if (_session) {
1448 _session->goto_start();
1450 /* force displayed area in editor to start no matter
1451 what "follow playhead" setting is.
1454 if (editor) {
1455 editor->center_screen (_session->current_start_frame ());
1460 void
1461 ARDOUR_UI::transport_goto_zero ()
1463 if (_session) {
1464 _session->request_locate (0);
1466 /* force displayed area in editor to start no matter
1467 what "follow playhead" setting is.
1470 if (editor) {
1471 editor->reset_x_origin (0);
1476 void
1477 ARDOUR_UI::transport_goto_wallclock ()
1479 if (_session && editor) {
1481 time_t now;
1482 struct tm tmnow;
1483 framepos_t frames;
1485 time (&now);
1486 localtime_r (&now, &tmnow);
1488 frames = tmnow.tm_hour * (60 * 60 * _session->frame_rate());
1489 frames += tmnow.tm_min * (60 * _session->frame_rate());
1490 frames += tmnow.tm_sec * _session->frame_rate();
1492 _session->request_locate (frames, _session->transport_rolling ());
1494 /* force displayed area in editor to start no matter
1495 what "follow playhead" setting is.
1498 if (editor) {
1499 editor->center_screen (frames);
1504 void
1505 ARDOUR_UI::transport_goto_end ()
1507 if (_session) {
1508 framepos_t const frame = _session->current_end_frame();
1509 _session->request_locate (frame);
1511 /* force displayed area in editor to start no matter
1512 what "follow playhead" setting is.
1515 if (editor) {
1516 editor->center_screen (frame);
1521 void
1522 ARDOUR_UI::transport_stop ()
1524 if (!_session) {
1525 return;
1528 if (_session->is_auditioning()) {
1529 _session->cancel_audition ();
1530 return;
1533 _session->request_stop (false, true);
1536 void
1537 ARDOUR_UI::transport_stop_and_forget_capture ()
1539 if (_session) {
1540 _session->request_stop (true, true);
1544 void
1545 ARDOUR_UI::remove_last_capture()
1547 if (editor) {
1548 editor->remove_last_capture();
1552 void
1553 ARDOUR_UI::transport_record (bool roll)
1556 if (_session) {
1557 switch (_session->record_status()) {
1558 case Session::Disabled:
1559 if (_session->ntracks() == 0) {
1560 MessageDialog msg (*editor, _("Please create 1 or more track\nbefore trying to record.\nCheck the Session menu."));
1561 msg.run ();
1562 return;
1564 _session->maybe_enable_record ();
1565 if (roll) {
1566 transport_roll ();
1568 break;
1569 case Session::Recording:
1570 if (roll) {
1571 _session->request_stop();
1572 } else {
1573 _session->disable_record (false, true);
1575 break;
1577 case Session::Enabled:
1578 _session->disable_record (false, true);
1581 //cerr << "ARDOUR_UI::transport_record () called roll = " << roll << " _session->record_status() = " << _session->record_status() << endl;
1584 void
1585 ARDOUR_UI::transport_roll ()
1587 if (!_session) {
1588 return;
1591 if (_session->is_auditioning()) {
1592 return;
1595 #if 0
1596 if (_session->config.get_external_sync()) {
1597 switch (_session->config.get_sync_source()) {
1598 case JACK:
1599 break;
1600 default:
1601 /* transport controlled by the master */
1602 return;
1605 #endif
1607 bool rolling = _session->transport_rolling();
1609 if (_session->get_play_loop()) {
1610 /* XXX it is not possible to just leave seamless loop and keep
1611 playing at present (nov 4th 2009)
1613 if (!Config->get_seamless_loop()) {
1614 _session->request_play_loop (false, true);
1616 } else if (_session->get_play_range () && !join_play_range_button.get_active()) {
1617 /* stop playing a range if we currently are */
1618 _session->request_play_range (0, true);
1621 if (join_play_range_button.get_active()) {
1622 _session->request_play_range (&editor->get_selection().time, true);
1625 if (!rolling) {
1626 _session->request_transport_speed (1.0f);
1630 void
1631 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
1634 if (!_session) {
1635 return;
1638 if (_session->is_auditioning()) {
1639 _session->cancel_audition ();
1640 return;
1643 #if 0
1644 if (_session->config.get_external_sync()) {
1645 switch (_session->config.get_sync_source()) {
1646 case JACK:
1647 break;
1648 default:
1649 /* transport controlled by the master */
1650 return;
1653 #endif
1655 bool rolling = _session->transport_rolling();
1656 bool affect_transport = true;
1658 if (rolling && roll_out_of_bounded_mode) {
1659 /* drop out of loop/range playback but leave transport rolling */
1660 if (_session->get_play_loop()) {
1661 if (Config->get_seamless_loop()) {
1662 /* the disk buffers contain copies of the loop - we can't
1663 just keep playing, so stop the transport. the user
1664 can restart as they wish.
1666 affect_transport = true;
1667 } else {
1668 /* disk buffers are normal, so we can keep playing */
1669 affect_transport = false;
1671 _session->request_play_loop (false, true);
1672 } else if (_session->get_play_range ()) {
1673 affect_transport = false;
1674 _session->request_play_range (0, true);
1678 if (affect_transport) {
1679 if (rolling) {
1680 _session->request_stop (with_abort, true);
1681 } else {
1682 if (join_play_range_button.get_active()) {
1683 _session->request_play_range (&editor->get_selection().time, true);
1686 _session->request_transport_speed (1.0f);
1691 void
1692 ARDOUR_UI::toggle_session_auto_loop ()
1694 if (!_session) {
1695 return;
1698 if (_session->get_play_loop()) {
1700 if (_session->transport_rolling()) {
1702 Location * looploc = _session->locations()->auto_loop_location();
1704 if (looploc) {
1705 _session->request_locate (looploc->start(), true);
1706 _session->request_play_loop (false);
1709 } else {
1710 _session->request_play_loop (false);
1712 } else {
1714 Location * looploc = _session->locations()->auto_loop_location();
1716 if (looploc) {
1717 _session->request_play_loop (true);
1722 void
1723 ARDOUR_UI::transport_play_selection ()
1725 if (!_session) {
1726 return;
1729 editor->play_selection ();
1732 void
1733 ARDOUR_UI::transport_rewind (int option)
1735 float current_transport_speed;
1737 if (_session) {
1738 current_transport_speed = _session->transport_speed();
1740 if (current_transport_speed >= 0.0f) {
1741 switch (option) {
1742 case 0:
1743 _session->request_transport_speed (-1.0f);
1744 break;
1745 case 1:
1746 _session->request_transport_speed (-4.0f);
1747 break;
1748 case -1:
1749 _session->request_transport_speed (-0.5f);
1750 break;
1752 } else {
1753 /* speed up */
1754 _session->request_transport_speed (current_transport_speed * 1.5f);
1759 void
1760 ARDOUR_UI::transport_forward (int option)
1762 float current_transport_speed;
1764 if (_session) {
1765 current_transport_speed = _session->transport_speed();
1767 if (current_transport_speed <= 0.0f) {
1768 switch (option) {
1769 case 0:
1770 _session->request_transport_speed (1.0f);
1771 break;
1772 case 1:
1773 _session->request_transport_speed (4.0f);
1774 break;
1775 case -1:
1776 _session->request_transport_speed (0.5f);
1777 break;
1779 } else {
1780 /* speed up */
1781 _session->request_transport_speed (current_transport_speed * 1.5f);
1787 void
1788 ARDOUR_UI::toggle_record_enable (uint32_t rid)
1790 if (_session == 0) {
1791 return;
1794 boost::shared_ptr<Route> r;
1796 if ((r = _session->route_by_remote_id (rid)) != 0) {
1798 Track* t;
1800 if ((t = dynamic_cast<Track*>(r.get())) != 0) {
1801 t->set_record_enabled (!t->record_enabled(), this);
1804 if (_session == 0) {
1805 return;
1809 void
1810 ARDOUR_UI::map_transport_state ()
1812 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::map_transport_state)
1814 if (!_session) {
1815 auto_loop_button.set_visual_state (0);
1816 play_selection_button.set_visual_state (0);
1817 roll_button.set_visual_state (0);
1818 stop_button.set_visual_state (1);
1819 return;
1822 float sp = _session->transport_speed();
1824 if (sp == 1.0f) {
1825 shuttle_fract = SHUTTLE_FRACT_SPEED1; /* speed = 1.0, believe it or not */
1826 shuttle_box.queue_draw ();
1827 } else if (sp == 0.0f) {
1828 shuttle_fract = 0;
1829 shuttle_box.queue_draw ();
1830 update_disk_space ();
1833 if (sp != 0.0) {
1835 /* we're rolling */
1837 if (_session->get_play_range()) {
1839 play_selection_button.set_visual_state (1);
1840 roll_button.set_visual_state (0);
1841 auto_loop_button.set_visual_state (0);
1843 } else if (_session->get_play_loop ()) {
1845 auto_loop_button.set_visual_state (1);
1846 play_selection_button.set_visual_state (0);
1847 roll_button.set_visual_state (0);
1849 } else {
1851 roll_button.set_visual_state (1);
1852 play_selection_button.set_visual_state (0);
1853 auto_loop_button.set_visual_state (0);
1856 if (join_play_range_button.get_active()) {
1857 /* light up both roll and play-selection if they are joined */
1858 roll_button.set_visual_state (1);
1859 play_selection_button.set_visual_state (1);
1862 stop_button.set_visual_state (0);
1864 } else {
1866 stop_button.set_visual_state (1);
1867 roll_button.set_visual_state (0);
1868 play_selection_button.set_visual_state (0);
1869 auto_loop_button.set_visual_state (0);
1873 void
1874 ARDOUR_UI::engine_stopped ()
1876 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
1877 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1878 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1881 void
1882 ARDOUR_UI::engine_running ()
1884 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
1885 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, true);
1886 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, false);
1888 Glib::RefPtr<Action> action;
1889 const char* action_name = 0;
1891 switch (engine->frames_per_cycle()) {
1892 case 32:
1893 action_name = X_("JACKLatency32");
1894 break;
1895 case 64:
1896 action_name = X_("JACKLatency64");
1897 break;
1898 case 128:
1899 action_name = X_("JACKLatency128");
1900 break;
1901 case 512:
1902 action_name = X_("JACKLatency512");
1903 break;
1904 case 1024:
1905 action_name = X_("JACKLatency1024");
1906 break;
1907 case 2048:
1908 action_name = X_("JACKLatency2048");
1909 break;
1910 case 4096:
1911 action_name = X_("JACKLatency4096");
1912 break;
1913 case 8192:
1914 action_name = X_("JACKLatency8192");
1915 break;
1916 default:
1917 /* XXX can we do anything useful ? */
1918 break;
1921 if (action_name) {
1923 action = ActionManager::get_action (X_("JACK"), action_name);
1925 if (action) {
1926 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (action);
1927 ract->set_active ();
1932 void
1933 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
1935 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
1936 /* we can't rely on the original string continuing to exist when we are called
1937 again in the GUI thread, so make a copy and note that we need to
1938 free it later.
1940 char *copy = strdup (reason);
1941 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
1942 return;
1945 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1946 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1948 update_sample_rate (0);
1950 string msgstr;
1952 /* if the reason is a non-empty string, it means that the backend was shutdown
1953 rather than just Ardour.
1956 if (strlen (reason)) {
1957 msgstr = string_compose (_("The audio backend (JACK) was shutdown because:\n\n%1"), reason);
1958 } else {
1959 msgstr = string_compose (_("\
1960 JACK has either been shutdown or it\n\
1961 disconnected %1 because %1\n\
1962 was not fast enough. Try to restart\n\
1963 JACK, reconnect and save the session."), PROGRAM_NAME);
1966 MessageDialog msg (*editor, msgstr);
1967 pop_back_splash ();
1968 msg.run ();
1970 if (free_reason) {
1971 free ((char*) reason);
1975 int32_t
1976 ARDOUR_UI::do_engine_start ()
1978 try {
1979 engine->start();
1982 catch (...) {
1983 engine->stop ();
1984 error << _("Unable to start the session running")
1985 << endmsg;
1986 unload_session ();
1987 return -2;
1990 return 0;
1993 void
1994 ARDOUR_UI::setup_theme ()
1996 theme_manager->setup_theme();
1999 void
2000 ARDOUR_UI::update_clocks ()
2002 if (!editor || !editor->dragging_playhead()) {
2003 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position()); /* EMIT_SIGNAL */
2007 void
2008 ARDOUR_UI::start_clocking ()
2010 clock_signal_connection = RapidScreenUpdate.connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2013 void
2014 ARDOUR_UI::stop_clocking ()
2016 clock_signal_connection.disconnect ();
2019 void
2020 ARDOUR_UI::toggle_clocking ()
2022 #if 0
2023 if (clock_button.get_active()) {
2024 start_clocking ();
2025 } else {
2026 stop_clocking ();
2028 #endif
2031 gint
2032 ARDOUR_UI::_blink (void *arg)
2035 ((ARDOUR_UI *) arg)->blink ();
2036 return TRUE;
2039 void
2040 ARDOUR_UI::blink ()
2042 Blink (blink_on = !blink_on); /* EMIT_SIGNAL */
2045 void
2046 ARDOUR_UI::start_blinking ()
2048 /* Start the blink signal. Everybody with a blinking widget
2049 uses Blink to drive the widget's state.
2052 if (blink_timeout_tag < 0) {
2053 blink_on = false;
2054 blink_timeout_tag = g_timeout_add (240, _blink, this);
2058 void
2059 ARDOUR_UI::stop_blinking ()
2061 if (blink_timeout_tag >= 0) {
2062 g_source_remove (blink_timeout_tag);
2063 blink_timeout_tag = -1;
2068 /** Ask the user for the name of a new shapshot and then take it.
2071 void
2072 ARDOUR_UI::snapshot_session (bool switch_to_it)
2074 ArdourPrompter prompter (true);
2075 string snapname;
2077 prompter.set_name ("Prompter");
2078 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2079 prompter.set_title (_("Take Snapshot"));
2080 prompter.set_title (_("Take Snapshot"));
2081 prompter.set_prompt (_("Name of new snapshot"));
2083 if (!switch_to_it) {
2084 char timebuf[128];
2085 time_t n;
2086 struct tm local_time;
2088 time (&n);
2089 localtime_r (&n, &local_time);
2090 strftime (timebuf, sizeof(timebuf), "%FT%T", &local_time);
2091 prompter.set_initial_text (timebuf);
2094 again:
2095 switch (prompter.run()) {
2096 case RESPONSE_ACCEPT:
2098 prompter.get_result (snapname);
2100 bool do_save = (snapname.length() != 0);
2102 if (do_save) {
2103 if (snapname.find ('/') != string::npos) {
2104 MessageDialog msg (_("To ensure compatibility with various systems\n"
2105 "snapshot names may not contain a '/' character"));
2106 msg.run ();
2107 goto again;
2109 if (snapname.find ('\\') != string::npos) {
2110 MessageDialog msg (_("To ensure compatibility with various systems\n"
2111 "snapshot names may not contain a '\\' character"));
2112 msg.run ();
2113 goto again;
2117 vector<sys::path> p;
2118 get_state_files_in_directory (_session->session_directory().root_path(), p);
2119 vector<string> n = get_file_names_no_extension (p);
2120 if (find (n.begin(), n.end(), snapname) != n.end()) {
2122 ArdourDialog confirm (_("Confirm Snapshot Overwrite"), true);
2123 Label m (_("A snapshot already exists with that name. Do you want to overwrite it?"));
2124 confirm.get_vbox()->pack_start (m, true, true);
2125 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2126 confirm.add_button (_("Overwrite"), Gtk::RESPONSE_ACCEPT);
2127 confirm.show_all ();
2128 switch (confirm.run()) {
2129 case RESPONSE_CANCEL:
2130 do_save = false;
2134 if (do_save) {
2135 save_state (snapname, switch_to_it);
2137 break;
2140 default:
2141 break;
2145 void
2146 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2148 XMLNode* node = new XMLNode (X_("UI"));
2150 for (list<WindowProxyBase*>::iterator i = _window_proxies.begin(); i != _window_proxies.end(); ++i) {
2151 if (!(*i)->rc_configured()) {
2152 node->add_child_nocopy (*((*i)->get_state ()));
2156 _session->add_extra_xml (*node);
2158 save_state_canfail (name, switch_to_it);
2162 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2164 if (_session) {
2165 int ret;
2167 if (name.length() == 0) {
2168 name = _session->snap_name();
2171 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2172 return ret;
2175 cerr << "SS canfail\n";
2176 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2177 return 0;
2180 void
2181 ARDOUR_UI::primary_clock_value_changed ()
2183 if (_session) {
2184 _session->request_locate (primary_clock.current_time ());
2188 void
2189 ARDOUR_UI::big_clock_value_changed ()
2191 if (_session) {
2192 _session->request_locate (big_clock.current_time ());
2196 void
2197 ARDOUR_UI::secondary_clock_value_changed ()
2199 if (_session) {
2200 _session->request_locate (secondary_clock.current_time ());
2204 void
2205 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2207 if (_session == 0) {
2208 return;
2211 if (_session->step_editing()) {
2212 return;
2215 Session::RecordState const r = _session->record_status ();
2216 bool const h = _session->have_rec_enabled_track ();
2218 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2219 if (onoff) {
2220 rec_button.set_visual_state (2);
2221 } else {
2222 rec_button.set_visual_state (0);
2224 } else if (r == Session::Recording && h) {
2225 rec_button.set_visual_state (1);
2226 } else {
2227 rec_button.set_visual_state (0);
2231 void
2232 ARDOUR_UI::save_template ()
2234 ArdourPrompter prompter (true);
2235 string name;
2237 if (!check_audioengine()) {
2238 return;
2241 prompter.set_name (X_("Prompter"));
2242 prompter.set_title (_("Save Template"));
2243 prompter.set_prompt (_("Name for template:"));
2244 prompter.set_initial_text(_session->name() + _("-template"));
2245 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2247 switch (prompter.run()) {
2248 case RESPONSE_ACCEPT:
2249 prompter.get_result (name);
2251 if (name.length()) {
2252 _session->save_template (name);
2254 break;
2256 default:
2257 break;
2261 void
2262 ARDOUR_UI::edit_metadata ()
2264 SessionMetadataEditor dialog;
2265 dialog.set_session (_session);
2266 editor->ensure_float (dialog);
2267 dialog.run ();
2270 void
2271 ARDOUR_UI::import_metadata ()
2273 SessionMetadataImporter dialog;
2274 dialog.set_session (_session);
2275 editor->ensure_float (dialog);
2276 dialog.run ();
2279 void
2280 ARDOUR_UI::fontconfig_dialog ()
2282 #ifdef GTKOSX
2283 /* X11 users will always have fontconfig info around, but new GTK-OSX users
2284 may not and it can take a while to build it. Warn them.
2287 std::string fontconfig = Glib::build_filename (Glib::get_home_dir(), ".fontconfig");
2289 if (!Glib::file_test (fontconfig, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_DIR)) {
2290 MessageDialog msg (*_startup,
2291 string_compose (_("Welcome to %1.\n\n"
2292 "The program will take a bit longer to start up\n"
2293 "while the system fonts are checked.\n\n"
2294 "This will only be done once, and you will\n"
2295 "not see this message again\n"), PROGRAM_NAME),
2296 true,
2297 Gtk::MESSAGE_INFO,
2298 Gtk::BUTTONS_OK);
2299 pop_back_splash ();
2300 msg.show_all ();
2301 msg.present ();
2302 msg.run ();
2304 #endif
2307 void
2308 ARDOUR_UI::parse_cmdline_path (const std::string& cmdline_path, std::string& session_name, std::string& session_path, bool& existing_session)
2310 existing_session = false;
2312 if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_DIR)) {
2313 session_path = cmdline_path;
2314 existing_session = true;
2315 } else if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_REGULAR)) {
2316 session_path = Glib::path_get_dirname (string (cmdline_path));
2317 existing_session = true;
2318 } else {
2319 /* it doesn't exist, assume the best */
2320 session_path = Glib::path_get_dirname (string (cmdline_path));
2323 session_name = basename_nosuffix (string (cmdline_path));
2327 ARDOUR_UI::load_cmdline_session (const std::string& session_name, const std::string& session_path, bool& existing_session)
2329 /* when this is called, the backend audio system must be running */
2331 /* the main idea here is to deal with the fact that a cmdline argument for the session
2332 can be interpreted in different ways - it could be a directory or a file, and before
2333 we load, we need to know both the session directory and the snapshot (statefile) within it
2334 that we are supposed to use.
2337 if (session_name.length() == 0 || session_path.length() == 0) {
2338 return false;
2341 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_DIR)) {
2343 std::string predicted_session_file;
2345 predicted_session_file = session_path;
2346 predicted_session_file += '/';
2347 predicted_session_file += session_name;
2348 predicted_session_file += ARDOUR::statefile_suffix;
2350 if (Glib::file_test (predicted_session_file, Glib::FILE_TEST_EXISTS)) {
2351 existing_session = true;
2354 } else if (Glib::file_test (session_path, Glib::FILE_TEST_EXISTS)) {
2356 if (session_path.find (ARDOUR::statefile_suffix) == session_path.length() - 7) {
2357 /* existing .ardour file */
2358 existing_session = true;
2361 } else {
2362 existing_session = false;
2365 /* lets just try to load it */
2367 if (create_engine ()) {
2368 backend_audio_error (false, _startup);
2369 return -1;
2372 return load_session (session_path, session_name);
2375 bool
2376 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
2378 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2380 MessageDialog msg (str,
2381 false,
2382 Gtk::MESSAGE_WARNING,
2383 Gtk::BUTTONS_YES_NO,
2384 true);
2387 msg.set_name (X_("OpenExistingDialog"));
2388 msg.set_title (_("Open Existing Session"));
2389 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
2390 msg.set_position (Gtk::WIN_POS_MOUSE);
2391 pop_back_splash ();
2393 switch (msg.run()) {
2394 case RESPONSE_YES:
2395 return true;
2396 break;
2398 return false;
2402 ARDOUR_UI::build_session_from_nsd (const std::string& session_path, const std::string& session_name)
2404 BusProfile bus_profile;
2406 if (Profile->get_sae()) {
2408 bus_profile.master_out_channels = 2;
2409 bus_profile.input_ac = AutoConnectPhysical;
2410 bus_profile.output_ac = AutoConnectMaster;
2411 bus_profile.requested_physical_in = 0; // use all available
2412 bus_profile.requested_physical_out = 0; // use all available
2414 } else {
2416 /* get settings from advanced section of NSD */
2418 if (_startup->create_master_bus()) {
2419 bus_profile.master_out_channels = (uint32_t) _startup->master_channel_count();
2420 } else {
2421 bus_profile.master_out_channels = 0;
2424 if (_startup->connect_inputs()) {
2425 bus_profile.input_ac = AutoConnectPhysical;
2426 } else {
2427 bus_profile.input_ac = AutoConnectOption (0);
2430 /// @todo some minor tweaks.
2432 bus_profile.output_ac = AutoConnectOption (0);
2434 if (_startup->connect_outputs ()) {
2435 if (_startup->connect_outs_to_master()) {
2436 bus_profile.output_ac = AutoConnectMaster;
2437 } else if (_startup->connect_outs_to_physical()) {
2438 bus_profile.output_ac = AutoConnectPhysical;
2442 bus_profile.requested_physical_in = (uint32_t) _startup->input_limit_count();
2443 bus_profile.requested_physical_out = (uint32_t) _startup->output_limit_count();
2446 if (build_session (session_path, session_name, bus_profile)) {
2447 return -1;
2450 return 0;
2453 void
2454 ARDOUR_UI::idle_load (const std::string& path)
2456 if (_session) {
2457 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2458 /* /path/to/foo => /path/to/foo, foo */
2459 load_session (path, basename_nosuffix (path));
2460 } else {
2461 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2462 load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2464 } else {
2466 ARDOUR_COMMAND_LINE::session_name = path;
2469 * new_session_dialog doens't exist in A3
2470 * Try to remove all references to it to
2471 * see if it will compile. NOTE: this will
2472 * likely cause a runtime issue is my somewhat
2473 * uneducated guess.
2476 //if (new_session_dialog) {
2479 /* make it break out of Dialog::run() and
2480 start again.
2483 //new_session_dialog->response (1);
2488 void
2489 ARDOUR_UI::end_loading_messages ()
2491 // hide_splash ();
2494 void
2495 ARDOUR_UI::loading_message (const std::string& /*msg*/)
2497 // show_splash ();
2498 // splash->message (msg);
2499 flush_pending ();
2502 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
2504 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
2506 string session_name;
2507 string session_path;
2508 string template_name;
2509 int ret = -1;
2510 bool likely_new = false;
2512 if (! load_template.empty()) {
2513 should_be_new = true;
2514 template_name = load_template;
2517 while (ret != 0) {
2519 if (!should_be_new && !ARDOUR_COMMAND_LINE::session_name.empty()) {
2521 /* if they named a specific statefile, use it, otherwise they are
2522 just giving a session folder, and we want to use it as is
2523 to find the session.
2526 if (ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix) != string::npos) {
2527 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
2528 } else {
2529 session_path = ARDOUR_COMMAND_LINE::session_name;
2532 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
2534 } else {
2536 bool const apply = run_startup (should_be_new, load_template);
2538 if (!apply) {
2539 if (quit_on_cancel) {
2540 exit (1);
2541 } else {
2542 return ret;
2546 /* if we run the startup dialog again, offer more than just "new session" */
2548 should_be_new = false;
2550 session_name = _startup->session_name (likely_new);
2552 /* this shouldn't happen, but we catch it just in case it does */
2554 if (session_name.empty()) {
2555 continue;
2558 if (_startup->use_session_template()) {
2559 template_name = _startup->session_template_name();
2560 _session_is_new = true;
2563 if (session_name[0] == G_DIR_SEPARATOR ||
2564 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
2565 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)) {
2567 /* absolute path or cwd-relative path specified for session name: infer session folder
2568 from what was given.
2571 session_path = Glib::path_get_dirname (session_name);
2572 session_name = Glib::path_get_basename (session_name);
2574 } else {
2576 session_path = _startup->session_folder();
2578 if (session_name.find ('/') != string::npos) {
2579 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2580 "session names may not contain a '/' character"));
2581 msg.run ();
2582 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2583 continue;
2586 if (session_name.find ('\\') != string::npos) {
2587 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2588 "session names may not contain a '\\' character"));
2589 msg.run ();
2590 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2591 continue;
2596 if (create_engine ()) {
2597 break;
2600 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
2602 if (likely_new) {
2604 std::string existing = Glib::build_filename (session_path, session_name);
2606 if (!ask_about_loading_existing_session (existing)) {
2607 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2608 continue;
2612 _session_is_new = false;
2614 } else {
2616 if (!likely_new) {
2617 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
2618 msg.run ();
2619 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2620 continue;
2623 if (session_name.find ('/') != std::string::npos) {
2624 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2625 "session names may not contain a '/' character"));
2626 msg.run ();
2627 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2628 continue;
2631 if (session_name.find ('\\') != std::string::npos) {
2632 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2633 "session names may not contain a '\\' character"));
2634 msg.run ();
2635 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2636 continue;
2639 _session_is_new = true;
2642 if (likely_new && template_name.empty()) {
2644 ret = build_session_from_nsd (session_path, session_name);
2646 } else {
2648 ret = load_session (session_path, session_name, template_name);
2650 if (ret == -2) {
2651 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
2652 exit (1);
2655 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
2656 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
2657 exit (1);
2662 return ret;
2665 void
2666 ARDOUR_UI::close_session()
2668 if (!check_audioengine()) {
2669 return;
2672 if (unload_session (true)) {
2673 return;
2676 ARDOUR_COMMAND_LINE::session_name = "";
2678 if (get_session_parameters (true, false)) {
2679 exit (1);
2682 goto_editor_window ();
2685 /** @return -2 if the load failed because we are not connected to the AudioEngine */
2687 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
2689 Session *new_session;
2690 int unload_status;
2691 int retval = -1;
2693 session_loaded = false;
2695 if (!check_audioengine()) {
2696 return -2;
2699 unload_status = unload_session ();
2701 if (unload_status < 0) {
2702 goto out;
2703 } else if (unload_status > 0) {
2704 retval = 0;
2705 goto out;
2708 loading_message (string_compose (_("Please wait while %1loads your session"), PROGRAM_NAME));
2710 try {
2711 new_session = new Session (*engine, path, snap_name, 0, mix_template);
2714 /* this one is special */
2716 catch (AudioEngine::PortRegistrationFailure& err) {
2718 MessageDialog msg (err.what(),
2719 true,
2720 Gtk::MESSAGE_INFO,
2721 Gtk::BUTTONS_CLOSE);
2723 msg.set_title (_("Port Registration Error"));
2724 msg.set_secondary_text (_("Click the Close button to try again."));
2725 msg.set_position (Gtk::WIN_POS_CENTER);
2726 pop_back_splash ();
2727 msg.present ();
2729 int response = msg.run ();
2731 msg.hide ();
2733 switch (response) {
2734 case RESPONSE_CANCEL:
2735 exit (1);
2736 default:
2737 break;
2739 goto out;
2742 catch (...) {
2744 MessageDialog msg (string_compose(_("Session \"%1 (snapshot %2)\" did not load successfully"),path, snap_name),
2745 true,
2746 Gtk::MESSAGE_INFO,
2747 BUTTONS_OK);
2749 msg.set_title (_("Loading Error"));
2750 msg.set_secondary_text (_("Click the Refresh button to try again."));
2751 msg.add_button (Stock::REFRESH, 1);
2752 msg.set_position (Gtk::WIN_POS_CENTER);
2753 pop_back_splash ();
2754 msg.present ();
2756 int response = msg.run ();
2758 switch (response) {
2759 case 1:
2760 break;
2761 default:
2762 exit (1);
2765 msg.hide ();
2767 goto out;
2771 list<string> const u = new_session->unknown_processors ();
2772 if (!u.empty()) {
2773 MissingPluginDialog d (_session, u);
2774 d.run ();
2778 /* Now the session been created, add the transport controls */
2779 new_session->add_controllable(roll_controllable);
2780 new_session->add_controllable(stop_controllable);
2781 new_session->add_controllable(goto_start_controllable);
2782 new_session->add_controllable(goto_end_controllable);
2783 new_session->add_controllable(auto_loop_controllable);
2784 new_session->add_controllable(play_selection_controllable);
2785 new_session->add_controllable(rec_controllable);
2787 set_session (new_session);
2789 session_loaded = true;
2791 goto_editor_window ();
2793 if (_session) {
2794 _session->set_clean ();
2797 flush_pending ();
2798 retval = 0;
2800 out:
2801 return retval;
2805 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
2807 Session *new_session;
2808 int x;
2810 if (!check_audioengine()) {
2811 return -1;
2814 session_loaded = false;
2816 x = unload_session ();
2818 if (x < 0) {
2819 return -1;
2820 } else if (x > 0) {
2821 return 0;
2824 _session_is_new = true;
2826 try {
2827 new_session = new Session (*engine, path, snap_name, &bus_profile);
2830 catch (...) {
2832 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
2833 pop_back_splash ();
2834 msg.run ();
2835 return -1;
2838 /* Give the new session the default GUI state, if such things exist */
2840 XMLNode* n;
2841 n = Config->instant_xml (X_("Editor"));
2842 if (n) {
2843 new_session->add_instant_xml (*n, false);
2845 n = Config->instant_xml (X_("Mixer"));
2846 if (n) {
2847 new_session->add_instant_xml (*n, false);
2850 /* Put the playhead at 0 and scroll fully left */
2851 n = new_session->instant_xml (X_("Editor"));
2852 if (n) {
2853 n->add_property (X_("playhead"), X_("0"));
2854 n->add_property (X_("left-frame"), X_("0"));
2857 set_session (new_session);
2859 session_loaded = true;
2861 new_session->save_state(new_session->name());
2863 return 0;
2866 void
2867 ARDOUR_UI::launch_chat ()
2869 #ifdef __APPLE__
2870 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
2871 #else
2872 open_uri("http://webchat.freenode.net/?channels=ardour");
2873 #endif
2876 void
2877 ARDOUR_UI::show_about ()
2879 if (about == 0) {
2880 about = new About;
2881 about->signal_response().connect(sigc::mem_fun (*this, &ARDOUR_UI::about_signal_response) );
2884 about->set_transient_for(*editor);
2885 about->show_all ();
2888 void
2889 ARDOUR_UI::launch_manual ()
2891 PBD::open_uri("http://ardour.org/flossmanual");
2894 void
2895 ARDOUR_UI::launch_reference ()
2897 PBD::open_uri("http://ardour.org/refmanual");
2900 void
2901 ARDOUR_UI::hide_about ()
2903 if (about) {
2904 about->get_window()->set_cursor ();
2905 about->hide ();
2909 void
2910 ARDOUR_UI::about_signal_response (int /*response*/)
2912 hide_about();
2915 void
2916 ARDOUR_UI::show_splash ()
2918 if (splash == 0) {
2919 try {
2920 splash = new Splash;
2921 } catch (...) {
2922 return;
2926 splash->show ();
2927 splash->present ();
2928 splash->queue_draw ();
2929 splash->get_window()->process_updates (true);
2930 flush_pending ();
2933 void
2934 ARDOUR_UI::hide_splash ()
2936 if (splash) {
2937 splash->hide();
2941 void
2942 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title,
2943 const string& plural_msg, const string& singular_msg)
2945 size_t removed;
2947 removed = rep.paths.size();
2949 if (removed == 0) {
2950 MessageDialog msgd (*editor,
2951 _("No audio files were ready for cleanup"),
2952 true,
2953 Gtk::MESSAGE_INFO,
2954 (Gtk::ButtonsType)(Gtk::BUTTONS_OK) );
2955 msgd.set_secondary_text (_("If this seems suprising, \n\
2956 check for any existing snapshots.\n\
2957 These may still include regions that\n\
2958 require some unused files to continue to exist."));
2960 msgd.run ();
2961 return;
2964 ArdourDialog results (_("Clean-up"), true, false);
2966 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
2967 CleanupResultsModelColumns() {
2968 add (visible_name);
2969 add (fullpath);
2971 Gtk::TreeModelColumn<std::string> visible_name;
2972 Gtk::TreeModelColumn<std::string> fullpath;
2976 CleanupResultsModelColumns results_columns;
2977 Glib::RefPtr<Gtk::ListStore> results_model;
2978 Gtk::TreeView results_display;
2980 results_model = ListStore::create (results_columns);
2981 results_display.set_model (results_model);
2982 results_display.append_column (list_title, results_columns.visible_name);
2984 results_display.set_name ("CleanupResultsList");
2985 results_display.set_headers_visible (true);
2986 results_display.set_headers_clickable (false);
2987 results_display.set_reorderable (false);
2989 Gtk::ScrolledWindow list_scroller;
2990 Gtk::Label txt;
2991 Gtk::VBox dvbox;
2992 Gtk::HBox dhbox; // the hbox for the image and text
2993 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
2994 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
2996 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
2998 const string dead_sound_directory = _session->session_directory().dead_sound_path().to_string();
3000 /* subst:
3001 %1 - number of files removed
3002 %2 - location of "dead_sounds"
3003 %3 - size of files affected
3004 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
3007 const char* bprefix;
3008 double space_adjusted = 0;
3010 if (rep.space < 100000.0f) {
3011 bprefix = X_("kilo");
3012 } else if (rep.space < 1000000.0f * 1000) {
3013 bprefix = X_("mega");
3014 space_adjusted = truncf((float)rep.space / 1000.0);
3015 } else {
3016 bprefix = X_("giga");
3017 space_adjusted = truncf((float)rep.space / (1000000.0 * 1000));
3020 if (removed > 1) {
3021 txt.set_text (string_compose (plural_msg, removed, _session->path() + "dead_sounds", space_adjusted, bprefix));
3022 } else {
3023 txt.set_text (string_compose (singular_msg, removed, _session->path() + "dead_sounds", space_adjusted, bprefix));
3026 dhbox.pack_start (*dimage, true, false, 5);
3027 dhbox.pack_start (txt, true, false, 5);
3029 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
3030 TreeModel::Row row = *(results_model->append());
3031 row[results_columns.visible_name] = *i;
3032 row[results_columns.fullpath] = *i;
3035 list_scroller.add (results_display);
3036 list_scroller.set_size_request (-1, 150);
3037 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
3039 dvbox.pack_start (dhbox, true, false, 5);
3040 dvbox.pack_start (list_scroller, true, false, 5);
3041 ddhbox.pack_start (dvbox, true, false, 5);
3043 results.get_vbox()->pack_start (ddhbox, true, false, 5);
3044 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
3045 results.set_default_response (RESPONSE_CLOSE);
3046 results.set_position (Gtk::WIN_POS_MOUSE);
3048 results_display.show();
3049 list_scroller.show();
3050 txt.show();
3051 dvbox.show();
3052 dhbox.show();
3053 ddhbox.show();
3054 dimage->show();
3056 //results.get_vbox()->show();
3057 results.set_resizable (false);
3059 results.run ();
3063 void
3064 ARDOUR_UI::cleanup ()
3066 if (_session == 0) {
3067 /* shouldn't happen: menu item is insensitive */
3068 return;
3072 MessageDialog checker (_("Are you sure you want to cleanup?"),
3073 true,
3074 Gtk::MESSAGE_QUESTION,
3075 (Gtk::ButtonsType)(Gtk::BUTTONS_NONE));
3077 checker.set_secondary_text(_("Cleanup is a destructive operation.\n\
3078 ALL undo/redo information will be lost if you cleanup.\n\
3079 After cleanup, unused audio files will be moved to a \
3080 \"dead sounds\" location."));
3082 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3083 checker.add_button (_("Clean Up"), RESPONSE_ACCEPT);
3084 checker.set_default_response (RESPONSE_CANCEL);
3086 checker.set_name (_("CleanupDialog"));
3087 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3088 checker.set_position (Gtk::WIN_POS_MOUSE);
3090 switch (checker.run()) {
3091 case RESPONSE_ACCEPT:
3092 break;
3093 default:
3094 return;
3097 ARDOUR::CleanupReport rep;
3099 editor->prepare_for_cleanup ();
3101 /* do not allow flush until a session is reloaded */
3103 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3104 if (act) {
3105 act->set_sensitive (false);
3108 if (_session->cleanup_sources (rep)) {
3109 editor->finish_cleanup ();
3110 return;
3113 editor->finish_cleanup ();
3115 checker.hide();
3116 display_cleanup_results (rep,
3117 _("cleaned files"),
3118 _("\
3119 The following %1 files were not in use and \n\
3120 have been moved to:\n\
3121 %2. \n\n\
3122 Flushing the wastebasket will \n\
3123 release an additional\n\
3124 %3 %4bytes of disk space.\n"),
3125 _("\
3126 The following file was not in use and \n \
3127 has been moved to:\n \
3128 %2. \n\n\
3129 Flushing the wastebasket will \n\
3130 release an additional\n\
3131 %3 %4bytes of disk space.\n"
3136 void
3137 ARDOUR_UI::flush_trash ()
3139 if (_session == 0) {
3140 /* shouldn't happen: menu item is insensitive */
3141 return;
3144 ARDOUR::CleanupReport rep;
3146 if (_session->cleanup_trash_sources (rep)) {
3147 return;
3150 display_cleanup_results (rep,
3151 _("deleted file"),
3152 _("The following %1 files were deleted from\n\
3153 %2,\n\
3154 releasing %3 %4bytes of disk space"),
3155 _("The following file was deleted from\n\
3156 %2,\n\
3157 releasing %3 %4bytes of disk space"));
3160 void
3161 ARDOUR_UI::add_route (Gtk::Window* float_window)
3163 int count;
3165 if (!_session) {
3166 return;
3169 if (add_route_dialog == 0) {
3170 add_route_dialog = new AddRouteDialog (_session);
3171 if (float_window) {
3172 add_route_dialog->set_transient_for (*float_window);
3176 if (add_route_dialog->is_visible()) {
3177 /* we're already doing this */
3178 return;
3181 ResponseType r = (ResponseType) add_route_dialog->run ();
3183 add_route_dialog->hide();
3185 switch (r) {
3186 case RESPONSE_ACCEPT:
3187 break;
3188 default:
3189 return;
3190 break;
3193 if ((count = add_route_dialog->count()) <= 0) {
3194 return;
3197 string template_path = add_route_dialog->track_template();
3199 if (!template_path.empty()) {
3200 _session->new_route_from_template (count, template_path);
3201 return;
3204 uint32_t input_chan = add_route_dialog->channels ();
3205 uint32_t output_chan;
3206 string name_template = add_route_dialog->name_template ();
3207 bool track = add_route_dialog->track ();
3208 RouteGroup* route_group = add_route_dialog->route_group ();
3210 AutoConnectOption oac = Config->get_output_auto_connect();
3212 if (oac & AutoConnectMaster) {
3213 output_chan = (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan);
3214 } else {
3215 output_chan = input_chan;
3218 /* XXX do something with name template */
3220 if (add_route_dialog->type() == ARDOUR::DataType::MIDI) {
3221 if (track) {
3222 session_add_midi_track (route_group, count);
3223 } else {
3224 MessageDialog msg (*editor,
3225 _("Sorry, MIDI Busses are not supported at this time."));
3226 msg.run ();
3227 //session_add_midi_bus();
3229 } else {
3230 if (track) {
3231 session_add_audio_track (input_chan, output_chan, add_route_dialog->mode(), route_group, count);
3232 } else {
3233 session_add_audio_bus (input_chan, output_chan, route_group, count);
3238 XMLNode*
3239 ARDOUR_UI::mixer_settings () const
3241 XMLNode* node = 0;
3243 if (_session) {
3244 node = _session->instant_xml(X_("Mixer"));
3245 } else {
3246 node = Config->instant_xml(X_("Mixer"));
3249 if (!node) {
3250 node = new XMLNode (X_("Mixer"));
3253 return node;
3256 XMLNode*
3257 ARDOUR_UI::editor_settings () const
3259 XMLNode* node = 0;
3261 if (_session) {
3262 node = _session->instant_xml(X_("Editor"));
3263 } else {
3264 node = Config->instant_xml(X_("Editor"));
3267 if (!node) {
3268 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
3269 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
3273 if (!node) {
3274 node = new XMLNode (X_("Editor"));
3277 return node;
3280 XMLNode*
3281 ARDOUR_UI::keyboard_settings () const
3283 XMLNode* node = 0;
3285 node = Config->extra_xml(X_("Keyboard"));
3287 if (!node) {
3288 node = new XMLNode (X_("Keyboard"));
3290 return node;
3293 void
3294 ARDOUR_UI::create_xrun_marker (framepos_t where)
3296 editor->mouse_add_new_marker (where, false, true);
3299 void
3300 ARDOUR_UI::halt_on_xrun_message ()
3302 MessageDialog msg (*editor,
3303 _("Recording was stopped because your system could not keep up."));
3304 msg.run ();
3307 void
3308 ARDOUR_UI::xrun_handler (framepos_t where)
3310 if (!_session) {
3311 return;
3314 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
3316 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
3317 create_xrun_marker(where);
3320 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
3321 halt_on_xrun_message ();
3325 void
3326 ARDOUR_UI::disk_overrun_handler ()
3328 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
3330 if (!have_disk_speed_dialog_displayed) {
3331 have_disk_speed_dialog_displayed = true;
3332 MessageDialog* msg = new MessageDialog (*editor, string_compose (_("\
3333 The disk system on your computer\n\
3334 was not able to keep up with %1.\n\
3336 Specifically, it failed to write data to disk\n\
3337 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
3338 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3339 msg->show ();
3343 void
3344 ARDOUR_UI::disk_underrun_handler ()
3346 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
3348 if (!have_disk_speed_dialog_displayed) {
3349 have_disk_speed_dialog_displayed = true;
3350 MessageDialog* msg = new MessageDialog (*editor,
3351 string_compose (_("The disk system on your computer\n\
3352 was not able to keep up with %1.\n\
3354 Specifically, it failed to read data from disk\n\
3355 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
3356 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3357 msg->show ();
3361 void
3362 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
3364 have_disk_speed_dialog_displayed = false;
3365 delete msg;
3368 void
3369 ARDOUR_UI::session_dialog (std::string msg)
3371 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
3373 MessageDialog* d;
3375 if (editor) {
3376 d = new MessageDialog (*editor, msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3377 } else {
3378 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3381 d->show_all ();
3382 d->run ();
3383 delete d;
3387 ARDOUR_UI::pending_state_dialog ()
3389 HBox* hbox = new HBox();
3390 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3391 ArdourDialog dialog (_("Crash Recovery"), true);
3392 Label message (_("\
3393 This session appears to have been in\n\
3394 middle of recording when ardour or\n\
3395 the computer was shutdown.\n\
3397 Ardour can recover any captured audio for\n\
3398 you, or it can ignore it. Please decide\n\
3399 what you would like to do.\n"));
3400 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3401 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3402 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3403 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3404 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
3405 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
3406 dialog.set_default_response (RESPONSE_ACCEPT);
3407 dialog.set_position (WIN_POS_CENTER);
3408 message.show();
3409 image->show();
3410 hbox->show();
3412 switch (dialog.run ()) {
3413 case RESPONSE_ACCEPT:
3414 return 1;
3415 default:
3416 return 0;
3421 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
3423 HBox* hbox = new HBox();
3424 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3425 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
3426 Label message (string_compose (_("\
3427 This session was created with a sample rate of %1 Hz\n\
3429 The audioengine is currently running at %2 Hz\n"), desired, actual));
3431 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3432 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3433 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3434 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3435 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
3436 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
3437 dialog.set_default_response (RESPONSE_ACCEPT);
3438 dialog.set_position (WIN_POS_CENTER);
3439 message.show();
3440 image->show();
3441 hbox->show();
3443 switch (dialog.run ()) {
3444 case RESPONSE_ACCEPT:
3445 return 0;
3446 default:
3447 return 1;
3452 void
3453 ARDOUR_UI::disconnect_from_jack ()
3455 if (engine) {
3456 if( engine->disconnect_from_jack ()) {
3457 MessageDialog msg (*editor, _("Could not disconnect from JACK"));
3458 msg.run ();
3461 update_sample_rate (0);
3465 void
3466 ARDOUR_UI::reconnect_to_jack ()
3468 if (engine) {
3469 if (engine->reconnect_to_jack ()) {
3470 MessageDialog msg (*editor, _("Could not reconnect to JACK"));
3471 msg.run ();
3474 update_sample_rate (0);
3478 void
3479 ARDOUR_UI::use_config ()
3481 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
3482 if (node) {
3483 set_transport_controllable_state (*node);
3487 void
3488 ARDOUR_UI::update_transport_clocks (framepos_t pos)
3490 if (Config->get_primary_clock_delta_edit_cursor()) {
3491 primary_clock.set (pos, false, editor->get_preferred_edit_position(), 1);
3492 } else {
3493 primary_clock.set (pos, 0, true);
3496 if (Config->get_secondary_clock_delta_edit_cursor()) {
3497 secondary_clock.set (pos, false, editor->get_preferred_edit_position(), 2);
3498 } else {
3499 secondary_clock.set (pos);
3502 if (big_clock_window->get()) {
3503 big_clock.set (pos);
3508 void
3509 ARDOUR_UI::step_edit_status_change (bool yn)
3511 // XXX should really store pre-step edit status of things
3512 // we make insensitive
3514 if (yn) {
3515 rec_button.set_visual_state (3);
3516 rec_button.set_sensitive (false);
3517 } else {
3518 rec_button.set_visual_state (0);
3519 rec_button.set_sensitive (true);
3523 void
3524 ARDOUR_UI::record_state_changed ()
3526 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
3528 if (!_session || !big_clock_window->get()) {
3529 /* why bother - the clock isn't visible */
3530 return;
3533 Session::RecordState const r = _session->record_status ();
3534 bool const h = _session->have_rec_enabled_track ();
3536 if (r == Session::Recording && h) {
3537 big_clock.set_widget_name ("BigClockRecording");
3538 } else {
3539 big_clock.set_widget_name ("BigClockNonRecording");
3543 bool
3544 ARDOUR_UI::first_idle ()
3546 if (_session) {
3547 _session->allow_auto_play (true);
3550 if (editor) {
3551 editor->first_idle();
3554 Keyboard::set_can_save_keybindings (true);
3555 return false;
3558 void
3559 ARDOUR_UI::store_clock_modes ()
3561 XMLNode* node = new XMLNode(X_("ClockModes"));
3563 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
3564 node->add_property ((*x)->name().c_str(), enum_2_string ((*x)->mode()));
3567 _session->add_extra_xml (*node);
3568 _session->set_dirty ();
3573 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
3574 : Controllable (name), ui (u), type(tp)
3579 void
3580 ARDOUR_UI::TransportControllable::set_value (double val)
3582 if (type == ShuttleControl) {
3583 double fract;
3585 if (val == 0.5) {
3586 fract = 0.0;
3587 } else {
3588 if (val < 0.5) {
3589 fract = -((0.5 - val)/0.5);
3590 } else {
3591 fract = ((val - 0.5)/0.5);
3595 ui.set_shuttle_fract (fract);
3596 return;
3599 if (val < 0.5) {
3600 /* do nothing: these are radio-style actions */
3601 return;
3604 const char *action = 0;
3606 switch (type) {
3607 case Roll:
3608 action = X_("Roll");
3609 break;
3610 case Stop:
3611 action = X_("Stop");
3612 break;
3613 case GotoStart:
3614 action = X_("Goto Start");
3615 break;
3616 case GotoEnd:
3617 action = X_("Goto End");
3618 break;
3619 case AutoLoop:
3620 action = X_("Loop");
3621 break;
3622 case PlaySelection:
3623 action = X_("Play Selection");
3624 break;
3625 case RecordEnable:
3626 action = X_("Record");
3627 break;
3628 default:
3629 break;
3632 if (action == 0) {
3633 return;
3636 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
3638 if (act) {
3639 act->activate ();
3643 double
3644 ARDOUR_UI::TransportControllable::get_value (void) const
3646 float val = 0.0;
3648 switch (type) {
3649 case Roll:
3650 break;
3651 case Stop:
3652 break;
3653 case GotoStart:
3654 break;
3655 case GotoEnd:
3656 break;
3657 case AutoLoop:
3658 break;
3659 case PlaySelection:
3660 break;
3661 case RecordEnable:
3662 break;
3663 case ShuttleControl:
3664 break;
3665 default:
3666 break;
3669 return val;
3672 void
3673 ARDOUR_UI::TransportControllable::set_id (const string& str)
3675 _id = str;
3678 void
3679 ARDOUR_UI::setup_profile ()
3681 if (gdk_screen_width() < 1200) {
3682 Profile->set_small_screen ();
3686 if (getenv ("ARDOUR_SAE")) {
3687 Profile->set_sae ();
3688 Profile->set_single_package ();
3692 void
3693 ARDOUR_UI::toggle_translations ()
3695 using namespace Glib;
3697 RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("EnableTranslation"));
3698 if (act) {
3699 RefPtr<ToggleAction> ract = RefPtr<ToggleAction>::cast_dynamic (act);
3700 if (ract) {
3702 string i18n_killer = ARDOUR::translation_kill_path();
3704 bool already_enabled = !ARDOUR::translations_are_disabled ();
3706 if (ract->get_active ()) {
3707 /* we don't care about errors */
3708 int fd = ::open (i18n_killer.c_str(), O_RDONLY|O_CREAT, 0644);
3709 close (fd);
3710 } else {
3711 /* we don't care about errors */
3712 unlink (i18n_killer.c_str());
3715 if (already_enabled != ract->get_active()) {
3716 MessageDialog win (already_enabled ? _("Translations disabled") : _("Translations enabled"),
3717 false,
3718 Gtk::MESSAGE_WARNING,
3719 Gtk::BUTTONS_OK);
3720 win.set_secondary_text (string_compose (_("You must restart %1 for this to take effect."), PROGRAM_NAME));
3721 win.set_position (Gtk::WIN_POS_CENTER);
3722 win.present ();
3723 win.run ();
3729 /** Add a window proxy to our list, so that its state will be saved.
3730 * This call also causes the window to be created and opened if its
3731 * state was saved as `visible'.
3733 void
3734 ARDOUR_UI::add_window_proxy (WindowProxyBase* p)
3736 _window_proxies.push_back (p);
3737 p->maybe_show ();
3740 /** Remove a window proxy from our list. Must be called if a WindowProxy
3741 * is deleted, to prevent hanging pointers.
3743 void
3744 ARDOUR_UI::remove_window_proxy (WindowProxyBase* p)
3746 _window_proxies.remove (p);
3750 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
3752 MissingFileDialog dialog (s, str, type);
3754 dialog.show ();
3755 dialog.present ();
3757 int result = dialog.run ();
3758 dialog.hide ();
3760 switch (result) {
3761 case RESPONSE_OK:
3762 break;
3763 default:
3764 return 1; // quit entire session load
3767 result = dialog.get_action ();
3769 return result;
3773 ARDOUR_UI::ambiguous_file (std::string file, std::string path, std::vector<std::string> hits)
3775 AmbiguousFileDialog dialog (file, hits);
3777 dialog.show ();
3778 dialog.present ();
3780 dialog.run ();
3781 return dialog.get_which ();