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"
35 #include "add_route_dialog.h"
36 #include "add_video_dialog.h"
37 #include "ardour_ui.h"
38 #include "big_clock_window.h"
39 #include "bundle_manager.h"
40 #include "global_port_matrix.h"
41 #include "gui_object.h"
42 #include "gui_thread.h"
43 #include "keyeditor.h"
44 #include "location_ui.h"
45 #include "main_clock.h"
46 #include "meter_patterns.h"
47 #include "midi_tracer.h"
49 #include "public_editor.h"
50 #include "rc_option_editor.h"
51 #include "route_params_ui.h"
52 #include "shuttle_control.h"
53 #include "session_option_editor.h"
54 #include "speaker_dialog.h"
57 #include "theme_manager.h"
58 #include "time_info_box.h"
60 #include <gtkmm2ext/keyboard.h>
64 using namespace ARDOUR;
68 using namespace Gtkmm2ext;
71 ARDOUR_UI::set_session (Session *s)
73 SessionHandlePtr::set_session (s);
77 WM::Manager::instance().set_session (s);
78 /* Session option editor cannot exist across change-of-session */
79 session_option_editor.drop_window ();
80 /* Ditto for AddVideoDialog */
81 add_video_dialog.drop_window ();
85 const XMLNode* node = _session->extra_xml (X_("UI"));
88 const XMLNodeList& children = node->children();
89 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
90 if ((*i)->name() == GUIObjectState::xml_node_name) {
91 gui_object_state->load (**i);
97 WM::Manager::instance().set_session (s);
99 AutomationWatch::instance().set_session (s);
102 shuttle_box->set_session (s);
105 primary_clock->set_session (s);
106 secondary_clock->set_session (s);
107 big_clock->set_session (s);
108 time_info_box->set_session (s);
109 video_timeline->set_session (s);
111 /* sensitize menu bar options that are now valid */
113 ActionManager::set_sensitive (ActionManager::session_sensitive_actions, true);
114 ActionManager::set_sensitive (ActionManager::write_sensitive_actions, _session->writable());
116 if (_session->locations()->num_range_markers()) {
117 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, true);
119 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, false);
122 if (!_session->monitor_out()) {
123 Glib::RefPtr<Action> act = ActionManager::get_action (X_("options"), X_("SoloViaBus"));
125 act->set_sensitive (false);
129 /* allow wastebasket flush again */
131 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
133 act->set_sensitive (true);
136 /* there are never any selections on startup */
138 ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, false);
139 ActionManager::set_sensitive (ActionManager::track_selection_sensitive_actions, false);
140 ActionManager::set_sensitive (ActionManager::line_selection_sensitive_actions, false);
141 ActionManager::set_sensitive (ActionManager::point_selection_sensitive_actions, false);
142 ActionManager::set_sensitive (ActionManager::playlist_selection_sensitive_actions, false);
144 rec_button.set_sensitive (true);
146 solo_alert_button.set_active (_session->soloing());
148 setup_session_options ();
150 Blink.connect (sigc::mem_fun(*this, &ARDOUR_UI::transport_rec_enable_blink));
151 Blink.connect (sigc::mem_fun(*this, &ARDOUR_UI::solo_blink));
152 Blink.connect (sigc::mem_fun(*this, &ARDOUR_UI::sync_blink));
153 Blink.connect (sigc::mem_fun(*this, &ARDOUR_UI::audition_blink));
154 Blink.connect (sigc::mem_fun(*this, &ARDOUR_UI::feedback_blink));
156 _session->RecordStateChanged.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::record_state_changed, this), gui_context());
157 _session->StepEditStatusChange.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::step_edit_status_change, this, _1), gui_context());
158 _session->TransportStateChange.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::map_transport_state, this), gui_context());
159 _session->DirtyChanged.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_autosave, this), gui_context());
161 _session->Xrun.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::xrun_handler, this, _1), gui_context());
162 _session->SoloActive.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::soloing_changed, this, _1), gui_context());
163 _session->AuditionActive.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::auditioning_changed, this, _1), gui_context());
164 _session->locations()->added.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::handle_locations_change, this, _1), gui_context());
165 _session->locations()->removed.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::handle_locations_change, this, _1), gui_context());
166 _session->config.ParameterChanged.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_parameter_changed, this, _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);
283 if (ARDOUR_UI::instance()->video_timeline) {
284 ARDOUR_UI::instance()->video_timeline->close_session();
290 /* drop everything attached to the blink signal */
297 session_loaded = false;
299 update_buffer_load ();
305 _hide_splash (gpointer arg)
307 ((ARDOUR_UI*)arg)->hide_splash();
312 ARDOUR_UI::goto_editor_window ()
314 if (splash && splash->is_visible()) {
315 // in 2 seconds, hide the splash screen
316 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 2000);
319 editor->show_window ();
321 /* mixer should now be on top */
322 WM::Manager::instance().set_transient_for (editor);
323 _mixer_on_top = false;
327 ARDOUR_UI::goto_mixer_window ()
329 Glib::RefPtr<Gdk::Window> win;
330 Glib::RefPtr<Gdk::Screen> screen;
333 win = editor->get_window ();
337 screen = win->get_screen();
339 screen = Gdk::Screen::get_default();
342 if (screen && screen->get_height() < 700) {
343 Gtk::MessageDialog msg (_("This screen is not tall enough to display the mixer window"));
348 mixer->show_window ();
350 /* mixer should now be on top */
351 WM::Manager::instance().set_transient_for (mixer);
352 _mixer_on_top = true;
356 ARDOUR_UI::toggle_mixer_window ()
358 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("toggle-mixer"));
363 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
365 if (tact->get_active()) {
366 goto_mixer_window ();
373 ARDOUR_UI::toggle_meterbridge ()
375 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("toggle-meterbridge"));
380 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
382 if (tact->get_active()) {
383 meterbridge->show_window ();
385 meterbridge->hide_window (NULL);
390 ARDOUR_UI::toggle_editor_mixer ()
392 bool obscuring = false;
393 /* currently, if windows are on different
394 screens then we do nothing; but in the
395 future we may want to bring the window
396 to the front or something, so I'm leaving this
397 variable for future use
399 bool same_screen = true;
401 if (editor && mixer) {
403 /* remeber: Screen != Monitor (Screen is a separately rendered
404 * continuous geometry that make include 1 or more monitors.
407 if (editor->get_screen() != mixer->get_screen() && (mixer->get_screen() != 0) && (editor->get_screen() != 0)) {
408 // different screens, so don't do anything
411 // they are on the same screen, see if they are obscuring each other
416 editor->get_position (ex, ey);
417 editor->get_size (ew, eh);
419 mixer->get_position (mx, my);
420 mixer->get_size (mw, mh);
436 if (gdk_rectangle_intersect (&e, &m, &r)) {
442 if (mixer && !mixer->not_visible() && mixer->property_has_toplevel_focus()) {
443 if (obscuring && same_screen) {
444 goto_editor_window();
446 } else if (editor && !editor->not_visible() && editor->property_has_toplevel_focus()) {
447 if (obscuring && same_screen) {
450 } else if (mixer && mixer->not_visible()) {
451 if (obscuring && same_screen) {
452 goto_mixer_window ();
454 } else if (editor && editor->not_visible()) {
455 if (obscuring && same_screen) {
456 goto_editor_window ();
458 } else if (obscuring && same_screen) {
459 //it's unclear what to do here, so just do the opposite of what we did last time (old behavior)
461 goto_editor_window ();
463 goto_mixer_window ();
469 ARDOUR_UI::new_midi_tracer_window ()
471 RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("NewMIDITracer"));
476 std::list<MidiTracer*>::iterator i = _midi_tracer_windows.begin ();
477 while (i != _midi_tracer_windows.end() && (*i)->get_visible() == true) {
481 if (i == _midi_tracer_windows.end()) {
482 /* all our MIDITracer windows are visible; make a new one */
483 MidiTracer* t = new MidiTracer ();
485 _midi_tracer_windows.push_back (t);
487 /* re-use the hidden one */
493 ARDOUR_UI::create_bundle_manager ()
495 return new BundleManager (_session);
499 ARDOUR_UI::create_add_video_dialog ()
501 return new AddVideoDialog (_session);
505 ARDOUR_UI::create_session_option_editor ()
507 return new SessionOptionEditor (_session);
511 ARDOUR_UI::create_big_clock_window ()
513 return new BigClockWindow (*big_clock);
517 ARDOUR_UI::handle_locations_change (Location *)
520 if (_session->locations()->num_range_markers()) {
521 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, true);
523 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, false);
529 ARDOUR_UI::main_window_state_event_handler (GdkEventWindowState* ev, bool window_was_editor)
531 if (window_was_editor) {
533 if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
534 (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
535 if (big_clock_window) {
536 big_clock_window->set_transient_for (*editor);
542 if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
543 (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
544 if (big_clock_window) {
545 big_clock_window->set_transient_for (*mixer);
554 ARDOUR_UI::editor_meter_peak_button_release (GdkEventButton* ev)
556 if (ev->button == 1 && Gtkmm2ext::Keyboard::modifier_state_equals (ev->state, Gtkmm2ext::Keyboard::PrimaryModifier|Gtkmm2ext::Keyboard::TertiaryModifier)) {
557 ArdourMeter::ResetAllPeakDisplays ();
558 } else if (ev->button == 1 && Gtkmm2ext::Keyboard::modifier_state_equals (ev->state, Gtkmm2ext::Keyboard::PrimaryModifier)) {
559 if (_session->master_out()) {
560 ArdourMeter::ResetGroupPeakDisplays (_session->master_out()->route_group());
562 } else if (_session->master_out()) {
563 ArdourMeter::ResetRoutePeakDisplays (_session->master_out().get());