2 Copyright (C) 2000 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 /* This file contains any ARDOUR_UI methods that require knowledge of
21 the various dialog boxes, and exists so that no compilation dependency
22 exists between the main ARDOUR_UI modules and their respective classes.
23 This is to cut down on the compile times. It also helps with my sanity.
26 #include "ardour/session.h"
27 #include "ardour/audioengine.h"
28 #include "ardour/automation_watch.h"
31 #include "add_route_dialog.h"
32 #include "add_video_dialog.h"
33 #include "ardour_ui.h"
34 #include "big_clock_window.h"
35 #include "bundle_manager.h"
36 #include "global_port_matrix.h"
37 #include "gui_object.h"
38 #include "gui_thread.h"
39 #include "keyeditor.h"
40 #include "location_ui.h"
41 #include "main_clock.h"
42 #include "meter_patterns.h"
43 #include "midi_tracer.h"
45 #include "public_editor.h"
46 #include "rc_option_editor.h"
47 #include "route_params_ui.h"
48 #include "shuttle_control.h"
49 #include "session_option_editor.h"
50 #include "speaker_dialog.h"
53 #include "theme_manager.h"
54 #include "time_info_box.h"
56 #include <gtkmm2ext/keyboard.h>
60 using namespace ARDOUR;
64 using namespace Gtkmm2ext;
67 ARDOUR_UI::set_session (Session *s)
69 SessionHandlePtr::set_session (s);
73 WM::Manager::instance().set_session (s);
74 /* Session option editor cannot exist across change-of-session */
75 session_option_editor.drop_window ();
76 /* Ditto for AddVideoDialog */
77 add_video_dialog.drop_window ();
81 const XMLNode* node = _session->extra_xml (X_("UI"));
84 const XMLNodeList& children = node->children();
85 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
86 if ((*i)->name() == GUIObjectState::xml_node_name) {
87 gui_object_state->load (**i);
93 WM::Manager::instance().set_session (s);
95 AutomationWatch::instance().set_session (s);
98 shuttle_box->set_session (s);
101 primary_clock->set_session (s);
102 secondary_clock->set_session (s);
103 big_clock->set_session (s);
104 time_info_box->set_session (s);
105 video_timeline->set_session (s);
107 /* sensitize menu bar options that are now valid */
109 ActionManager::set_sensitive (ActionManager::session_sensitive_actions, true);
110 ActionManager::set_sensitive (ActionManager::write_sensitive_actions, _session->writable());
112 if (_session->locations()->num_range_markers()) {
113 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, true);
115 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, false);
118 if (!_session->monitor_out()) {
119 Glib::RefPtr<Action> act = ActionManager::get_action (X_("options"), X_("SoloViaBus"));
121 act->set_sensitive (false);
125 /* allow wastebasket flush again */
127 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
129 act->set_sensitive (true);
132 /* there are never any selections on startup */
134 ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, false);
135 ActionManager::set_sensitive (ActionManager::track_selection_sensitive_actions, false);
136 ActionManager::set_sensitive (ActionManager::line_selection_sensitive_actions, false);
137 ActionManager::set_sensitive (ActionManager::point_selection_sensitive_actions, false);
138 ActionManager::set_sensitive (ActionManager::playlist_selection_sensitive_actions, false);
140 rec_button.set_sensitive (true);
142 solo_alert_button.set_active (_session->soloing());
144 setup_session_options ();
146 Blink.connect (sigc::mem_fun(*this, &ARDOUR_UI::transport_rec_enable_blink));
147 Blink.connect (sigc::mem_fun(*this, &ARDOUR_UI::solo_blink));
148 Blink.connect (sigc::mem_fun(*this, &ARDOUR_UI::sync_blink));
149 Blink.connect (sigc::mem_fun(*this, &ARDOUR_UI::audition_blink));
150 Blink.connect (sigc::mem_fun(*this, &ARDOUR_UI::feedback_blink));
152 _session->RecordStateChanged.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::record_state_changed, this), gui_context());
153 _session->StepEditStatusChange.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::step_edit_status_change, this, _1), gui_context());
154 _session->TransportStateChange.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::map_transport_state, this), gui_context());
155 _session->DirtyChanged.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_autosave, this), gui_context());
157 _session->Xrun.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::xrun_handler, this, _1), gui_context());
158 _session->SoloActive.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::soloing_changed, this, _1), gui_context());
159 _session->AuditionActive.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::auditioning_changed, this, _1), gui_context());
160 _session->locations()->added.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::handle_locations_change, this, _1), gui_context());
161 _session->locations()->removed.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::handle_locations_change, this, _1), gui_context());
162 _session->config.ParameterChanged.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_parameter_changed, this, _1), gui_context ());
164 #ifdef HAVE_JACK_SESSION
165 engine->JackSessionEvent.connect (*_session, MISSING_INVALIDATOR, boost::bind (&Session::jack_session_event, _session, _1), gui_context());
168 /* Clocks are on by default after we are connected to a session, so show that here.
171 connect_dependents_to_session (s);
173 /* listen to clock mode changes. don't do this earlier because otherwise as the clocks
174 restore their modes or are explicitly set, we will cause the "new" mode to be saved
175 back to the session XML ("Extra") state.
178 AudioClock::ModeChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::store_clock_modes));
180 Glib::signal_idle().connect (sigc::mem_fun (*this, &ARDOUR_UI::first_idle));
185 map_transport_state ();
187 second_connection = Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::every_second), 1000);
188 point_one_second_connection = Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::every_point_one_seconds), 100);
189 point_zero_something_second_connection = Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::every_point_zero_something_seconds), 40);
194 meter_box.remove(*editor_meter);
197 editor_meter_peak_display.hide();
200 if (_session && _session->master_out()) {
201 editor_meter = new LevelMeterHBox(_session);
202 editor_meter->set_meter (_session->master_out()->shared_peak_meter().get());
203 editor_meter->clear_meters();
204 editor_meter->set_type (_session->master_out()->meter_type());
205 editor_meter->setup_meters (30, 12, 6);
206 meter_box.pack_start(*editor_meter);
208 ArdourMeter::ResetAllPeakDisplays.connect (sigc::mem_fun(*this, &ARDOUR_UI::reset_peak_display));
209 ArdourMeter::ResetRoutePeakDisplays.connect (sigc::mem_fun(*this, &ARDOUR_UI::reset_route_peak_display));
210 ArdourMeter::ResetGroupPeakDisplays.connect (sigc::mem_fun(*this, &ARDOUR_UI::reset_group_peak_display));
212 editor_meter_peak_display.set_name ("meterbridge peakindicator");
213 editor_meter_peak_display.set_elements((ArdourButton::Element) (ArdourButton::Edge|ArdourButton::Body));
214 editor_meter_peak_display.unset_flags (Gtk::CAN_FOCUS);
215 editor_meter_peak_display.set_size_request(6, -1);
216 editor_meter_peak_display.set_corner_radius(2);
217 editor_meter_peak_display.show();
219 editor_meter_max_peak = -INFINITY;
220 editor_meter_peak_display.signal_button_release_event().connect (sigc::mem_fun(*this, &ARDOUR_UI::editor_meter_peak_button_release), false);
226 ARDOUR_UI::unload_session (bool hide_stuff)
229 ARDOUR_UI::instance()->video_timeline->sync_session_state();
232 if (_session && _session->dirty()) {
233 std::vector<std::string> actions;
234 actions.push_back (_("Don't close"));
235 actions.push_back (_("Just close"));
236 actions.push_back (_("Save and close"));
237 switch (ask_about_saving_session (actions)) {
243 _session->save_state ("");
251 meterbridge->hide ();
252 theme_manager->hide ();
253 audio_port_matrix->hide();
254 midi_port_matrix->hide();
255 route_params->hide();
258 second_connection.disconnect ();
259 point_one_second_connection.disconnect ();
260 point_zero_something_second_connection.disconnect();
263 meter_box.remove(*editor_meter);
266 editor_meter_peak_display.hide();
269 ActionManager::set_sensitive (ActionManager::session_sensitive_actions, false);
271 rec_button.set_sensitive (false);
273 WM::Manager::instance().set_session ((ARDOUR::Session*) 0);
274 ARDOUR_UI::instance()->video_timeline->close_session();
279 /* drop everything attached to the blink signal */
286 session_loaded = false;
288 update_buffer_load ();
294 _hide_splash (gpointer arg)
296 ((ARDOUR_UI*)arg)->hide_splash();
301 ARDOUR_UI::goto_editor_window ()
303 if (splash && splash->is_visible()) {
304 // in 2 seconds, hide the splash screen
305 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 2000);
308 editor->show_window ();
310 /* mixer should now be on top */
311 WM::Manager::instance().set_transient_for (editor);
312 _mixer_on_top = false;
316 ARDOUR_UI::goto_mixer_window ()
318 Glib::RefPtr<Gdk::Window> win;
319 Glib::RefPtr<Gdk::Screen> screen;
322 win = editor->get_window ();
326 screen = win->get_screen();
328 screen = Gdk::Screen::get_default();
331 if (screen && screen->get_height() < 700) {
332 Gtk::MessageDialog msg (_("This screen is not tall enough to display the mixer window"));
337 mixer->show_window ();
339 /* mixer should now be on top */
340 WM::Manager::instance().set_transient_for (mixer);
341 _mixer_on_top = true;
345 ARDOUR_UI::toggle_mixer_window ()
347 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("toggle-mixer"));
352 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
354 if (tact->get_active()) {
355 goto_mixer_window ();
362 ARDOUR_UI::toggle_meterbridge ()
364 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("toggle-meterbridge"));
369 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
371 if (tact->get_active()) {
372 meterbridge->show_window ();
374 meterbridge->hide_window (NULL);
379 ARDOUR_UI::toggle_editor_mixer ()
381 bool obscuring = false;
382 /* currently, if windows are on different
383 screens then we do nothing; but in the
384 future we may want to bring the window
385 to the front or something, so I'm leaving this
386 variable for future use
388 bool same_screen = true;
390 if (editor && mixer) {
392 /* remeber: Screen != Monitor (Screen is a separately rendered
393 * continuous geometry that make include 1 or more monitors.
396 if (editor->get_screen() != mixer->get_screen() && (mixer->get_screen() != 0) && (editor->get_screen() != 0)) {
397 // different screens, so don't do anything
400 // they are on the same screen, see if they are obscuring each other
405 editor->get_position (ex, ey);
406 editor->get_size (ew, eh);
408 mixer->get_position (mx, my);
409 mixer->get_size (mw, mh);
425 if (gdk_rectangle_intersect (&e, &m, &r)) {
431 if (mixer && !mixer->not_visible() && mixer->property_has_toplevel_focus()) {
432 if (obscuring && same_screen) {
433 goto_editor_window();
435 } else if (editor && !editor->not_visible() && editor->property_has_toplevel_focus()) {
436 if (obscuring && same_screen) {
439 } else if (mixer && mixer->not_visible()) {
440 if (obscuring && same_screen) {
441 goto_mixer_window ();
443 } else if (editor && editor->not_visible()) {
444 if (obscuring && same_screen) {
445 goto_editor_window ();
447 } else if (obscuring && same_screen) {
448 //it's unclear what to do here, so just do the opposite of what we did last time (old behavior)
450 goto_editor_window ();
452 goto_mixer_window ();
458 ARDOUR_UI::new_midi_tracer_window ()
460 RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("NewMIDITracer"));
465 std::list<MidiTracer*>::iterator i = _midi_tracer_windows.begin ();
466 while (i != _midi_tracer_windows.end() && (*i)->get_visible() == true) {
470 if (i == _midi_tracer_windows.end()) {
471 /* all our MIDITracer windows are visible; make a new one */
472 MidiTracer* t = new MidiTracer ();
474 _midi_tracer_windows.push_back (t);
476 /* re-use the hidden one */
482 ARDOUR_UI::create_bundle_manager ()
484 return new BundleManager (_session);
488 ARDOUR_UI::create_add_video_dialog ()
490 return new AddVideoDialog (_session);
494 ARDOUR_UI::create_session_option_editor ()
496 return new SessionOptionEditor (_session);
500 ARDOUR_UI::create_big_clock_window ()
502 return new BigClockWindow (*big_clock);
506 ARDOUR_UI::handle_locations_change (Location *)
509 if (_session->locations()->num_range_markers()) {
510 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, true);
512 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, false);
518 ARDOUR_UI::main_window_state_event_handler (GdkEventWindowState* ev, bool window_was_editor)
520 if (window_was_editor) {
522 if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
523 (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
524 if (big_clock_window) {
525 big_clock_window->set_transient_for (*editor);
531 if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
532 (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
533 if (big_clock_window) {
534 big_clock_window->set_transient_for (*mixer);
543 ARDOUR_UI::editor_meter_peak_button_release (GdkEventButton* ev)
545 if (ev->button == 1 && Gtkmm2ext::Keyboard::modifier_state_equals (ev->state, Gtkmm2ext::Keyboard::PrimaryModifier|Gtkmm2ext::Keyboard::TertiaryModifier)) {
546 ArdourMeter::ResetAllPeakDisplays ();
547 } else if (ev->button == 1 && Gtkmm2ext::Keyboard::modifier_state_equals (ev->state, Gtkmm2ext::Keyboard::PrimaryModifier)) {
548 if (_session->master_out()) {
549 ArdourMeter::ResetGroupPeakDisplays (_session->master_out()->route_group());
551 } else if (_session->master_out()) {
552 ArdourMeter::ResetRoutePeakDisplays (_session->master_out().get());