Show editor window after opening a new session when one is closed. Should fix #3312.
[ArdourMidi.git] / gtk2_ardour / ardour_ui.cc
blob94d5a4d8d46ca1e079898e81661b5a9324e33ba2
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/popup.h"
53 #include "gtkmm2ext/window_title.h"
55 #include "midi++/manager.h"
57 #include "ardour/ardour.h"
58 #include "ardour/profile.h"
59 #include "ardour/session_directory.h"
60 #include "ardour/session_route.h"
61 #include "ardour/session_state_utils.h"
62 #include "ardour/session_utils.h"
63 #include "ardour/port.h"
64 #include "ardour/audioengine.h"
65 #include "ardour/playlist.h"
66 #include "ardour/utils.h"
67 #include "ardour/audio_diskstream.h"
68 #include "ardour/audiofilesource.h"
69 #include "ardour/recent_sessions.h"
70 #include "ardour/port.h"
71 #include "ardour/audio_track.h"
72 #include "ardour/midi_track.h"
73 #include "ardour/filesystem_paths.h"
74 #include "ardour/filename_extensions.h"
76 typedef uint64_t microseconds_t;
78 #include "actions.h"
79 #include "ardour_ui.h"
80 #include "public_editor.h"
81 #include "audio_clock.h"
82 #include "keyboard.h"
83 #include "mixer_ui.h"
84 #include "prompter.h"
85 #include "opts.h"
86 #include "add_route_dialog.h"
87 #include "about.h"
88 #include "splash.h"
89 #include "utils.h"
90 #include "gui_thread.h"
91 #include "theme_manager.h"
92 #include "bundle_manager.h"
93 #include "session_metadata_dialog.h"
94 #include "gain_meter.h"
95 #include "route_time_axis.h"
96 #include "startup.h"
97 #include "engine_dialog.h"
98 #include "processor_box.h"
99 #include "time_axis_view_item.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 (PROGRAM_NAME, 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, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
244 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
246 /* handle dialog requests */
248 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, 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 TimeAxisViewItem::set_constant_heights ();
292 starting.connect (sigc::mem_fun(*this, &ARDOUR_UI::startup));
293 stopping.connect (sigc::mem_fun(*this, &ARDOUR_UI::shutdown));
295 platform_setup ();
298 /** @return true if a session was chosen and `apply' clicked, otherwise false if `cancel' was clicked */
299 bool
300 ARDOUR_UI::run_startup (bool should_be_new, string load_template)
302 if (_startup == 0) {
303 _startup = new ArdourStartup ();
306 XMLNode* audio_setup = Config->extra_xml ("AudioSetup");
308 if (audio_setup && _startup->engine_control()) {
309 _startup->engine_control()->set_state (*audio_setup);
312 _startup->set_new_only (should_be_new);
313 if (!load_template.empty()) {
314 _startup->set_load_template( load_template );
316 _startup->present ();
318 main().run();
320 _startup->hide ();
322 switch (_startup->response()) {
323 case RESPONSE_OK:
324 return true;
325 default:
326 return false;
331 ARDOUR_UI::create_engine ()
333 // this gets called every time by new_session()
335 if (engine) {
336 return 0;
339 loading_message (_("Starting audio engine"));
341 try {
342 engine = new ARDOUR::AudioEngine (ARDOUR_COMMAND_LINE::jack_client_name, ARDOUR_COMMAND_LINE::jack_session_uuid);
344 } catch (...) {
346 return -1;
349 engine->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
350 engine->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
351 engine->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
353 engine->Halted.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
355 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
357 post_engine ();
359 return 0;
362 void
363 ARDOUR_UI::post_engine ()
365 /* Things to be done once we create the AudioEngine
368 ARDOUR::init_post_engine ();
370 ActionManager::init ();
371 _tooltips.enable();
373 if (setup_windows ()) {
374 throw failed_constructor ();
377 check_memory_locking();
379 /* this is the first point at which all the keybindings are available */
381 if (ARDOUR_COMMAND_LINE::show_key_actions) {
382 vector<string> names;
383 vector<string> paths;
384 vector<string> keys;
385 vector<AccelKey> bindings;
387 ActionManager::get_all_actions (names, paths, keys, bindings);
389 vector<string>::iterator n;
390 vector<string>::iterator k;
391 for (n = names.begin(), k = keys.begin(); n != names.end(); ++n, ++k) {
392 cerr << "Action: " << (*n) << " bound to " << (*k) << endl;
395 exit (0);
398 blink_timeout_tag = -1;
400 /* this being a GUI and all, we want peakfiles */
402 AudioFileSource::set_build_peakfiles (true);
403 AudioFileSource::set_build_missing_peakfiles (true);
405 /* set default clock modes */
407 if (Profile->get_sae()) {
408 primary_clock.set_mode (AudioClock::BBT);
409 secondary_clock.set_mode (AudioClock::MinSec);
410 } else {
411 primary_clock.set_mode (AudioClock::Timecode);
412 secondary_clock.set_mode (AudioClock::BBT);
415 /* start the time-of-day-clock */
417 #ifndef GTKOSX
418 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
419 update_wall_clock ();
420 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 60000);
421 #endif
423 update_disk_space ();
424 update_cpu_load ();
425 update_sample_rate (engine->frame_rate());
427 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
428 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
429 Config->map_parameters (pc);
431 /* now start and maybe save state */
433 if (do_engine_start () == 0) {
434 if (_session && _session_is_new) {
435 /* we need to retain initial visual
436 settings for a new session
438 _session->save_state ("");
443 ARDOUR_UI::~ARDOUR_UI ()
445 delete keyboard;
446 delete editor;
447 delete mixer;
448 delete add_route_dialog;
451 void
452 ARDOUR_UI::pop_back_splash ()
454 if (Splash::instance()) {
455 // Splash::instance()->pop_back();
456 Splash::instance()->hide ();
460 gint
461 ARDOUR_UI::configure_timeout ()
463 if (last_configure_time == 0) {
464 /* no configure events yet */
465 return true;
468 /* force a gap of 0.5 seconds since the last configure event
471 if (get_microseconds() - last_configure_time < 500000) {
472 return true;
473 } else {
474 have_configure_timeout = false;
475 cerr << "config event-driven save\n";
476 save_ardour_state ();
477 return false;
481 gboolean
482 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
484 if (have_configure_timeout) {
485 last_configure_time = get_microseconds();
486 } else {
487 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
488 have_configure_timeout = true;
491 return FALSE;
494 void
495 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
497 const XMLProperty* prop;
499 if ((prop = node.property ("roll")) != 0) {
500 roll_controllable->set_id (prop->value());
502 if ((prop = node.property ("stop")) != 0) {
503 stop_controllable->set_id (prop->value());
505 if ((prop = node.property ("goto-start")) != 0) {
506 goto_start_controllable->set_id (prop->value());
508 if ((prop = node.property ("goto-end")) != 0) {
509 goto_end_controllable->set_id (prop->value());
511 if ((prop = node.property ("auto-loop")) != 0) {
512 auto_loop_controllable->set_id (prop->value());
514 if ((prop = node.property ("play-selection")) != 0) {
515 play_selection_controllable->set_id (prop->value());
517 if ((prop = node.property ("rec")) != 0) {
518 rec_controllable->set_id (prop->value());
520 if ((prop = node.property ("shuttle")) != 0) {
521 shuttle_controllable->set_id (prop->value());
525 XMLNode&
526 ARDOUR_UI::get_transport_controllable_state ()
528 XMLNode* node = new XMLNode(X_("TransportControllables"));
529 char buf[64];
531 roll_controllable->id().print (buf, sizeof (buf));
532 node->add_property (X_("roll"), buf);
533 stop_controllable->id().print (buf, sizeof (buf));
534 node->add_property (X_("stop"), buf);
535 goto_start_controllable->id().print (buf, sizeof (buf));
536 node->add_property (X_("goto_start"), buf);
537 goto_end_controllable->id().print (buf, sizeof (buf));
538 node->add_property (X_("goto_end"), buf);
539 auto_loop_controllable->id().print (buf, sizeof (buf));
540 node->add_property (X_("auto_loop"), buf);
541 play_selection_controllable->id().print (buf, sizeof (buf));
542 node->add_property (X_("play_selection"), buf);
543 rec_controllable->id().print (buf, sizeof (buf));
544 node->add_property (X_("rec"), buf);
545 shuttle_controllable->id().print (buf, sizeof (buf));
546 node->add_property (X_("shuttle"), buf);
548 return *node;
552 gint
553 ARDOUR_UI::autosave_session ()
555 if (g_main_depth() > 1) {
556 /* inside a recursive main loop,
557 give up because we may not be able to
558 take a lock.
560 return 1;
563 if (!Config->get_periodic_safety_backups()) {
564 return 1;
567 if (_session) {
568 _session->maybe_write_autosave();
571 return 1;
574 void
575 ARDOUR_UI::update_autosave ()
577 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_autosave)
579 if (_session && _session->dirty()) {
580 if (_autosave_connection.connected()) {
581 _autosave_connection.disconnect();
584 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
585 Config->get_periodic_safety_backup_interval() * 1000);
587 } else {
588 if (_autosave_connection.connected()) {
589 _autosave_connection.disconnect();
594 void
595 ARDOUR_UI::backend_audio_error (bool we_set_params, Gtk::Window* toplevel)
597 string title;
598 if (we_set_params) {
599 title = string_compose (_("%1 could not start JACK"), PROGRAM_NAME);
600 } else {
601 title = string_compose (_("%1 could not connect to JACK."), PROGRAM_NAME);
604 MessageDialog win (title,
605 false,
606 Gtk::MESSAGE_INFO,
607 Gtk::BUTTONS_NONE);
609 if (we_set_params) {
610 win.set_secondary_text(_("There are several possible reasons:\n\
612 1) You requested audio parameters that are not supported..\n\
613 2) JACK is running as another user.\n\
615 Please consider the possibilities, and perhaps try different parameters."));
616 } else {
617 win.set_secondary_text(_("There are several possible reasons:\n\
619 1) JACK is not running.\n\
620 2) JACK is running as another user, perhaps root.\n\
621 3) There is already another client called \"ardour\".\n\
623 Please consider the possibilities, and perhaps (re)start JACK."));
626 if (toplevel) {
627 win.set_transient_for (*toplevel);
630 if (we_set_params) {
631 win.add_button (Stock::OK, RESPONSE_CLOSE);
632 } else {
633 win.add_button (Stock::QUIT, RESPONSE_CLOSE);
636 win.set_default_response (RESPONSE_CLOSE);
638 win.show_all ();
639 win.set_position (Gtk::WIN_POS_CENTER);
640 pop_back_splash ();
642 /* we just don't care about the result, but we want to block */
644 win.run ();
647 void
648 ARDOUR_UI::startup ()
650 if (get_session_parameters (true, ARDOUR_COMMAND_LINE::new_session, ARDOUR_COMMAND_LINE::load_template)) {
651 exit (1);
654 use_config ();
656 goto_editor_window ();
658 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
659 show ();
662 void
663 ARDOUR_UI::no_memory_warning ()
665 XMLNode node (X_("no-memory-warning"));
666 Config->add_instant_xml (node);
669 void
670 ARDOUR_UI::check_memory_locking ()
672 #ifdef __APPLE__
673 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
674 return;
675 #else // !__APPLE__
677 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
679 if (engine->is_realtime() && memory_warning_node == 0) {
681 struct rlimit limits;
682 int64_t ram;
683 long pages, page_size;
685 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0) {
686 ram = 0;
687 } else {
688 ram = (int64_t) pages * (int64_t) page_size;
691 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
692 return;
695 if (limits.rlim_cur != RLIM_INFINITY) {
697 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
700 MessageDialog msg (string_compose (_("WARNING: Your system has a limit for maximum amount of locked memory. "
701 "This might cause %1 to run out of memory before your system "
702 "runs out of memory. \n\n"
703 "You can view the memory limit with 'ulimit -l', "
704 "and it is normally controlled by /etc/security/limits.conf"),
705 PROGRAM_NAME).c_str());
707 VBox* vbox = msg.get_vbox();
708 HBox hbox;
709 CheckButton cb (_("Do not show this window again"));
711 cb.signal_toggled().connect (sigc::mem_fun (*this, &ARDOUR_UI::no_memory_warning));
713 hbox.pack_start (cb, true, false);
714 vbox->pack_start (hbox);
715 cb.show();
716 vbox->show();
717 hbox.show ();
719 pop_back_splash ();
721 editor->ensure_float (msg);
722 msg.run ();
726 #endif // !__APPLE__
730 void
731 ARDOUR_UI::finish()
733 if (_session) {
734 int tries = 0;
736 if (_session->transport_rolling() && (++tries < 8)) {
737 _session->request_stop (false, true);
738 usleep (10000);
741 if (_session->dirty()) {
742 switch (ask_about_saving_session(_("quit"))) {
743 case -1:
744 return;
745 break;
746 case 1:
747 /* use the default name */
748 if (save_state_canfail ("")) {
749 /* failed - don't quit */
750 MessageDialog msg (*editor,
751 _("\
752 Ardour was unable to save your session.\n\n\
753 If you still wish to quit, please use the\n\n\
754 \"Just quit\" option."));
755 pop_back_splash();
756 msg.run ();
757 return;
759 break;
760 case 0:
761 break;
765 second_connection.disconnect ();
766 point_one_second_connection.disconnect ();
767 point_oh_five_second_connection.disconnect ();
768 point_zero_one_second_connection.disconnect();
770 // _session->set_deletion_in_progress ();
771 _session->remove_pending_capture_state ();
772 delete _session;
773 _session = 0;
776 cerr << "Save before quit\n";
777 save_ardour_state ();
779 ArdourDialog::close_all_dialogs ();
780 engine->stop (true);
781 quit ();
785 ARDOUR_UI::ask_about_saving_session (const string & what)
787 ArdourDialog window (_("Unsaved Session"));
788 Gtk::HBox dhbox; // the hbox for the image and text
789 Gtk::Label prompt_label;
790 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
792 string msg;
794 msg = string_compose(_("Don't %1"), what);
795 window.add_button (msg, RESPONSE_REJECT);
796 msg = string_compose(_("Just %1"), what);
797 window.add_button (msg, RESPONSE_APPLY);
798 msg = string_compose(_("Save and %1"), what);
799 window.add_button (msg, RESPONSE_ACCEPT);
801 window.set_default_response (RESPONSE_ACCEPT);
803 Gtk::Button noquit_button (msg);
804 noquit_button.set_name ("EditorGTKButton");
806 string prompt;
807 string type;
809 if (_session->snap_name() == _session->name()) {
810 type = _("session");
811 } else {
812 type = _("snapshot");
814 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?"),
815 type, _session->snap_name());
817 prompt_label.set_text (prompt);
818 prompt_label.set_name (X_("PrompterLabel"));
819 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
821 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
822 dhbox.set_homogeneous (false);
823 dhbox.pack_start (*dimage, false, false, 5);
824 dhbox.pack_start (prompt_label, true, false, 5);
825 window.get_vbox()->pack_start (dhbox);
827 window.set_name (_("Prompter"));
828 window.set_position (Gtk::WIN_POS_MOUSE);
829 window.set_modal (true);
830 window.set_resizable (false);
832 dhbox.show();
833 prompt_label.show();
834 dimage->show();
835 window.show();
836 window.set_keep_above (true);
837 window.present ();
839 ResponseType r = (ResponseType) window.run();
841 window.hide ();
843 switch (r) {
844 case RESPONSE_ACCEPT: // save and get out of here
845 return 1;
846 case RESPONSE_APPLY: // get out of here
847 return 0;
848 default:
849 break;
852 return -1;
855 gint
856 ARDOUR_UI::every_second ()
858 update_cpu_load ();
859 update_buffer_load ();
860 update_disk_space ();
861 return TRUE;
864 gint
865 ARDOUR_UI::every_point_one_seconds ()
867 update_speed_display ();
868 RapidScreenUpdate(); /* EMIT_SIGNAL */
869 return TRUE;
872 gint
873 ARDOUR_UI::every_point_zero_one_seconds ()
875 // august 2007: actual update frequency: 40Hz, not 100Hz
877 SuperRapidScreenUpdate(); /* EMIT_SIGNAL */
878 return TRUE;
881 void
882 ARDOUR_UI::update_sample_rate (nframes_t)
884 char buf[32];
886 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
888 if (!engine->connected()) {
890 snprintf (buf, sizeof (buf), _("disconnected"));
892 } else {
894 nframes_t rate = engine->frame_rate();
896 if (fmod (rate, 1000.0) != 0.0) {
897 snprintf (buf, sizeof (buf), _("%.1f kHz / %4.1f ms"),
898 (float) rate/1000.0f,
899 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
900 } else {
901 snprintf (buf, sizeof (buf), _("%u kHz / %4.1f ms"),
902 rate/1000,
903 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
907 sample_rate_label.set_text (buf);
910 void
911 ARDOUR_UI::update_cpu_load ()
913 char buf[32];
914 snprintf (buf, sizeof (buf), _("DSP: %5.1f%%"), engine->get_cpu_load());
915 cpu_load_label.set_text (buf);
918 void
919 ARDOUR_UI::update_buffer_load ()
921 char buf[64];
922 uint32_t c, p;
924 if (_session) {
925 c = _session->capture_load ();
926 p = _session->playback_load ();
928 snprintf (buf, sizeof (buf), _("Buffers p:%" PRIu32 "%% c:%" PRIu32 "%%"),
929 _session->playback_load(), _session->capture_load());
930 buffer_load_label.set_text (buf);
931 } else {
932 buffer_load_label.set_text ("");
936 void
937 ARDOUR_UI::count_recenabled_streams (Route& route)
939 Track* track = dynamic_cast<Track*>(&route);
940 if (track && track->record_enabled()) {
941 rec_enabled_streams += track->n_inputs().n_total();
945 void
946 ARDOUR_UI::update_disk_space()
948 if (_session == 0) {
949 return;
952 nframes_t frames = _session->available_capture_duration();
953 char buf[64];
954 nframes_t fr = _session->frame_rate();
956 if (frames == max_frames) {
957 strcpy (buf, _("Disk: 24hrs+"));
958 } else {
959 rec_enabled_streams = 0;
960 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams);
962 if (rec_enabled_streams) {
963 frames /= rec_enabled_streams;
966 int hrs;
967 int mins;
968 int secs;
970 hrs = frames / (fr * 3600);
971 frames -= hrs * fr * 3600;
972 mins = frames / (fr * 60);
973 frames -= mins * fr * 60;
974 secs = frames / fr;
976 snprintf (buf, sizeof(buf), _("Disk: %02dh:%02dm:%02ds"), hrs, mins, secs);
979 disk_space_label.set_text (buf);
981 // An attempt to make the disk space label flash red when space has run out.
983 if (frames < fr * 60 * 5) {
984 /* disk_space_box.style ("disk_space_label_empty"); */
985 } else {
986 /* disk_space_box.style ("disk_space_label"); */
991 gint
992 ARDOUR_UI::update_wall_clock ()
994 time_t now;
995 struct tm *tm_now;
996 char buf[16];
998 time (&now);
999 tm_now = localtime (&now);
1001 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1002 wall_clock_label.set_text (buf);
1004 return TRUE;
1007 gint
1008 ARDOUR_UI::session_menu (GdkEventButton */*ev*/)
1010 session_popup_menu->popup (0, 0);
1011 return TRUE;
1014 void
1015 ARDOUR_UI::redisplay_recent_sessions ()
1017 std::vector<sys::path> session_directories;
1018 RecentSessionsSorter cmp;
1020 recent_session_display.set_model (Glib::RefPtr<TreeModel>(0));
1021 recent_session_model->clear ();
1023 ARDOUR::RecentSessions rs;
1024 ARDOUR::read_recent_sessions (rs);
1026 if (rs.empty()) {
1027 recent_session_display.set_model (recent_session_model);
1028 return;
1031 // sort them alphabetically
1032 sort (rs.begin(), rs.end(), cmp);
1034 for (ARDOUR::RecentSessions::iterator i = rs.begin(); i != rs.end(); ++i) {
1035 session_directories.push_back ((*i).second);
1038 for (vector<sys::path>::const_iterator i = session_directories.begin();
1039 i != session_directories.end(); ++i)
1041 std::vector<sys::path> state_file_paths;
1043 // now get available states for this session
1045 get_state_files_in_directory (*i, state_file_paths);
1047 vector<string*>* states;
1048 vector<const gchar*> item;
1049 string fullpath = (*i).to_string();
1051 /* remove any trailing / */
1053 if (fullpath[fullpath.length()-1] == '/') {
1054 fullpath = fullpath.substr (0, fullpath.length()-1);
1057 /* check whether session still exists */
1058 if (!Glib::file_test(fullpath.c_str(), Glib::FILE_TEST_EXISTS)) {
1059 /* session doesn't exist */
1060 cerr << "skipping non-existent session " << fullpath << endl;
1061 continue;
1064 /* now get available states for this session */
1066 if ((states = Session::possible_states (fullpath)) == 0) {
1067 /* no state file? */
1068 continue;
1071 std::vector<string> state_file_names(get_file_names_no_extension (state_file_paths));
1073 Gtk::TreeModel::Row row = *(recent_session_model->append());
1075 row[recent_session_columns.visible_name] = Glib::path_get_basename (fullpath);
1076 row[recent_session_columns.fullpath] = fullpath;
1078 if (state_file_names.size() > 1) {
1080 // add the children
1082 for (std::vector<std::string>::iterator i2 = state_file_names.begin();
1083 i2 != state_file_names.end(); ++i2)
1086 Gtk::TreeModel::Row child_row = *(recent_session_model->append (row.children()));
1088 child_row[recent_session_columns.visible_name] = *i2;
1089 child_row[recent_session_columns.fullpath] = fullpath;
1094 recent_session_display.set_model (recent_session_model);
1097 void
1098 ARDOUR_UI::build_session_selector ()
1100 session_selector_window = new ArdourDialog (_("Recent Sessions"));
1102 Gtk::ScrolledWindow *scroller = manage (new Gtk::ScrolledWindow);
1104 session_selector_window->add_button (Stock::CANCEL, RESPONSE_CANCEL);
1105 session_selector_window->add_button (Stock::OPEN, RESPONSE_ACCEPT);
1106 session_selector_window->set_default_response (RESPONSE_ACCEPT);
1107 recent_session_model = TreeStore::create (recent_session_columns);
1108 recent_session_display.set_model (recent_session_model);
1109 recent_session_display.append_column (_("Recent Sessions"), recent_session_columns.visible_name);
1110 recent_session_display.set_headers_visible (false);
1111 recent_session_display.get_selection()->set_mode (SELECTION_BROWSE);
1112 recent_session_display.signal_row_activated().connect (sigc::mem_fun (*this, &ARDOUR_UI::recent_session_row_activated));
1114 scroller->add (recent_session_display);
1115 scroller->set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
1117 session_selector_window->set_name ("SessionSelectorWindow");
1118 session_selector_window->set_size_request (200, 400);
1119 session_selector_window->get_vbox()->pack_start (*scroller);
1121 recent_session_display.show();
1122 scroller->show();
1123 //session_selector_window->get_vbox()->show();
1126 void
1127 ARDOUR_UI::recent_session_row_activated (const TreePath& /*path*/, TreeViewColumn* /*col*/)
1129 session_selector_window->response (RESPONSE_ACCEPT);
1132 void
1133 ARDOUR_UI::open_recent_session ()
1135 bool can_return = (_session != 0);
1137 if (session_selector_window == 0) {
1138 build_session_selector ();
1141 redisplay_recent_sessions ();
1143 while (true) {
1145 session_selector_window->set_position (WIN_POS_MOUSE);
1147 ResponseType r = (ResponseType) session_selector_window->run ();
1149 switch (r) {
1150 case RESPONSE_ACCEPT:
1151 break;
1152 default:
1153 if (can_return) {
1154 session_selector_window->hide();
1155 return;
1156 } else {
1157 exit (1);
1161 if (recent_session_display.get_selection()->count_selected_rows() == 0) {
1162 continue;
1165 session_selector_window->hide();
1167 Gtk::TreeModel::iterator i = recent_session_display.get_selection()->get_selected();
1169 if (i == recent_session_model->children().end()) {
1170 return;
1173 Glib::ustring path = (*i)[recent_session_columns.fullpath];
1174 Glib::ustring state = (*i)[recent_session_columns.visible_name];
1176 _session_is_new = false;
1178 if (load_session (path, state) == 0) {
1179 break;
1182 can_return = false;
1186 bool
1187 ARDOUR_UI::check_audioengine ()
1189 if (engine) {
1190 if (!engine->connected()) {
1191 MessageDialog msg (string_compose (_("%1 is not connected to JACK\n"
1192 "You cannot open or close sessions in this condition"),
1193 PROGRAM_NAME));
1194 pop_back_splash ();
1195 msg.run ();
1196 return false;
1198 return true;
1199 } else {
1200 return false;
1204 void
1205 ARDOUR_UI::open_session ()
1207 if (!check_audioengine()) {
1208 return;
1212 /* popup selector window */
1214 if (open_session_selector == 0) {
1216 /* ardour sessions are folders */
1218 open_session_selector = new Gtk::FileChooserDialog (_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1219 open_session_selector->add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1220 open_session_selector->add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1221 open_session_selector->set_default_response(Gtk::RESPONSE_ACCEPT);
1223 FileFilter session_filter;
1224 session_filter.add_pattern ("*.ardour");
1225 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1226 open_session_selector->add_filter (session_filter);
1227 open_session_selector->set_filter (session_filter);
1230 int response = open_session_selector->run();
1231 open_session_selector->hide ();
1233 switch (response) {
1234 case RESPONSE_ACCEPT:
1235 break;
1236 default:
1237 open_session_selector->hide();
1238 return;
1241 open_session_selector->hide();
1242 string session_path = open_session_selector->get_filename();
1243 string path, name;
1244 bool isnew;
1246 if (session_path.length() > 0) {
1247 if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1248 _session_is_new = isnew;
1249 load_session (path, name);
1255 void
1256 ARDOUR_UI::session_add_midi_route (bool disk, RouteGroup* route_group, uint32_t how_many)
1258 list<boost::shared_ptr<MidiTrack> > tracks;
1260 if (_session == 0) {
1261 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1262 return;
1265 try {
1266 if (disk) {
1268 tracks = _session->new_midi_track (ARDOUR::Normal, route_group, how_many);
1270 if (tracks.size() != how_many) {
1271 if (how_many == 1) {
1272 error << _("could not create a new midi track") << endmsg;
1273 } else {
1274 error << string_compose (_("could not create %1 new midi tracks"), how_many) << endmsg;
1277 } /*else {
1278 if ((route = _session->new_midi_route ()) == 0) {
1279 error << _("could not create new midi bus") << endmsg;
1284 catch (...) {
1285 MessageDialog msg (*editor,
1286 _("There are insufficient JACK ports available\n\
1287 to create a new track or bus.\n\
1288 You should save Ardour, exit and\n\
1289 restart JACK with more ports."));
1290 msg.run ();
1295 void
1296 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)
1298 list<boost::shared_ptr<AudioTrack> > tracks;
1299 RouteList routes;
1301 if (_session == 0) {
1302 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1303 return;
1306 try {
1307 if (track) {
1308 tracks = _session->new_audio_track (input_channels, output_channels, mode, route_group, how_many);
1310 if (tracks.size() != how_many) {
1311 if (how_many == 1) {
1312 error << _("could not create a new audio track") << endmsg;
1313 } else {
1314 error << string_compose (_("could only create %1 of %2 new audio %3"),
1315 tracks.size(), how_many, (track ? _("tracks") : _("busses"))) << endmsg;
1319 } else {
1321 routes = _session->new_audio_route (aux, input_channels, output_channels, route_group, how_many);
1323 if (routes.size() != how_many) {
1324 if (how_many == 1) {
1325 error << _("could not create a new audio track") << endmsg;
1326 } else {
1327 error << string_compose (_("could not create %1 new audio tracks"), how_many) << endmsg;
1333 catch (...) {
1334 MessageDialog msg (*editor,
1335 _("There are insufficient JACK ports available\n\
1336 to create a new track or bus.\n\
1337 You should save Ardour, exit and\n\
1338 restart JACK with more ports."));
1339 pop_back_splash ();
1340 msg.run ();
1344 void
1345 ARDOUR_UI::do_transport_locate (nframes_t new_position)
1347 nframes_t _preroll = 0;
1349 if (_session) {
1350 // XXX CONFIG_CHANGE FIX - requires AnyTime handling
1351 // _preroll = _session->convert_to_frames_at (new_position, Config->get_preroll());
1353 if (new_position > _preroll) {
1354 new_position -= _preroll;
1355 } else {
1356 new_position = 0;
1359 _session->request_locate (new_position);
1363 void
1364 ARDOUR_UI::transport_goto_start ()
1366 if (_session) {
1367 _session->goto_start();
1369 /* force displayed area in editor to start no matter
1370 what "follow playhead" setting is.
1373 if (editor) {
1374 editor->center_screen (_session->current_start_frame ());
1379 void
1380 ARDOUR_UI::transport_goto_zero ()
1382 if (_session) {
1383 _session->request_locate (0);
1385 /* force displayed area in editor to start no matter
1386 what "follow playhead" setting is.
1389 if (editor) {
1390 editor->reset_x_origin (0);
1395 void
1396 ARDOUR_UI::transport_goto_wallclock ()
1398 if (_session && editor) {
1400 time_t now;
1401 struct tm tmnow;
1402 nframes64_t frames;
1404 time (&now);
1405 localtime_r (&now, &tmnow);
1407 frames = tmnow.tm_hour * (60 * 60 * _session->frame_rate());
1408 frames += tmnow.tm_min * (60 * _session->frame_rate());
1409 frames += tmnow.tm_sec * _session->frame_rate();
1411 _session->request_locate (frames);
1413 /* force displayed area in editor to start no matter
1414 what "follow playhead" setting is.
1417 if (editor) {
1418 editor->center_screen (frames);
1423 void
1424 ARDOUR_UI::transport_goto_end ()
1426 if (_session) {
1427 nframes_t const frame = _session->current_end_frame();
1428 _session->request_locate (frame);
1430 /* force displayed area in editor to start no matter
1431 what "follow playhead" setting is.
1434 if (editor) {
1435 editor->center_screen (frame);
1440 void
1441 ARDOUR_UI::transport_stop ()
1443 if (!_session) {
1444 return;
1447 if (_session->is_auditioning()) {
1448 _session->cancel_audition ();
1449 return;
1452 _session->request_stop (false, true);
1455 void
1456 ARDOUR_UI::transport_stop_and_forget_capture ()
1458 if (_session) {
1459 _session->request_stop (true, true);
1463 void
1464 ARDOUR_UI::remove_last_capture()
1466 if (editor) {
1467 editor->remove_last_capture();
1471 void
1472 ARDOUR_UI::transport_record (bool roll)
1475 if (_session) {
1476 switch (_session->record_status()) {
1477 case Session::Disabled:
1478 if (_session->ntracks() == 0) {
1479 MessageDialog msg (*editor, _("Please create 1 or more track\nbefore trying to record.\nCheck the Session menu."));
1480 msg.run ();
1481 return;
1483 _session->maybe_enable_record ();
1484 if (roll) {
1485 transport_roll ();
1487 break;
1488 case Session::Recording:
1489 if (roll) {
1490 _session->request_stop();
1491 } else {
1492 _session->disable_record (false, true);
1494 break;
1496 case Session::Enabled:
1497 _session->disable_record (false, true);
1500 //cerr << "ARDOUR_UI::transport_record () called roll = " << roll << " _session->record_status() = " << _session->record_status() << endl;
1503 void
1504 ARDOUR_UI::transport_roll ()
1506 if (!_session) {
1507 return;
1510 if (_session->is_auditioning()) {
1511 return;
1514 if (_session->config.get_external_sync()) {
1515 switch (_session->config.get_sync_source()) {
1516 case JACK:
1517 break;
1518 default:
1519 /* transport controlled by the master */
1520 return;
1524 bool rolling = _session->transport_rolling();
1526 if (_session->get_play_loop()) {
1527 /* XXX it is not possible to just leave seamless loop and keep
1528 playing at present (nov 4th 2009)
1530 if (!Config->get_seamless_loop()) {
1531 _session->request_play_loop (false, true);
1533 } else if (_session->get_play_range () && !join_play_range_button.get_active()) {
1534 /* stop playing a range if we currently are */
1535 _session->request_play_range (0, true);
1538 if (join_play_range_button.get_active()) {
1539 _session->request_play_range (&editor->get_selection().time, true);
1542 if (!rolling) {
1543 _session->request_transport_speed (1.0f);
1547 void
1548 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
1551 if (!_session) {
1552 return;
1555 if (_session->is_auditioning()) {
1556 _session->cancel_audition ();
1557 return;
1560 if (_session->config.get_external_sync()) {
1561 switch (_session->config.get_sync_source()) {
1562 case JACK:
1563 break;
1564 default:
1565 /* transport controlled by the master */
1566 return;
1570 bool rolling = _session->transport_rolling();
1571 bool affect_transport = true;
1573 if (rolling && roll_out_of_bounded_mode) {
1574 /* drop out of loop/range playback but leave transport rolling */
1575 if (_session->get_play_loop()) {
1576 if (Config->get_seamless_loop()) {
1577 /* the disk buffers contain copies of the loop - we can't
1578 just keep playing, so stop the transport. the user
1579 can restart as they wish.
1581 affect_transport = true;
1582 } else {
1583 /* disk buffers are normal, so we can keep playing */
1584 affect_transport = false;
1586 _session->request_play_loop (false, true);
1587 } else if (_session->get_play_range ()) {
1588 affect_transport = false;
1589 _session->request_play_range (0, true);
1593 if (affect_transport) {
1594 if (rolling) {
1595 _session->request_stop (with_abort, true);
1596 } else {
1597 if (join_play_range_button.get_active()) {
1598 _session->request_play_range (&editor->get_selection().time, true);
1601 _session->request_transport_speed (1.0f);
1606 void
1607 ARDOUR_UI::toggle_session_auto_loop ()
1609 if (_session) {
1610 if (_session->get_play_loop()) {
1611 if (_session->transport_rolling()) {
1612 Location * looploc = _session->locations()->auto_loop_location();
1613 if (looploc) {
1614 _session->request_locate (looploc->start(), true);
1616 } else {
1617 _session->request_play_loop (false);
1619 } else {
1620 Location * looploc = _session->locations()->auto_loop_location();
1621 if (looploc) {
1622 _session->request_play_loop (true);
1628 void
1629 ARDOUR_UI::transport_play_selection ()
1631 if (!_session) {
1632 return;
1635 editor->play_selection ();
1638 void
1639 ARDOUR_UI::transport_rewind (int option)
1641 float current_transport_speed;
1643 if (_session) {
1644 current_transport_speed = _session->transport_speed();
1646 if (current_transport_speed >= 0.0f) {
1647 switch (option) {
1648 case 0:
1649 _session->request_transport_speed (-1.0f);
1650 break;
1651 case 1:
1652 _session->request_transport_speed (-4.0f);
1653 break;
1654 case -1:
1655 _session->request_transport_speed (-0.5f);
1656 break;
1658 } else {
1659 /* speed up */
1660 _session->request_transport_speed (current_transport_speed * 1.5f);
1665 void
1666 ARDOUR_UI::transport_forward (int option)
1668 float current_transport_speed;
1670 if (_session) {
1671 current_transport_speed = _session->transport_speed();
1673 if (current_transport_speed <= 0.0f) {
1674 switch (option) {
1675 case 0:
1676 _session->request_transport_speed (1.0f);
1677 break;
1678 case 1:
1679 _session->request_transport_speed (4.0f);
1680 break;
1681 case -1:
1682 _session->request_transport_speed (0.5f);
1683 break;
1685 } else {
1686 /* speed up */
1687 _session->request_transport_speed (current_transport_speed * 1.5f);
1693 void
1694 ARDOUR_UI::toggle_record_enable (uint32_t dstream)
1696 if (_session == 0) {
1697 return;
1700 boost::shared_ptr<Route> r;
1702 if ((r = _session->route_by_remote_id (dstream)) != 0) {
1704 Track* t;
1706 if ((t = dynamic_cast<Track*>(r.get())) != 0) {
1707 t->set_record_enabled (!t->record_enabled());
1710 if (_session == 0) {
1711 return;
1715 void
1716 ARDOUR_UI::map_transport_state ()
1718 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::map_transport_state)
1720 if (!_session) {
1721 auto_loop_button.set_visual_state (0);
1722 play_selection_button.set_visual_state (0);
1723 roll_button.set_visual_state (0);
1724 stop_button.set_visual_state (1);
1725 return;
1728 float sp = _session->transport_speed();
1730 if (sp == 1.0f) {
1731 shuttle_fract = SHUTTLE_FRACT_SPEED1; /* speed = 1.0, believe it or not */
1732 shuttle_box.queue_draw ();
1733 } else if (sp == 0.0f) {
1734 shuttle_fract = 0;
1735 shuttle_box.queue_draw ();
1736 update_disk_space ();
1739 if (sp != 0.0) {
1741 /* we're rolling */
1743 if (_session->get_play_range()) {
1745 play_selection_button.set_visual_state (1);
1746 roll_button.set_visual_state (0);
1747 auto_loop_button.set_visual_state (0);
1749 } else if (_session->get_play_loop ()) {
1751 auto_loop_button.set_visual_state (1);
1752 play_selection_button.set_visual_state (0);
1753 roll_button.set_visual_state (0);
1755 } else {
1757 roll_button.set_visual_state (1);
1758 play_selection_button.set_visual_state (0);
1759 auto_loop_button.set_visual_state (0);
1762 if (join_play_range_button.get_active()) {
1763 /* light up both roll and play-selection if they are joined */
1764 roll_button.set_visual_state (1);
1765 play_selection_button.set_visual_state (1);
1768 stop_button.set_visual_state (0);
1770 } else {
1772 stop_button.set_visual_state (1);
1773 roll_button.set_visual_state (0);
1774 play_selection_button.set_visual_state (0);
1775 auto_loop_button.set_visual_state (0);
1779 void
1780 ARDOUR_UI::engine_stopped ()
1782 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
1783 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1784 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1787 void
1788 ARDOUR_UI::engine_running ()
1790 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
1791 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, true);
1792 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, false);
1794 Glib::RefPtr<Action> action;
1795 const char* action_name = 0;
1797 switch (engine->frames_per_cycle()) {
1798 case 32:
1799 action_name = X_("JACKLatency32");
1800 break;
1801 case 64:
1802 action_name = X_("JACKLatency64");
1803 break;
1804 case 128:
1805 action_name = X_("JACKLatency128");
1806 break;
1807 case 512:
1808 action_name = X_("JACKLatency512");
1809 break;
1810 case 1024:
1811 action_name = X_("JACKLatency1024");
1812 break;
1813 case 2048:
1814 action_name = X_("JACKLatency2048");
1815 break;
1816 case 4096:
1817 action_name = X_("JACKLatency4096");
1818 break;
1819 case 8192:
1820 action_name = X_("JACKLatency8192");
1821 break;
1822 default:
1823 /* XXX can we do anything useful ? */
1824 break;
1827 if (action_name) {
1829 action = ActionManager::get_action (X_("JACK"), action_name);
1831 if (action) {
1832 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (action);
1833 ract->set_active ();
1838 void
1839 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
1841 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
1842 /* we can't rely on the original string continuing to exist when we are called
1843 again in the GUI thread, so make a copy and note that we need to
1844 free it later.
1846 char *copy = strdup (reason);
1847 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
1848 return;
1851 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1852 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1854 update_sample_rate (0);
1856 string msgstr;
1858 /* if the reason is a non-empty string, it means that the backend was shutdown
1859 rather than just Ardour.
1862 if (strlen (reason)) {
1863 msgstr = string_compose (_("The audio backend (JACK) was shutdown because:\n\n%1"), reason);
1864 } else {
1865 msgstr = _("\
1866 JACK has either been shutdown or it\n\
1867 disconnected Ardour because Ardour\n\
1868 was not fast enough. Try to restart\n\
1869 JACK, reconnect and save the session.");
1872 MessageDialog msg (*editor, msgstr);
1873 pop_back_splash ();
1874 msg.run ();
1876 if (free_reason) {
1877 free ((char*) reason);
1881 int32_t
1882 ARDOUR_UI::do_engine_start ()
1884 try {
1885 engine->start();
1888 catch (...) {
1889 engine->stop ();
1890 error << _("Unable to start the session running")
1891 << endmsg;
1892 unload_session ();
1893 return -2;
1896 return 0;
1899 void
1900 ARDOUR_UI::setup_theme ()
1902 theme_manager->setup_theme();
1905 void
1906 ARDOUR_UI::update_clocks ()
1908 if (!editor || !editor->dragging_playhead()) {
1909 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position()); /* EMIT_SIGNAL */
1913 void
1914 ARDOUR_UI::start_clocking ()
1916 clock_signal_connection = RapidScreenUpdate.connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
1919 void
1920 ARDOUR_UI::stop_clocking ()
1922 clock_signal_connection.disconnect ();
1925 void
1926 ARDOUR_UI::toggle_clocking ()
1928 #if 0
1929 if (clock_button.get_active()) {
1930 start_clocking ();
1931 } else {
1932 stop_clocking ();
1934 #endif
1937 gint
1938 ARDOUR_UI::_blink (void *arg)
1941 ((ARDOUR_UI *) arg)->blink ();
1942 return TRUE;
1945 void
1946 ARDOUR_UI::blink ()
1948 Blink (blink_on = !blink_on); /* EMIT_SIGNAL */
1951 void
1952 ARDOUR_UI::start_blinking ()
1954 /* Start the blink signal. Everybody with a blinking widget
1955 uses Blink to drive the widget's state.
1958 if (blink_timeout_tag < 0) {
1959 blink_on = false;
1960 blink_timeout_tag = g_timeout_add (240, _blink, this);
1964 void
1965 ARDOUR_UI::stop_blinking ()
1967 if (blink_timeout_tag >= 0) {
1968 g_source_remove (blink_timeout_tag);
1969 blink_timeout_tag = -1;
1974 /** Ask the user for the name of a new shapshot and then take it.
1977 void
1978 ARDOUR_UI::snapshot_session (bool switch_to_it)
1980 ArdourPrompter prompter (true);
1981 string snapname;
1983 prompter.set_name ("Prompter");
1984 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1985 prompter.set_title (_("Take Snapshot"));
1986 prompter.set_title (_("Take Snapshot"));
1987 prompter.set_prompt (_("Name of new snapshot"));
1989 if (!switch_to_it) {
1990 char timebuf[128];
1991 time_t n;
1992 struct tm local_time;
1994 time (&n);
1995 localtime_r (&n, &local_time);
1996 strftime (timebuf, sizeof(timebuf), "%FT%T", &local_time);
1997 prompter.set_initial_text (timebuf);
2000 again:
2001 switch (prompter.run()) {
2002 case RESPONSE_ACCEPT:
2004 prompter.get_result (snapname);
2006 bool do_save = (snapname.length() != 0);
2008 if (do_save) {
2009 if (snapname.find ('/') != string::npos) {
2010 MessageDialog msg (_("To ensure compatibility with various systems\n"
2011 "snapshot names may not contain a '/' character"));
2012 msg.run ();
2013 goto again;
2015 if (snapname.find ('\\') != string::npos) {
2016 MessageDialog msg (_("To ensure compatibility with various systems\n"
2017 "snapshot names may not contain a '\\' character"));
2018 msg.run ();
2019 goto again;
2023 vector<sys::path> p;
2024 get_state_files_in_directory (_session->session_directory().root_path(), p);
2025 vector<string> n = get_file_names_no_extension (p);
2026 if (find (n.begin(), n.end(), snapname) != n.end()) {
2028 ArdourDialog confirm (_("Confirm Snapshot Overwrite"), true);
2029 Label m (_("A snapshot already exists with that name. Do you want to overwrite it?"));
2030 confirm.get_vbox()->pack_start (m, true, true);
2031 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2032 confirm.add_button (_("Overwrite"), Gtk::RESPONSE_ACCEPT);
2033 confirm.show_all ();
2034 switch (confirm.run()) {
2035 case RESPONSE_CANCEL:
2036 do_save = false;
2040 if (do_save) {
2041 save_state (snapname, switch_to_it);
2043 break;
2046 default:
2047 break;
2051 void
2052 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2054 save_state_canfail (name, switch_to_it);
2058 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2060 if (_session) {
2061 int ret;
2063 if (name.length() == 0) {
2064 name = _session->snap_name();
2067 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2068 return ret;
2071 cerr << "SS canfail\n";
2072 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2073 return 0;
2076 void
2077 ARDOUR_UI::primary_clock_value_changed ()
2079 if (_session) {
2080 _session->request_locate (primary_clock.current_time ());
2084 void
2085 ARDOUR_UI::big_clock_value_changed ()
2087 if (_session) {
2088 _session->request_locate (big_clock.current_time ());
2092 void
2093 ARDOUR_UI::secondary_clock_value_changed ()
2095 if (_session) {
2096 _session->request_locate (secondary_clock.current_time ());
2100 void
2101 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2103 if (_session == 0) {
2104 return;
2107 Session::RecordState const r = _session->record_status ();
2108 bool const h = _session->have_rec_enabled_track ();
2110 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2111 if (onoff) {
2112 rec_button.set_visual_state (2);
2113 } else {
2114 rec_button.set_visual_state (0);
2116 } else if (r == Session::Recording && h) {
2117 rec_button.set_visual_state (1);
2118 } else {
2119 rec_button.set_visual_state (0);
2123 void
2124 ARDOUR_UI::save_template ()
2126 ArdourPrompter prompter (true);
2127 string name;
2129 if (!check_audioengine()) {
2130 return;
2133 prompter.set_name (X_("Prompter"));
2134 prompter.set_title (_("Save Mix Template"));
2135 prompter.set_prompt (_("Name for mix template:"));
2136 prompter.set_initial_text(_session->name() + _("-template"));
2137 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2139 switch (prompter.run()) {
2140 case RESPONSE_ACCEPT:
2141 prompter.get_result (name);
2143 if (name.length()) {
2144 _session->save_template (name);
2146 break;
2148 default:
2149 break;
2153 void
2154 ARDOUR_UI::edit_metadata ()
2156 SessionMetadataEditor dialog;
2157 dialog.set_session (_session);
2158 editor->ensure_float (dialog);
2159 dialog.run ();
2162 void
2163 ARDOUR_UI::import_metadata ()
2165 SessionMetadataImporter dialog;
2166 dialog.set_session (_session);
2167 editor->ensure_float (dialog);
2168 dialog.run ();
2171 void
2172 ARDOUR_UI::fontconfig_dialog ()
2174 #ifdef GTKOSX
2175 /* X11 users will always have fontconfig info around, but new GTK-OSX users
2176 may not and it can take a while to build it. Warn them.
2179 Glib::ustring fontconfig = Glib::build_filename (Glib::get_home_dir(), ".fontconfig");
2181 if (!Glib::file_test (fontconfig, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_DIR)) {
2182 MessageDialog msg (*_startup,
2183 _("Welcome to Ardour.\n\n"
2184 "The program will take a bit longer to start up\n"
2185 "while the system fonts are checked.\n\n"
2186 "This will only be done once, and you will\n"
2187 "not see this message again\n"),
2188 true,
2189 Gtk::MESSAGE_INFO,
2190 Gtk::BUTTONS_OK);
2191 pop_back_splash ();
2192 msg.show_all ();
2193 msg.present ();
2194 msg.run ();
2196 #endif
2199 void
2200 ARDOUR_UI::parse_cmdline_path (const Glib::ustring& cmdline_path, Glib::ustring& session_name, Glib::ustring& session_path, bool& existing_session)
2202 existing_session = false;
2204 if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_DIR)) {
2205 session_path = cmdline_path;
2206 existing_session = true;
2207 } else if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_REGULAR)) {
2208 session_path = Glib::path_get_dirname (string (cmdline_path));
2209 existing_session = true;
2210 } else {
2211 /* it doesn't exist, assume the best */
2212 session_path = Glib::path_get_dirname (string (cmdline_path));
2215 session_name = basename_nosuffix (string (cmdline_path));
2219 ARDOUR_UI::load_cmdline_session (const Glib::ustring& session_name, const Glib::ustring& session_path, bool& existing_session)
2221 /* when this is called, the backend audio system must be running */
2223 /* the main idea here is to deal with the fact that a cmdline argument for the session
2224 can be interpreted in different ways - it could be a directory or a file, and before
2225 we load, we need to know both the session directory and the snapshot (statefile) within it
2226 that we are supposed to use.
2229 if (session_name.length() == 0 || session_path.length() == 0) {
2230 return false;
2233 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_DIR)) {
2235 Glib::ustring predicted_session_file;
2237 predicted_session_file = session_path;
2238 predicted_session_file += '/';
2239 predicted_session_file += session_name;
2240 predicted_session_file += ARDOUR::statefile_suffix;
2242 if (Glib::file_test (predicted_session_file, Glib::FILE_TEST_EXISTS)) {
2243 existing_session = true;
2246 } else if (Glib::file_test (session_path, Glib::FILE_TEST_EXISTS)) {
2248 if (session_path.find (ARDOUR::statefile_suffix) == session_path.length() - 7) {
2249 /* existing .ardour file */
2250 existing_session = true;
2253 } else {
2254 existing_session = false;
2257 /* lets just try to load it */
2259 if (create_engine ()) {
2260 backend_audio_error (false, _startup);
2261 return -1;
2264 return load_session (session_path, session_name);
2267 bool
2268 ARDOUR_UI::ask_about_loading_existing_session (const Glib::ustring& session_path)
2270 Glib::ustring str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2272 MessageDialog msg (str,
2273 false,
2274 Gtk::MESSAGE_WARNING,
2275 Gtk::BUTTONS_YES_NO,
2276 true);
2279 msg.set_name (X_("OpenExistingDialog"));
2280 msg.set_title (_("Open Existing Session"));
2281 msg.set_wmclass (X_("existing_session"), "Ardour");
2282 msg.set_position (Gtk::WIN_POS_MOUSE);
2283 pop_back_splash ();
2285 switch (msg.run()) {
2286 case RESPONSE_YES:
2287 return true;
2288 break;
2290 return false;
2294 ARDOUR_UI::build_session_from_nsd (const Glib::ustring& session_path, const Glib::ustring& session_name)
2296 BusProfile bus_profile;
2298 if (Profile->get_sae()) {
2300 bus_profile.master_out_channels = 2;
2301 bus_profile.input_ac = AutoConnectPhysical;
2302 bus_profile.output_ac = AutoConnectMaster;
2303 bus_profile.requested_physical_in = 0; // use all available
2304 bus_profile.requested_physical_out = 0; // use all available
2306 } else {
2308 /* get settings from advanced section of NSD */
2310 if (_startup->create_master_bus()) {
2311 bus_profile.master_out_channels = (uint32_t) _startup->master_channel_count();
2312 } else {
2313 bus_profile.master_out_channels = 0;
2316 if (_startup->connect_inputs()) {
2317 bus_profile.input_ac = AutoConnectPhysical;
2318 } else {
2319 bus_profile.input_ac = AutoConnectOption (0);
2322 /// @todo some minor tweaks.
2324 bus_profile.output_ac = AutoConnectOption (0);
2326 if (_startup->connect_outputs ()) {
2327 if (_startup->connect_outs_to_master()) {
2328 bus_profile.output_ac = AutoConnectMaster;
2329 } else if (_startup->connect_outs_to_physical()) {
2330 bus_profile.output_ac = AutoConnectPhysical;
2334 bus_profile.requested_physical_in = (uint32_t) _startup->input_limit_count();
2335 bus_profile.requested_physical_out = (uint32_t) _startup->output_limit_count();
2338 if (build_session (session_path, session_name, bus_profile)) {
2339 return -1;
2342 return 0;
2345 void
2346 ARDOUR_UI::idle_load (const Glib::ustring& path)
2348 if (_session) {
2349 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2350 /* /path/to/foo => /path/to/foo, foo */
2351 load_session (path, basename_nosuffix (path));
2352 } else {
2353 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2354 load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2356 } else {
2358 ARDOUR_COMMAND_LINE::session_name = path;
2361 * new_session_dialog doens't exist in A3
2362 * Try to remove all references to it to
2363 * see if it will compile. NOTE: this will
2364 * likely cause a runtime issue is my somewhat
2365 * uneducated guess.
2368 //if (new_session_dialog) {
2371 /* make it break out of Dialog::run() and
2372 start again.
2375 //new_session_dialog->response (1);
2380 void
2381 ARDOUR_UI::end_loading_messages ()
2383 // hide_splash ();
2386 void
2387 ARDOUR_UI::loading_message (const std::string& /*msg*/)
2389 // show_splash ();
2390 // splash->message (msg);
2391 flush_pending ();
2394 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
2396 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
2398 Glib::ustring session_name;
2399 Glib::ustring session_path;
2400 Glib::ustring template_name;
2401 int ret = -1;
2402 bool likely_new = false;
2404 if (! load_template.empty()) {
2405 should_be_new = true;
2406 template_name = load_template;
2409 while (ret != 0) {
2411 if (!should_be_new && !ARDOUR_COMMAND_LINE::session_name.empty()) {
2413 /* if they named a specific statefile, use it, otherwise they are
2414 just giving a session folder, and we want to use it as is
2415 to find the session.
2418 if (ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix) != string::npos) {
2419 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
2420 } else {
2421 session_path = ARDOUR_COMMAND_LINE::session_name;
2424 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
2426 } else {
2428 bool const apply = run_startup (should_be_new, load_template);
2429 if (!apply) {
2430 if (quit_on_cancel) {
2431 exit (1);
2432 } else {
2433 return ret;
2437 /* if we run the startup dialog again, offer more than just "new session" */
2439 should_be_new = false;
2441 session_name = _startup->session_name (likely_new);
2443 /* this shouldn't happen, but we catch it just in case it does */
2445 if (session_name.empty()) {
2446 break;
2448 if (_startup->use_session_template()) {
2449 template_name = _startup->session_template_name();
2450 _session_is_new = true;
2453 if (session_name[0] == '/' ||
2454 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == '/') ||
2455 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == '/')) {
2457 /* absolute path or cwd-relative path specified for session name: infer session folder
2458 from what was given.
2461 session_path = Glib::path_get_dirname (session_name);
2462 session_name = Glib::path_get_basename (session_name);
2464 } else {
2466 session_path = _startup->session_folder();
2470 if (create_engine ()) {
2471 break;
2474 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
2476 if (likely_new) {
2478 Glib::ustring existing = Glib::build_filename (session_path, session_name);
2480 if (!ask_about_loading_existing_session (existing)) {
2481 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2482 continue;
2486 _session_is_new = false;
2488 } else {
2490 if (!likely_new) {
2491 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
2492 msg.run ();
2493 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2494 continue;
2497 if (session_name.find ('/') != Glib::ustring::npos) {
2498 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2499 "session names may not contain a '/' character"));
2500 msg.run ();
2501 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2502 continue;
2505 if (session_name.find ('\\') != Glib::ustring::npos) {
2506 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2507 "session names may not contain a '\\' character"));
2508 msg.run ();
2509 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2510 continue;
2513 _session_is_new = true;
2516 if (likely_new && template_name.empty()) {
2518 ret = build_session_from_nsd (session_path, session_name);
2520 } else {
2522 ret = load_session (session_path, session_name, template_name);
2523 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
2524 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
2525 exit (1);
2530 return ret;
2533 void
2534 ARDOUR_UI::close_session()
2536 if (!check_audioengine()) {
2537 return;
2540 if (unload_session (true)) {
2541 return;
2544 ARDOUR_COMMAND_LINE::session_name = "";
2546 if (get_session_parameters (true, false)) {
2547 exit (1);
2550 goto_editor_window ();
2551 show ();
2555 ARDOUR_UI::load_session (const Glib::ustring& path, const Glib::ustring& snap_name, Glib::ustring mix_template)
2557 Session *new_session;
2558 int unload_status;
2559 int retval = -1;
2561 session_loaded = false;
2563 if (!check_audioengine()) {
2564 return -1;
2567 unload_status = unload_session ();
2569 if (unload_status < 0) {
2570 goto out;
2571 } else if (unload_status > 0) {
2572 retval = 0;
2573 goto out;
2576 loading_message (string_compose (_("Please wait while %1loads your session"), PROGRAM_NAME));
2578 try {
2579 new_session = new Session (*engine, path, snap_name, 0, mix_template);
2582 /* this one is special */
2584 catch (AudioEngine::PortRegistrationFailure& err) {
2586 MessageDialog msg (err.what(),
2587 true,
2588 Gtk::MESSAGE_INFO,
2589 Gtk::BUTTONS_CLOSE);
2591 msg.set_title (_("Port Registration Error"));
2592 msg.set_secondary_text (_("Click the Close button to try again."));
2593 msg.set_position (Gtk::WIN_POS_CENTER);
2594 pop_back_splash ();
2595 msg.present ();
2597 int response = msg.run ();
2599 msg.hide ();
2601 switch (response) {
2602 case RESPONSE_CANCEL:
2603 exit (1);
2604 default:
2605 break;
2607 goto out;
2610 catch (...) {
2612 MessageDialog msg (string_compose(_("Session \"%1 (snapshot %2)\" did not load successfully"), path, snap_name),
2613 true,
2614 Gtk::MESSAGE_INFO,
2615 Gtk::BUTTONS_CLOSE);
2617 msg.set_title (_("Loading Error"));
2618 msg.set_secondary_text (_("Click the Close button to try again."));
2619 msg.set_position (Gtk::WIN_POS_CENTER);
2620 pop_back_splash ();
2621 msg.present ();
2623 int response = msg.run ();
2625 msg.hide ();
2627 switch (response) {
2628 case RESPONSE_CANCEL:
2629 exit (1);
2630 default:
2631 break;
2633 goto out;
2636 set_session (new_session);
2638 session_loaded = true;
2640 goto_editor_window ();
2642 if (_session) {
2643 _session->set_clean ();
2646 flush_pending ();
2647 retval = 0;
2649 out:
2650 return retval;
2654 ARDOUR_UI::build_session (const Glib::ustring& path, const Glib::ustring& snap_name, BusProfile& bus_profile)
2656 Session *new_session;
2657 int x;
2659 if (!check_audioengine()) {
2660 return -1;
2663 session_loaded = false;
2665 x = unload_session ();
2667 if (x < 0) {
2668 return -1;
2669 } else if (x > 0) {
2670 return 0;
2673 _session_is_new = true;
2675 try {
2676 new_session = new Session (*engine, path, snap_name, &bus_profile);
2679 catch (...) {
2681 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
2682 pop_back_splash ();
2683 msg.run ();
2684 return -1;
2687 set_session (new_session);
2689 session_loaded = true;
2691 new_session->save_state(new_session->name());
2693 return 0;
2696 void
2697 ARDOUR_UI::show ()
2699 if (editor) {
2700 editor->show_window ();
2702 if (!shown_flag) {
2703 editor->present ();
2706 shown_flag = true;
2710 void
2711 ARDOUR_UI::launch_chat ()
2713 #ifdef __APPLE__
2714 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
2715 #else
2716 open_uri("http://webchat.freenode.net/?channels=ardour");
2717 #endif
2720 void
2721 ARDOUR_UI::show_about ()
2723 if (about == 0) {
2724 about = new About;
2725 about->signal_response().connect(sigc::mem_fun (*this, &ARDOUR_UI::about_signal_response) );
2728 about->set_transient_for(*editor);
2729 about->show_all ();
2732 void
2733 ARDOUR_UI::hide_about ()
2735 if (about) {
2736 about->get_window()->set_cursor ();
2737 about->hide ();
2741 void
2742 ARDOUR_UI::about_signal_response (int /*response*/)
2744 hide_about();
2747 void
2748 ARDOUR_UI::show_splash ()
2750 if (splash == 0) {
2751 try {
2752 splash = new Splash;
2753 } catch (...) {
2754 return;
2758 splash->show ();
2759 splash->present ();
2760 splash->queue_draw ();
2761 splash->get_window()->process_updates (true);
2762 flush_pending ();
2765 void
2766 ARDOUR_UI::hide_splash ()
2768 if (splash) {
2769 splash->hide();
2773 void
2774 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title,
2775 const string& plural_msg, const string& singular_msg)
2777 size_t removed;
2779 removed = rep.paths.size();
2781 if (removed == 0) {
2782 MessageDialog msgd (*editor,
2783 _("No audio files were ready for cleanup"),
2784 true,
2785 Gtk::MESSAGE_INFO,
2786 (Gtk::ButtonsType)(Gtk::BUTTONS_OK) );
2787 msgd.set_secondary_text (_("If this seems suprising, \n\
2788 check for any existing snapshots.\n\
2789 These may still include regions that\n\
2790 require some unused files to continue to exist."));
2792 msgd.run ();
2793 return;
2796 ArdourDialog results (_("Clean-up"), true, false);
2798 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
2799 CleanupResultsModelColumns() {
2800 add (visible_name);
2801 add (fullpath);
2803 Gtk::TreeModelColumn<Glib::ustring> visible_name;
2804 Gtk::TreeModelColumn<Glib::ustring> fullpath;
2808 CleanupResultsModelColumns results_columns;
2809 Glib::RefPtr<Gtk::ListStore> results_model;
2810 Gtk::TreeView results_display;
2812 results_model = ListStore::create (results_columns);
2813 results_display.set_model (results_model);
2814 results_display.append_column (list_title, results_columns.visible_name);
2816 results_display.set_name ("CleanupResultsList");
2817 results_display.set_headers_visible (true);
2818 results_display.set_headers_clickable (false);
2819 results_display.set_reorderable (false);
2821 Gtk::ScrolledWindow list_scroller;
2822 Gtk::Label txt;
2823 Gtk::VBox dvbox;
2824 Gtk::HBox dhbox; // the hbox for the image and text
2825 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
2826 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
2828 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
2830 const string dead_sound_directory = _session->session_directory().dead_sound_path().to_string();
2832 /* subst:
2833 %1 - number of files removed
2834 %2 - location of "dead_sounds"
2835 %3 - size of files affected
2836 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
2839 const char* bprefix;
2840 double space_adjusted = 0;
2842 if (rep.space < 100000.0f) {
2843 bprefix = X_("kilo");
2844 } else if (rep.space < 1000000.0f * 1000) {
2845 bprefix = X_("mega");
2846 space_adjusted = truncf((float)rep.space / 1000.0);
2847 } else {
2848 bprefix = X_("giga");
2849 space_adjusted = truncf((float)rep.space / (1000000.0 * 1000));
2852 if (removed > 1) {
2853 txt.set_text (string_compose (plural_msg, removed, _session->path() + "dead_sounds", space_adjusted, bprefix));
2854 } else {
2855 txt.set_text (string_compose (singular_msg, removed, _session->path() + "dead_sounds", space_adjusted, bprefix));
2858 dhbox.pack_start (*dimage, true, false, 5);
2859 dhbox.pack_start (txt, true, false, 5);
2861 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
2862 TreeModel::Row row = *(results_model->append());
2863 row[results_columns.visible_name] = *i;
2864 row[results_columns.fullpath] = *i;
2867 list_scroller.add (results_display);
2868 list_scroller.set_size_request (-1, 150);
2869 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
2871 dvbox.pack_start (dhbox, true, false, 5);
2872 dvbox.pack_start (list_scroller, true, false, 5);
2873 ddhbox.pack_start (dvbox, true, false, 5);
2875 results.get_vbox()->pack_start (ddhbox, true, false, 5);
2876 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
2877 results.set_default_response (RESPONSE_CLOSE);
2878 results.set_position (Gtk::WIN_POS_MOUSE);
2880 results_display.show();
2881 list_scroller.show();
2882 txt.show();
2883 dvbox.show();
2884 dhbox.show();
2885 ddhbox.show();
2886 dimage->show();
2888 //results.get_vbox()->show();
2889 results.set_resizable (false);
2891 results.run ();
2895 void
2896 ARDOUR_UI::cleanup ()
2898 if (_session == 0) {
2899 /* shouldn't happen: menu item is insensitive */
2900 return;
2904 MessageDialog checker (_("Are you sure you want to cleanup?"),
2905 true,
2906 Gtk::MESSAGE_QUESTION,
2907 (Gtk::ButtonsType)(Gtk::BUTTONS_NONE));
2909 checker.set_secondary_text(_("Cleanup is a destructive operation.\n\
2910 ALL undo/redo information will be lost if you cleanup.\n\
2911 After cleanup, unused audio files will be moved to a \
2912 \"dead sounds\" location."));
2914 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
2915 checker.add_button (_("Clean Up"), RESPONSE_ACCEPT);
2916 checker.set_default_response (RESPONSE_CANCEL);
2918 checker.set_name (_("CleanupDialog"));
2919 checker.set_wmclass (X_("ardour_cleanup"), "Ardour");
2920 checker.set_position (Gtk::WIN_POS_MOUSE);
2922 switch (checker.run()) {
2923 case RESPONSE_ACCEPT:
2924 break;
2925 default:
2926 return;
2929 ARDOUR::CleanupReport rep;
2931 editor->prepare_for_cleanup ();
2933 /* do not allow flush until a session is reloaded */
2935 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
2936 if (act) {
2937 act->set_sensitive (false);
2940 if (_session->cleanup_sources (rep)) {
2941 editor->finish_cleanup ();
2942 return;
2945 editor->finish_cleanup ();
2947 checker.hide();
2948 display_cleanup_results (rep,
2949 _("cleaned files"),
2950 _("\
2951 The following %1 files were not in use and \n\
2952 have been moved to:\n\
2953 %2. \n\n\
2954 Flushing the wastebasket will \n\
2955 release an additional\n\
2956 %3 %4bytes of disk space.\n"),
2957 _("\
2958 The following file was not in use and \n \
2959 has been moved to:\n \
2960 %2. \n\n\
2961 Flushing the wastebasket will \n\
2962 release an additional\n\
2963 %3 %4bytes of disk space.\n"
2968 void
2969 ARDOUR_UI::flush_trash ()
2971 if (_session == 0) {
2972 /* shouldn't happen: menu item is insensitive */
2973 return;
2976 ARDOUR::CleanupReport rep;
2978 if (_session->cleanup_trash_sources (rep)) {
2979 return;
2982 display_cleanup_results (rep,
2983 _("deleted file"),
2984 _("The following %1 files were deleted from\n\
2985 %2,\n\
2986 releasing %3 %4bytes of disk space"),
2987 _("The following file was deleted from\n\
2988 %2,\n\
2989 releasing %3 %4bytes of disk space"));
2992 void
2993 ARDOUR_UI::add_route (Gtk::Window* float_window)
2995 int count;
2997 if (!_session) {
2998 return;
3001 if (add_route_dialog == 0) {
3002 add_route_dialog = new AddRouteDialog (_session);
3003 if (float_window) {
3004 add_route_dialog->set_transient_for (*float_window);
3008 if (add_route_dialog->is_visible()) {
3009 /* we're already doing this */
3010 return;
3013 ResponseType r = (ResponseType) add_route_dialog->run ();
3015 add_route_dialog->hide();
3017 switch (r) {
3018 case RESPONSE_ACCEPT:
3019 break;
3020 default:
3021 return;
3022 break;
3025 if ((count = add_route_dialog->count()) <= 0) {
3026 return;
3029 string template_path = add_route_dialog->track_template();
3031 if (!template_path.empty()) {
3032 _session->new_route_from_template (count, template_path);
3033 return;
3036 uint32_t input_chan = add_route_dialog->channels ();
3037 uint32_t output_chan;
3038 string name_template = add_route_dialog->name_template ();
3039 bool track = add_route_dialog->track ();
3040 bool aux = !track && add_route_dialog->aux();
3041 RouteGroup* route_group = add_route_dialog->route_group ();
3043 AutoConnectOption oac = Config->get_output_auto_connect();
3045 if (oac & AutoConnectMaster) {
3046 output_chan = (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan);
3047 } else {
3048 output_chan = input_chan;
3051 /* XXX do something with name template */
3053 if (add_route_dialog->type() == ARDOUR::DataType::MIDI) {
3054 if (track) {
3055 session_add_midi_track (route_group, count);
3056 } else {
3057 MessageDialog msg (*editor,
3058 _("Sorry, MIDI Busses are not supported at this time."));
3059 msg.run ();
3060 //session_add_midi_bus();
3062 } else {
3063 if (track) {
3064 session_add_audio_track (input_chan, output_chan, add_route_dialog->mode(), route_group, count);
3065 } else {
3066 session_add_audio_bus (aux, input_chan, output_chan, route_group, count);
3071 XMLNode*
3072 ARDOUR_UI::mixer_settings () const
3074 XMLNode* node = 0;
3076 if (_session) {
3077 node = _session->instant_xml(X_("Mixer"));
3078 } else {
3079 node = Config->instant_xml(X_("Mixer"));
3082 if (!node) {
3083 node = new XMLNode (X_("Mixer"));
3086 return node;
3089 XMLNode*
3090 ARDOUR_UI::editor_settings () const
3092 XMLNode* node = 0;
3094 if (_session) {
3095 node = _session->instant_xml(X_("Editor"));
3096 } else {
3097 node = Config->instant_xml(X_("Editor"));
3100 if (!node) {
3101 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
3102 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
3106 if (!node) {
3107 node = new XMLNode (X_("Editor"));
3110 return node;
3113 XMLNode*
3114 ARDOUR_UI::keyboard_settings () const
3116 XMLNode* node = 0;
3118 node = Config->extra_xml(X_("Keyboard"));
3120 if (!node) {
3121 node = new XMLNode (X_("Keyboard"));
3123 return node;
3126 void
3127 ARDOUR_UI::create_xrun_marker(nframes_t where)
3129 editor->mouse_add_new_marker (where, false, true);
3132 void
3133 ARDOUR_UI::halt_on_xrun_message ()
3135 MessageDialog msg (*editor,
3136 _("Recording was stopped because your system could not keep up."));
3137 msg.run ();
3140 void
3141 ARDOUR_UI::xrun_handler(nframes_t where)
3143 if (!_session) {
3144 return;
3147 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
3149 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
3150 create_xrun_marker(where);
3153 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
3154 halt_on_xrun_message ();
3158 void
3159 ARDOUR_UI::disk_overrun_handler ()
3161 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
3163 if (!have_disk_speed_dialog_displayed) {
3164 have_disk_speed_dialog_displayed = true;
3165 MessageDialog* msg = new MessageDialog (*editor, _("\
3166 The disk system on your computer\n\
3167 was not able to keep up with Ardour.\n\
3169 Specifically, it failed to write data to disk\n\
3170 quickly enough to keep up with recording.\n"));
3171 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3172 msg->show ();
3176 void
3177 ARDOUR_UI::disk_underrun_handler ()
3179 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
3181 if (!have_disk_speed_dialog_displayed) {
3182 have_disk_speed_dialog_displayed = true;
3183 MessageDialog* msg = new MessageDialog (*editor,
3184 _("The disk system on your computer\n\
3185 was not able to keep up with Ardour.\n\
3187 Specifically, it failed to read data from disk\n\
3188 quickly enough to keep up with playback.\n"));
3189 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3190 msg->show ();
3194 void
3195 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
3197 have_disk_speed_dialog_displayed = false;
3198 delete msg;
3201 void
3202 ARDOUR_UI::session_dialog (std::string msg)
3204 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
3206 MessageDialog* d;
3208 if (editor) {
3209 d = new MessageDialog (*editor, msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3210 } else {
3211 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3214 d->show_all ();
3215 d->run ();
3216 delete d;
3220 ARDOUR_UI::pending_state_dialog ()
3222 HBox* hbox = new HBox();
3223 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3224 ArdourDialog dialog (_("Crash Recovery"), true);
3225 Label message (_("\
3226 This session appears to have been in\n\
3227 middle of recording when ardour or\n\
3228 the computer was shutdown.\n\
3230 Ardour can recover any captured audio for\n\
3231 you, or it can ignore it. Please decide\n\
3232 what you would like to do.\n"));
3233 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3234 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3235 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3236 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3237 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
3238 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
3239 dialog.set_default_response (RESPONSE_ACCEPT);
3240 dialog.set_position (WIN_POS_CENTER);
3241 message.show();
3242 image->show();
3243 hbox->show();
3245 switch (dialog.run ()) {
3246 case RESPONSE_ACCEPT:
3247 return 1;
3248 default:
3249 return 0;
3254 ARDOUR_UI::sr_mismatch_dialog (nframes_t desired, nframes_t actual)
3256 HBox* hbox = new HBox();
3257 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3258 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
3259 Label message (string_compose (_("\
3260 This session was created with a sample rate of %1 Hz\n\
3262 The audioengine is currently running at %2 Hz\n"), desired, actual));
3264 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3265 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3266 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3267 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3268 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
3269 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
3270 dialog.set_default_response (RESPONSE_ACCEPT);
3271 dialog.set_position (WIN_POS_CENTER);
3272 message.show();
3273 image->show();
3274 hbox->show();
3276 switch (dialog.run ()) {
3277 case RESPONSE_ACCEPT:
3278 return 0;
3279 default:
3280 return 1;
3285 void
3286 ARDOUR_UI::disconnect_from_jack ()
3288 if (engine) {
3289 if( engine->disconnect_from_jack ()) {
3290 MessageDialog msg (*editor, _("Could not disconnect from JACK"));
3291 msg.run ();
3294 update_sample_rate (0);
3298 void
3299 ARDOUR_UI::reconnect_to_jack ()
3301 if (engine) {
3302 if (engine->reconnect_to_jack ()) {
3303 MessageDialog msg (*editor, _("Could not reconnect to JACK"));
3304 msg.run ();
3307 update_sample_rate (0);
3311 void
3312 ARDOUR_UI::use_config ()
3315 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
3316 if (node) {
3317 set_transport_controllable_state (*node);
3320 node = Config->extra_xml (X_("UI"));
3322 if (node) {
3323 const XMLProperty* prop = node->property (X_("show-big-clock"));
3324 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleBigClock"));
3325 if (act) {
3326 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
3327 tact->set_active (string_is_affirmative (prop->value()));
3332 void
3333 ARDOUR_UI::update_transport_clocks (nframes_t pos)
3335 if (Config->get_primary_clock_delta_edit_cursor()) {
3336 primary_clock.set (pos, false, editor->get_preferred_edit_position(), 1);
3337 } else {
3338 primary_clock.set (pos, 0, true);
3341 if (Config->get_secondary_clock_delta_edit_cursor()) {
3342 secondary_clock.set (pos, false, editor->get_preferred_edit_position(), 2);
3343 } else {
3344 secondary_clock.set (pos);
3347 if (big_clock_window) {
3348 big_clock.set (pos);
3352 void
3353 ARDOUR_UI::record_state_changed ()
3355 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
3357 if (!_session || !big_clock_window) {
3358 /* why bother - the clock isn't visible */
3359 return;
3362 Session::RecordState const r = _session->record_status ();
3363 bool const h = _session->have_rec_enabled_track ();
3365 if (r == Session::Recording && h) {
3366 big_clock.set_widget_name ("BigClockRecording");
3367 } else {
3368 big_clock.set_widget_name ("BigClockNonRecording");
3372 bool
3373 ARDOUR_UI::first_idle ()
3375 if (_session) {
3376 _session->allow_auto_play (true);
3379 if (editor) {
3380 editor->first_idle();
3383 Keyboard::set_can_save_keybindings (true);
3384 return false;
3387 void
3388 ARDOUR_UI::store_clock_modes ()
3390 XMLNode* node = new XMLNode(X_("ClockModes"));
3392 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
3393 node->add_property ((*x)->name().c_str(), enum_2_string ((*x)->mode()));
3396 _session->add_extra_xml (*node);
3397 _session->set_dirty ();
3402 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
3403 : Controllable (name), ui (u), type(tp)
3408 void
3409 ARDOUR_UI::TransportControllable::set_value (float val)
3411 if (type == ShuttleControl) {
3412 double fract;
3414 if (val == 0.5f) {
3415 fract = 0.0;
3416 } else {
3417 if (val < 0.5f) {
3418 fract = -((0.5f - val)/0.5f);
3419 } else {
3420 fract = ((val - 0.5f)/0.5f);
3424 ui.set_shuttle_fract (fract);
3425 return;
3428 if (val < 0.5f) {
3429 /* do nothing: these are radio-style actions */
3430 return;
3433 const char *action = 0;
3435 switch (type) {
3436 case Roll:
3437 action = X_("Roll");
3438 break;
3439 case Stop:
3440 action = X_("Stop");
3441 break;
3442 case GotoStart:
3443 action = X_("Goto Start");
3444 break;
3445 case GotoEnd:
3446 action = X_("Goto End");
3447 break;
3448 case AutoLoop:
3449 action = X_("Loop");
3450 break;
3451 case PlaySelection:
3452 action = X_("Play Selection");
3453 break;
3454 case RecordEnable:
3455 action = X_("Record");
3456 break;
3457 default:
3458 break;
3461 if (action == 0) {
3462 return;
3465 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
3467 if (act) {
3468 act->activate ();
3472 float
3473 ARDOUR_UI::TransportControllable::get_value (void) const
3475 float val = 0.0f;
3477 switch (type) {
3478 case Roll:
3479 break;
3480 case Stop:
3481 break;
3482 case GotoStart:
3483 break;
3484 case GotoEnd:
3485 break;
3486 case AutoLoop:
3487 break;
3488 case PlaySelection:
3489 break;
3490 case RecordEnable:
3491 break;
3492 case ShuttleControl:
3493 break;
3494 default:
3495 break;
3498 return val;
3501 void
3502 ARDOUR_UI::TransportControllable::set_id (const string& str)
3504 _id = str;
3507 void
3508 ARDOUR_UI::setup_profile ()
3510 if (gdk_screen_width() < 1200) {
3511 Profile->set_small_screen ();
3515 if (getenv ("ARDOUR_SAE")) {
3516 Profile->set_sae ();
3517 Profile->set_single_package ();