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.
21 #include "gtk2ardour-config.h"
37 #include <sys/resource.h>
39 #include <gtkmm/messagedialog.h>
40 #include <gtkmm/accelmap.h>
42 #include "pbd/error.h"
43 #include "pbd/basename.h"
44 #include "pbd/compose.h"
45 #include "pbd/failed_constructor.h"
46 #include "pbd/enumwriter.h"
47 #include "pbd/memento_command.h"
48 #include "pbd/openuri.h"
49 #include "pbd/file_utils.h"
51 #include "gtkmm2ext/application.h"
52 #include "gtkmm2ext/bindings.h"
53 #include "gtkmm2ext/gtk_ui.h"
54 #include "gtkmm2ext/utils.h"
55 #include "gtkmm2ext/click_box.h"
56 #include "gtkmm2ext/fastmeter.h"
57 #include "gtkmm2ext/popup.h"
58 #include "gtkmm2ext/window_title.h"
60 #include "midi++/manager.h"
62 #include "ardour/ardour.h"
63 #include "ardour/callback.h"
64 #include "ardour/profile.h"
65 #include "ardour/session_directory.h"
66 #include "ardour/session_route.h"
67 #include "ardour/session_state_utils.h"
68 #include "ardour/session_utils.h"
69 #include "ardour/port.h"
70 #include "ardour/audioengine.h"
71 #include "ardour/playlist.h"
72 #include "ardour/utils.h"
73 #include "ardour/audio_diskstream.h"
74 #include "ardour/audiofilesource.h"
75 #include "ardour/recent_sessions.h"
76 #include "ardour/port.h"
77 #include "ardour/audio_track.h"
78 #include "ardour/midi_track.h"
79 #include "ardour/filesystem_paths.h"
80 #include "ardour/filename_extensions.h"
82 typedef uint64_t microseconds_t
;
86 #include "add_route_dialog.h"
87 #include "ambiguous_file_dialog.h"
88 #include "ardour_ui.h"
89 #include "audio_clock.h"
90 #include "bundle_manager.h"
91 #include "engine_dialog.h"
92 #include "gain_meter.h"
93 #include "global_port_matrix.h"
94 #include "gui_object.h"
95 #include "gui_thread.h"
97 #include "location_ui.h"
98 #include "missing_file_dialog.h"
99 #include "missing_plugin_dialog.h"
100 #include "mixer_ui.h"
102 #include "processor_box.h"
103 #include "prompter.h"
104 #include "public_editor.h"
105 #include "route_time_axis.h"
106 #include "session_metadata_dialog.h"
107 #include "shuttle_control.h"
108 #include "speaker_dialog.h"
111 #include "theme_manager.h"
112 #include "time_axis_view_item.h"
114 #include "window_proxy.h"
118 using namespace ARDOUR
;
120 using namespace Gtkmm2ext
;
123 ARDOUR_UI
*ARDOUR_UI::theArdourUI
= 0;
124 UIConfiguration
*ARDOUR_UI::ui_config
= 0;
126 sigc::signal
<void,bool> ARDOUR_UI::Blink
;
127 sigc::signal
<void> ARDOUR_UI::RapidScreenUpdate
;
128 sigc::signal
<void> ARDOUR_UI::SuperRapidScreenUpdate
;
129 sigc::signal
<void, framepos_t
, bool, framepos_t
> ARDOUR_UI::Clock
;
131 bool could_be_a_valid_path (const string
& path
);
133 ARDOUR_UI::ARDOUR_UI (int *argcp
, char **argvp
[])
135 : Gtkmm2ext::UI (PROGRAM_NAME
, argcp
, argvp
)
137 , gui_object_state (new GUIObjectState
)
138 , primary_clock (new AudioClock (X_("primary"), false, X_("TransportClockDisplay"), true, true, false, true))
139 , secondary_clock (new AudioClock (X_("secondary"), false, X_("SecondaryClockDisplay"), true, true, false, true))
140 , preroll_clock (new AudioClock (X_("preroll"), false, X_("PreRollClock"), true, false, true))
141 , postroll_clock (new AudioClock (X_("postroll"), false, X_("PostRollClock"), true, false, true))
145 , preroll_button (_("pre\nroll"))
146 , postroll_button (_("post\nroll"))
150 , big_clock (new AudioClock (X_("bigclock"), false, "BigClockNonRecording", true, true, false, false))
154 , roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll
))
155 , stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop
))
156 , goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart
))
157 , goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd
))
158 , auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop
))
159 , play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection
))
160 , rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable
))
162 , roll_button (roll_controllable
)
163 , stop_button (stop_controllable
)
164 , goto_start_button (goto_start_controllable
)
165 , goto_end_button (goto_end_controllable
)
166 , auto_loop_button (auto_loop_controllable
)
167 , play_selection_button (play_selection_controllable
)
168 , rec_button (rec_controllable
)
170 , auto_return_button (_("Auto Return"))
171 , auto_play_button (_("Auto Play"))
172 , auto_input_button (_("Auto Input"))
173 // , click_button (_("Click"))
174 , time_master_button (_("time\nmaster"))
176 , auditioning_alert_button (_("AUDITION"))
177 , solo_alert_button (_("SOLO"))
179 , error_log_button (_("Errors"))
182 using namespace Gtk::Menu_Helpers
;
188 // _auto_display_errors = false;
190 * This was commented out as it wasn't defined
191 * in A3 IIRC. If this is not needed it should
192 * be completely removed.
200 if (theArdourUI
== 0) {
204 ui_config
= new UIConfiguration();
205 theme_manager
= new ThemeManager();
213 _session_is_new
= false;
214 big_clock_window
= 0;
215 big_clock_height
= 0;
216 big_clock_resize_in_progress
= false;
217 session_selector_window
= 0;
218 last_key_press_time
= 0;
219 _will_create_new_session_automatically
= false;
220 add_route_dialog
= 0;
223 rc_option_editor
= 0;
224 session_option_editor
= 0;
226 open_session_selector
= 0;
227 have_configure_timeout
= false;
228 have_disk_speed_dialog_displayed
= false;
229 session_loaded
= false;
230 ignore_dual_punch
= false;
231 original_big_clock_width
= -1;
232 original_big_clock_height
= -1;
233 original_big_clock_font_size
= 0;
235 roll_button
.unset_flags (Gtk::CAN_FOCUS
);
236 stop_button
.unset_flags (Gtk::CAN_FOCUS
);
237 goto_start_button
.unset_flags (Gtk::CAN_FOCUS
);
238 goto_end_button
.unset_flags (Gtk::CAN_FOCUS
);
239 auto_loop_button
.unset_flags (Gtk::CAN_FOCUS
);
240 play_selection_button
.unset_flags (Gtk::CAN_FOCUS
);
241 rec_button
.unset_flags (Gtk::CAN_FOCUS
);
242 join_play_range_button
.unset_flags (Gtk::CAN_FOCUS
);
243 last_configure_time
= 0;
246 ARDOUR::Diskstream::DiskOverrun
.connect (forever_connections
, MISSING_INVALIDATOR
, boost::bind (&ARDOUR_UI::disk_overrun_handler
, this), gui_context());
247 ARDOUR::Diskstream::DiskUnderrun
.connect (forever_connections
, MISSING_INVALIDATOR
, boost::bind (&ARDOUR_UI::disk_underrun_handler
, this), gui_context());
249 /* handle dialog requests */
251 ARDOUR::Session::Dialog
.connect (forever_connections
, MISSING_INVALIDATOR
, ui_bind (&ARDOUR_UI::session_dialog
, this, _1
), gui_context());
253 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
255 ARDOUR::Session::AskAboutPendingState
.connect_same_thread (forever_connections
, boost::bind (&ARDOUR_UI::pending_state_dialog
, this));
257 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
259 ARDOUR::Session::AskAboutSampleRateMismatch
.connect_same_thread (forever_connections
, boost::bind (&ARDOUR_UI::sr_mismatch_dialog
, this, _1
, _2
));
261 /* handle requests to quit (coming from JACK session) */
263 ARDOUR::Session::Quit
.connect (forever_connections
, MISSING_INVALIDATOR
, ui_bind (&ARDOUR_UI::finish
, this), gui_context ());
265 /* handle requests to deal with missing files */
267 ARDOUR::Session::MissingFile
.connect_same_thread (forever_connections
, boost::bind (&ARDOUR_UI::missing_file
, this, _1
, _2
, _3
));
269 /* and ambiguous files */
271 ARDOUR::FileSource::AmbiguousFileName
.connect_same_thread (forever_connections
, boost::bind (&ARDOUR_UI::ambiguous_file
, this, _1
, _2
, _3
));
273 /* lets get this party started */
276 if (ARDOUR::init (ARDOUR_COMMAND_LINE::use_vst
, ARDOUR_COMMAND_LINE::try_hw_optimization
)) {
277 throw failed_constructor ();
280 setup_gtk_ardour_enums ();
283 GainMeter::setup_slider_pix ();
284 RouteTimeAxisView::setup_slider_pix ();
285 SendProcessorEntry::setup_slider_pix ();
286 SessionEvent::create_per_thread_pool ("GUI", 512);
288 } catch (failed_constructor
& err
) {
289 error
<< string_compose (_("could not initialize %1."), PROGRAM_NAME
) << endmsg
;
294 /* we like keyboards */
296 keyboard
= new ArdourKeyboard(*this);
298 XMLNode
* node
= ARDOUR_UI::instance()->keyboard_settings();
300 keyboard
->set_state (*node
, Stateful::loading_state_version
);
303 /* we don't like certain modifiers */
304 Bindings::set_ignored_state (GDK_LOCK_MASK
|GDK_MOD2_MASK
|GDK_MOD3_MASK
);
308 TimeAxisViewItem::set_constant_heights ();
310 /* The following must happen after ARDOUR::init() so that Config is set up */
312 location_ui
= new ActionWindowProxy
<LocationUIWindow
> (X_("locations"), Config
->extra_xml (X_("UI")), X_("ToggleLocations"));
313 big_clock_window
= new ActionWindowProxy
<Gtk::Window
> (X_("bigclock"), Config
->extra_xml (X_("UI")), X_("ToggleBigClock"));
314 speaker_config_window
= new ActionWindowProxy
<SpeakerDialog
> (X_("speakerconf"), Config
->extra_xml (X_("UI")), X_("toggle-speaker-config"));
316 for (ARDOUR::DataType::iterator i
= ARDOUR::DataType::begin(); i
!= ARDOUR::DataType::end(); ++i
) {
317 _global_port_matrix
[*i
] = new ActionWindowProxy
<GlobalPortMatrixWindow
> (
318 string_compose ("GlobalPortMatrix-%1", (*i
).to_string()),
319 Config
->extra_xml (X_("UI")),
320 string_compose ("toggle-%1-connection-manager", (*i
).to_string())
326 SpeakerDialog
* s
= new SpeakerDialog ();
327 s
->signal_unmap().connect (sigc::bind (sigc::ptr_fun (&ActionManager::uncheck_toggleaction
), X_("<Actions>/Common/toggle-speaker-config")));
328 speaker_config_window
->set (s
);
330 starting
.connect (sigc::mem_fun(*this, &ARDOUR_UI::startup
));
331 stopping
.connect (sigc::mem_fun(*this, &ARDOUR_UI::shutdown
));
334 /** @return true if a session was chosen and `apply' clicked, otherwise false if `cancel' was clicked */
336 ARDOUR_UI::run_startup (bool should_be_new
, string load_template
)
339 _startup
= new ArdourStartup ();
341 XMLNode
* audio_setup
= Config
->extra_xml ("AudioSetup");
343 if (audio_setup
&& _startup
->engine_control()) {
344 _startup
->engine_control()->set_state (*audio_setup
);
347 _startup
->set_new_only (should_be_new
);
348 if (!load_template
.empty()) {
349 _startup
->set_load_template( load_template
);
351 _startup
->present ();
357 switch (_startup
->response()) {
366 ARDOUR_UI::create_engine ()
368 // this gets called every time by new_session()
374 loading_message (_("Starting audio engine"));
377 engine
= new ARDOUR::AudioEngine (ARDOUR_COMMAND_LINE::jack_client_name
, ARDOUR_COMMAND_LINE::jack_session_uuid
);
384 engine
->Stopped
.connect (forever_connections
, MISSING_INVALIDATOR
, boost::bind (&ARDOUR_UI::engine_stopped
, this), gui_context());
385 engine
->Running
.connect (forever_connections
, MISSING_INVALIDATOR
, boost::bind (&ARDOUR_UI::engine_running
, this), gui_context());
386 engine
->SampleRateChanged
.connect (forever_connections
, MISSING_INVALIDATOR
, ui_bind (&ARDOUR_UI::update_sample_rate
, this, _1
), gui_context());
388 engine
->Halted
.connect_same_thread (forever_connections
, boost::bind (&ARDOUR_UI::engine_halted
, this, _1
, false));
390 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports
);
398 ARDOUR_UI::post_engine ()
400 /* Things to be done once we create the AudioEngine
403 ARDOUR::init_post_engine ();
405 ActionManager::init ();
408 if (setup_windows ()) {
409 throw failed_constructor ();
412 check_memory_locking();
414 /* this is the first point at which all the keybindings are available */
416 if (ARDOUR_COMMAND_LINE::show_key_actions
) {
417 vector
<string
> names
;
418 vector
<string
> paths
;
419 vector
<string
> tooltips
;
421 vector
<AccelKey
> bindings
;
423 ActionManager::get_all_actions (names
, paths
, tooltips
, keys
, bindings
);
425 vector
<string
>::iterator n
;
426 vector
<string
>::iterator k
;
427 for (n
= names
.begin(), k
= keys
.begin(); n
!= names
.end(); ++n
, ++k
) {
428 cerr
<< "Action: " << (*n
) << " bound to " << (*k
) << endl
;
434 blink_timeout_tag
= -1;
436 /* this being a GUI and all, we want peakfiles */
438 AudioFileSource::set_build_peakfiles (true);
439 AudioFileSource::set_build_missing_peakfiles (true);
441 /* set default clock modes */
443 if (Profile
->get_sae()) {
444 primary_clock
->set_mode (AudioClock::BBT
);
445 secondary_clock
->set_mode (AudioClock::MinSec
);
447 primary_clock
->set_mode (AudioClock::Timecode
);
448 secondary_clock
->set_mode (AudioClock::BBT
);
451 /* start the time-of-day-clock */
454 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
455 update_wall_clock ();
456 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock
), 60000);
459 update_disk_space ();
461 update_sample_rate (engine
->frame_rate());
463 Config
->ParameterChanged
.connect (forever_connections
, MISSING_INVALIDATOR
, ui_bind (&ARDOUR_UI::parameter_changed
, this, _1
), gui_context());
464 boost::function
<void (string
)> pc (boost::bind (&ARDOUR_UI::parameter_changed
, this, _1
));
465 Config
->map_parameters (pc
);
467 /* now start and maybe save state */
469 if (do_engine_start () == 0) {
470 if (_session
&& _session_is_new
) {
471 /* we need to retain initial visual
472 settings for a new session
474 _session
->save_state ("");
479 ARDOUR_UI::~ARDOUR_UI ()
484 delete add_route_dialog
;
488 ARDOUR_UI::pop_back_splash ()
490 if (Splash::instance()) {
491 // Splash::instance()->pop_back();
492 Splash::instance()->hide ();
497 ARDOUR_UI::configure_timeout ()
499 if (last_configure_time
== 0) {
500 /* no configure events yet */
504 /* force a gap of 0.5 seconds since the last configure event
507 if (get_microseconds() - last_configure_time
< 500000) {
510 have_configure_timeout
= false;
511 cerr
<< "config event-driven save\n";
512 save_ardour_state ();
518 ARDOUR_UI::configure_handler (GdkEventConfigure
* /*conf*/)
520 if (have_configure_timeout
) {
521 last_configure_time
= get_microseconds();
523 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout
), 100);
524 have_configure_timeout
= true;
531 ARDOUR_UI::set_transport_controllable_state (const XMLNode
& node
)
533 const XMLProperty
* prop
;
535 if ((prop
= node
.property ("roll")) != 0) {
536 roll_controllable
->set_id (prop
->value());
538 if ((prop
= node
.property ("stop")) != 0) {
539 stop_controllable
->set_id (prop
->value());
541 if ((prop
= node
.property ("goto-start")) != 0) {
542 goto_start_controllable
->set_id (prop
->value());
544 if ((prop
= node
.property ("goto-end")) != 0) {
545 goto_end_controllable
->set_id (prop
->value());
547 if ((prop
= node
.property ("auto-loop")) != 0) {
548 auto_loop_controllable
->set_id (prop
->value());
550 if ((prop
= node
.property ("play-selection")) != 0) {
551 play_selection_controllable
->set_id (prop
->value());
553 if ((prop
= node
.property ("rec")) != 0) {
554 rec_controllable
->set_id (prop
->value());
556 if ((prop
= node
.property ("shuttle")) != 0) {
557 shuttle_box
->controllable()->set_id (prop
->value());
563 ARDOUR_UI::get_transport_controllable_state ()
565 XMLNode
* node
= new XMLNode(X_("TransportControllables"));
568 roll_controllable
->id().print (buf
, sizeof (buf
));
569 node
->add_property (X_("roll"), buf
);
570 stop_controllable
->id().print (buf
, sizeof (buf
));
571 node
->add_property (X_("stop"), buf
);
572 goto_start_controllable
->id().print (buf
, sizeof (buf
));
573 node
->add_property (X_("goto_start"), buf
);
574 goto_end_controllable
->id().print (buf
, sizeof (buf
));
575 node
->add_property (X_("goto_end"), buf
);
576 auto_loop_controllable
->id().print (buf
, sizeof (buf
));
577 node
->add_property (X_("auto_loop"), buf
);
578 play_selection_controllable
->id().print (buf
, sizeof (buf
));
579 node
->add_property (X_("play_selection"), buf
);
580 rec_controllable
->id().print (buf
, sizeof (buf
));
581 node
->add_property (X_("rec"), buf
);
582 shuttle_box
->controllable()->id().print (buf
, sizeof (buf
));
583 node
->add_property (X_("shuttle"), buf
);
590 ARDOUR_UI::autosave_session ()
592 if (g_main_depth() > 1) {
593 /* inside a recursive main loop,
594 give up because we may not be able to
600 if (!Config
->get_periodic_safety_backups()) {
605 _session
->maybe_write_autosave();
612 ARDOUR_UI::update_autosave ()
614 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_autosave
)
616 if (_session
&& _session
->dirty()) {
617 if (_autosave_connection
.connected()) {
618 _autosave_connection
.disconnect();
621 _autosave_connection
= Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session
),
622 Config
->get_periodic_safety_backup_interval() * 1000);
625 if (_autosave_connection
.connected()) {
626 _autosave_connection
.disconnect();
632 ARDOUR_UI::backend_audio_error (bool we_set_params
, Gtk::Window
* toplevel
)
636 title
= string_compose (_("%1 could not start JACK"), PROGRAM_NAME
);
638 title
= string_compose (_("%1 could not connect to JACK."), PROGRAM_NAME
);
641 MessageDialog
win (title
,
647 win
.set_secondary_text(_("There are several possible reasons:\n\
649 1) You requested audio parameters that are not supported..\n\
650 2) JACK is running as another user.\n\
652 Please consider the possibilities, and perhaps try different parameters."));
654 win
.set_secondary_text(_("There are several possible reasons:\n\
656 1) JACK is not running.\n\
657 2) JACK is running as another user, perhaps root.\n\
658 3) There is already another client called \"ardour\".\n\
660 Please consider the possibilities, and perhaps (re)start JACK."));
664 win
.set_transient_for (*toplevel
);
668 win
.add_button (Stock::OK
, RESPONSE_CLOSE
);
670 win
.add_button (Stock::QUIT
, RESPONSE_CLOSE
);
673 win
.set_default_response (RESPONSE_CLOSE
);
676 win
.set_position (Gtk::WIN_POS_CENTER
);
679 /* we just don't care about the result, but we want to block */
685 ARDOUR_UI::startup ()
687 Application
* app
= Application::instance ();
689 app
->ShouldQuit
.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish
));
690 app
->ShouldLoad
.connect (sigc::mem_fun (*this, &ARDOUR_UI::idle_load
));
693 call_the_mothership (VERSIONSTRING
);
698 if (get_session_parameters (true, ARDOUR_COMMAND_LINE::new_session
, ARDOUR_COMMAND_LINE::load_template
)) {
704 goto_editor_window ();
706 /* Add the window proxies here; their addition may cause windows to be opened, and we want them
707 to be opened on top of the editor window that goto_editor_window() just opened.
709 add_window_proxy (location_ui
);
710 add_window_proxy (big_clock_window
);
711 for (ARDOUR::DataType::iterator i
= ARDOUR::DataType::begin(); i
!= ARDOUR::DataType::end(); ++i
) {
712 add_window_proxy (_global_port_matrix
[*i
]);
715 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME
));
719 ARDOUR_UI::no_memory_warning ()
721 XMLNode
node (X_("no-memory-warning"));
722 Config
->add_instant_xml (node
);
726 ARDOUR_UI::check_memory_locking ()
729 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
733 XMLNode
* memory_warning_node
= Config
->instant_xml (X_("no-memory-warning"));
735 if (engine
->is_realtime() && memory_warning_node
== 0) {
737 struct rlimit limits
;
739 long pages
, page_size
;
741 if ((page_size
= sysconf (_SC_PAGESIZE
)) < 0 ||(pages
= sysconf (_SC_PHYS_PAGES
)) < 0) {
744 ram
= (int64_t) pages
* (int64_t) page_size
;
747 if (getrlimit (RLIMIT_MEMLOCK
, &limits
)) {
751 if (limits
.rlim_cur
!= RLIM_INFINITY
) {
753 if (ram
== 0 || ((double) limits
.rlim_cur
/ ram
) < 0.75) {
757 _("WARNING: Your system has a limit for maximum amount of locked memory. "
758 "This might cause %1 to run out of memory before your system "
759 "runs out of memory. \n\n"
760 "You can view the memory limit with 'ulimit -l', "
761 "and it is normally controlled by /etc/security/limits.conf"),
762 PROGRAM_NAME
).c_str());
764 VBox
* vbox
= msg
.get_vbox();
766 CheckButton
cb (_("Do not show this window again"));
768 cb
.signal_toggled().connect (sigc::mem_fun (*this, &ARDOUR_UI::no_memory_warning
));
770 hbox
.pack_start (cb
, true, false);
771 vbox
->pack_start (hbox
);
778 editor
->ensure_float (msg
);
788 ARDOUR_UI::queue_finish ()
790 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish
));
794 ARDOUR_UI::idle_finish ()
797 return false; /* do not call again */
806 if (_session
->transport_rolling() && (++tries
< 8)) {
807 _session
->request_stop (false, true);
811 if (_session
->dirty()) {
812 vector
<string
> actions
;
813 actions
.push_back (_("Don't quit"));
814 actions
.push_back (_("Just quit"));
815 actions
.push_back (_("Save and quit"));
816 switch (ask_about_saving_session(actions
)) {
821 /* use the default name */
822 if (save_state_canfail ("")) {
823 /* failed - don't quit */
824 MessageDialog
msg (*editor
,
826 Ardour was unable to save your session.\n\n\
827 If you still wish to quit, please use the\n\n\
828 \"Just quit\" option."));
839 second_connection
.disconnect ();
840 point_one_second_connection
.disconnect ();
841 point_oh_five_second_connection
.disconnect ();
842 point_zero_one_second_connection
.disconnect();
845 /* Save state before deleting the session, as that causes some
846 windows to be destroyed before their visible state can be
849 save_ardour_state ();
852 // _session->set_deletion_in_progress ();
853 _session
->set_clean ();
854 _session
->remove_pending_capture_state ();
859 ArdourDialog::close_all_dialogs ();
865 ARDOUR_UI::ask_about_saving_session (const vector
<string
>& actions
)
867 ArdourDialog
window (_("Unsaved Session"));
868 Gtk::HBox dhbox
; // the hbox for the image and text
869 Gtk::Label prompt_label
;
870 Gtk::Image
* dimage
= manage (new Gtk::Image(Stock::DIALOG_WARNING
, Gtk::ICON_SIZE_DIALOG
));
874 assert (actions
.size() >= 3);
876 window
.add_button (actions
[0], RESPONSE_REJECT
);
877 window
.add_button (actions
[1], RESPONSE_APPLY
);
878 window
.add_button (actions
[2], RESPONSE_ACCEPT
);
880 window
.set_default_response (RESPONSE_ACCEPT
);
882 Gtk::Button
noquit_button (msg
);
883 noquit_button
.set_name ("EditorGTKButton");
887 if (_session
->snap_name() == _session
->name()) {
888 prompt
= string_compose(_("The session \"%1\"\nhas not been saved.\n\nAny changes made this time\nwill be lost unless you save it.\n\nWhat do you want to do?"),
889 _session
->snap_name());
891 prompt
= string_compose(_("The snapshot \"%1\"\nhas not been saved.\n\nAny changes made this time\nwill be lost unless you save it.\n\nWhat do you want to do?"),
892 _session
->snap_name());
895 prompt_label
.set_text (prompt
);
896 prompt_label
.set_name (X_("PrompterLabel"));
897 prompt_label
.set_alignment(ALIGN_LEFT
, ALIGN_TOP
);
899 dimage
->set_alignment(ALIGN_CENTER
, ALIGN_TOP
);
900 dhbox
.set_homogeneous (false);
901 dhbox
.pack_start (*dimage
, false, false, 5);
902 dhbox
.pack_start (prompt_label
, true, false, 5);
903 window
.get_vbox()->pack_start (dhbox
);
905 window
.set_name (_("Prompter"));
906 window
.set_position (Gtk::WIN_POS_MOUSE
);
907 window
.set_modal (true);
908 window
.set_resizable (false);
914 window
.set_keep_above (true);
917 ResponseType r
= (ResponseType
) window
.run();
922 case RESPONSE_ACCEPT
: // save and get out of here
924 case RESPONSE_APPLY
: // get out of here
934 ARDOUR_UI::every_second ()
937 update_buffer_load ();
938 update_disk_space ();
943 ARDOUR_UI::every_point_one_seconds ()
945 shuttle_box
->update_speed_display ();
946 RapidScreenUpdate(); /* EMIT_SIGNAL */
951 ARDOUR_UI::every_point_zero_one_seconds ()
953 // august 2007: actual update frequency: 40Hz, not 100Hz
955 SuperRapidScreenUpdate(); /* EMIT_SIGNAL */
960 ARDOUR_UI::update_sample_rate (framecnt_t
)
964 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate
, ignored
)
966 if (!engine
->connected()) {
968 snprintf (buf
, sizeof (buf
), _("disconnected"));
972 framecnt_t rate
= engine
->frame_rate();
974 if (fmod (rate
, 1000.0) != 0.0) {
975 snprintf (buf
, sizeof (buf
), _("%.1f kHz / %4.1f ms"),
976 (float) rate
/1000.0f
,
977 (engine
->frames_per_cycle() / (float) rate
) * 1000.0f
);
979 snprintf (buf
, sizeof (buf
), _("%" PRId64
" kHz / %4.1f ms"),
981 (engine
->frames_per_cycle() / (float) rate
) * 1000.0f
);
985 sample_rate_label
.set_text (buf
);
989 ARDOUR_UI::update_format ()
992 format_label
.set_text ("");
998 switch (_session
->config
.get_native_file_header_format ()) {
1024 switch (_session
->config
.get_native_file_data_format ()) {
1036 format_label
.set_text (s
.str ());
1040 ARDOUR_UI::update_cpu_load ()
1043 snprintf (buf
, sizeof (buf
), _("DSP: %5.1f%%"), engine
->get_cpu_load());
1044 cpu_load_label
.set_text (buf
);
1048 ARDOUR_UI::update_buffer_load ()
1053 snprintf (buf
, sizeof (buf
), _("Buffers p:%" PRIu32
"%% c:%" PRIu32
"%%"),
1054 _session
->playback_load(), _session
->capture_load());
1055 buffer_load_label
.set_text (buf
);
1057 buffer_load_label
.set_text ("");
1062 ARDOUR_UI::count_recenabled_streams (Route
& route
)
1064 Track
* track
= dynamic_cast<Track
*>(&route
);
1065 if (track
&& track
->record_enabled()) {
1066 rec_enabled_streams
+= track
->n_inputs().n_total();
1071 ARDOUR_UI::update_disk_space()
1073 if (_session
== 0) {
1077 framecnt_t frames
= _session
->available_capture_duration();
1079 framecnt_t fr
= _session
->frame_rate();
1081 if (frames
== max_framecnt
) {
1082 strcpy (buf
, _("Disk: 24hrs+"));
1084 rec_enabled_streams
= 0;
1085 _session
->foreach_route (this, &ARDOUR_UI::count_recenabled_streams
);
1087 if (rec_enabled_streams
) {
1088 frames
/= rec_enabled_streams
;
1095 hrs
= frames
/ (fr
* 3600);
1096 frames
-= hrs
* fr
* 3600;
1097 mins
= frames
/ (fr
* 60);
1098 frames
-= mins
* fr
* 60;
1101 snprintf (buf
, sizeof(buf
), _("Disk: %02dh:%02dm:%02ds"), hrs
, mins
, secs
);
1104 disk_space_label
.set_text (buf
);
1106 // An attempt to make the disk space label flash red when space has run out.
1108 if (frames
< fr
* 60 * 5) {
1109 /* disk_space_box.style ("disk_space_label_empty"); */
1111 /* disk_space_box.style ("disk_space_label"); */
1117 ARDOUR_UI::update_wall_clock ()
1124 tm_now
= localtime (&now
);
1126 sprintf (buf
, "%02d:%02d", tm_now
->tm_hour
, tm_now
->tm_min
);
1127 wall_clock_label
.set_text (buf
);
1133 ARDOUR_UI::session_menu (GdkEventButton */
*ev*/
)
1135 session_popup_menu
->popup (0, 0);
1140 ARDOUR_UI::redisplay_recent_sessions ()
1142 std::vector
<sys::path
> session_directories
;
1143 RecentSessionsSorter cmp
;
1145 recent_session_display
.set_model (Glib::RefPtr
<TreeModel
>(0));
1146 recent_session_model
->clear ();
1148 ARDOUR::RecentSessions rs
;
1149 ARDOUR::read_recent_sessions (rs
);
1152 recent_session_display
.set_model (recent_session_model
);
1156 // sort them alphabetically
1157 sort (rs
.begin(), rs
.end(), cmp
);
1159 for (ARDOUR::RecentSessions::iterator i
= rs
.begin(); i
!= rs
.end(); ++i
) {
1160 session_directories
.push_back ((*i
).second
);
1163 for (vector
<sys::path
>::const_iterator i
= session_directories
.begin();
1164 i
!= session_directories
.end(); ++i
)
1166 std::vector
<sys::path
> state_file_paths
;
1168 // now get available states for this session
1170 get_state_files_in_directory (*i
, state_file_paths
);
1172 vector
<string
*>* states
;
1173 vector
<const gchar
*> item
;
1174 string fullpath
= (*i
).to_string();
1176 /* remove any trailing / */
1178 if (fullpath
[fullpath
.length()-1] == '/') {
1179 fullpath
= fullpath
.substr (0, fullpath
.length()-1);
1182 /* check whether session still exists */
1183 if (!Glib::file_test(fullpath
.c_str(), Glib::FILE_TEST_EXISTS
)) {
1184 /* session doesn't exist */
1185 cerr
<< "skipping non-existent session " << fullpath
<< endl
;
1189 /* now get available states for this session */
1191 if ((states
= Session::possible_states (fullpath
)) == 0) {
1192 /* no state file? */
1196 std::vector
<string
> state_file_names(get_file_names_no_extension (state_file_paths
));
1198 Gtk::TreeModel::Row row
= *(recent_session_model
->append());
1200 row
[recent_session_columns
.visible_name
] = Glib::path_get_basename (fullpath
);
1201 row
[recent_session_columns
.fullpath
] = fullpath
;
1203 if (state_file_names
.size() > 1) {
1207 for (std::vector
<std::string
>::iterator i2
= state_file_names
.begin();
1208 i2
!= state_file_names
.end(); ++i2
)
1211 Gtk::TreeModel::Row child_row
= *(recent_session_model
->append (row
.children()));
1213 child_row
[recent_session_columns
.visible_name
] = *i2
;
1214 child_row
[recent_session_columns
.fullpath
] = fullpath
;
1219 recent_session_display
.set_model (recent_session_model
);
1223 ARDOUR_UI::build_session_selector ()
1225 session_selector_window
= new ArdourDialog (_("Recent Sessions"));
1227 Gtk::ScrolledWindow
*scroller
= manage (new Gtk::ScrolledWindow
);
1229 session_selector_window
->add_button (Stock::CANCEL
, RESPONSE_CANCEL
);
1230 session_selector_window
->add_button (Stock::OPEN
, RESPONSE_ACCEPT
);
1231 session_selector_window
->set_default_response (RESPONSE_ACCEPT
);
1232 recent_session_model
= TreeStore::create (recent_session_columns
);
1233 recent_session_display
.set_model (recent_session_model
);
1234 recent_session_display
.append_column (_("Recent Sessions"), recent_session_columns
.visible_name
);
1235 recent_session_display
.set_headers_visible (false);
1236 recent_session_display
.get_selection()->set_mode (SELECTION_BROWSE
);
1237 recent_session_display
.signal_row_activated().connect (sigc::mem_fun (*this, &ARDOUR_UI::recent_session_row_activated
));
1239 scroller
->add (recent_session_display
);
1240 scroller
->set_policy (Gtk::POLICY_NEVER
, Gtk::POLICY_AUTOMATIC
);
1242 session_selector_window
->set_name ("SessionSelectorWindow");
1243 session_selector_window
->set_size_request (200, 400);
1244 session_selector_window
->get_vbox()->pack_start (*scroller
);
1246 recent_session_display
.show();
1248 //session_selector_window->get_vbox()->show();
1252 ARDOUR_UI::recent_session_row_activated (const TreePath
& /*path*/, TreeViewColumn
* /*col*/)
1254 session_selector_window
->response (RESPONSE_ACCEPT
);
1258 ARDOUR_UI::open_recent_session ()
1260 bool can_return
= (_session
!= 0);
1262 if (session_selector_window
== 0) {
1263 build_session_selector ();
1266 redisplay_recent_sessions ();
1270 session_selector_window
->set_position (WIN_POS_MOUSE
);
1272 ResponseType r
= (ResponseType
) session_selector_window
->run ();
1275 case RESPONSE_ACCEPT
:
1279 session_selector_window
->hide();
1286 if (recent_session_display
.get_selection()->count_selected_rows() == 0) {
1290 session_selector_window
->hide();
1292 Gtk::TreeModel::iterator i
= recent_session_display
.get_selection()->get_selected();
1294 if (i
== recent_session_model
->children().end()) {
1298 std::string path
= (*i
)[recent_session_columns
.fullpath
];
1299 std::string state
= (*i
)[recent_session_columns
.visible_name
];
1301 _session_is_new
= false;
1303 if (load_session (path
, state
) == 0) {
1312 ARDOUR_UI::check_audioengine ()
1315 if (!engine
->connected()) {
1316 MessageDialog
msg (string_compose (
1317 _("%1 is not connected to JACK\n"
1318 "You cannot open or close sessions in this condition"),
1331 ARDOUR_UI::open_session ()
1333 if (!check_audioengine()) {
1338 /* popup selector window */
1340 if (open_session_selector
== 0) {
1342 /* ardour sessions are folders */
1344 open_session_selector
= new Gtk::FileChooserDialog (_("Open Session"), FILE_CHOOSER_ACTION_OPEN
);
1345 open_session_selector
->add_button (Gtk::Stock::CANCEL
, Gtk::RESPONSE_CANCEL
);
1346 open_session_selector
->add_button (Gtk::Stock::OPEN
, Gtk::RESPONSE_ACCEPT
);
1347 open_session_selector
->set_default_response(Gtk::RESPONSE_ACCEPT
);
1349 FileFilter session_filter
;
1350 session_filter
.add_pattern ("*.ardour");
1351 session_filter
.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME
));
1352 open_session_selector
->add_filter (session_filter
);
1353 open_session_selector
->set_filter (session_filter
);
1356 int response
= open_session_selector
->run();
1357 open_session_selector
->hide ();
1360 case RESPONSE_ACCEPT
:
1363 open_session_selector
->hide();
1367 open_session_selector
->hide();
1368 string session_path
= open_session_selector
->get_filename();
1372 if (session_path
.length() > 0) {
1373 if (ARDOUR::find_session (session_path
, path
, name
, isnew
) == 0) {
1374 _session_is_new
= isnew
;
1375 load_session (path
, name
);
1382 ARDOUR_UI::session_add_midi_route (bool disk
, RouteGroup
* route_group
, uint32_t how_many
, string
const & name_template
)
1384 list
<boost::shared_ptr
<MidiTrack
> > tracks
;
1386 if (_session
== 0) {
1387 warning
<< _("You cannot add a track without a session already loaded.") << endmsg
;
1394 tracks
= _session
->new_midi_track (ARDOUR::Normal
, route_group
, how_many
, name_template
);
1396 if (tracks
.size() != how_many
) {
1397 if (how_many
== 1) {
1398 error
<< _("could not create a new midi track") << endmsg
;
1400 error
<< string_compose (_("could not create %1 new midi tracks"), how_many
) << endmsg
;
1404 if ((route = _session->new_midi_route ()) == 0) {
1405 error << _("could not create new midi bus") << endmsg;
1411 MessageDialog
msg (*editor
,
1412 string_compose (_("There are insufficient JACK ports available\n\
1413 to create a new track or bus.\n\
1414 You should save %1, exit and\n\
1415 restart JACK with more ports."), PROGRAM_NAME
));
1422 ARDOUR_UI::session_add_audio_route (
1424 int32_t input_channels
,
1425 int32_t output_channels
,
1426 ARDOUR::TrackMode mode
,
1427 RouteGroup
* route_group
,
1429 string
const & name_template
1432 list
<boost::shared_ptr
<AudioTrack
> > tracks
;
1435 if (_session
== 0) {
1436 warning
<< _("You cannot add a track or bus without a session already loaded.") << endmsg
;
1442 tracks
= _session
->new_audio_track (input_channels
, output_channels
, mode
, route_group
, how_many
, name_template
);
1444 if (tracks
.size() != how_many
) {
1445 if (how_many
== 1) {
1446 error
<< _("could not create a new audio track") << endmsg
;
1448 error
<< string_compose (_("could only create %1 of %2 new audio %3"),
1449 tracks
.size(), how_many
, (track
? _("tracks") : _("busses"))) << endmsg
;
1455 routes
= _session
->new_audio_route (input_channels
, output_channels
, route_group
, how_many
, name_template
);
1457 if (routes
.size() != how_many
) {
1458 if (how_many
== 1) {
1459 error
<< _("could not create a new audio bus") << endmsg
;
1461 error
<< string_compose (_("could not create %1 new audio busses"), how_many
) << endmsg
;
1468 MessageDialog
msg (*editor
,
1469 string_compose (_("There are insufficient JACK ports available\n\
1470 to create a new track or bus.\n\
1471 You should save %1, exit and\n\
1472 restart JACK with more ports."), PROGRAM_NAME
));
1479 ARDOUR_UI::do_transport_locate (framepos_t new_position
, bool with_roll
)
1481 framecnt_t _preroll
= 0;
1484 // XXX CONFIG_CHANGE FIX - requires AnyTime handling
1485 // _preroll = _session->convert_to_frames_at (new_position, Config->get_preroll());
1487 if (new_position
> _preroll
) {
1488 new_position
-= _preroll
;
1493 _session
->request_locate (new_position
, with_roll
);
1498 ARDOUR_UI::transport_goto_start ()
1501 _session
->goto_start();
1503 /* force displayed area in editor to start no matter
1504 what "follow playhead" setting is.
1508 editor
->center_screen (_session
->current_start_frame ());
1514 ARDOUR_UI::transport_goto_zero ()
1517 _session
->request_locate (0);
1519 /* force displayed area in editor to start no matter
1520 what "follow playhead" setting is.
1524 editor
->reset_x_origin (0);
1530 ARDOUR_UI::transport_goto_wallclock ()
1532 if (_session
&& editor
) {
1539 localtime_r (&now
, &tmnow
);
1541 frames
= tmnow
.tm_hour
* (60 * 60 * _session
->frame_rate());
1542 frames
+= tmnow
.tm_min
* (60 * _session
->frame_rate());
1543 frames
+= tmnow
.tm_sec
* _session
->frame_rate();
1545 _session
->request_locate (frames
, _session
->transport_rolling ());
1547 /* force displayed area in editor to start no matter
1548 what "follow playhead" setting is.
1552 editor
->center_screen (frames
);
1558 ARDOUR_UI::transport_goto_end ()
1561 framepos_t
const frame
= _session
->current_end_frame();
1562 _session
->request_locate (frame
);
1564 /* force displayed area in editor to start no matter
1565 what "follow playhead" setting is.
1569 editor
->center_screen (frame
);
1575 ARDOUR_UI::transport_stop ()
1581 if (_session
->is_auditioning()) {
1582 _session
->cancel_audition ();
1586 _session
->request_stop (false, true);
1590 ARDOUR_UI::transport_stop_and_forget_capture ()
1593 _session
->request_stop (true, true);
1598 ARDOUR_UI::remove_last_capture()
1601 editor
->remove_last_capture();
1606 ARDOUR_UI::transport_record (bool roll
)
1610 switch (_session
->record_status()) {
1611 case Session::Disabled
:
1612 if (_session
->ntracks() == 0) {
1613 MessageDialog
msg (*editor
, _("Please create 1 or more track\nbefore trying to record.\nCheck the Session menu."));
1617 _session
->maybe_enable_record ();
1622 case Session::Recording
:
1624 _session
->request_stop();
1626 _session
->disable_record (false, true);
1630 case Session::Enabled
:
1631 _session
->disable_record (false, true);
1634 //cerr << "ARDOUR_UI::transport_record () called roll = " << roll << " _session->record_status() = " << _session->record_status() << endl;
1638 ARDOUR_UI::transport_roll ()
1644 if (_session
->is_auditioning()) {
1649 if (_session
->config
.get_external_sync()) {
1650 switch (_session
->config
.get_sync_source()) {
1654 /* transport controlled by the master */
1660 bool rolling
= _session
->transport_rolling();
1662 if (_session
->get_play_loop()) {
1663 /* XXX it is not possible to just leave seamless loop and keep
1664 playing at present (nov 4th 2009)
1666 if (!Config
->get_seamless_loop()) {
1667 _session
->request_play_loop (false, true);
1669 } else if (_session
->get_play_range () && !join_play_range_button
.get_active()) {
1670 /* stop playing a range if we currently are */
1671 _session
->request_play_range (0, true);
1674 if (join_play_range_button
.get_active()) {
1675 _session
->request_play_range (&editor
->get_selection().time
, true);
1679 _session
->request_transport_speed (1.0f
);
1684 ARDOUR_UI::toggle_roll (bool with_abort
, bool roll_out_of_bounded_mode
)
1691 if (_session
->is_auditioning()) {
1692 _session
->cancel_audition ();
1696 if (_session
->config
.get_external_sync()) {
1697 switch (_session
->config
.get_sync_source()) {
1701 /* transport controlled by the master */
1706 bool rolling
= _session
->transport_rolling();
1707 bool affect_transport
= true;
1709 if (rolling
&& roll_out_of_bounded_mode
) {
1710 /* drop out of loop/range playback but leave transport rolling */
1711 if (_session
->get_play_loop()) {
1712 if (Config
->get_seamless_loop()) {
1713 /* the disk buffers contain copies of the loop - we can't
1714 just keep playing, so stop the transport. the user
1715 can restart as they wish.
1717 affect_transport
= true;
1719 /* disk buffers are normal, so we can keep playing */
1720 affect_transport
= false;
1722 _session
->request_play_loop (false, true);
1723 } else if (_session
->get_play_range ()) {
1724 affect_transport
= false;
1725 _session
->request_play_range (0, true);
1729 if (affect_transport
) {
1731 _session
->request_stop (with_abort
, true);
1733 if (join_play_range_button
.get_active()) {
1734 _session
->request_play_range (&editor
->get_selection().time
, true);
1737 _session
->request_transport_speed (1.0f
);
1743 ARDOUR_UI::toggle_session_auto_loop ()
1749 if (_session
->get_play_loop()) {
1751 if (_session
->transport_rolling()) {
1753 Location
* looploc
= _session
->locations()->auto_loop_location();
1756 _session
->request_locate (looploc
->start(), true);
1757 _session
->request_play_loop (false);
1761 _session
->request_play_loop (false);
1765 Location
* looploc
= _session
->locations()->auto_loop_location();
1768 _session
->request_play_loop (true);
1774 ARDOUR_UI::transport_play_selection ()
1780 editor
->play_selection ();
1784 ARDOUR_UI::transport_rewind (int option
)
1786 float current_transport_speed
;
1789 current_transport_speed
= _session
->transport_speed();
1791 if (current_transport_speed
>= 0.0f
) {
1794 _session
->request_transport_speed (-1.0f
);
1797 _session
->request_transport_speed (-4.0f
);
1800 _session
->request_transport_speed (-0.5f
);
1805 _session
->request_transport_speed (current_transport_speed
* 1.5f
);
1811 ARDOUR_UI::transport_forward (int option
)
1813 float current_transport_speed
;
1816 current_transport_speed
= _session
->transport_speed();
1818 if (current_transport_speed
<= 0.0f
) {
1821 _session
->request_transport_speed (1.0f
);
1824 _session
->request_transport_speed (4.0f
);
1827 _session
->request_transport_speed (0.5f
);
1832 _session
->request_transport_speed (current_transport_speed
* 1.5f
);
1839 ARDOUR_UI::toggle_record_enable (uint32_t rid
)
1841 if (_session
== 0) {
1845 boost::shared_ptr
<Route
> r
;
1847 if ((r
= _session
->route_by_remote_id (rid
)) != 0) {
1851 if ((t
= dynamic_cast<Track
*>(r
.get())) != 0) {
1852 t
->set_record_enabled (!t
->record_enabled(), this);
1855 if (_session
== 0) {
1861 ARDOUR_UI::map_transport_state ()
1864 auto_loop_button
.set_visual_state (0);
1865 play_selection_button
.set_visual_state (0);
1866 roll_button
.set_visual_state (0);
1867 stop_button
.set_visual_state (1);
1871 shuttle_box
->map_transport_state ();
1873 float sp
= _session
->transport_speed();
1879 if (_session
->get_play_range()) {
1881 play_selection_button
.set_visual_state (1);
1882 roll_button
.set_visual_state (0);
1883 auto_loop_button
.set_visual_state (0);
1885 } else if (_session
->get_play_loop ()) {
1887 auto_loop_button
.set_visual_state (1);
1888 play_selection_button
.set_visual_state (0);
1889 roll_button
.set_visual_state (0);
1893 roll_button
.set_visual_state (1);
1894 play_selection_button
.set_visual_state (0);
1895 auto_loop_button
.set_visual_state (0);
1898 if (join_play_range_button
.get_active()) {
1899 /* light up both roll and play-selection if they are joined */
1900 roll_button
.set_visual_state (1);
1901 play_selection_button
.set_visual_state (1);
1904 stop_button
.set_visual_state (0);
1908 stop_button
.set_visual_state (1);
1909 roll_button
.set_visual_state (0);
1910 play_selection_button
.set_visual_state (0);
1911 auto_loop_button
.set_visual_state (0);
1912 update_disk_space ();
1917 ARDOUR_UI::engine_stopped ()
1919 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped
)
1920 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions
, false);
1921 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions
, true);
1925 ARDOUR_UI::engine_running ()
1927 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running
)
1928 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions
, true);
1929 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions
, false);
1931 Glib::RefPtr
<Action
> action
;
1932 const char* action_name
= 0;
1934 switch (engine
->frames_per_cycle()) {
1936 action_name
= X_("JACKLatency32");
1939 action_name
= X_("JACKLatency64");
1942 action_name
= X_("JACKLatency128");
1945 action_name
= X_("JACKLatency512");
1948 action_name
= X_("JACKLatency1024");
1951 action_name
= X_("JACKLatency2048");
1954 action_name
= X_("JACKLatency4096");
1957 action_name
= X_("JACKLatency8192");
1960 /* XXX can we do anything useful ? */
1966 action
= ActionManager::get_action (X_("JACK"), action_name
);
1969 Glib::RefPtr
<RadioAction
> ract
= Glib::RefPtr
<RadioAction
>::cast_dynamic (action
);
1970 ract
->set_active ();
1976 ARDOUR_UI::engine_halted (const char* reason
, bool free_reason
)
1978 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
1979 /* we can't rely on the original string continuing to exist when we are called
1980 again in the GUI thread, so make a copy and note that we need to
1983 char *copy
= strdup (reason
);
1984 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&ARDOUR_UI::engine_halted
, this, copy
, true));
1988 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions
, false);
1989 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions
, true);
1991 update_sample_rate (0);
1995 /* if the reason is a non-empty string, it means that the backend was shutdown
1996 rather than just Ardour.
1999 if (strlen (reason
)) {
2000 msgstr
= string_compose (_("The audio backend (JACK) was shutdown because:\n\n%1"), reason
);
2002 msgstr
= string_compose (_("\
2003 JACK has either been shutdown or it\n\
2004 disconnected %1 because %1\n\
2005 was not fast enough. Try to restart\n\
2006 JACK, reconnect and save the session."), PROGRAM_NAME
);
2009 MessageDialog
msg (*editor
, msgstr
);
2014 free ((char*) reason
);
2019 ARDOUR_UI::do_engine_start ()
2027 error
<< _("Unable to start the session running")
2037 ARDOUR_UI::setup_theme ()
2039 theme_manager
->setup_theme();
2043 ARDOUR_UI::update_clocks ()
2045 if (!editor
|| !editor
->dragging_playhead()) {
2046 Clock (_session
->audible_frame(), false, editor
->get_preferred_edit_position()); /* EMIT_SIGNAL */
2051 ARDOUR_UI::start_clocking ()
2053 clock_signal_connection
= RapidScreenUpdate
.connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks
));
2057 ARDOUR_UI::stop_clocking ()
2059 clock_signal_connection
.disconnect ();
2063 ARDOUR_UI::toggle_clocking ()
2066 if (clock_button
.get_active()) {
2075 ARDOUR_UI::_blink (void *arg
)
2078 ((ARDOUR_UI
*) arg
)->blink ();
2085 Blink (blink_on
= !blink_on
); /* EMIT_SIGNAL */
2089 ARDOUR_UI::start_blinking ()
2091 /* Start the blink signal. Everybody with a blinking widget
2092 uses Blink to drive the widget's state.
2095 if (blink_timeout_tag
< 0) {
2097 blink_timeout_tag
= g_timeout_add (240, _blink
, this);
2102 ARDOUR_UI::stop_blinking ()
2104 if (blink_timeout_tag
>= 0) {
2105 g_source_remove (blink_timeout_tag
);
2106 blink_timeout_tag
= -1;
2111 /** Ask the user for the name of a new shapshot and then take it.
2115 ARDOUR_UI::snapshot_session (bool switch_to_it
)
2117 ArdourPrompter
prompter (true);
2120 prompter
.set_name ("Prompter");
2121 prompter
.add_button (Gtk::Stock::SAVE
, Gtk::RESPONSE_ACCEPT
);
2122 prompter
.set_title (_("Take Snapshot"));
2123 prompter
.set_prompt (_("Name of new snapshot"));
2125 if (!switch_to_it
) {
2128 struct tm local_time
;
2131 localtime_r (&n
, &local_time
);
2132 strftime (timebuf
, sizeof(timebuf
), "%FT%T", &local_time
);
2133 prompter
.set_initial_text (timebuf
);
2137 switch (prompter
.run()) {
2138 case RESPONSE_ACCEPT
:
2140 prompter
.get_result (snapname
);
2142 bool do_save
= (snapname
.length() != 0);
2145 if (snapname
.find ('/') != string::npos
) {
2146 MessageDialog
msg (_("To ensure compatibility with various systems\n"
2147 "snapshot names may not contain a '/' character"));
2151 if (snapname
.find ('\\') != string::npos
) {
2152 MessageDialog
msg (_("To ensure compatibility with various systems\n"
2153 "snapshot names may not contain a '\\' character"));
2159 vector
<sys::path
> p
;
2160 get_state_files_in_directory (_session
->session_directory().root_path(), p
);
2161 vector
<string
> n
= get_file_names_no_extension (p
);
2162 if (find (n
.begin(), n
.end(), snapname
) != n
.end()) {
2164 ArdourDialog
confirm (_("Confirm Snapshot Overwrite"), true);
2165 Label
m (_("A snapshot already exists with that name. Do you want to overwrite it?"));
2166 confirm
.get_vbox()->pack_start (m
, true, true);
2167 confirm
.add_button (Gtk::Stock::CANCEL
, Gtk::RESPONSE_CANCEL
);
2168 confirm
.add_button (_("Overwrite"), Gtk::RESPONSE_ACCEPT
);
2169 confirm
.show_all ();
2170 switch (confirm
.run()) {
2171 case RESPONSE_CANCEL
:
2177 save_state (snapname
, switch_to_it
);
2187 /** Ask the user for the name of a new shapshot and then take it.
2191 ARDOUR_UI::rename_session ()
2197 ArdourPrompter
prompter (true);
2200 prompter
.set_name ("Prompter");
2201 prompter
.add_button (Gtk::Stock::SAVE
, Gtk::RESPONSE_ACCEPT
);
2202 prompter
.set_title (_("Rename Session"));
2203 prompter
.set_prompt (_("New session name"));
2206 switch (prompter
.run()) {
2207 case RESPONSE_ACCEPT
:
2209 prompter
.get_result (name
);
2211 bool do_rename
= (name
.length() != 0);
2214 if (name
.find ('/') != string::npos
) {
2215 MessageDialog
msg (_("To ensure compatibility with various systems\n"
2216 "session names may not contain a '/' character"));
2220 if (name
.find ('\\') != string::npos
) {
2221 MessageDialog
msg (_("To ensure compatibility with various systems\n"
2222 "session names may not contain a '\\' character"));
2227 switch (_session
->rename (name
)) {
2229 MessageDialog
msg (_("That name is already in use by another directory/folder. Please try again."));
2230 msg
.set_position (WIN_POS_MOUSE
);
2238 MessageDialog
msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
2239 msg
.set_position (WIN_POS_MOUSE
);
2255 ARDOUR_UI::save_state (const string
& name
, bool switch_to_it
)
2257 XMLNode
* node
= new XMLNode (X_("UI"));
2259 for (list
<WindowProxyBase
*>::iterator i
= _window_proxies
.begin(); i
!= _window_proxies
.end(); ++i
) {
2260 if (!(*i
)->rc_configured()) {
2261 node
->add_child_nocopy (*((*i
)->get_state ()));
2265 node
->add_child_nocopy (gui_object_state
->get_state());
2267 _session
->add_extra_xml (*node
);
2269 save_state_canfail (name
, switch_to_it
);
2273 ARDOUR_UI::save_state_canfail (string name
, bool switch_to_it
)
2278 if (name
.length() == 0) {
2279 name
= _session
->snap_name();
2282 if ((ret
= _session
->save_state (name
, false, switch_to_it
)) != 0) {
2287 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2292 ARDOUR_UI::primary_clock_value_changed ()
2295 _session
->request_locate (primary_clock
->current_time ());
2300 ARDOUR_UI::big_clock_value_changed ()
2303 _session
->request_locate (big_clock
->current_time ());
2308 ARDOUR_UI::secondary_clock_value_changed ()
2311 _session
->request_locate (secondary_clock
->current_time ());
2316 ARDOUR_UI::transport_rec_enable_blink (bool onoff
)
2318 if (_session
== 0) {
2322 if (_session
->step_editing()) {
2326 Session::RecordState
const r
= _session
->record_status ();
2327 bool const h
= _session
->have_rec_enabled_track ();
2329 if (r
== Session::Enabled
|| (r
== Session::Recording
&& !h
)) {
2331 rec_button
.set_visual_state (2);
2333 rec_button
.set_visual_state (0);
2335 } else if (r
== Session::Recording
&& h
) {
2336 rec_button
.set_visual_state (1);
2338 rec_button
.set_visual_state (0);
2343 ARDOUR_UI::save_template ()
2345 ArdourPrompter
prompter (true);
2348 if (!check_audioengine()) {
2352 prompter
.set_name (X_("Prompter"));
2353 prompter
.set_title (_("Save Template"));
2354 prompter
.set_prompt (_("Name for template:"));
2355 prompter
.set_initial_text(_session
->name() + _("-template"));
2356 prompter
.add_button (Gtk::Stock::SAVE
, Gtk::RESPONSE_ACCEPT
);
2358 switch (prompter
.run()) {
2359 case RESPONSE_ACCEPT
:
2360 prompter
.get_result (name
);
2362 if (name
.length()) {
2363 _session
->save_template (name
);
2373 ARDOUR_UI::edit_metadata ()
2375 SessionMetadataEditor dialog
;
2376 dialog
.set_session (_session
);
2377 editor
->ensure_float (dialog
);
2382 ARDOUR_UI::import_metadata ()
2384 SessionMetadataImporter dialog
;
2385 dialog
.set_session (_session
);
2386 editor
->ensure_float (dialog
);
2391 ARDOUR_UI::ask_about_loading_existing_session (const std::string
& session_path
)
2393 std::string str
= string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path
);
2395 MessageDialog
msg (str
,
2397 Gtk::MESSAGE_WARNING
,
2398 Gtk::BUTTONS_YES_NO
,
2402 msg
.set_name (X_("OpenExistingDialog"));
2403 msg
.set_title (_("Open Existing Session"));
2404 msg
.set_wmclass (X_("existing_session"), PROGRAM_NAME
);
2405 msg
.set_position (Gtk::WIN_POS_MOUSE
);
2408 switch (msg
.run()) {
2417 ARDOUR_UI::build_session_from_nsd (const std::string
& session_path
, const std::string
& session_name
)
2419 BusProfile bus_profile
;
2421 if (Profile
->get_sae()) {
2423 bus_profile
.master_out_channels
= 2;
2424 bus_profile
.input_ac
= AutoConnectPhysical
;
2425 bus_profile
.output_ac
= AutoConnectMaster
;
2426 bus_profile
.requested_physical_in
= 0; // use all available
2427 bus_profile
.requested_physical_out
= 0; // use all available
2431 /* get settings from advanced section of NSD */
2433 if (_startup
->create_master_bus()) {
2434 bus_profile
.master_out_channels
= (uint32_t) _startup
->master_channel_count();
2436 bus_profile
.master_out_channels
= 0;
2439 if (_startup
->connect_inputs()) {
2440 bus_profile
.input_ac
= AutoConnectPhysical
;
2442 bus_profile
.input_ac
= AutoConnectOption (0);
2445 /// @todo some minor tweaks.
2447 bus_profile
.output_ac
= AutoConnectOption (0);
2449 if (_startup
->connect_outputs ()) {
2450 if (_startup
->connect_outs_to_master()) {
2451 bus_profile
.output_ac
= AutoConnectMaster
;
2452 } else if (_startup
->connect_outs_to_physical()) {
2453 bus_profile
.output_ac
= AutoConnectPhysical
;
2457 bus_profile
.requested_physical_in
= (uint32_t) _startup
->input_limit_count();
2458 bus_profile
.requested_physical_out
= (uint32_t) _startup
->output_limit_count();
2461 if (build_session (session_path
, session_name
, bus_profile
)) {
2469 ARDOUR_UI::idle_load (const std::string
& path
)
2472 if (Glib::file_test (path
, Glib::FILE_TEST_IS_DIR
)) {
2473 /* /path/to/foo => /path/to/foo, foo */
2474 load_session (path
, basename_nosuffix (path
));
2476 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2477 load_session (Glib::path_get_dirname (path
), basename_nosuffix (path
));
2481 ARDOUR_COMMAND_LINE::session_name
= path
;
2484 * new_session_dialog doens't exist in A3
2485 * Try to remove all references to it to
2486 * see if it will compile. NOTE: this will
2487 * likely cause a runtime issue is my somewhat
2491 //if (new_session_dialog) {
2494 /* make it break out of Dialog::run() and
2498 //new_session_dialog->response (1);
2504 ARDOUR_UI::end_loading_messages ()
2510 ARDOUR_UI::loading_message (const std::string
& /*msg*/)
2513 // splash->message (msg);
2517 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
2519 ARDOUR_UI::get_session_parameters (bool quit_on_cancel
, bool should_be_new
, string load_template
)
2521 string session_name
;
2522 string session_path
;
2523 string template_name
;
2525 bool likely_new
= false;
2527 if (!load_template
.empty()) {
2528 should_be_new
= true;
2529 template_name
= load_template
;
2534 if (!should_be_new
&& !ARDOUR_COMMAND_LINE::session_name
.empty()) {
2536 /* if they named a specific statefile, use it, otherwise they are
2537 just giving a session folder, and we want to use it as is
2538 to find the session.
2541 string::size_type suffix
= ARDOUR_COMMAND_LINE::session_name
.find (statefile_suffix
);
2543 if (suffix
!= string::npos
) {
2544 session_path
= Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name
);
2545 session_name
= ARDOUR_COMMAND_LINE::session_name
.substr (0, suffix
);
2546 session_name
= Glib::path_get_basename (session_name
);
2548 session_path
= ARDOUR_COMMAND_LINE::session_name
;
2549 session_name
= Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name
);
2554 bool const apply
= run_startup (should_be_new
, load_template
);
2557 if (quit_on_cancel
) {
2564 /* if we run the startup dialog again, offer more than just "new session" */
2566 should_be_new
= false;
2568 session_name
= _startup
->session_name (likely_new
);
2570 /* this shouldn't happen, but we catch it just in case it does */
2572 if (session_name
.empty()) {
2576 if (_startup
->use_session_template()) {
2577 template_name
= _startup
->session_template_name();
2578 _session_is_new
= true;
2581 if (session_name
[0] == G_DIR_SEPARATOR
||
2582 (session_name
.length() > 2 && session_name
[0] == '.' && session_name
[1] == G_DIR_SEPARATOR
) ||
2583 (session_name
.length() > 3 && session_name
[0] == '.' && session_name
[1] == '.' && session_name
[2] == G_DIR_SEPARATOR
)) {
2585 /* absolute path or cwd-relative path specified for session name: infer session folder
2586 from what was given.
2589 session_path
= Glib::path_get_dirname (session_name
);
2590 session_name
= Glib::path_get_basename (session_name
);
2594 session_path
= _startup
->session_folder();
2596 if (session_name
.find ('/') != string::npos
) {
2597 MessageDialog
msg (*_startup
,
2598 _("To ensure compatibility with various systems\n"
2599 "session names may not contain a '/' character"));
2601 ARDOUR_COMMAND_LINE::session_name
= ""; // cancel that
2605 if (session_name
.find ('\\') != string::npos
) {
2606 MessageDialog
msg (*_startup
,
2607 _("To ensure compatibility with various systems\n"
2608 "session names may not contain a '\\' character"));
2610 ARDOUR_COMMAND_LINE::session_name
= ""; // cancel that
2616 if (create_engine ()) {
2620 if (Glib::file_test (session_path
, Glib::FileTest (G_FILE_TEST_EXISTS
| G_FILE_TEST_IS_DIR
))) {
2624 std::string existing
= Glib::build_filename (session_path
, session_name
);
2626 if (!ask_about_loading_existing_session (existing
)) {
2627 ARDOUR_COMMAND_LINE::session_name
= ""; // cancel that
2632 _session_is_new
= false;
2637 MessageDialog
msg (string_compose (_("There is no existing session at \"%1\""), session_path
));
2639 ARDOUR_COMMAND_LINE::session_name
= ""; // cancel that
2643 if (session_name
.find ('/') != std::string::npos
) {
2644 MessageDialog
msg (*_startup
,
2645 _("To ensure compatibility with various systems\n"
2646 "session names may not contain a '/' character"));
2648 ARDOUR_COMMAND_LINE::session_name
= ""; // cancel that
2652 if (session_name
.find ('\\') != std::string::npos
) {
2653 MessageDialog
msg (*_startup
,
2654 _("To ensure compatibility with various systems\n"
2655 "session names may not contain a '\\' character"));
2657 ARDOUR_COMMAND_LINE::session_name
= ""; // cancel that
2661 _session_is_new
= true;
2664 if (likely_new
&& template_name
.empty()) {
2666 ret
= build_session_from_nsd (session_path
, session_name
);
2670 ret
= load_session (session_path
, session_name
, template_name
);
2673 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
2677 if (!ARDOUR_COMMAND_LINE::immediate_save
.empty()) {
2678 _session
->save_state (ARDOUR_COMMAND_LINE::immediate_save
, false);
2688 ARDOUR_UI::close_session()
2690 if (!check_audioengine()) {
2694 if (unload_session (true)) {
2698 ARDOUR_COMMAND_LINE::session_name
= "";
2700 if (get_session_parameters (true, false)) {
2704 goto_editor_window ();
2707 /** @param snap_name Snapshot name (without .ardour suffix).
2708 * @return -2 if the load failed because we are not connected to the AudioEngine.
2711 ARDOUR_UI::load_session (const std::string
& path
, const std::string
& snap_name
, std::string mix_template
)
2713 Session
*new_session
;
2717 session_loaded
= false;
2719 if (!check_audioengine()) {
2723 unload_status
= unload_session ();
2725 if (unload_status
< 0) {
2727 } else if (unload_status
> 0) {
2732 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME
));
2735 new_session
= new Session (*engine
, path
, snap_name
, 0, mix_template
);
2738 /* this one is special */
2740 catch (AudioEngine::PortRegistrationFailure
& err
) {
2742 MessageDialog
msg (err
.what(),
2745 Gtk::BUTTONS_CLOSE
);
2747 msg
.set_title (_("Port Registration Error"));
2748 msg
.set_secondary_text (_("Click the Close button to try again."));
2749 msg
.set_position (Gtk::WIN_POS_CENTER
);
2753 int response
= msg
.run ();
2758 case RESPONSE_CANCEL
:
2768 MessageDialog
msg (string_compose(
2769 _("Session \"%1 (snapshot %2)\" did not load successfully"),
2775 msg
.set_title (_("Loading Error"));
2776 msg
.set_secondary_text (_("Click the Refresh button to try again."));
2777 msg
.add_button (Stock::REFRESH
, 1);
2778 msg
.set_position (Gtk::WIN_POS_CENTER
);
2782 int response
= msg
.run ();
2797 list
<string
> const u
= new_session
->unknown_processors ();
2799 MissingPluginDialog
d (_session
, u
);
2804 /* Now the session been created, add the transport controls */
2805 new_session
->add_controllable(roll_controllable
);
2806 new_session
->add_controllable(stop_controllable
);
2807 new_session
->add_controllable(goto_start_controllable
);
2808 new_session
->add_controllable(goto_end_controllable
);
2809 new_session
->add_controllable(auto_loop_controllable
);
2810 new_session
->add_controllable(play_selection_controllable
);
2811 new_session
->add_controllable(rec_controllable
);
2813 set_session (new_session
);
2815 session_loaded
= true;
2817 goto_editor_window ();
2820 _session
->set_clean ();
2831 ARDOUR_UI::build_session (const std::string
& path
, const std::string
& snap_name
, BusProfile
& bus_profile
)
2833 Session
*new_session
;
2836 if (!check_audioengine()) {
2840 session_loaded
= false;
2842 x
= unload_session ();
2850 _session_is_new
= true;
2853 new_session
= new Session (*engine
, path
, snap_name
, &bus_profile
);
2858 MessageDialog
msg (string_compose(_("Could not create session in \"%1\""), path
));
2864 /* Give the new session the default GUI state, if such things exist */
2867 n
= Config
->instant_xml (X_("Editor"));
2869 new_session
->add_instant_xml (*n
, false);
2871 n
= Config
->instant_xml (X_("Mixer"));
2873 new_session
->add_instant_xml (*n
, false);
2876 /* Put the playhead at 0 and scroll fully left */
2877 n
= new_session
->instant_xml (X_("Editor"));
2879 n
->add_property (X_("playhead"), X_("0"));
2880 n
->add_property (X_("left-frame"), X_("0"));
2883 set_session (new_session
);
2885 session_loaded
= true;
2887 new_session
->save_state(new_session
->name());
2893 ARDOUR_UI::launch_chat ()
2896 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
2898 open_uri("http://webchat.freenode.net/?channels=ardour");
2903 ARDOUR_UI::show_about ()
2907 about
->signal_response().connect(sigc::mem_fun (*this, &ARDOUR_UI::about_signal_response
) );
2910 about
->set_transient_for(*editor
);
2915 ARDOUR_UI::launch_manual ()
2917 PBD::open_uri("http://ardour.org/flossmanual");
2921 ARDOUR_UI::launch_reference ()
2923 PBD::open_uri("http://ardour.org/refmanual");
2927 ARDOUR_UI::hide_about ()
2930 about
->get_window()->set_cursor ();
2936 ARDOUR_UI::about_signal_response (int /*response*/)
2942 ARDOUR_UI::show_splash ()
2946 splash
= new Splash
;
2954 splash
->queue_draw ();
2955 splash
->get_window()->process_updates (true);
2960 ARDOUR_UI::hide_splash ()
2968 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport
& rep
, const gchar
* list_title
,
2969 const string
& plural_msg
, const string
& singular_msg
)
2973 removed
= rep
.paths
.size();
2976 MessageDialog
msgd (*editor
,
2977 _("No files were ready for clean-up"),
2980 (Gtk::ButtonsType
)(Gtk::BUTTONS_OK
) );
2981 msgd
.set_title (_("Clean-up"));
2982 msgd
.set_secondary_text (_("If this seems suprising, \n\
2983 check for any existing snapshots.\n\
2984 These may still include regions that\n\
2985 require some unused files to continue to exist."));
2991 ArdourDialog
results (_("Clean-up"), true, false);
2993 struct CleanupResultsModelColumns
: public Gtk::TreeModel::ColumnRecord
{
2994 CleanupResultsModelColumns() {
2998 Gtk::TreeModelColumn
<std::string
> visible_name
;
2999 Gtk::TreeModelColumn
<std::string
> fullpath
;
3003 CleanupResultsModelColumns results_columns
;
3004 Glib::RefPtr
<Gtk::ListStore
> results_model
;
3005 Gtk::TreeView results_display
;
3007 results_model
= ListStore::create (results_columns
);
3008 results_display
.set_model (results_model
);
3009 results_display
.append_column (list_title
, results_columns
.visible_name
);
3011 results_display
.set_name ("CleanupResultsList");
3012 results_display
.set_headers_visible (true);
3013 results_display
.set_headers_clickable (false);
3014 results_display
.set_reorderable (false);
3016 Gtk::ScrolledWindow list_scroller
;
3019 Gtk::HBox dhbox
; // the hbox for the image and text
3020 Gtk::HBox ddhbox
; // the hbox we eventually pack into the dialog's vbox
3021 Gtk::Image
* dimage
= manage (new Gtk::Image(Stock::DIALOG_INFO
, Gtk::ICON_SIZE_DIALOG
));
3023 dimage
->set_alignment(ALIGN_LEFT
, ALIGN_TOP
);
3025 const string dead_directory
= _session
->session_directory().dead_path().to_string();
3028 %1 - number of files removed
3029 %2 - location of "dead"
3030 %3 - size of files affected
3031 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
3034 const char* bprefix
;
3035 double space_adjusted
= 0;
3037 if (rep
.space
< 1000) {
3039 space_adjusted
= rep
.space
;
3040 } else if (rep
.space
< 1000000) {
3041 bprefix
= X_("kilo");
3042 space_adjusted
= truncf((float)rep
.space
/ 1000.0);
3043 } else if (rep
.space
< 1000000 * 1000) {
3044 bprefix
= X_("mega");
3045 space_adjusted
= truncf((float)rep
.space
/ (1000.0 * 1000.0));
3047 bprefix
= X_("giga");
3048 space_adjusted
= truncf((float)rep
.space
/ (1000.0 * 1000 * 1000.0));
3052 txt
.set_text (string_compose (plural_msg
, removed
, dead_directory
, space_adjusted
, bprefix
));
3054 txt
.set_text (string_compose (singular_msg
, removed
, dead_directory
, space_adjusted
, bprefix
));
3057 dhbox
.pack_start (*dimage
, true, false, 5);
3058 dhbox
.pack_start (txt
, true, false, 5);
3060 for (vector
<string
>::iterator i
= rep
.paths
.begin(); i
!= rep
.paths
.end(); ++i
) {
3061 TreeModel::Row row
= *(results_model
->append());
3062 row
[results_columns
.visible_name
] = *i
;
3063 row
[results_columns
.fullpath
] = *i
;
3066 list_scroller
.add (results_display
);
3067 list_scroller
.set_size_request (-1, 150);
3068 list_scroller
.set_policy (Gtk::POLICY_NEVER
, Gtk::POLICY_AUTOMATIC
);
3070 dvbox
.pack_start (dhbox
, true, false, 5);
3071 dvbox
.pack_start (list_scroller
, true, false, 5);
3072 ddhbox
.pack_start (dvbox
, true, false, 5);
3074 results
.get_vbox()->pack_start (ddhbox
, true, false, 5);
3075 results
.add_button (Stock::CLOSE
, RESPONSE_CLOSE
);
3076 results
.set_default_response (RESPONSE_CLOSE
);
3077 results
.set_position (Gtk::WIN_POS_MOUSE
);
3079 results_display
.show();
3080 list_scroller
.show();
3087 //results.get_vbox()->show();
3088 results
.set_resizable (false);
3095 ARDOUR_UI::cleanup ()
3097 if (_session
== 0) {
3098 /* shouldn't happen: menu item is insensitive */
3103 MessageDialog
checker (_("Are you sure you want to clean-up?"),
3105 Gtk::MESSAGE_QUESTION
,
3106 (Gtk::ButtonsType
)(Gtk::BUTTONS_NONE
));
3108 checker
.set_title (_("Clean-up"));
3110 checker
.set_secondary_text(_("Clean-up is a destructive operation.\n\
3111 ALL undo/redo information will be lost if you clean-up.\n\
3112 Clean-up will move all unused files to a \"dead\" location."));
3114 checker
.add_button (Stock::CANCEL
, RESPONSE_CANCEL
);
3115 checker
.add_button (_("Clean-up"), RESPONSE_ACCEPT
);
3116 checker
.set_default_response (RESPONSE_CANCEL
);
3118 checker
.set_name (_("CleanupDialog"));
3119 checker
.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME
);
3120 checker
.set_position (Gtk::WIN_POS_MOUSE
);
3122 switch (checker
.run()) {
3123 case RESPONSE_ACCEPT
:
3129 ARDOUR::CleanupReport rep
;
3131 editor
->prepare_for_cleanup ();
3133 /* do not allow flush until a session is reloaded */
3135 Glib::RefPtr
<Action
> act
= ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3137 act
->set_sensitive (false);
3140 if (_session
->cleanup_sources (rep
)) {
3141 editor
->finish_cleanup ();
3145 editor
->finish_cleanup ();
3148 display_cleanup_results (rep
,
3151 The following %1 files were not in use and \n\
3152 have been moved to:\n\n\
3154 After a restart of Ardour,\n\n\
3155 Session -> Clean-up -> Flush Wastebasket\n\n\
3156 will release an additional\n\
3157 %3 %4bytes of disk space.\n"),
3159 The following file was not in use and \n\
3160 has been moved to:\n \
3162 After a restart of Ardour,\n\n\
3163 Session -> Clean-up -> Flush Wastebasket\n\n\
3164 will release an additional\n\
3165 %3 %4bytes of disk space.\n"
3171 ARDOUR_UI::flush_trash ()
3173 if (_session
== 0) {
3174 /* shouldn't happen: menu item is insensitive */
3178 ARDOUR::CleanupReport rep
;
3180 if (_session
->cleanup_trash_sources (rep
)) {
3184 display_cleanup_results (rep
,
3186 _("The following %1 files were deleted from\n\
3188 releasing %3 %4bytes of disk space"),
3189 _("The following file was deleted from\n\
3191 releasing %3 %4bytes of disk space"));
3195 ARDOUR_UI::add_route (Gtk::Window
* float_window
)
3203 if (add_route_dialog
== 0) {
3204 add_route_dialog
= new AddRouteDialog (_session
);
3206 add_route_dialog
->set_transient_for (*float_window
);
3210 if (add_route_dialog
->is_visible()) {
3211 /* we're already doing this */
3215 ResponseType r
= (ResponseType
) add_route_dialog
->run ();
3217 add_route_dialog
->hide();
3220 case RESPONSE_ACCEPT
:
3227 if ((count
= add_route_dialog
->count()) <= 0) {
3231 string template_path
= add_route_dialog
->track_template();
3233 if (!template_path
.empty()) {
3234 _session
->new_route_from_template (count
, template_path
);
3238 uint32_t input_chan
= add_route_dialog
->channels ();
3239 uint32_t output_chan
;
3240 string name_template
= add_route_dialog
->name_template ();
3241 bool track
= add_route_dialog
->track ();
3242 RouteGroup
* route_group
= add_route_dialog
->route_group ();
3244 AutoConnectOption oac
= Config
->get_output_auto_connect();
3246 if (oac
& AutoConnectMaster
) {
3247 output_chan
= (_session
->master_out() ? _session
->master_out()->n_inputs().n_audio() : input_chan
);
3249 output_chan
= input_chan
;
3252 /* XXX do something with name template */
3254 if (add_route_dialog
->type() == ARDOUR::DataType::MIDI
) {
3256 session_add_midi_track (route_group
, count
, name_template
);
3258 MessageDialog
msg (*editor
,
3259 _("Sorry, MIDI Busses are not supported at this time."));
3261 //session_add_midi_bus();
3265 session_add_audio_track (input_chan
, output_chan
, add_route_dialog
->mode(), route_group
, count
, name_template
);
3267 session_add_audio_bus (input_chan
, output_chan
, route_group
, count
, name_template
);
3273 ARDOUR_UI::mixer_settings () const
3278 node
= _session
->instant_xml(X_("Mixer"));
3280 node
= Config
->instant_xml(X_("Mixer"));
3284 node
= new XMLNode (X_("Mixer"));
3291 ARDOUR_UI::editor_settings () const
3296 node
= _session
->instant_xml(X_("Editor"));
3298 node
= Config
->instant_xml(X_("Editor"));
3302 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
3303 node
= Config
->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
3308 node
= new XMLNode (X_("Editor"));
3315 ARDOUR_UI::keyboard_settings () const
3319 node
= Config
->extra_xml(X_("Keyboard"));
3322 node
= new XMLNode (X_("Keyboard"));
3329 ARDOUR_UI::create_xrun_marker (framepos_t where
)
3331 editor
->mouse_add_new_marker (where
, false, true);
3335 ARDOUR_UI::halt_on_xrun_message ()
3337 MessageDialog
msg (*editor
,
3338 _("Recording was stopped because your system could not keep up."));
3343 ARDOUR_UI::xrun_handler (framepos_t where
)
3349 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler
, where
)
3351 if (_session
&& Config
->get_create_xrun_marker() && _session
->actively_recording()) {
3352 create_xrun_marker(where
);
3355 if (_session
&& Config
->get_stop_recording_on_xrun() && _session
->actively_recording()) {
3356 halt_on_xrun_message ();
3361 ARDOUR_UI::disk_overrun_handler ()
3363 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler
)
3365 if (!have_disk_speed_dialog_displayed
) {
3366 have_disk_speed_dialog_displayed
= true;
3367 MessageDialog
* msg
= new MessageDialog (*editor
, string_compose (_("\
3368 The disk system on your computer\n\
3369 was not able to keep up with %1.\n\
3371 Specifically, it failed to write data to disk\n\
3372 quickly enough to keep up with recording.\n"), PROGRAM_NAME
));
3373 msg
->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone
), msg
));
3379 ARDOUR_UI::disk_underrun_handler ()
3381 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler
)
3383 if (!have_disk_speed_dialog_displayed
) {
3384 have_disk_speed_dialog_displayed
= true;
3385 MessageDialog
* msg
= new MessageDialog (
3386 *editor
, string_compose (_("The disk system on your computer\n\
3387 was not able to keep up with %1.\n\
3389 Specifically, it failed to read data from disk\n\
3390 quickly enough to keep up with playback.\n"), PROGRAM_NAME
));
3391 msg
->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone
), msg
));
3397 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog
* msg
)
3399 have_disk_speed_dialog_displayed
= false;
3404 ARDOUR_UI::session_dialog (std::string msg
)
3406 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog
, msg
)
3411 d
= new MessageDialog (*editor
, msg
, false, MESSAGE_INFO
, BUTTONS_OK
, true);
3413 d
= new MessageDialog (msg
, false, MESSAGE_INFO
, BUTTONS_OK
, true);
3422 ARDOUR_UI::pending_state_dialog ()
3424 HBox
* hbox
= new HBox();
3425 Image
* image
= new Image (Stock::DIALOG_QUESTION
, ICON_SIZE_DIALOG
);
3426 ArdourDialog
dialog (_("Crash Recovery"), true);
3428 This session appears to have been in\n\
3429 middle of recording when ardour or\n\
3430 the computer was shutdown.\n\
3432 Ardour can recover any captured audio for\n\
3433 you, or it can ignore it. Please decide\n\
3434 what you would like to do.\n"));
3435 image
->set_alignment(ALIGN_CENTER
, ALIGN_TOP
);
3436 hbox
->pack_start (*image
, PACK_EXPAND_WIDGET
, 12);
3437 hbox
->pack_end (message
, PACK_EXPAND_PADDING
, 12);
3438 dialog
.get_vbox()->pack_start(*hbox
, PACK_EXPAND_PADDING
, 6);
3439 dialog
.add_button (_("Ignore crash data"), RESPONSE_REJECT
);
3440 dialog
.add_button (_("Recover from crash"), RESPONSE_ACCEPT
);
3441 dialog
.set_default_response (RESPONSE_ACCEPT
);
3442 dialog
.set_position (WIN_POS_CENTER
);
3447 switch (dialog
.run ()) {
3448 case RESPONSE_ACCEPT
:
3456 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired
, framecnt_t actual
)
3458 HBox
* hbox
= new HBox();
3459 Image
* image
= new Image (Stock::DIALOG_QUESTION
, ICON_SIZE_DIALOG
);
3460 ArdourDialog
dialog (_("Sample Rate Mismatch"), true);
3461 Label
message (string_compose (_("\
3462 This session was created with a sample rate of %1 Hz\n\
3464 The audioengine is currently running at %2 Hz\n"), desired
, actual
));
3466 image
->set_alignment(ALIGN_CENTER
, ALIGN_TOP
);
3467 hbox
->pack_start (*image
, PACK_EXPAND_WIDGET
, 12);
3468 hbox
->pack_end (message
, PACK_EXPAND_PADDING
, 12);
3469 dialog
.get_vbox()->pack_start(*hbox
, PACK_EXPAND_PADDING
, 6);
3470 dialog
.add_button (_("Do not load session"), RESPONSE_REJECT
);
3471 dialog
.add_button (_("Load session anyway"), RESPONSE_ACCEPT
);
3472 dialog
.set_default_response (RESPONSE_ACCEPT
);
3473 dialog
.set_position (WIN_POS_CENTER
);
3478 switch (dialog
.run ()) {
3479 case RESPONSE_ACCEPT
:
3488 ARDOUR_UI::disconnect_from_jack ()
3491 if( engine
->disconnect_from_jack ()) {
3492 MessageDialog
msg (*editor
, _("Could not disconnect from JACK"));
3496 update_sample_rate (0);
3501 ARDOUR_UI::reconnect_to_jack ()
3504 if (engine
->reconnect_to_jack ()) {
3505 MessageDialog
msg (*editor
, _("Could not reconnect to JACK"));
3509 update_sample_rate (0);
3514 ARDOUR_UI::use_config ()
3516 XMLNode
* node
= Config
->extra_xml (X_("TransportControllables"));
3518 set_transport_controllable_state (*node
);
3523 ARDOUR_UI::update_transport_clocks (framepos_t pos
)
3525 if (Config
->get_primary_clock_delta_edit_cursor()) {
3526 primary_clock
->set (pos
, false, editor
->get_preferred_edit_position(), 1);
3528 primary_clock
->set (pos
, 0, true);
3531 if (Config
->get_secondary_clock_delta_edit_cursor()) {
3532 secondary_clock
->set (pos
, false, editor
->get_preferred_edit_position(), 2);
3534 secondary_clock
->set (pos
);
3537 if (big_clock_window
->get()) {
3538 big_clock
->set (pos
);
3544 ARDOUR_UI::step_edit_status_change (bool yn
)
3546 // XXX should really store pre-step edit status of things
3547 // we make insensitive
3550 rec_button
.set_visual_state (3);
3551 rec_button
.set_sensitive (false);
3553 rec_button
.set_visual_state (0);
3554 rec_button
.set_sensitive (true);
3559 ARDOUR_UI::record_state_changed ()
3561 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed
);
3563 if (!_session
|| !big_clock_window
->get()) {
3564 /* why bother - the clock isn't visible */
3568 Session::RecordState
const r
= _session
->record_status ();
3569 bool const h
= _session
->have_rec_enabled_track ();
3571 if (r
== Session::Recording
&& h
) {
3572 big_clock
->set_widget_name ("BigClockRecording");
3574 big_clock
->set_widget_name ("BigClockNonRecording");
3579 ARDOUR_UI::first_idle ()
3582 _session
->allow_auto_play (true);
3586 editor
->first_idle();
3589 Keyboard::set_can_save_keybindings (true);
3594 ARDOUR_UI::store_clock_modes ()
3596 XMLNode
* node
= new XMLNode(X_("ClockModes"));
3598 for (vector
<AudioClock
*>::iterator x
= AudioClock::clocks
.begin(); x
!= AudioClock::clocks
.end(); ++x
) {
3599 XMLNode
* child
= new XMLNode (X_("Clock"));
3601 child
->add_property (X_("name"), (*x
)->name());
3602 child
->add_property (X_("mode"), enum_2_string ((*x
)->mode()));
3603 child
->add_property (X_("on"), ((*x
)->off() ? X_("no") : X_("yes")));
3605 node
->add_child_nocopy (*child
);
3608 _session
->add_extra_xml (*node
);
3609 _session
->set_dirty ();
3612 ARDOUR_UI::TransportControllable::TransportControllable (std::string name
, ARDOUR_UI
& u
, ToggleType tp
)
3613 : Controllable (name
), ui (u
), type(tp
)
3619 ARDOUR_UI::TransportControllable::set_value (double val
)
3622 /* do nothing: these are radio-style actions */
3626 const char *action
= 0;
3630 action
= X_("Roll");
3633 action
= X_("Stop");
3636 action
= X_("Goto Start");
3639 action
= X_("Goto End");
3642 action
= X_("Loop");
3645 action
= X_("Play Selection");
3648 action
= X_("Record");
3658 Glib::RefPtr
<Action
> act
= ActionManager::get_action ("Transport", action
);
3666 ARDOUR_UI::TransportControllable::get_value (void) const
3693 ARDOUR_UI::TransportControllable::set_id (const string
& str
)
3699 ARDOUR_UI::setup_profile ()
3701 if (gdk_screen_width() < 1200) {
3702 Profile
->set_small_screen ();
3706 if (getenv ("ARDOUR_SAE")) {
3707 Profile
->set_sae ();
3708 Profile
->set_single_package ();
3713 ARDOUR_UI::toggle_translations ()
3715 using namespace Glib
;
3717 RefPtr
<Action
> act
= ActionManager::get_action (X_("Main"), X_("EnableTranslation"));
3719 RefPtr
<ToggleAction
> ract
= RefPtr
<ToggleAction
>::cast_dynamic (act
);
3722 string i18n_killer
= ARDOUR::translation_kill_path();
3724 bool already_enabled
= !ARDOUR::translations_are_disabled ();
3726 if (ract
->get_active ()) {
3727 /* we don't care about errors */
3728 int fd
= ::open (i18n_killer
.c_str(), O_RDONLY
|O_CREAT
, 0644);
3731 /* we don't care about errors */
3732 unlink (i18n_killer
.c_str());
3735 if (already_enabled
!= ract
->get_active()) {
3736 MessageDialog
win (already_enabled
? _("Translations disabled") : _("Translations enabled"),
3738 Gtk::MESSAGE_WARNING
,
3740 win
.set_secondary_text (string_compose (_("You must restart %1 for this to take effect."), PROGRAM_NAME
));
3741 win
.set_position (Gtk::WIN_POS_CENTER
);
3749 /** Add a window proxy to our list, so that its state will be saved.
3750 * This call also causes the window to be created and opened if its
3751 * state was saved as `visible'.
3754 ARDOUR_UI::add_window_proxy (WindowProxyBase
* p
)
3756 _window_proxies
.push_back (p
);
3760 /** Remove a window proxy from our list. Must be called if a WindowProxy
3761 * is deleted, to prevent hanging pointers.
3764 ARDOUR_UI::remove_window_proxy (WindowProxyBase
* p
)
3766 _window_proxies
.remove (p
);
3770 ARDOUR_UI::missing_file (Session
*s
, std::string str
, DataType type
)
3772 MissingFileDialog
dialog (s
, str
, type
);
3777 int result
= dialog
.run ();
3784 return 1; // quit entire session load
3787 result
= dialog
.get_action ();
3793 ARDOUR_UI::ambiguous_file (std::string file
, std::string path
, std::vector
<std::string
> hits
)
3795 AmbiguousFileDialog
dialog (file
, hits
);
3801 return dialog
.get_which ();