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 editor_meter->show();
207 meter_box.pack_start(*editor_meter);
209 ArdourMeter::ResetAllPeakDisplays.connect (sigc::mem_fun(*this, &ARDOUR_UI::reset_peak_display));
210 ArdourMeter::ResetRoutePeakDisplays.connect (sigc::mem_fun(*this, &ARDOUR_UI::reset_route_peak_display));
211 ArdourMeter::ResetGroupPeakDisplays.connect (sigc::mem_fun(*this, &ARDOUR_UI::reset_group_peak_display));
213 editor_meter_peak_display.set_name ("meterbridge peakindicator");
214 editor_meter_peak_display.set_elements((ArdourButton::Element) (ArdourButton::Edge|ArdourButton::Body));
215 editor_meter_peak_display.unset_flags (Gtk::CAN_FOCUS);
216 editor_meter_peak_display.set_size_request(6, -1);
217 editor_meter_peak_display.set_corner_radius(2);
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);
222 if (Config->get_show_editor_meter()) {
224 editor_meter_peak_display.show();
227 editor_meter_peak_display.hide();
234 ARDOUR_UI::unload_session (bool hide_stuff)
237 ARDOUR_UI::instance()->video_timeline->sync_session_state();
240 if (_session && _session->dirty()) {
241 std::vector<std::string> actions;
242 actions.push_back (_("Don't close"));
243 actions.push_back (_("Just close"));
244 actions.push_back (_("Save and close"));
245 switch (ask_about_saving_session (actions)) {
251 _session->save_state ("");
259 meterbridge->hide ();
260 theme_manager->hide ();
261 audio_port_matrix->hide();
262 midi_port_matrix->hide();
263 route_params->hide();
266 second_connection.disconnect ();
267 point_one_second_connection.disconnect ();
268 point_zero_something_second_connection.disconnect();
271 meter_box.remove(*editor_meter);
274 editor_meter_peak_display.hide();
277 ActionManager::set_sensitive (ActionManager::session_sensitive_actions, false);
279 rec_button.set_sensitive (false);
281 WM::Manager::instance().set_session ((ARDOUR::Session*) 0);
282 ARDOUR_UI::instance()->video_timeline->close_session();
287 /* drop everything attached to the blink signal */
294 session_loaded = false;
296 update_buffer_load ();
302 _hide_splash (gpointer arg)
304 ((ARDOUR_UI*)arg)->hide_splash();
309 ARDOUR_UI::goto_editor_window ()
311 if (splash && splash->is_visible()) {
312 // in 2 seconds, hide the splash screen
313 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 2000);
316 editor->show_window ();
318 /* mixer should now be on top */
319 WM::Manager::instance().set_transient_for (editor);
320 _mixer_on_top = false;
324 ARDOUR_UI::goto_mixer_window ()
326 Glib::RefPtr<Gdk::Window> win;
327 Glib::RefPtr<Gdk::Screen> screen;
330 win = editor->get_window ();
334 screen = win->get_screen();
336 screen = Gdk::Screen::get_default();
339 if (screen && screen->get_height() < 700) {
340 Gtk::MessageDialog msg (_("This screen is not tall enough to display the mixer window"));
345 mixer->show_window ();
347 /* mixer should now be on top */
348 WM::Manager::instance().set_transient_for (mixer);
349 _mixer_on_top = true;
353 ARDOUR_UI::toggle_mixer_window ()
355 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("toggle-mixer"));
360 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
362 if (tact->get_active()) {
363 goto_mixer_window ();
370 ARDOUR_UI::toggle_meterbridge ()
372 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("toggle-meterbridge"));
377 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
379 if (tact->get_active()) {
380 meterbridge->show_window ();
382 meterbridge->hide_window (NULL);
387 ARDOUR_UI::toggle_editor_mixer ()
389 bool obscuring = false;
390 /* currently, if windows are on different
391 screens then we do nothing; but in the
392 future we may want to bring the window
393 to the front or something, so I'm leaving this
394 variable for future use
396 bool same_screen = true;
398 if (editor && mixer) {
400 /* remeber: Screen != Monitor (Screen is a separately rendered
401 * continuous geometry that make include 1 or more monitors.
404 if (editor->get_screen() != mixer->get_screen() && (mixer->get_screen() != 0) && (editor->get_screen() != 0)) {
405 // different screens, so don't do anything
408 // they are on the same screen, see if they are obscuring each other
413 editor->get_position (ex, ey);
414 editor->get_size (ew, eh);
416 mixer->get_position (mx, my);
417 mixer->get_size (mw, mh);
433 if (gdk_rectangle_intersect (&e, &m, &r)) {
439 if (mixer && !mixer->not_visible() && mixer->property_has_toplevel_focus()) {
440 if (obscuring && same_screen) {
441 goto_editor_window();
443 } else if (editor && !editor->not_visible() && editor->property_has_toplevel_focus()) {
444 if (obscuring && same_screen) {
447 } else if (mixer && mixer->not_visible()) {
448 if (obscuring && same_screen) {
449 goto_mixer_window ();
451 } else if (editor && editor->not_visible()) {
452 if (obscuring && same_screen) {
453 goto_editor_window ();
455 } else if (obscuring && same_screen) {
456 //it's unclear what to do here, so just do the opposite of what we did last time (old behavior)
458 goto_editor_window ();
460 goto_mixer_window ();
466 ARDOUR_UI::new_midi_tracer_window ()
468 RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("NewMIDITracer"));
473 std::list<MidiTracer*>::iterator i = _midi_tracer_windows.begin ();
474 while (i != _midi_tracer_windows.end() && (*i)->get_visible() == true) {
478 if (i == _midi_tracer_windows.end()) {
479 /* all our MIDITracer windows are visible; make a new one */
480 MidiTracer* t = new MidiTracer ();
482 _midi_tracer_windows.push_back (t);
484 /* re-use the hidden one */
490 ARDOUR_UI::create_bundle_manager ()
492 return new BundleManager (_session);
496 ARDOUR_UI::create_add_video_dialog ()
498 return new AddVideoDialog (_session);
502 ARDOUR_UI::create_session_option_editor ()
504 return new SessionOptionEditor (_session);
508 ARDOUR_UI::create_big_clock_window ()
510 return new BigClockWindow (*big_clock);
514 ARDOUR_UI::handle_locations_change (Location *)
517 if (_session->locations()->num_range_markers()) {
518 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, true);
520 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, false);
526 ARDOUR_UI::main_window_state_event_handler (GdkEventWindowState* ev, bool window_was_editor)
528 if (window_was_editor) {
530 if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
531 (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
532 if (big_clock_window) {
533 big_clock_window->set_transient_for (*editor);
539 if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
540 (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
541 if (big_clock_window) {
542 big_clock_window->set_transient_for (*mixer);
551 ARDOUR_UI::editor_meter_peak_button_release (GdkEventButton* ev)
553 if (ev->button == 1 && Gtkmm2ext::Keyboard::modifier_state_equals (ev->state, Gtkmm2ext::Keyboard::PrimaryModifier|Gtkmm2ext::Keyboard::TertiaryModifier)) {
554 ArdourMeter::ResetAllPeakDisplays ();
555 } else if (ev->button == 1 && Gtkmm2ext::Keyboard::modifier_state_equals (ev->state, Gtkmm2ext::Keyboard::PrimaryModifier)) {
556 if (_session->master_out()) {
557 ArdourMeter::ResetGroupPeakDisplays (_session->master_out()->route_group());
559 } else if (_session->master_out()) {
560 ArdourMeter::ResetRoutePeakDisplays (_session->master_out().get());