put the issue of using a monitor section into ~/.config/ardour.rc, not the session...
[ardour2.git] / gtk2_ardour / ardour_ui.cc
blob1a5daf08c39ac1e4b77333ca755228069b8f9091
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 #define __STDC_FORMAT_MACROS 1
21 #include <stdint.h>
23 #include <algorithm>
24 #include <cmath>
25 #include <fcntl.h>
26 #include <signal.h>
27 #include <unistd.h>
28 #include <time.h>
29 #include <cerrno>
30 #include <fstream>
32 #include <iostream>
34 #include <sys/resource.h>
36 #include <gtkmm/messagedialog.h>
37 #include <gtkmm/accelmap.h>
39 #include "pbd/error.h"
40 #include "pbd/basename.h"
41 #include "pbd/compose.h"
42 #include "pbd/failed_constructor.h"
43 #include "pbd/enumwriter.h"
44 #include "pbd/memento_command.h"
45 #include "pbd/openuri.h"
46 #include "pbd/file_utils.h"
48 #include "gtkmm2ext/gtk_ui.h"
49 #include "gtkmm2ext/utils.h"
50 #include "gtkmm2ext/click_box.h"
51 #include "gtkmm2ext/fastmeter.h"
52 #include "gtkmm2ext/stop_signal.h"
53 #include "gtkmm2ext/popup.h"
54 #include "gtkmm2ext/window_title.h"
56 #include "midi++/manager.h"
58 #include "ardour/ardour.h"
59 #include "ardour/profile.h"
60 #include "ardour/session_directory.h"
61 #include "ardour/session_route.h"
62 #include "ardour/session_state_utils.h"
63 #include "ardour/session_utils.h"
64 #include "ardour/port.h"
65 #include "ardour/audioengine.h"
66 #include "ardour/playlist.h"
67 #include "ardour/utils.h"
68 #include "ardour/audio_diskstream.h"
69 #include "ardour/audiofilesource.h"
70 #include "ardour/recent_sessions.h"
71 #include "ardour/port.h"
72 #include "ardour/audio_track.h"
73 #include "ardour/midi_track.h"
74 #include "ardour/filesystem_paths.h"
75 #include "ardour/filename_extensions.h"
77 typedef uint64_t microseconds_t;
79 #include "actions.h"
80 #include "ardour_ui.h"
81 #include "public_editor.h"
82 #include "audio_clock.h"
83 #include "keyboard.h"
84 #include "mixer_ui.h"
85 #include "prompter.h"
86 #include "opts.h"
87 #include "add_route_dialog.h"
88 #include "about.h"
89 #include "splash.h"
90 #include "utils.h"
91 #include "gui_thread.h"
92 #include "theme_manager.h"
93 #include "bundle_manager.h"
94 #include "session_metadata_dialog.h"
95 #include "gain_meter.h"
96 #include "route_time_axis.h"
97 #include "startup.h"
98 #include "engine_dialog.h"
99 #include "processor_box.h"
101 #include "i18n.h"
103 using namespace ARDOUR;
104 using namespace PBD;
105 using namespace Gtkmm2ext;
106 using namespace Gtk;
108 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
109 UIConfiguration *ARDOUR_UI::ui_config = 0;
111 sigc::signal<void,bool> ARDOUR_UI::Blink;
112 sigc::signal<void> ARDOUR_UI::RapidScreenUpdate;
113 sigc::signal<void> ARDOUR_UI::SuperRapidScreenUpdate;
114 sigc::signal<void,nframes_t, bool, nframes_t> ARDOUR_UI::Clock;
116 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[])
118 : Gtkmm2ext::UI (X_("gui"), argcp, argvp),
120 primary_clock (X_("primary"), false, X_("TransportClockDisplay"), true, true, false, true),
121 secondary_clock (X_("secondary"), false, X_("SecondaryClockDisplay"), true, true, false, true),
122 preroll_clock (X_("preroll"), false, X_("PreRollClock"), true, false, true),
123 postroll_clock (X_("postroll"), false, X_("PostRollClock"), true, false, true),
125 /* preroll stuff */
127 preroll_button (_("pre\nroll")),
128 postroll_button (_("post\nroll")),
130 /* big clock */
132 big_clock (X_("bigclock"), false, "BigClockNonRecording", true, true, false, false),
134 /* transport */
136 roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll)),
137 stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop)),
138 goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart)),
139 goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd)),
140 auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop)),
141 play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection)),
142 rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable)),
143 shuttle_controllable (new TransportControllable ("shuttle", *this, TransportControllable::ShuttleControl)),
144 shuttle_controller_binding_proxy (shuttle_controllable),
146 roll_button (roll_controllable),
147 stop_button (stop_controllable),
148 goto_start_button (goto_start_controllable),
149 goto_end_button (goto_end_controllable),
150 auto_loop_button (auto_loop_controllable),
151 play_selection_button (play_selection_controllable),
152 rec_button (rec_controllable),
154 shuttle_units_button (_("% ")),
156 punch_in_button (_("Punch In")),
157 punch_out_button (_("Punch Out")),
158 auto_return_button (_("Auto Return")),
159 auto_play_button (_("Auto Play")),
160 auto_input_button (_("Auto Input")),
161 click_button (_("Click")),
162 time_master_button (_("time\nmaster")),
164 auditioning_alert_button (_("AUDITION")),
165 solo_alert_button (_("SOLO")),
166 shown_flag (false),
167 error_log_button (_("Errors"))
170 using namespace Gtk::Menu_Helpers;
172 Gtkmm2ext::init();
175 #ifdef TOP_MENUBAR
176 // _auto_display_errors = false;
178 * This was commented out as it wasn't defined
179 * in A3 IIRC. If this is not needed it should
180 * be completely removed.
182 #endif
184 about = 0;
185 splash = 0;
186 _startup = 0;
188 if (theArdourUI == 0) {
189 theArdourUI = this;
192 ui_config = new UIConfiguration();
193 theme_manager = new ThemeManager();
195 editor = 0;
196 mixer = 0;
197 editor = 0;
198 engine = 0;
199 _session_is_new = false;
200 big_clock_window = 0;
201 big_clock_height = 0;
202 big_clock_resize_in_progress = false;
203 session_selector_window = 0;
204 last_key_press_time = 0;
205 _will_create_new_session_automatically = false;
206 add_route_dialog = 0;
207 route_params = 0;
208 rc_option_editor = 0;
209 session_option_editor = 0;
210 location_ui = 0;
211 open_session_selector = 0;
212 have_configure_timeout = false;
213 have_disk_speed_dialog_displayed = false;
214 session_loaded = false;
215 last_speed_displayed = -1.0f;
216 ignore_dual_punch = false;
217 _mixer_on_top = false;
218 original_big_clock_width = -1;
219 original_big_clock_height = -1;
220 original_big_clock_font_size = 0;
222 roll_button.unset_flags (Gtk::CAN_FOCUS);
223 stop_button.unset_flags (Gtk::CAN_FOCUS);
224 goto_start_button.unset_flags (Gtk::CAN_FOCUS);
225 goto_end_button.unset_flags (Gtk::CAN_FOCUS);
226 auto_loop_button.unset_flags (Gtk::CAN_FOCUS);
227 play_selection_button.unset_flags (Gtk::CAN_FOCUS);
228 rec_button.unset_flags (Gtk::CAN_FOCUS);
230 last_configure_time= 0;
232 shuttle_grabbed = false;
233 shuttle_fract = 0.0;
234 shuttle_max_speed = 8.0f;
236 shuttle_style_menu = 0;
237 shuttle_unit_menu = 0;
239 // We do not have jack linked in yet so;
241 last_shuttle_request = last_peak_grab = 0; // get_microseconds();
243 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
244 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
246 /* handle dialog requests */
248 ARDOUR::Session::Dialog.connect (forever_connections, ui_bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
250 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
252 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
254 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
256 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
258 /* lets get this party started */
260 try {
261 if (ARDOUR::init (ARDOUR_COMMAND_LINE::use_vst, ARDOUR_COMMAND_LINE::try_hw_optimization)) {
262 throw failed_constructor ();
265 setup_gtk_ardour_enums ();
266 setup_profile ();
268 GainMeter::setup_slider_pix ();
269 RouteTimeAxisView::setup_slider_pix ();
270 SendProcessorEntry::setup_slider_pix ();
271 SessionEvent::create_per_thread_pool ("GUI", 512);
273 } catch (failed_constructor& err) {
274 error << _("could not initialize Ardour.") << endmsg;
275 // pass it on up
276 throw;
279 /* we like keyboards */
281 keyboard = new ArdourKeyboard(*this);
283 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
284 if (node) {
285 keyboard->set_state (*node, Stateful::loading_state_version);
288 reset_dpi();
290 starting.connect (sigc::mem_fun(*this, &ARDOUR_UI::startup));
291 stopping.connect (sigc::mem_fun(*this, &ARDOUR_UI::shutdown));
293 platform_setup ();
296 /** @return true if a session was chosen and `apply' clicked, otherwise false if `cancel' was clicked */
297 bool
298 ARDOUR_UI::run_startup (bool should_be_new)
300 if (_startup == 0) {
301 _startup = new ArdourStartup ();
304 _startup->set_new_only (should_be_new);
305 _startup->present ();
307 main().run();
309 _startup->hide ();
311 switch (_startup->response()) {
312 case RESPONSE_OK:
313 return true;
314 default:
315 return false;
320 ARDOUR_UI::create_engine ()
322 // this gets called every time by new_session()
324 if (engine) {
325 return 0;
328 loading_message (_("Starting audio engine"));
330 try {
331 engine = new ARDOUR::AudioEngine (ARDOUR_COMMAND_LINE::jack_client_name);
333 } catch (...) {
335 return -1;
338 engine->Stopped.connect (forever_connections, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
339 engine->Running.connect (forever_connections, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
340 engine->Halted.connect (forever_connections, boost::bind (&ARDOUR_UI::engine_halted, this), gui_context());
341 engine->SampleRateChanged.connect (forever_connections, ui_bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
343 post_engine ();
345 return 0;
348 void
349 ARDOUR_UI::post_engine ()
351 /* Things to be done once we create the AudioEngine
354 MIDI::Manager::instance()->set_api_data (engine->jack());
355 setup_midi ();
357 ARDOUR::init_post_engine ();
359 ActionManager::init ();
360 _tooltips.enable();
362 if (setup_windows ()) {
363 throw failed_constructor ();
366 check_memory_locking();
368 /* this is the first point at which all the keybindings are available */
370 if (ARDOUR_COMMAND_LINE::show_key_actions) {
371 vector<string> names;
372 vector<string> paths;
373 vector<string> keys;
374 vector<AccelKey> bindings;
376 ActionManager::get_all_actions (names, paths, keys, bindings);
378 vector<string>::iterator n;
379 vector<string>::iterator k;
380 for (n = names.begin(), k = keys.begin(); n != names.end(); ++n, ++k) {
381 cerr << "Action: " << (*n) << " bound to " << (*k) << endl;
384 exit (0);
387 blink_timeout_tag = -1;
389 /* this being a GUI and all, we want peakfiles */
391 AudioFileSource::set_build_peakfiles (true);
392 AudioFileSource::set_build_missing_peakfiles (true);
394 /* set default clock modes */
396 if (Profile->get_sae()) {
397 primary_clock.set_mode (AudioClock::BBT);
398 secondary_clock.set_mode (AudioClock::MinSec);
399 } else {
400 primary_clock.set_mode (AudioClock::Timecode);
401 secondary_clock.set_mode (AudioClock::BBT);
404 /* start the time-of-day-clock */
406 #ifndef GTKOSX
407 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
408 update_wall_clock ();
409 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 60000);
410 #endif
412 update_disk_space ();
413 update_cpu_load ();
414 update_sample_rate (engine->frame_rate());
416 Config->ParameterChanged.connect (forever_connections, ui_bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
417 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
418 Config->map_parameters (pc);
420 /* now start and maybe save state */
422 if (do_engine_start () == 0) {
423 if (_session && _session_is_new) {
424 /* we need to retain initial visual
425 settings for a new session
427 _session->save_state ("");
432 ARDOUR_UI::~ARDOUR_UI ()
434 delete keyboard;
435 delete editor;
436 delete mixer;
437 delete add_route_dialog;
440 void
441 ARDOUR_UI::pop_back_splash ()
443 if (Splash::instance()) {
444 // Splash::instance()->pop_back();
445 Splash::instance()->hide ();
449 gint
450 ARDOUR_UI::configure_timeout ()
452 if (last_configure_time == 0) {
453 /* no configure events yet */
454 return true;
457 /* force a gap of 0.5 seconds since the last configure event
460 if (get_microseconds() - last_configure_time < 500000) {
461 return true;
462 } else {
463 have_configure_timeout = false;
464 cerr << "config event-driven save\n";
465 save_ardour_state ();
466 return false;
470 gboolean
471 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
473 if (have_configure_timeout) {
474 last_configure_time = get_microseconds();
475 } else {
476 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
477 have_configure_timeout = true;
480 return FALSE;
483 void
484 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
486 const XMLProperty* prop;
488 if ((prop = node.property ("roll")) != 0) {
489 roll_controllable->set_id (prop->value());
491 if ((prop = node.property ("stop")) != 0) {
492 stop_controllable->set_id (prop->value());
494 if ((prop = node.property ("goto-start")) != 0) {
495 goto_start_controllable->set_id (prop->value());
497 if ((prop = node.property ("goto-end")) != 0) {
498 goto_end_controllable->set_id (prop->value());
500 if ((prop = node.property ("auto-loop")) != 0) {
501 auto_loop_controllable->set_id (prop->value());
503 if ((prop = node.property ("play-selection")) != 0) {
504 play_selection_controllable->set_id (prop->value());
506 if ((prop = node.property ("rec")) != 0) {
507 rec_controllable->set_id (prop->value());
509 if ((prop = node.property ("shuttle")) != 0) {
510 shuttle_controllable->set_id (prop->value());
514 XMLNode&
515 ARDOUR_UI::get_transport_controllable_state ()
517 XMLNode* node = new XMLNode(X_("TransportControllables"));
518 char buf[64];
520 roll_controllable->id().print (buf, sizeof (buf));
521 node->add_property (X_("roll"), buf);
522 stop_controllable->id().print (buf, sizeof (buf));
523 node->add_property (X_("stop"), buf);
524 goto_start_controllable->id().print (buf, sizeof (buf));
525 node->add_property (X_("goto_start"), buf);
526 goto_end_controllable->id().print (buf, sizeof (buf));
527 node->add_property (X_("goto_end"), buf);
528 auto_loop_controllable->id().print (buf, sizeof (buf));
529 node->add_property (X_("auto_loop"), buf);
530 play_selection_controllable->id().print (buf, sizeof (buf));
531 node->add_property (X_("play_selection"), buf);
532 rec_controllable->id().print (buf, sizeof (buf));
533 node->add_property (X_("rec"), buf);
534 shuttle_controllable->id().print (buf, sizeof (buf));
535 node->add_property (X_("shuttle"), buf);
537 return *node;
541 gint
542 ARDOUR_UI::autosave_session ()
544 if (g_main_depth() > 1) {
545 /* inside a recursive main loop,
546 give up because we may not be able to
547 take a lock.
549 return 1;
552 if (!Config->get_periodic_safety_backups()) {
553 return 1;
556 if (_session) {
557 _session->maybe_write_autosave();
560 return 1;
563 void
564 ARDOUR_UI::update_autosave ()
566 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_autosave)
568 if (_session && _session->dirty()) {
569 if (_autosave_connection.connected()) {
570 _autosave_connection.disconnect();
573 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
574 Config->get_periodic_safety_backup_interval() * 1000);
576 } else {
577 if (_autosave_connection.connected()) {
578 _autosave_connection.disconnect();
583 void
584 ARDOUR_UI::backend_audio_error (bool we_set_params, Gtk::Window* toplevel)
586 string title;
587 if (we_set_params) {
588 title = string_compose (_("%1 could not start JACK"), PROGRAM_NAME);
589 } else {
590 title = string_compose (_("%1 could not connect to JACK."), PROGRAM_NAME);
593 MessageDialog win (title,
594 false,
595 Gtk::MESSAGE_INFO,
596 Gtk::BUTTONS_NONE);
598 if (we_set_params) {
599 win.set_secondary_text(_("There are several possible reasons:\n\
601 1) You requested audio parameters that are not supported..\n\
602 2) JACK is running as another user.\n\
604 Please consider the possibilities, and perhaps try different parameters."));
605 } else {
606 win.set_secondary_text(_("There are several possible reasons:\n\
608 1) JACK is not running.\n\
609 2) JACK is running as another user, perhaps root.\n\
610 3) There is already another client called \"ardour\".\n\
612 Please consider the possibilities, and perhaps (re)start JACK."));
615 if (toplevel) {
616 win.set_transient_for (*toplevel);
619 if (we_set_params) {
620 win.add_button (Stock::OK, RESPONSE_CLOSE);
621 } else {
622 win.add_button (Stock::QUIT, RESPONSE_CLOSE);
625 win.set_default_response (RESPONSE_CLOSE);
627 win.show_all ();
628 win.set_position (Gtk::WIN_POS_CENTER);
629 pop_back_splash ();
631 /* we just don't care about the result, but we want to block */
633 win.run ();
636 void
637 ARDOUR_UI::startup ()
639 XMLNode* audio_setup = Config->extra_xml ("AudioSetup");
641 if (audio_setup && _startup && _startup->engine_control()) {
642 _startup->engine_control()->set_state (*audio_setup);
645 if (get_session_parameters (true, ARDOUR_COMMAND_LINE::new_session)) {
646 exit (1);
649 use_config ();
651 goto_editor_window ();
653 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
654 show ();
657 void
658 ARDOUR_UI::no_memory_warning ()
660 XMLNode node (X_("no-memory-warning"));
661 Config->add_instant_xml (node);
664 void
665 ARDOUR_UI::check_memory_locking ()
667 #ifdef __APPLE__
668 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
669 return;
670 #else // !__APPLE__
672 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
674 if (engine->is_realtime() && memory_warning_node == 0) {
676 struct rlimit limits;
677 int64_t ram;
678 long pages, page_size;
680 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0) {
681 ram = 0;
682 } else {
683 ram = (int64_t) pages * (int64_t) page_size;
686 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
687 return;
690 if (limits.rlim_cur != RLIM_INFINITY) {
692 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
695 MessageDialog msg (string_compose (_("WARNING: Your system has a limit for maximum amount of locked memory. "
696 "This might cause %1 to run out of memory before your system "
697 "runs out of memory. \n\n"
698 "You can view the memory limit with 'ulimit -l', "
699 "and it is normally controlled by /etc/security/limits.conf"),
700 PROGRAM_NAME).c_str());
702 VBox* vbox = msg.get_vbox();
703 HBox hbox;
704 CheckButton cb (_("Do not show this window again"));
706 cb.signal_toggled().connect (sigc::mem_fun (*this, &ARDOUR_UI::no_memory_warning));
708 hbox.pack_start (cb, true, false);
709 vbox->pack_start (hbox);
710 cb.show();
711 vbox->show();
712 hbox.show ();
714 pop_back_splash ();
716 editor->ensure_float (msg);
717 msg.run ();
721 #endif // !__APPLE__
725 void
726 ARDOUR_UI::finish()
728 if (_session) {
730 if (_session->transport_rolling()) {
731 _session->request_stop ();
732 usleep (250000);
735 if (_session->dirty()) {
736 switch (ask_about_saving_session(_("quit"))) {
737 case -1:
738 return;
739 break;
740 case 1:
741 /* use the default name */
742 if (save_state_canfail ("")) {
743 /* failed - don't quit */
744 MessageDialog msg (*editor,
745 _("\
746 Ardour was unable to save your session.\n\n\
747 If you still wish to quit, please use the\n\n\
748 \"Just quit\" option."));
749 pop_back_splash();
750 msg.run ();
751 return;
753 break;
754 case 0:
755 break;
759 second_connection.disconnect ();
760 point_one_second_connection.disconnect ();
761 point_oh_five_second_connection.disconnect ();
762 point_zero_one_second_connection.disconnect();
764 // _session->set_deletion_in_progress ();
765 _session->remove_pending_capture_state ();
766 delete _session;
767 _session = 0;
770 ArdourDialog::close_all_dialogs ();
771 engine->stop (true);
772 cerr << "Save before quit\n";
773 save_ardour_state ();
774 quit ();
778 ARDOUR_UI::ask_about_saving_session (const string & what)
780 ArdourDialog window (_("ardour: save session?"));
781 Gtk::HBox dhbox; // the hbox for the image and text
782 Gtk::Label prompt_label;
783 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
785 string msg;
787 msg = string_compose(_("Don't %1"), what);
788 window.add_button (msg, RESPONSE_REJECT);
789 msg = string_compose(_("Just %1"), what);
790 window.add_button (msg, RESPONSE_APPLY);
791 msg = string_compose(_("Save and %1"), what);
792 window.add_button (msg, RESPONSE_ACCEPT);
794 window.set_default_response (RESPONSE_ACCEPT);
796 Gtk::Button noquit_button (msg);
797 noquit_button.set_name ("EditorGTKButton");
799 string prompt;
800 string type;
802 if (_session->snap_name() == _session->name()) {
803 type = _("session");
804 } else {
805 type = _("snapshot");
807 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?"),
808 type, _session->snap_name());
810 prompt_label.set_text (prompt);
811 prompt_label.set_name (X_("PrompterLabel"));
812 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
814 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
815 dhbox.set_homogeneous (false);
816 dhbox.pack_start (*dimage, false, false, 5);
817 dhbox.pack_start (prompt_label, true, false, 5);
818 window.get_vbox()->pack_start (dhbox);
820 window.set_name (_("Prompter"));
821 window.set_position (Gtk::WIN_POS_MOUSE);
822 window.set_modal (true);
823 window.set_resizable (false);
825 dhbox.show();
826 prompt_label.show();
827 dimage->show();
828 window.show();
829 window.set_keep_above (true);
830 window.present ();
832 ResponseType r = (ResponseType) window.run();
834 window.hide ();
836 switch (r) {
837 case RESPONSE_ACCEPT: // save and get out of here
838 return 1;
839 case RESPONSE_APPLY: // get out of here
840 return 0;
841 default:
842 break;
845 return -1;
848 gint
849 ARDOUR_UI::every_second ()
851 update_cpu_load ();
852 update_buffer_load ();
853 update_disk_space ();
854 return TRUE;
857 gint
858 ARDOUR_UI::every_point_one_seconds ()
860 update_speed_display ();
861 RapidScreenUpdate(); /* EMIT_SIGNAL */
862 return TRUE;
865 gint
866 ARDOUR_UI::every_point_zero_one_seconds ()
868 // august 2007: actual update frequency: 40Hz, not 100Hz
870 SuperRapidScreenUpdate(); /* EMIT_SIGNAL */
871 return TRUE;
874 void
875 ARDOUR_UI::update_sample_rate (nframes_t)
877 char buf[32];
879 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
881 if (!engine->connected()) {
883 snprintf (buf, sizeof (buf), _("disconnected"));
885 } else {
887 nframes_t rate = engine->frame_rate();
889 if (fmod (rate, 1000.0) != 0.0) {
890 snprintf (buf, sizeof (buf), _("%.1f kHz / %4.1f ms"),
891 (float) rate/1000.0f,
892 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
893 } else {
894 snprintf (buf, sizeof (buf), _("%u kHz / %4.1f ms"),
895 rate/1000,
896 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
900 sample_rate_label.set_text (buf);
903 void
904 ARDOUR_UI::update_cpu_load ()
906 char buf[32];
907 snprintf (buf, sizeof (buf), _("DSP: %5.1f%%"), engine->get_cpu_load());
908 cpu_load_label.set_text (buf);
911 void
912 ARDOUR_UI::update_buffer_load ()
914 char buf[64];
915 uint32_t c, p;
917 if (_session) {
918 c = _session->capture_load ();
919 p = _session->playback_load ();
921 push_buffer_stats (c, p);
923 snprintf (buf, sizeof (buf), _("Buffers p:%" PRIu32 "%% c:%" PRIu32 "%%"),
924 _session->playback_load(), _session->capture_load());
925 buffer_load_label.set_text (buf);
926 } else {
927 buffer_load_label.set_text ("");
931 void
932 ARDOUR_UI::count_recenabled_streams (Route& route)
934 Track* track = dynamic_cast<Track*>(&route);
935 if (track && track->diskstream()->record_enabled()) {
936 rec_enabled_streams += track->n_inputs().n_total();
940 void
941 ARDOUR_UI::update_disk_space()
943 if (_session == 0) {
944 return;
947 nframes_t frames = _session->available_capture_duration();
948 char buf[64];
949 nframes_t fr = _session->frame_rate();
951 if (frames == max_frames) {
952 strcpy (buf, _("Disk: 24hrs+"));
953 } else {
954 rec_enabled_streams = 0;
955 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams);
957 if (rec_enabled_streams) {
958 frames /= rec_enabled_streams;
961 int hrs;
962 int mins;
963 int secs;
965 hrs = frames / (fr * 3600);
966 frames -= hrs * fr * 3600;
967 mins = frames / (fr * 60);
968 frames -= mins * fr * 60;
969 secs = frames / fr;
971 snprintf (buf, sizeof(buf), _("Disk: %02dh:%02dm:%02ds"), hrs, mins, secs);
974 disk_space_label.set_text (buf);
976 // An attempt to make the disk space label flash red when space has run out.
978 if (frames < fr * 60 * 5) {
979 /* disk_space_box.style ("disk_space_label_empty"); */
980 } else {
981 /* disk_space_box.style ("disk_space_label"); */
986 gint
987 ARDOUR_UI::update_wall_clock ()
989 time_t now;
990 struct tm *tm_now;
991 char buf[16];
993 time (&now);
994 tm_now = localtime (&now);
996 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
997 wall_clock_label.set_text (buf);
999 return TRUE;
1002 gint
1003 ARDOUR_UI::session_menu (GdkEventButton */*ev*/)
1005 session_popup_menu->popup (0, 0);
1006 return TRUE;
1009 void
1010 ARDOUR_UI::redisplay_recent_sessions ()
1012 std::vector<sys::path> session_directories;
1013 RecentSessionsSorter cmp;
1015 recent_session_display.set_model (Glib::RefPtr<TreeModel>(0));
1016 recent_session_model->clear ();
1018 ARDOUR::RecentSessions rs;
1019 ARDOUR::read_recent_sessions (rs);
1021 if (rs.empty()) {
1022 recent_session_display.set_model (recent_session_model);
1023 return;
1026 // sort them alphabetically
1027 sort (rs.begin(), rs.end(), cmp);
1029 for (ARDOUR::RecentSessions::iterator i = rs.begin(); i != rs.end(); ++i) {
1030 session_directories.push_back ((*i).second);
1033 for (vector<sys::path>::const_iterator i = session_directories.begin();
1034 i != session_directories.end(); ++i)
1036 std::vector<sys::path> state_file_paths;
1038 // now get available states for this session
1040 get_state_files_in_directory (*i, state_file_paths);
1042 vector<string*>* states;
1043 vector<const gchar*> item;
1044 string fullpath = (*i).to_string();
1046 /* remove any trailing / */
1048 if (fullpath[fullpath.length()-1] == '/') {
1049 fullpath = fullpath.substr (0, fullpath.length()-1);
1052 /* check whether session still exists */
1053 if (!Glib::file_test(fullpath.c_str(), Glib::FILE_TEST_EXISTS)) {
1054 /* session doesn't exist */
1055 cerr << "skipping non-existent session " << fullpath << endl;
1056 continue;
1059 /* now get available states for this session */
1061 if ((states = Session::possible_states (fullpath)) == 0) {
1062 /* no state file? */
1063 continue;
1066 std::vector<string> state_file_names(get_file_names_no_extension (state_file_paths));
1068 Gtk::TreeModel::Row row = *(recent_session_model->append());
1070 row[recent_session_columns.visible_name] = Glib::path_get_basename (fullpath);
1071 row[recent_session_columns.fullpath] = fullpath;
1073 if (state_file_names.size() > 1) {
1075 // add the children
1077 for (std::vector<std::string>::iterator i2 = state_file_names.begin();
1078 i2 != state_file_names.end(); ++i2)
1081 Gtk::TreeModel::Row child_row = *(recent_session_model->append (row.children()));
1083 child_row[recent_session_columns.visible_name] = *i2;
1084 child_row[recent_session_columns.fullpath] = fullpath;
1089 recent_session_display.set_model (recent_session_model);
1092 void
1093 ARDOUR_UI::build_session_selector ()
1095 session_selector_window = new ArdourDialog (_("Recent Sessions"));
1097 Gtk::ScrolledWindow *scroller = manage (new Gtk::ScrolledWindow);
1099 session_selector_window->add_button (Stock::CANCEL, RESPONSE_CANCEL);
1100 session_selector_window->add_button (Stock::OPEN, RESPONSE_ACCEPT);
1101 session_selector_window->set_default_response (RESPONSE_ACCEPT);
1102 recent_session_model = TreeStore::create (recent_session_columns);
1103 recent_session_display.set_model (recent_session_model);
1104 recent_session_display.append_column (_("Recent Sessions"), recent_session_columns.visible_name);
1105 recent_session_display.set_headers_visible (false);
1106 recent_session_display.get_selection()->set_mode (SELECTION_BROWSE);
1107 recent_session_display.signal_row_activated().connect (sigc::mem_fun (*this, &ARDOUR_UI::recent_session_row_activated));
1109 scroller->add (recent_session_display);
1110 scroller->set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
1112 session_selector_window->set_name ("SessionSelectorWindow");
1113 session_selector_window->set_size_request (200, 400);
1114 session_selector_window->get_vbox()->pack_start (*scroller);
1116 recent_session_display.show();
1117 scroller->show();
1118 //session_selector_window->get_vbox()->show();
1121 void
1122 ARDOUR_UI::recent_session_row_activated (const TreePath& /*path*/, TreeViewColumn* /*col*/)
1124 session_selector_window->response (RESPONSE_ACCEPT);
1127 void
1128 ARDOUR_UI::open_recent_session ()
1130 bool can_return = (_session != 0);
1132 if (session_selector_window == 0) {
1133 build_session_selector ();
1136 redisplay_recent_sessions ();
1138 while (true) {
1140 session_selector_window->set_position (WIN_POS_MOUSE);
1142 ResponseType r = (ResponseType) session_selector_window->run ();
1144 switch (r) {
1145 case RESPONSE_ACCEPT:
1146 break;
1147 default:
1148 if (can_return) {
1149 session_selector_window->hide();
1150 return;
1151 } else {
1152 exit (1);
1156 if (recent_session_display.get_selection()->count_selected_rows() == 0) {
1157 continue;
1160 session_selector_window->hide();
1162 Gtk::TreeModel::iterator i = recent_session_display.get_selection()->get_selected();
1164 if (i == recent_session_model->children().end()) {
1165 return;
1168 Glib::ustring path = (*i)[recent_session_columns.fullpath];
1169 Glib::ustring state = (*i)[recent_session_columns.visible_name];
1171 _session_is_new = false;
1173 if (load_session (path, state) == 0) {
1174 break;
1177 can_return = false;
1181 bool
1182 ARDOUR_UI::check_audioengine ()
1184 if (engine) {
1185 if (!engine->connected()) {
1186 MessageDialog msg (string_compose (_("%1 is not connected to JACK\n"
1187 "You cannot open or close sessions in this condition"),
1188 PROGRAM_NAME));
1189 pop_back_splash ();
1190 msg.run ();
1191 return false;
1193 return true;
1194 } else {
1195 return false;
1199 void
1200 ARDOUR_UI::open_session ()
1202 if (!check_audioengine()) {
1203 return;
1207 /* popup selector window */
1209 if (open_session_selector == 0) {
1211 /* ardour sessions are folders */
1213 open_session_selector = new Gtk::FileChooserDialog (_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1214 open_session_selector->add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1215 open_session_selector->add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1216 open_session_selector->set_default_response(Gtk::RESPONSE_ACCEPT);
1218 FileFilter session_filter;
1219 session_filter.add_pattern ("*.ardour");
1220 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1221 open_session_selector->add_filter (session_filter);
1222 open_session_selector->set_filter (session_filter);
1225 int response = open_session_selector->run();
1226 open_session_selector->hide ();
1228 switch (response) {
1229 case RESPONSE_ACCEPT:
1230 break;
1231 default:
1232 open_session_selector->hide();
1233 return;
1236 open_session_selector->hide();
1237 string session_path = open_session_selector->get_filename();
1238 string path, name;
1239 bool isnew;
1241 if (session_path.length() > 0) {
1242 if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1243 _session_is_new = isnew;
1244 load_session (path, name);
1250 void
1251 ARDOUR_UI::session_add_midi_route (bool disk, RouteGroup* route_group, uint32_t how_many)
1253 list<boost::shared_ptr<MidiTrack> > tracks;
1255 if (_session == 0) {
1256 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1257 return;
1260 try {
1261 if (disk) {
1263 tracks = _session->new_midi_track (ARDOUR::Normal, route_group, how_many);
1265 if (tracks.size() != how_many) {
1266 if (how_many == 1) {
1267 error << _("could not create a new midi track") << endmsg;
1268 } else {
1269 error << string_compose (_("could not create %1 new midi tracks"), how_many) << endmsg;
1272 } /*else {
1273 if ((route = _session->new_midi_route ()) == 0) {
1274 error << _("could not create new midi bus") << endmsg;
1279 catch (...) {
1280 MessageDialog msg (*editor,
1281 _("There are insufficient JACK ports available\n\
1282 to create a new track or bus.\n\
1283 You should save Ardour, exit and\n\
1284 restart JACK with more ports."));
1285 msg.run ();
1290 void
1291 ARDOUR_UI::session_add_audio_route (bool track, bool aux, int32_t input_channels, int32_t output_channels, ARDOUR::TrackMode mode, RouteGroup* route_group, uint32_t how_many)
1293 list<boost::shared_ptr<AudioTrack> > tracks;
1294 RouteList routes;
1296 if (_session == 0) {
1297 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1298 return;
1301 try {
1302 if (track) {
1303 tracks = _session->new_audio_track (input_channels, output_channels, mode, route_group, how_many);
1305 if (tracks.size() != how_many) {
1306 if (how_many == 1) {
1307 error << _("could not create a new audio track") << endmsg;
1308 } else {
1309 error << string_compose (_("could only create %1 of %2 new audio %3"),
1310 tracks.size(), how_many, (track ? _("tracks") : _("busses"))) << endmsg;
1314 } else {
1316 routes = _session->new_audio_route (aux, input_channels, output_channels, route_group, how_many);
1318 if (routes.size() != how_many) {
1319 if (how_many == 1) {
1320 error << _("could not create a new audio track") << endmsg;
1321 } else {
1322 error << string_compose (_("could not create %1 new audio tracks"), how_many) << endmsg;
1327 #if CONTROLOUTS
1328 if (need_control_room_outs) {
1329 pan_t pans[2];
1331 pans[0] = 0.5;
1332 pans[1] = 0.5;
1334 route->set_stereo_control_outs (control_lr_channels);
1335 route->control_outs()->set_stereo_pan (pans, this);
1337 #endif /* CONTROLOUTS */
1340 catch (...) {
1341 MessageDialog msg (*editor,
1342 _("There are insufficient JACK ports available\n\
1343 to create a new track or bus.\n\
1344 You should save Ardour, exit and\n\
1345 restart JACK with more ports."));
1346 pop_back_splash ();
1347 msg.run ();
1351 void
1352 ARDOUR_UI::do_transport_locate (nframes_t new_position)
1354 nframes_t _preroll = 0;
1356 if (_session) {
1357 // XXX CONFIG_CHANGE FIX - requires AnyTime handling
1358 // _preroll = _session->convert_to_frames_at (new_position, Config->get_preroll());
1360 if (new_position > _preroll) {
1361 new_position -= _preroll;
1362 } else {
1363 new_position = 0;
1366 _session->request_locate (new_position);
1370 void
1371 ARDOUR_UI::transport_goto_start ()
1373 if (_session) {
1374 _session->goto_start();
1376 /* force displayed area in editor to start no matter
1377 what "follow playhead" setting is.
1380 if (editor) {
1381 editor->center_screen (_session->current_start_frame ());
1386 void
1387 ARDOUR_UI::transport_goto_zero ()
1389 if (_session) {
1390 _session->request_locate (0);
1392 /* force displayed area in editor to start no matter
1393 what "follow playhead" setting is.
1396 if (editor) {
1397 editor->reset_x_origin (0);
1402 void
1403 ARDOUR_UI::transport_goto_wallclock ()
1405 if (_session && editor) {
1407 time_t now;
1408 struct tm tmnow;
1409 nframes64_t frames;
1411 time (&now);
1412 localtime_r (&now, &tmnow);
1414 frames = tmnow.tm_hour * (60 * 60 * _session->frame_rate());
1415 frames += tmnow.tm_min * (60 * _session->frame_rate());
1416 frames += tmnow.tm_sec * _session->frame_rate();
1418 _session->request_locate (frames);
1420 /* force displayed area in editor to start no matter
1421 what "follow playhead" setting is.
1424 if (editor) {
1425 editor->center_screen (frames);
1430 void
1431 ARDOUR_UI::transport_goto_end ()
1433 if (_session) {
1434 nframes_t const frame = _session->current_end_frame();
1435 _session->request_locate (frame);
1437 /* force displayed area in editor to start no matter
1438 what "follow playhead" setting is.
1441 if (editor) {
1442 editor->center_screen (frame);
1447 void
1448 ARDOUR_UI::transport_stop ()
1450 if (!_session) {
1451 return;
1454 if (_session->is_auditioning()) {
1455 _session->cancel_audition ();
1456 return;
1459 _session->request_stop ();
1462 void
1463 ARDOUR_UI::transport_stop_and_forget_capture ()
1465 if (_session) {
1466 _session->request_stop (true);
1470 void
1471 ARDOUR_UI::remove_last_capture()
1473 if (editor) {
1474 editor->remove_last_capture();
1478 void
1479 ARDOUR_UI::transport_record (bool roll)
1482 if (_session) {
1483 switch (_session->record_status()) {
1484 case Session::Disabled:
1485 if (_session->ntracks() == 0) {
1486 MessageDialog msg (*editor, _("Please create 1 or more track\nbefore trying to record.\nCheck the Session menu."));
1487 msg.run ();
1488 return;
1490 _session->maybe_enable_record ();
1491 if (roll) {
1492 transport_roll ();
1494 break;
1495 case Session::Recording:
1496 if (roll) {
1497 _session->request_stop();
1498 } else {
1499 _session->disable_record (false, true);
1501 break;
1503 case Session::Enabled:
1504 _session->disable_record (false, true);
1507 //cerr << "ARDOUR_UI::transport_record () called roll = " << roll << " _session->record_status() = " << _session->record_status() << endl;
1510 void
1511 ARDOUR_UI::transport_roll ()
1513 if (!_session) {
1514 return;
1517 if (_session->is_auditioning()) {
1518 return;
1521 if (_session->config.get_external_sync()) {
1522 switch (_session->config.get_sync_source()) {
1523 case JACK:
1524 break;
1525 default:
1526 /* transport controlled by the master */
1527 return;
1531 bool rolling = _session->transport_rolling();
1533 if (_session->get_play_loop()) {
1534 _session->request_play_loop (false, true);
1535 } else if (_session->get_play_range () && !join_play_range_button.get_active()) {
1536 /* stop playing a range if we currently are */
1537 _session->request_play_range (0, true);
1540 if (join_play_range_button.get_active()) {
1541 _session->request_play_range (&editor->get_selection().time, true);
1544 if (!rolling) {
1545 _session->request_transport_speed (1.0f);
1548 map_transport_state ();
1551 void
1552 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
1555 if (!_session) {
1556 return;
1559 if (_session->is_auditioning()) {
1560 _session->cancel_audition ();
1561 return;
1564 if (_session->config.get_external_sync()) {
1565 switch (_session->config.get_sync_source()) {
1566 case JACK:
1567 break;
1568 default:
1569 /* transport controlled by the master */
1570 return;
1574 bool rolling = _session->transport_rolling();
1575 bool affect_transport = true;
1577 if (rolling && roll_out_of_bounded_mode) {
1578 /* drop out of loop/range playback but leave transport rolling */
1579 if (_session->get_play_loop()) {
1580 if (Config->get_seamless_loop()) {
1581 /* the disk buffers contain copies of the loop - we can't
1582 just keep playing, so stop the transport. the user
1583 can restart as they wish.
1585 affect_transport = true;
1586 } else {
1587 /* disk buffers are normal, so we can keep playing */
1588 affect_transport = false;
1590 _session->request_play_loop (false, true);
1591 } else if (_session->get_play_range ()) {
1592 affect_transport = false;
1593 _session->request_play_range (0, true);
1597 if (affect_transport) {
1598 if (rolling) {
1599 _session->request_stop (with_abort, true);
1600 } else {
1601 if (join_play_range_button.get_active()) {
1602 _session->request_play_range (&editor->get_selection().time, true);
1605 _session->request_transport_speed (1.0f);
1609 map_transport_state ();
1612 void
1613 ARDOUR_UI::toggle_session_auto_loop ()
1615 if (_session) {
1616 if (_session->get_play_loop()) {
1617 if (_session->transport_rolling()) {
1618 Location * looploc = _session->locations()->auto_loop_location();
1619 if (looploc) {
1620 _session->request_locate (looploc->start(), true);
1622 } else {
1623 _session->request_play_loop (false);
1625 } else {
1626 Location * looploc = _session->locations()->auto_loop_location();
1627 if (looploc) {
1628 _session->request_play_loop (true);
1634 void
1635 ARDOUR_UI::transport_play_selection ()
1637 if (!_session) {
1638 return;
1641 editor->play_selection ();
1644 void
1645 ARDOUR_UI::transport_rewind (int option)
1647 float current_transport_speed;
1649 if (_session) {
1650 current_transport_speed = _session->transport_speed();
1652 if (current_transport_speed >= 0.0f) {
1653 switch (option) {
1654 case 0:
1655 _session->request_transport_speed (-1.0f);
1656 break;
1657 case 1:
1658 _session->request_transport_speed (-4.0f);
1659 break;
1660 case -1:
1661 _session->request_transport_speed (-0.5f);
1662 break;
1664 } else {
1665 /* speed up */
1666 _session->request_transport_speed (current_transport_speed * 1.5f);
1671 void
1672 ARDOUR_UI::transport_forward (int option)
1674 float current_transport_speed;
1676 if (_session) {
1677 current_transport_speed = _session->transport_speed();
1679 if (current_transport_speed <= 0.0f) {
1680 switch (option) {
1681 case 0:
1682 _session->request_transport_speed (1.0f);
1683 break;
1684 case 1:
1685 _session->request_transport_speed (4.0f);
1686 break;
1687 case -1:
1688 _session->request_transport_speed (0.5f);
1689 break;
1691 } else {
1692 /* speed up */
1693 _session->request_transport_speed (current_transport_speed * 1.5f);
1699 void
1700 ARDOUR_UI::toggle_record_enable (uint32_t dstream)
1702 if (_session == 0) {
1703 return;
1706 boost::shared_ptr<Route> r;
1708 if ((r = _session->route_by_remote_id (dstream)) != 0) {
1710 Track* t;
1712 if ((t = dynamic_cast<Track*>(r.get())) != 0) {
1713 t->diskstream()->set_record_enabled (!t->diskstream()->record_enabled());
1716 if (_session == 0) {
1717 return;
1721 void
1722 ARDOUR_UI::map_transport_state ()
1724 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::map_transport_state)
1726 if (!_session) {
1727 auto_loop_button.set_visual_state (0);
1728 play_selection_button.set_visual_state (0);
1729 roll_button.set_visual_state (0);
1730 stop_button.set_visual_state (1);
1731 return;
1734 float sp = _session->transport_speed();
1736 if (sp == 1.0f) {
1737 shuttle_fract = SHUTTLE_FRACT_SPEED1; /* speed = 1.0, believe it or not */
1738 shuttle_box.queue_draw ();
1739 } else if (sp == 0.0f) {
1740 shuttle_fract = 0;
1741 shuttle_box.queue_draw ();
1742 update_disk_space ();
1745 if (sp != 0.0) {
1747 /* we're rolling */
1749 if (_session->get_play_range()) {
1751 play_selection_button.set_visual_state (1);
1752 roll_button.set_visual_state (0);
1753 auto_loop_button.set_visual_state (0);
1755 } else if (_session->get_play_loop ()) {
1757 auto_loop_button.set_visual_state (1);
1758 play_selection_button.set_visual_state (0);
1759 roll_button.set_visual_state (0);
1761 } else {
1763 roll_button.set_visual_state (1);
1764 play_selection_button.set_visual_state (0);
1765 auto_loop_button.set_visual_state (0);
1768 if (join_play_range_button.get_active()) {
1769 /* light up both roll and play-selection if they are joined */
1770 roll_button.set_visual_state (1);
1771 play_selection_button.set_visual_state (1);
1774 stop_button.set_visual_state (0);
1776 } else {
1778 stop_button.set_visual_state (1);
1779 roll_button.set_visual_state (0);
1780 play_selection_button.set_visual_state (0);
1781 auto_loop_button.set_visual_state (0);
1786 void
1787 ARDOUR_UI::engine_stopped ()
1789 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
1790 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1791 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1794 void
1795 ARDOUR_UI::engine_running ()
1797 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
1798 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, true);
1799 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, false);
1801 Glib::RefPtr<Action> action;
1802 const char* action_name = 0;
1804 switch (engine->frames_per_cycle()) {
1805 case 32:
1806 action_name = X_("JACKLatency32");
1807 break;
1808 case 64:
1809 action_name = X_("JACKLatency64");
1810 break;
1811 case 128:
1812 action_name = X_("JACKLatency128");
1813 break;
1814 case 512:
1815 action_name = X_("JACKLatency512");
1816 break;
1817 case 1024:
1818 action_name = X_("JACKLatency1024");
1819 break;
1820 case 2048:
1821 action_name = X_("JACKLatency2048");
1822 break;
1823 case 4096:
1824 action_name = X_("JACKLatency4096");
1825 break;
1826 case 8192:
1827 action_name = X_("JACKLatency8192");
1828 break;
1829 default:
1830 /* XXX can we do anything useful ? */
1831 break;
1834 if (action_name) {
1836 action = ActionManager::get_action (X_("JACK"), action_name);
1838 if (action) {
1839 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (action);
1840 ract->set_active ();
1845 void
1846 ARDOUR_UI::engine_halted ()
1848 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_halted)
1850 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1851 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1853 update_sample_rate (0);
1855 MessageDialog msg (*editor,
1856 _("\
1857 JACK has either been shutdown or it\n\
1858 disconnected Ardour because Ardour\n\
1859 was not fast enough. Try to restart\n\
1860 JACK, reconnect and save the session."));
1861 pop_back_splash ();
1862 msg.run ();
1865 int32_t
1866 ARDOUR_UI::do_engine_start ()
1868 try {
1869 engine->start();
1872 catch (...) {
1873 engine->stop ();
1874 error << _("Unable to start the session running")
1875 << endmsg;
1876 unload_session ();
1877 return -2;
1880 return 0;
1883 void
1884 ARDOUR_UI::setup_theme ()
1886 theme_manager->setup_theme();
1889 void
1890 ARDOUR_UI::update_clocks ()
1892 if (!editor || !editor->dragging_playhead()) {
1893 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position()); /* EMIT_SIGNAL */
1897 void
1898 ARDOUR_UI::start_clocking ()
1900 clock_signal_connection = RapidScreenUpdate.connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
1903 void
1904 ARDOUR_UI::stop_clocking ()
1906 clock_signal_connection.disconnect ();
1909 void
1910 ARDOUR_UI::toggle_clocking ()
1912 #if 0
1913 if (clock_button.get_active()) {
1914 start_clocking ();
1915 } else {
1916 stop_clocking ();
1918 #endif
1921 gint
1922 ARDOUR_UI::_blink (void *arg)
1925 ((ARDOUR_UI *) arg)->blink ();
1926 return TRUE;
1929 void
1930 ARDOUR_UI::blink ()
1932 Blink (blink_on = !blink_on); /* EMIT_SIGNAL */
1935 void
1936 ARDOUR_UI::start_blinking ()
1938 /* Start the blink signal. Everybody with a blinking widget
1939 uses Blink to drive the widget's state.
1942 if (blink_timeout_tag < 0) {
1943 blink_on = false;
1944 blink_timeout_tag = g_timeout_add (240, _blink, this);
1948 void
1949 ARDOUR_UI::stop_blinking ()
1951 if (blink_timeout_tag >= 0) {
1952 g_source_remove (blink_timeout_tag);
1953 blink_timeout_tag = -1;
1958 /** Ask the user for the name of a new shapshot and then take it.
1960 void
1961 ARDOUR_UI::snapshot_session ()
1963 ArdourPrompter prompter (true);
1964 string snapname;
1965 char timebuf[128];
1966 time_t n;
1967 struct tm local_time;
1969 time (&n);
1970 localtime_r (&n, &local_time);
1971 strftime (timebuf, sizeof(timebuf), "%FT%T", &local_time);
1973 prompter.set_name ("Prompter");
1974 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1975 prompter.set_title (_("Take Snapshot"));
1976 prompter.set_prompt (_("Name of New Snapshot"));
1977 prompter.set_initial_text (timebuf);
1979 again:
1980 switch (prompter.run()) {
1981 case RESPONSE_ACCEPT:
1983 prompter.get_result (snapname);
1985 bool do_save = (snapname.length() != 0);
1987 if (do_save) {
1988 if (snapname.find ('/') != string::npos) {
1989 MessageDialog msg (_("To ensure compatibility with various systems\n"
1990 "snapshot names may not contain a '/' character"));
1991 msg.run ();
1992 goto again;
1994 if (snapname.find ('\\') != string::npos) {
1995 MessageDialog msg (_("To ensure compatibility with various systems\n"
1996 "snapshot names may not contain a '\\' character"));
1997 msg.run ();
1998 goto again;
2002 vector<sys::path> p;
2003 get_state_files_in_directory (_session->session_directory().root_path(), p);
2004 vector<string> n = get_file_names_no_extension (p);
2005 if (find (n.begin(), n.end(), snapname) != n.end()) {
2007 ArdourDialog confirm (_("Confirm snapshot overwrite"), true);
2008 Label m (_("A snapshot already exists with that name. Do you want to overwrite it?"));
2009 confirm.get_vbox()->pack_start (m, true, true);
2010 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2011 confirm.add_button (_("Overwrite"), Gtk::RESPONSE_ACCEPT);
2012 confirm.show_all ();
2013 switch (confirm.run()) {
2014 case RESPONSE_CANCEL:
2015 do_save = false;
2019 if (do_save) {
2020 save_state (snapname);
2022 break;
2025 default:
2026 break;
2030 void
2031 ARDOUR_UI::save_state (const string & name)
2033 save_state_canfail (name);
2037 ARDOUR_UI::save_state_canfail (string name)
2039 if (_session) {
2040 int ret;
2042 if (name.length() == 0) {
2043 name = _session->snap_name();
2046 if ((ret = _session->save_state (name)) != 0) {
2047 return ret;
2050 cerr << "SS canfail\n";
2051 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2052 return 0;
2055 void
2056 ARDOUR_UI::primary_clock_value_changed ()
2058 if (_session) {
2059 _session->request_locate (primary_clock.current_time ());
2063 void
2064 ARDOUR_UI::big_clock_value_changed ()
2066 if (_session) {
2067 _session->request_locate (big_clock.current_time ());
2071 void
2072 ARDOUR_UI::secondary_clock_value_changed ()
2074 if (_session) {
2075 _session->request_locate (secondary_clock.current_time ());
2079 void
2080 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2082 if (_session == 0) {
2083 return;
2086 Session::RecordState const r = _session->record_status ();
2087 bool const h = _session->have_rec_enabled_diskstream ();
2089 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2090 if (onoff) {
2091 rec_button.set_visual_state (2);
2092 } else {
2093 rec_button.set_visual_state (0);
2095 } else if (r == Session::Recording && h) {
2096 rec_button.set_visual_state (1);
2097 } else {
2098 rec_button.set_visual_state (0);
2102 void
2103 ARDOUR_UI::save_template ()
2105 ArdourPrompter prompter (true);
2106 string name;
2108 if (!check_audioengine()) {
2109 return;
2112 prompter.set_name (X_("Prompter"));
2113 prompter.set_title (_("Save Mix Template"));
2114 prompter.set_prompt (_("Name for mix template:"));
2115 prompter.set_initial_text(_session->name() + _("-template"));
2116 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2118 switch (prompter.run()) {
2119 case RESPONSE_ACCEPT:
2120 prompter.get_result (name);
2122 if (name.length()) {
2123 _session->save_template (name);
2125 break;
2127 default:
2128 break;
2132 void
2133 ARDOUR_UI::edit_metadata ()
2135 SessionMetadataEditor dialog;
2136 dialog.set_session (_session);
2137 editor->ensure_float (dialog);
2138 dialog.run ();
2141 void
2142 ARDOUR_UI::import_metadata ()
2144 SessionMetadataImporter dialog;
2145 dialog.set_session (_session);
2146 editor->ensure_float (dialog);
2147 dialog.run ();
2150 void
2151 ARDOUR_UI::fontconfig_dialog ()
2153 #ifdef GTKOSX
2154 /* X11 users will always have fontconfig info around, but new GTK-OSX users
2155 may not and it can take a while to build it. Warn them.
2158 Glib::ustring fontconfig = Glib::build_filename (Glib::get_home_dir(), ".fontconfig");
2160 if (!Glib::file_test (fontconfig, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_DIR)) {
2161 MessageDialog msg (*_startup,
2162 _("Welcome to Ardour.\n\n"
2163 "The program will take a bit longer to start up\n"
2164 "while the system fonts are checked.\n\n"
2165 "This will only be done once, and you will\n"
2166 "not see this message again\n"),
2167 true,
2168 Gtk::MESSAGE_INFO,
2169 Gtk::BUTTONS_OK);
2170 pop_back_splash ();
2171 msg.show_all ();
2172 msg.present ();
2173 msg.run ();
2175 #endif
2178 void
2179 ARDOUR_UI::parse_cmdline_path (const Glib::ustring& cmdline_path, Glib::ustring& session_name, Glib::ustring& session_path, bool& existing_session)
2181 existing_session = false;
2183 if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_DIR)) {
2184 session_path = cmdline_path;
2185 existing_session = true;
2186 } else if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_REGULAR)) {
2187 session_path = Glib::path_get_dirname (string (cmdline_path));
2188 existing_session = true;
2189 } else {
2190 /* it doesn't exist, assume the best */
2191 session_path = Glib::path_get_dirname (string (cmdline_path));
2194 session_name = basename_nosuffix (string (cmdline_path));
2198 ARDOUR_UI::load_cmdline_session (const Glib::ustring& session_name, const Glib::ustring& session_path, bool& existing_session)
2200 /* when this is called, the backend audio system must be running */
2202 /* the main idea here is to deal with the fact that a cmdline argument for the session
2203 can be interpreted in different ways - it could be a directory or a file, and before
2204 we load, we need to know both the session directory and the snapshot (statefile) within it
2205 that we are supposed to use.
2208 if (session_name.length() == 0 || session_path.length() == 0) {
2209 return false;
2212 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_DIR)) {
2214 Glib::ustring predicted_session_file;
2216 predicted_session_file = session_path;
2217 predicted_session_file += '/';
2218 predicted_session_file += session_name;
2219 predicted_session_file += ARDOUR::statefile_suffix;
2221 if (Glib::file_test (predicted_session_file, Glib::FILE_TEST_EXISTS)) {
2222 existing_session = true;
2225 } else if (Glib::file_test (session_path, Glib::FILE_TEST_EXISTS)) {
2227 if (session_path.find (ARDOUR::statefile_suffix) == session_path.length() - 7) {
2228 /* existing .ardour file */
2229 existing_session = true;
2232 } else {
2233 existing_session = false;
2236 /* lets just try to load it */
2238 if (create_engine ()) {
2239 backend_audio_error (false, _startup);
2240 return -1;
2243 return load_session (session_path, session_name);
2246 bool
2247 ARDOUR_UI::ask_about_loading_existing_session (const Glib::ustring& session_path)
2249 Glib::ustring str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2251 MessageDialog msg (str,
2252 false,
2253 Gtk::MESSAGE_WARNING,
2254 Gtk::BUTTONS_YES_NO,
2255 true);
2258 msg.set_name (X_("OpenExistingDialog"));
2259 msg.set_title (_("Open Existing Session"));
2260 msg.set_wmclass (X_("existing_session"), "Ardour");
2261 msg.set_position (Gtk::WIN_POS_MOUSE);
2262 pop_back_splash ();
2264 switch (msg.run()) {
2265 case RESPONSE_YES:
2266 return true;
2267 break;
2269 return false;
2273 ARDOUR_UI::build_session_from_nsd (const Glib::ustring& session_path, const Glib::ustring& session_name)
2276 uint32_t mchns;
2277 AutoConnectOption iconnect;
2278 AutoConnectOption oconnect;
2279 uint32_t nphysin;
2280 uint32_t nphysout;
2282 if (Profile->get_sae()) {
2284 mchns = 2;
2285 iconnect = AutoConnectPhysical;
2286 oconnect = AutoConnectMaster;
2287 nphysin = 0; // use all available
2288 nphysout = 0; // use all available
2290 } else {
2292 /* get settings from advanced section of NSD */
2294 if (_startup->create_master_bus()) {
2295 mchns = (uint32_t) _startup->master_channel_count();
2296 } else {
2297 mchns = 0;
2300 if (_startup->connect_inputs()) {
2301 iconnect = AutoConnectPhysical;
2302 } else {
2303 iconnect = AutoConnectOption (0);
2306 /// @todo some minor tweaks.
2308 oconnect = AutoConnectOption (0);
2310 if (_startup->connect_outputs ()) {
2311 if (_startup->connect_outs_to_master()) {
2312 oconnect = AutoConnectMaster;
2313 } else if (_startup->connect_outs_to_physical()) {
2314 oconnect = AutoConnectPhysical;
2318 nphysin = (uint32_t) _startup->input_limit_count();
2319 nphysout = (uint32_t) _startup->output_limit_count();
2322 if (build_session (session_path,
2323 session_name,
2324 mchns,
2325 iconnect,
2326 oconnect,
2327 nphysin,
2328 nphysout,
2329 engine->frame_rate() * 60 * 5)) {
2331 return -1;
2334 return 0;
2337 void
2338 ARDOUR_UI::idle_load (const Glib::ustring& path)
2340 if (_session) {
2341 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2342 /* /path/to/foo => /path/to/foo, foo */
2343 load_session (path, basename_nosuffix (path));
2344 } else {
2345 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2346 load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2348 } else {
2350 ARDOUR_COMMAND_LINE::session_name = path;
2353 * new_session_dialog doens't exist in A3
2354 * Try to remove all references to it to
2355 * see if it will compile. NOTE: this will
2356 * likely cause a runtime issue is my somewhat
2357 * uneducated guess.
2360 //if (new_session_dialog) {
2363 /* make it break out of Dialog::run() and
2364 start again.
2367 //new_session_dialog->response (1);
2372 void
2373 ARDOUR_UI::end_loading_messages ()
2375 // hide_splash ();
2378 void
2379 ARDOUR_UI::loading_message (const std::string& /*msg*/)
2381 // show_splash ();
2382 // splash->message (msg);
2383 flush_pending ();
2386 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
2388 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new)
2390 Glib::ustring session_name;
2391 Glib::ustring session_path;
2392 Glib::ustring template_name;
2393 int ret = -1;
2394 bool likely_new = false;
2396 while (ret != 0) {
2398 if (!should_be_new && !ARDOUR_COMMAND_LINE::session_name.empty()) {
2400 /* if they named a specific statefile, use it, otherwise they are
2401 just giving a session folder, and we want to use it as is
2402 to find the session.
2405 if (ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix) != string::npos) {
2406 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
2407 } else {
2408 session_path = ARDOUR_COMMAND_LINE::session_name;
2411 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
2413 } else {
2415 bool const apply = run_startup (should_be_new);
2416 if (!apply) {
2417 if (quit_on_cancel) {
2418 exit (1);
2419 } else {
2420 return ret;
2424 /* if we run the startup dialog again, offer more than just "new session" */
2426 should_be_new = false;
2428 session_name = _startup->session_name (likely_new);
2430 /* this shouldn't happen, but we catch it just in case it does */
2432 if (session_name.empty()) {
2433 break;
2435 if (_startup->use_session_template()) {
2436 template_name = _startup->session_template_name();
2437 _session_is_new = true;
2440 if (session_name[0] == '/' ||
2441 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == '/') ||
2442 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == '/')) {
2444 /* absolute path or cwd-relative path specified for session name: infer session folder
2445 from what was given.
2448 session_path = Glib::path_get_dirname (session_name);
2449 session_name = Glib::path_get_basename (session_name);
2451 } else {
2453 session_path = _startup->session_folder();
2457 if (create_engine ()) {
2458 break;
2461 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
2463 if (likely_new) {
2465 Glib::ustring existing = Glib::build_filename (session_path, session_name);
2467 if (!ask_about_loading_existing_session (existing)) {
2468 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2469 continue;
2473 _session_is_new = false;
2475 } else {
2477 if (!likely_new) {
2478 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
2479 msg.run ();
2480 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2481 continue;
2484 if (session_name.find ('/') != Glib::ustring::npos) {
2485 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2486 "session names may not contain a '/' character"));
2487 msg.run ();
2488 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2489 continue;
2492 if (session_name.find ('\\') != Glib::ustring::npos) {
2493 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2494 "session names may not contain a '\\' character"));
2495 msg.run ();
2496 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2497 continue;
2500 _session_is_new = true;
2503 if (likely_new && template_name.empty()) {
2505 ret = build_session_from_nsd (session_path, session_name);
2507 } else {
2509 ret = load_session (session_path, session_name, template_name);
2510 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
2511 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
2512 exit (1);
2517 return ret;
2520 void
2521 ARDOUR_UI::close_session()
2523 if (!check_audioengine()) {
2524 return;
2527 if (unload_session (true)) {
2528 return;
2531 ARDOUR_COMMAND_LINE::session_name = "";
2532 get_session_parameters (true, false);
2536 ARDOUR_UI::load_session (const Glib::ustring& path, const Glib::ustring& snap_name, Glib::ustring mix_template)
2538 Session *new_session;
2539 int unload_status;
2540 int retval = -1;
2542 session_loaded = false;
2544 if (!check_audioengine()) {
2545 return -1;
2548 unload_status = unload_session ();
2550 if (unload_status < 0) {
2551 goto out;
2552 } else if (unload_status > 0) {
2553 retval = 0;
2554 goto out;
2557 loading_message (string_compose (_("Please wait while %1loads your session"), PROGRAM_NAME));
2559 try {
2560 new_session = new Session (*engine, path, snap_name, mix_template);
2563 /* this one is special */
2565 catch (AudioEngine::PortRegistrationFailure& err) {
2567 MessageDialog msg (err.what(),
2568 true,
2569 Gtk::MESSAGE_INFO,
2570 Gtk::BUTTONS_CLOSE);
2572 msg.set_title (_("Port Registration Error"));
2573 msg.set_secondary_text (_("Click the Close button to try again."));
2574 msg.set_position (Gtk::WIN_POS_CENTER);
2575 pop_back_splash ();
2576 msg.present ();
2578 int response = msg.run ();
2580 msg.hide ();
2582 switch (response) {
2583 case RESPONSE_CANCEL:
2584 exit (1);
2585 default:
2586 break;
2588 goto out;
2591 catch (...) {
2593 MessageDialog msg (string_compose(_("Session \"%1 (snapshot %2)\" did not load successfully"), path, snap_name),
2594 true,
2595 Gtk::MESSAGE_INFO,
2596 Gtk::BUTTONS_CLOSE);
2598 msg.set_title (_("Loading Error"));
2599 msg.set_secondary_text (_("Click the Close button to try again."));
2600 msg.set_position (Gtk::WIN_POS_CENTER);
2601 pop_back_splash ();
2602 msg.present ();
2604 int response = msg.run ();
2606 msg.hide ();
2608 switch (response) {
2609 case RESPONSE_CANCEL:
2610 exit (1);
2611 default:
2612 break;
2614 goto out;
2617 set_session (new_session);
2619 session_loaded = true;
2621 goto_editor_window ();
2623 if (_session) {
2624 _session->set_clean ();
2627 flush_pending ();
2628 retval = 0;
2630 out:
2631 return retval;
2635 ARDOUR_UI::build_session (const Glib::ustring& path, const Glib::ustring& snap_name,
2636 uint32_t master_channels,
2637 AutoConnectOption input_connect,
2638 AutoConnectOption output_connect,
2639 uint32_t nphysin,
2640 uint32_t nphysout,
2641 nframes_t initial_length)
2643 Session *new_session;
2644 int x;
2646 if (!check_audioengine()) {
2647 return -1;
2650 session_loaded = false;
2652 x = unload_session ();
2654 if (x < 0) {
2655 return -1;
2656 } else if (x > 0) {
2657 return 0;
2660 _session_is_new = true;
2662 try {
2663 new_session = new Session (*engine, path, snap_name, input_connect, output_connect,
2664 master_channels, nphysin, nphysout, initial_length);
2667 catch (...) {
2669 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
2670 pop_back_splash ();
2671 msg.run ();
2672 return -1;
2675 set_session (new_session);
2677 session_loaded = true;
2679 new_session->save_state(new_session->name());
2681 return 0;
2684 void
2685 ARDOUR_UI::show ()
2687 if (editor) {
2688 editor->show_window ();
2690 if (!shown_flag) {
2691 editor->present ();
2694 shown_flag = true;
2698 void
2699 ARDOUR_UI::launch_chat ()
2701 #ifdef __APPLE__
2702 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
2703 #else
2704 open_uri("http://webchat.freenode.net/?channels=ardour");
2705 #endif
2708 void
2709 ARDOUR_UI::show_about ()
2711 if (about == 0) {
2712 about = new About;
2713 about->signal_response().connect(sigc::mem_fun (*this, &ARDOUR_UI::about_signal_response) );
2716 about->set_transient_for(*editor);
2717 about->show_all ();
2720 void
2721 ARDOUR_UI::hide_about ()
2723 if (about) {
2724 about->get_window()->set_cursor ();
2725 about->hide ();
2729 void
2730 ARDOUR_UI::about_signal_response (int /*response*/)
2732 hide_about();
2735 void
2736 ARDOUR_UI::show_splash ()
2738 if (splash == 0) {
2739 try {
2740 splash = new Splash;
2741 } catch (...) {
2742 return;
2746 splash->show ();
2747 splash->present ();
2748 splash->queue_draw ();
2749 splash->get_window()->process_updates (true);
2750 flush_pending ();
2753 void
2754 ARDOUR_UI::hide_splash ()
2756 if (splash) {
2757 splash->hide();
2761 void
2762 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title,
2763 const string& plural_msg, const string& singular_msg)
2765 size_t removed;
2767 removed = rep.paths.size();
2769 if (removed == 0) {
2770 MessageDialog msgd (*editor,
2771 _("No audio files were ready for cleanup"),
2772 true,
2773 Gtk::MESSAGE_INFO,
2774 (Gtk::ButtonsType)(Gtk::BUTTONS_OK) );
2775 msgd.set_secondary_text (_("If this seems suprising, \n\
2776 check for any existing snapshots.\n\
2777 These may still include regions that\n\
2778 require some unused files to continue to exist."));
2780 msgd.run ();
2781 return;
2784 ArdourDialog results (_("ardour: cleanup"), true, false);
2786 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
2787 CleanupResultsModelColumns() {
2788 add (visible_name);
2789 add (fullpath);
2791 Gtk::TreeModelColumn<Glib::ustring> visible_name;
2792 Gtk::TreeModelColumn<Glib::ustring> fullpath;
2796 CleanupResultsModelColumns results_columns;
2797 Glib::RefPtr<Gtk::ListStore> results_model;
2798 Gtk::TreeView results_display;
2800 results_model = ListStore::create (results_columns);
2801 results_display.set_model (results_model);
2802 results_display.append_column (list_title, results_columns.visible_name);
2804 results_display.set_name ("CleanupResultsList");
2805 results_display.set_headers_visible (true);
2806 results_display.set_headers_clickable (false);
2807 results_display.set_reorderable (false);
2809 Gtk::ScrolledWindow list_scroller;
2810 Gtk::Label txt;
2811 Gtk::VBox dvbox;
2812 Gtk::HBox dhbox; // the hbox for the image and text
2813 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
2814 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
2816 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
2818 const string dead_sound_directory = _session->session_directory().dead_sound_path().to_string();
2820 /* subst:
2821 %1 - number of files removed
2822 %2 - location of "dead_sounds"
2823 %3 - size of files affected
2824 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
2827 const char* bprefix;
2828 double space_adjusted = 0;
2830 if (rep.space < 100000.0f) {
2831 bprefix = X_("kilo");
2832 } else if (rep.space < 1000000.0f * 1000) {
2833 bprefix = X_("mega");
2834 space_adjusted = truncf((float)rep.space / 1000.0);
2835 } else {
2836 bprefix = X_("giga");
2837 space_adjusted = truncf((float)rep.space / (1000000.0 * 1000));
2840 if (removed > 1) {
2841 txt.set_text (string_compose (plural_msg, removed, _session->path() + "dead_sounds", space_adjusted, bprefix));
2842 } else {
2843 txt.set_text (string_compose (singular_msg, removed, _session->path() + "dead_sounds", space_adjusted, bprefix));
2846 dhbox.pack_start (*dimage, true, false, 5);
2847 dhbox.pack_start (txt, true, false, 5);
2849 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
2850 TreeModel::Row row = *(results_model->append());
2851 row[results_columns.visible_name] = *i;
2852 row[results_columns.fullpath] = *i;
2855 list_scroller.add (results_display);
2856 list_scroller.set_size_request (-1, 150);
2857 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
2859 dvbox.pack_start (dhbox, true, false, 5);
2860 dvbox.pack_start (list_scroller, true, false, 5);
2861 ddhbox.pack_start (dvbox, true, false, 5);
2863 results.get_vbox()->pack_start (ddhbox, true, false, 5);
2864 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
2865 results.set_default_response (RESPONSE_CLOSE);
2866 results.set_position (Gtk::WIN_POS_MOUSE);
2868 results_display.show();
2869 list_scroller.show();
2870 txt.show();
2871 dvbox.show();
2872 dhbox.show();
2873 ddhbox.show();
2874 dimage->show();
2876 //results.get_vbox()->show();
2877 results.set_resizable (false);
2879 results.run ();
2883 void
2884 ARDOUR_UI::cleanup ()
2886 if (_session == 0) {
2887 /* shouldn't happen: menu item is insensitive */
2888 return;
2892 MessageDialog checker (_("Are you sure you want to cleanup?"),
2893 true,
2894 Gtk::MESSAGE_QUESTION,
2895 (Gtk::ButtonsType)(Gtk::BUTTONS_NONE));
2897 checker.set_secondary_text(_("Cleanup is a destructive operation.\n\
2898 ALL undo/redo information will be lost if you cleanup.\n\
2899 After cleanup, unused audio files will be moved to a \
2900 \"dead sounds\" location."));
2902 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
2903 checker.add_button (_("Clean Up"), RESPONSE_ACCEPT);
2904 checker.set_default_response (RESPONSE_CANCEL);
2906 checker.set_name (_("CleanupDialog"));
2907 checker.set_wmclass (X_("ardour_cleanup"), "Ardour");
2908 checker.set_position (Gtk::WIN_POS_MOUSE);
2910 switch (checker.run()) {
2911 case RESPONSE_ACCEPT:
2912 break;
2913 default:
2914 return;
2917 ARDOUR::CleanupReport rep;
2919 editor->prepare_for_cleanup ();
2921 /* do not allow flush until a session is reloaded */
2923 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
2924 if (act) {
2925 act->set_sensitive (false);
2928 if (_session->cleanup_sources (rep)) {
2929 editor->finish_cleanup ();
2930 return;
2933 editor->finish_cleanup ();
2935 checker.hide();
2936 display_cleanup_results (rep,
2937 _("cleaned files"),
2938 _("\
2939 The following %1 files were not in use and \n\
2940 have been moved to:\n\
2941 %2. \n\n\
2942 Flushing the wastebasket will \n\
2943 release an additional\n\
2944 %3 %4bytes of disk space.\n"),
2945 _("\
2946 The following file was not in use and \n \
2947 has been moved to:\n \
2948 %2. \n\n\
2949 Flushing the wastebasket will \n\
2950 release an additional\n\
2951 %3 %4bytes of disk space.\n"
2956 void
2957 ARDOUR_UI::flush_trash ()
2959 if (_session == 0) {
2960 /* shouldn't happen: menu item is insensitive */
2961 return;
2964 ARDOUR::CleanupReport rep;
2966 if (_session->cleanup_trash_sources (rep)) {
2967 return;
2970 display_cleanup_results (rep,
2971 _("deleted file"),
2972 _("The following %1 files were deleted from\n\
2973 %2,\n\
2974 releasing %3 %4bytes of disk space"),
2975 _("The following file was deleted from\n\
2976 %2,\n\
2977 releasing %3 %4bytes of disk space"));
2980 void
2981 ARDOUR_UI::add_route (Gtk::Window* float_window)
2983 int count;
2985 if (!_session) {
2986 return;
2989 if (add_route_dialog == 0) {
2990 add_route_dialog = new AddRouteDialog (_session);
2991 if (float_window) {
2992 add_route_dialog->set_transient_for (*float_window);
2996 if (add_route_dialog->is_visible()) {
2997 /* we're already doing this */
2998 return;
3001 ResponseType r = (ResponseType) add_route_dialog->run ();
3003 add_route_dialog->hide();
3005 switch (r) {
3006 case RESPONSE_ACCEPT:
3007 break;
3008 default:
3009 return;
3010 break;
3013 if ((count = add_route_dialog->count()) <= 0) {
3014 return;
3017 string template_path = add_route_dialog->track_template();
3019 if (!template_path.empty()) {
3020 _session->new_route_from_template (count, template_path);
3021 return;
3024 uint32_t input_chan = add_route_dialog->channels ();
3025 uint32_t output_chan;
3026 string name_template = add_route_dialog->name_template ();
3027 bool track = add_route_dialog->track ();
3028 bool aux = !track && add_route_dialog->aux();
3029 RouteGroup* route_group = add_route_dialog->route_group ();
3031 AutoConnectOption oac = Config->get_output_auto_connect();
3033 if (oac & AutoConnectMaster) {
3034 output_chan = (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan);
3035 } else {
3036 output_chan = input_chan;
3039 /* XXX do something with name template */
3041 if (add_route_dialog->type() == ARDOUR::DataType::MIDI) {
3042 if (track) {
3043 session_add_midi_track (route_group, count);
3044 } else {
3045 MessageDialog msg (*editor,
3046 _("Sorry, MIDI Busses are not supported at this time."));
3047 msg.run ();
3048 //session_add_midi_bus();
3050 } else {
3051 if (track) {
3052 session_add_audio_track (input_chan, output_chan, add_route_dialog->mode(), route_group, count);
3053 } else {
3054 session_add_audio_bus (aux, input_chan, output_chan, route_group, count);
3059 XMLNode*
3060 ARDOUR_UI::mixer_settings () const
3062 XMLNode* node = 0;
3064 if (_session) {
3065 node = _session->instant_xml(X_("Mixer"));
3066 } else {
3067 node = Config->instant_xml(X_("Mixer"));
3070 if (!node) {
3071 node = new XMLNode (X_("Mixer"));
3074 return node;
3077 XMLNode*
3078 ARDOUR_UI::editor_settings () const
3080 XMLNode* node = 0;
3082 if (_session) {
3083 node = _session->instant_xml(X_("Editor"));
3084 } else {
3085 node = Config->instant_xml(X_("Editor"));
3088 if (!node) {
3089 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
3090 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
3094 if (!node) {
3095 node = new XMLNode (X_("Editor"));
3098 return node;
3101 XMLNode*
3102 ARDOUR_UI::keyboard_settings () const
3104 XMLNode* node = 0;
3106 node = Config->extra_xml(X_("Keyboard"));
3108 if (!node) {
3109 node = new XMLNode (X_("Keyboard"));
3111 return node;
3114 void
3115 ARDOUR_UI::create_xrun_marker(nframes_t where)
3117 editor->mouse_add_new_marker (where, false, true);
3120 void
3121 ARDOUR_UI::halt_on_xrun_message ()
3123 MessageDialog msg (*editor,
3124 _("Recording was stopped because your system could not keep up."));
3125 msg.run ();
3128 void
3129 ARDOUR_UI::xrun_handler(nframes_t where)
3131 if (!_session) {
3132 return;
3135 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
3137 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
3138 create_xrun_marker(where);
3141 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
3142 halt_on_xrun_message ();
3146 void
3147 ARDOUR_UI::push_buffer_stats (uint32_t capture, uint32_t playback)
3149 time_t now;
3150 time (&now);
3152 while (disk_buffer_stats.size() > 60) {
3153 disk_buffer_stats.pop_front ();
3156 disk_buffer_stats.push_back (DiskBufferStat (now, capture, playback));
3159 void
3160 ARDOUR_UI::write_buffer_stats ()
3162 std::ofstream fout;
3163 struct tm tm;
3164 char buf[64];
3165 char path[PATH_MAX+1]; int fd;
3167 strcpy (path, "ardourBufferingXXXXXX");
3169 if ((fd = mkstemp (path )) < 0) {
3170 cerr << X_("cannot find temporary name for buffer stats") << endl;
3171 return;
3174 fout.open (path);
3175 close (fd);
3177 if (!fout) {
3178 cerr << string_compose (X_("cannot open file %1 for buffer stats"), path) << endl;
3179 return;
3182 for (list<DiskBufferStat>::iterator i = disk_buffer_stats.begin(); i != disk_buffer_stats.end(); ++i) {
3183 localtime_r (&(*i).when, &tm);
3184 strftime (buf, sizeof (buf), "%T", &tm);
3185 fout << buf << ' ' << (*i).capture << ' ' << (*i).playback << endl;
3188 disk_buffer_stats.clear ();
3190 fout.close ();
3192 cerr << "buffering statistics can be found in: " << path << endl;
3195 void
3196 ARDOUR_UI::disk_overrun_handler ()
3198 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
3200 write_buffer_stats ();
3202 if (!have_disk_speed_dialog_displayed) {
3203 have_disk_speed_dialog_displayed = true;
3204 MessageDialog* msg = new MessageDialog (*editor, _("\
3205 The disk system on your computer\n\
3206 was not able to keep up with Ardour.\n\
3208 Specifically, it failed to write data to disk\n\
3209 quickly enough to keep up with recording.\n"));
3210 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3211 msg->show ();
3215 void
3216 ARDOUR_UI::disk_underrun_handler ()
3218 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
3220 write_buffer_stats ();
3222 if (!have_disk_speed_dialog_displayed) {
3223 have_disk_speed_dialog_displayed = true;
3224 MessageDialog* msg = new MessageDialog (*editor,
3225 _("The disk system on your computer\n\
3226 was not able to keep up with Ardour.\n\
3228 Specifically, it failed to read data from disk\n\
3229 quickly enough to keep up with playback.\n"));
3230 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3231 msg->show ();
3235 void
3236 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
3238 have_disk_speed_dialog_displayed = false;
3239 delete msg;
3242 void
3243 ARDOUR_UI::session_dialog (std::string msg)
3245 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
3247 MessageDialog* d;
3249 if (editor) {
3250 d = new MessageDialog (*editor, msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3251 } else {
3252 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3255 d->show_all ();
3256 d->run ();
3257 delete d;
3261 ARDOUR_UI::pending_state_dialog ()
3263 HBox* hbox = new HBox();
3264 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3265 ArdourDialog dialog (_("Crash Recovery"), true);
3266 Label message (_("\
3267 This session appears to have been in\n\
3268 middle of recording when ardour or\n\
3269 the computer was shutdown.\n\
3271 Ardour can recover any captured audio for\n\
3272 you, or it can ignore it. Please decide\n\
3273 what you would like to do.\n"));
3274 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3275 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3276 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3277 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3278 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
3279 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
3280 dialog.set_default_response (RESPONSE_ACCEPT);
3281 dialog.set_position (WIN_POS_CENTER);
3282 message.show();
3283 image->show();
3284 hbox->show();
3286 switch (dialog.run ()) {
3287 case RESPONSE_ACCEPT:
3288 return 1;
3289 default:
3290 return 0;
3295 ARDOUR_UI::sr_mismatch_dialog (nframes_t desired, nframes_t actual)
3297 HBox* hbox = new HBox();
3298 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3299 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
3300 Label message (string_compose (_("\
3301 This session was created with a sample rate of %1 Hz\n\
3303 The audioengine is currently running at %2 Hz\n"), desired, actual));
3305 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3306 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3307 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3308 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3309 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
3310 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
3311 dialog.set_default_response (RESPONSE_ACCEPT);
3312 dialog.set_position (WIN_POS_CENTER);
3313 message.show();
3314 image->show();
3315 hbox->show();
3317 switch (dialog.run ()) {
3318 case RESPONSE_ACCEPT:
3319 return 0;
3320 default:
3321 return 1;
3326 void
3327 ARDOUR_UI::disconnect_from_jack ()
3329 if (engine) {
3330 if( engine->disconnect_from_jack ()) {
3331 MessageDialog msg (*editor, _("Could not disconnect from JACK"));
3332 msg.run ();
3335 update_sample_rate (0);
3339 void
3340 ARDOUR_UI::reconnect_to_jack ()
3342 if (engine) {
3343 if (engine->reconnect_to_jack ()) {
3344 MessageDialog msg (*editor, _("Could not reconnect to JACK"));
3345 msg.run ();
3348 update_sample_rate (0);
3352 void
3353 ARDOUR_UI::use_config ()
3356 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
3357 if (node) {
3358 set_transport_controllable_state (*node);
3361 node = Config->extra_xml (X_("UI"));
3363 if (node) {
3364 const XMLProperty* prop = node->property (X_("show-big-clock"));
3365 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleBigClock"));
3366 if (act) {
3367 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
3368 tact->set_active (string_is_affirmative (prop->value()));
3373 void
3374 ARDOUR_UI::update_transport_clocks (nframes_t pos)
3376 if (Config->get_primary_clock_delta_edit_cursor()) {
3377 primary_clock.set (pos, false, editor->get_preferred_edit_position(), 1);
3378 } else {
3379 primary_clock.set (pos, 0, true);
3382 if (Config->get_secondary_clock_delta_edit_cursor()) {
3383 secondary_clock.set (pos, false, editor->get_preferred_edit_position(), 2);
3384 } else {
3385 secondary_clock.set (pos);
3388 if (big_clock_window) {
3389 big_clock.set (pos);
3393 void
3394 ARDOUR_UI::record_state_changed ()
3396 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
3398 if (!_session || !big_clock_window) {
3399 /* why bother - the clock isn't visible */
3400 return;
3403 Session::RecordState const r = _session->record_status ();
3404 bool const h = _session->have_rec_enabled_diskstream ();
3406 if (r == Session::Recording && h) {
3407 big_clock.set_widget_name ("BigClockRecording");
3408 } else {
3409 big_clock.set_widget_name ("BigClockNonRecording");
3413 bool
3414 ARDOUR_UI::first_idle ()
3416 if (_session) {
3417 _session->allow_auto_play (true);
3420 if (editor) {
3421 editor->first_idle();
3424 Keyboard::set_can_save_keybindings (true);
3425 return false;
3428 void
3429 ARDOUR_UI::store_clock_modes ()
3431 XMLNode* node = new XMLNode(X_("ClockModes"));
3433 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
3434 node->add_property ((*x)->name().c_str(), enum_2_string ((*x)->mode()));
3437 _session->add_extra_xml (*node);
3438 _session->set_dirty ();
3443 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
3444 : Controllable (name), ui (u), type(tp)
3449 void
3450 ARDOUR_UI::TransportControllable::set_value (float val)
3452 if (type == ShuttleControl) {
3453 double fract;
3455 if (val == 0.5f) {
3456 fract = 0.0;
3457 } else {
3458 if (val < 0.5f) {
3459 fract = -((0.5f - val)/0.5f);
3460 } else {
3461 fract = ((val - 0.5f)/0.5f);
3465 ui.set_shuttle_fract (fract);
3466 return;
3469 if (val < 0.5f) {
3470 /* do nothing: these are radio-style actions */
3471 return;
3474 const char *action = 0;
3476 switch (type) {
3477 case Roll:
3478 action = X_("Roll");
3479 break;
3480 case Stop:
3481 action = X_("Stop");
3482 break;
3483 case GotoStart:
3484 action = X_("Goto Start");
3485 break;
3486 case GotoEnd:
3487 action = X_("Goto End");
3488 break;
3489 case AutoLoop:
3490 action = X_("Loop");
3491 break;
3492 case PlaySelection:
3493 action = X_("Play Selection");
3494 break;
3495 case RecordEnable:
3496 action = X_("Record");
3497 break;
3498 default:
3499 break;
3502 if (action == 0) {
3503 return;
3506 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
3508 if (act) {
3509 act->activate ();
3513 float
3514 ARDOUR_UI::TransportControllable::get_value (void) const
3516 float val = 0.0f;
3518 switch (type) {
3519 case Roll:
3520 break;
3521 case Stop:
3522 break;
3523 case GotoStart:
3524 break;
3525 case GotoEnd:
3526 break;
3527 case AutoLoop:
3528 break;
3529 case PlaySelection:
3530 break;
3531 case RecordEnable:
3532 break;
3533 case ShuttleControl:
3534 break;
3535 default:
3536 break;
3539 return val;
3542 void
3543 ARDOUR_UI::TransportControllable::set_id (const string& str)
3545 _id = str;
3548 void
3549 ARDOUR_UI::setup_profile ()
3551 if (gdk_screen_width() < 1200) {
3552 Profile->set_small_screen ();
3556 if (getenv ("ARDOUR_SAE")) {
3557 Profile->set_sae ();
3558 Profile->set_single_package ();