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 /* Clocks are on by default after we are connected to a session, so show that here.
167 connect_dependents_to_session (s);
169 /* listen to clock mode changes. don't do this earlier because otherwise as the clocks
170 restore their modes or are explicitly set, we will cause the "new" mode to be saved
171 back to the session XML ("Extra") state.
174 AudioClock::ModeChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::store_clock_modes));
176 Glib::signal_idle().connect (sigc::mem_fun (*this, &ARDOUR_UI::first_idle));
181 map_transport_state ();
183 second_connection = Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::every_second), 1000);
184 point_one_second_connection = Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::every_point_one_seconds), 100);
185 point_zero_something_second_connection = Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::every_point_zero_something_seconds), 40);
190 meter_box.remove(*editor_meter);
193 editor_meter_peak_display.hide();
196 if (_session && _session->master_out()) {
197 editor_meter = new LevelMeterHBox(_session);
198 editor_meter->set_meter (_session->master_out()->shared_peak_meter().get());
199 editor_meter->clear_meters();
200 editor_meter->set_type (_session->master_out()->meter_type());
201 editor_meter->setup_meters (30, 12, 6);
202 editor_meter->show();
203 meter_box.pack_start(*editor_meter);
205 ArdourMeter::ResetAllPeakDisplays.connect (sigc::mem_fun(*this, &ARDOUR_UI::reset_peak_display));
206 ArdourMeter::ResetRoutePeakDisplays.connect (sigc::mem_fun(*this, &ARDOUR_UI::reset_route_peak_display));
207 ArdourMeter::ResetGroupPeakDisplays.connect (sigc::mem_fun(*this, &ARDOUR_UI::reset_group_peak_display));
209 editor_meter_peak_display.set_name ("meterbridge peakindicator");
210 editor_meter_peak_display.set_elements((ArdourButton::Element) (ArdourButton::Edge|ArdourButton::Body));
211 editor_meter_peak_display.unset_flags (Gtk::CAN_FOCUS);
212 editor_meter_peak_display.set_size_request(6, -1);
213 editor_meter_peak_display.set_corner_radius(2);
215 editor_meter_max_peak = -INFINITY;
216 editor_meter_peak_display.signal_button_release_event().connect (sigc::mem_fun(*this, &ARDOUR_UI::editor_meter_peak_button_release), false);
218 if (Config->get_show_editor_meter()) {
220 editor_meter_peak_display.show();
223 editor_meter_peak_display.hide();
230 ARDOUR_UI::unload_session (bool hide_stuff)
233 ARDOUR_UI::instance()->video_timeline->sync_session_state();
236 if (_session && _session->dirty()) {
237 std::vector<std::string> actions;
238 actions.push_back (_("Don't close"));
239 actions.push_back (_("Just close"));
240 actions.push_back (_("Save and close"));
241 switch (ask_about_saving_session (actions)) {
247 _session->save_state ("");
255 meterbridge->hide ();
256 theme_manager->hide ();
257 audio_port_matrix->hide();
258 midi_port_matrix->hide();
259 route_params->hide();
262 second_connection.disconnect ();
263 point_one_second_connection.disconnect ();
264 point_zero_something_second_connection.disconnect();
267 meter_box.remove(*editor_meter);
270 editor_meter_peak_display.hide();
273 ActionManager::set_sensitive (ActionManager::session_sensitive_actions, false);
275 rec_button.set_sensitive (false);
277 WM::Manager::instance().set_session ((ARDOUR::Session*) 0);
279 if (ARDOUR_UI::instance()->video_timeline) {
280 ARDOUR_UI::instance()->video_timeline->close_session();
286 /* drop everything attached to the blink signal */
293 session_loaded = false;
295 update_buffer_load ();
301 _hide_splash (gpointer arg)
303 ((ARDOUR_UI*)arg)->hide_splash();
308 ARDOUR_UI::goto_editor_window ()
310 if (splash && splash->is_visible()) {
311 // in 2 seconds, hide the splash screen
312 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 2000);
315 editor->show_window ();
317 /* mixer should now be on top */
318 WM::Manager::instance().set_transient_for (editor);
319 _mixer_on_top = false;
323 ARDOUR_UI::goto_mixer_window ()
325 Glib::RefPtr<Gdk::Window> win;
326 Glib::RefPtr<Gdk::Screen> screen;
329 win = editor->get_window ();
333 screen = win->get_screen();
335 screen = Gdk::Screen::get_default();
338 if (screen && screen->get_height() < 700) {
339 Gtk::MessageDialog msg (_("This screen is not tall enough to display the mixer window"));
344 mixer->show_window ();
346 /* mixer should now be on top */
347 WM::Manager::instance().set_transient_for (mixer);
348 _mixer_on_top = true;
352 ARDOUR_UI::toggle_mixer_window ()
354 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("toggle-mixer"));
359 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
361 if (tact->get_active()) {
362 goto_mixer_window ();
369 ARDOUR_UI::toggle_meterbridge ()
371 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("toggle-meterbridge"));
376 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
378 if (tact->get_active()) {
379 meterbridge->show_window ();
381 meterbridge->hide_window (NULL);
386 ARDOUR_UI::toggle_editor_mixer ()
388 bool obscuring = false;
389 /* currently, if windows are on different
390 screens then we do nothing; but in the
391 future we may want to bring the window
392 to the front or something, so I'm leaving this
393 variable for future use
395 bool same_screen = true;
397 if (editor && mixer) {
399 /* remeber: Screen != Monitor (Screen is a separately rendered
400 * continuous geometry that make include 1 or more monitors.
403 if (editor->get_screen() != mixer->get_screen() && (mixer->get_screen() != 0) && (editor->get_screen() != 0)) {
404 // different screens, so don't do anything
407 // they are on the same screen, see if they are obscuring each other
412 editor->get_position (ex, ey);
413 editor->get_size (ew, eh);
415 mixer->get_position (mx, my);
416 mixer->get_size (mw, mh);
432 if (gdk_rectangle_intersect (&e, &m, &r)) {
438 if (mixer && !mixer->not_visible() && mixer->property_has_toplevel_focus()) {
439 if (obscuring && same_screen) {
440 goto_editor_window();
442 } else if (editor && !editor->not_visible() && editor->property_has_toplevel_focus()) {
443 if (obscuring && same_screen) {
446 } else if (mixer && mixer->not_visible()) {
447 if (obscuring && same_screen) {
448 goto_mixer_window ();
450 } else if (editor && editor->not_visible()) {
451 if (obscuring && same_screen) {
452 goto_editor_window ();
454 } else if (obscuring && same_screen) {
455 //it's unclear what to do here, so just do the opposite of what we did last time (old behavior)
457 goto_editor_window ();
459 goto_mixer_window ();
465 ARDOUR_UI::new_midi_tracer_window ()
467 RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("NewMIDITracer"));
472 std::list<MidiTracer*>::iterator i = _midi_tracer_windows.begin ();
473 while (i != _midi_tracer_windows.end() && (*i)->get_visible() == true) {
477 if (i == _midi_tracer_windows.end()) {
478 /* all our MIDITracer windows are visible; make a new one */
479 MidiTracer* t = new MidiTracer ();
481 _midi_tracer_windows.push_back (t);
483 /* re-use the hidden one */
489 ARDOUR_UI::create_bundle_manager ()
491 return new BundleManager (_session);
495 ARDOUR_UI::create_add_video_dialog ()
497 return new AddVideoDialog (_session);
501 ARDOUR_UI::create_session_option_editor ()
503 return new SessionOptionEditor (_session);
507 ARDOUR_UI::create_big_clock_window ()
509 return new BigClockWindow (*big_clock);
513 ARDOUR_UI::handle_locations_change (Location *)
516 if (_session->locations()->num_range_markers()) {
517 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, true);
519 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, false);
525 ARDOUR_UI::main_window_state_event_handler (GdkEventWindowState* ev, bool window_was_editor)
527 if (window_was_editor) {
529 if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
530 (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
531 if (big_clock_window) {
532 big_clock_window->set_transient_for (*editor);
538 if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
539 (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
540 if (big_clock_window) {
541 big_clock_window->set_transient_for (*mixer);
550 ARDOUR_UI::editor_meter_peak_button_release (GdkEventButton* ev)
552 if (ev->button == 1 && Gtkmm2ext::Keyboard::modifier_state_equals (ev->state, Gtkmm2ext::Keyboard::PrimaryModifier|Gtkmm2ext::Keyboard::TertiaryModifier)) {
553 ArdourMeter::ResetAllPeakDisplays ();
554 } else if (ev->button == 1 && Gtkmm2ext::Keyboard::modifier_state_equals (ev->state, Gtkmm2ext::Keyboard::PrimaryModifier)) {
555 if (_session->master_out()) {
556 ArdourMeter::ResetGroupPeakDisplays (_session->master_out()->route_group());
558 } else if (_session->master_out()) {
559 ArdourMeter::ResetRoutePeakDisplays (_session->master_out().get());