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/audioengine.h"
27 #include "ardour/automation_watch.h"
28 #include "ardour/profile.h"
29 #include "ardour/session.h"
36 #include "add_route_dialog.h"
37 #include "add_video_dialog.h"
38 #include "ardour_ui.h"
39 #include "big_clock_window.h"
40 #include "bundle_manager.h"
41 #include "global_port_matrix.h"
42 #include "gui_object.h"
43 #include "gui_thread.h"
44 #include "keyeditor.h"
45 #include "location_ui.h"
46 #include "main_clock.h"
47 #include "meter_patterns.h"
48 #include "midi_tracer.h"
50 #include "public_editor.h"
51 #include "rc_option_editor.h"
52 #include "route_params_ui.h"
53 #include "shuttle_control.h"
54 #include "session_option_editor.h"
55 #include "speaker_dialog.h"
58 #include "theme_manager.h"
59 #include "time_info_box.h"
61 #include <gtkmm2ext/keyboard.h>
65 using namespace ARDOUR;
69 using namespace Gtkmm2ext;
72 ARDOUR_UI::set_session (Session *s)
74 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);
193 if (meter_box.get_parent()) {
194 transport_tearoff_hbox.remove (meter_box);
195 transport_tearoff_hbox.remove (editor_meter_peak_display);
199 meter_box.remove(*editor_meter);
202 editor_meter_peak_display.hide();
205 if (meter_box.get_parent()) {
206 transport_tearoff_hbox.remove (meter_box);
207 transport_tearoff_hbox.remove (editor_meter_peak_display);
211 _session->master_out() &&
212 _session->master_out()->n_outputs().n(DataType::AUDIO) > 0) {
214 if (!ARDOUR::Profile->get_trx()) {
215 editor_meter = new LevelMeterHBox(_session);
216 editor_meter->set_meter (_session->master_out()->shared_peak_meter().get());
217 editor_meter->clear_meters();
218 editor_meter->set_type (_session->master_out()->meter_type());
219 editor_meter->setup_meters (30, 12, 6);
220 editor_meter->show();
221 meter_box.pack_start(*editor_meter);
224 ArdourMeter::ResetAllPeakDisplays.connect (sigc::mem_fun(*this, &ARDOUR_UI::reset_peak_display));
225 ArdourMeter::ResetRoutePeakDisplays.connect (sigc::mem_fun(*this, &ARDOUR_UI::reset_route_peak_display));
226 ArdourMeter::ResetGroupPeakDisplays.connect (sigc::mem_fun(*this, &ARDOUR_UI::reset_group_peak_display));
228 editor_meter_peak_display.set_name ("meterbridge peakindicator");
229 editor_meter_peak_display.set_elements((ArdourButton::Element) (ArdourButton::Edge|ArdourButton::Body));
230 editor_meter_peak_display.unset_flags (Gtk::CAN_FOCUS);
231 editor_meter_peak_display.set_size_request(6, -1);
232 editor_meter_peak_display.set_corner_radius(2);
234 editor_meter_max_peak = -INFINITY;
235 editor_meter_peak_display.signal_button_release_event().connect (sigc::mem_fun(*this, &ARDOUR_UI::editor_meter_peak_button_release), false);
237 if (Config->get_show_editor_meter() && !ARDOUR::Profile->get_trx()) {
238 transport_tearoff_hbox.pack_start (meter_box, false, false);
239 transport_tearoff_hbox.pack_start (editor_meter_peak_display, false, false);
241 editor_meter_peak_display.show();
247 ARDOUR_UI::unload_session (bool hide_stuff)
250 ARDOUR_UI::instance()->video_timeline->sync_session_state();
253 if (_session && _session->dirty()) {
254 std::vector<std::string> actions;
255 actions.push_back (_("Don't close"));
256 actions.push_back (_("Just close"));
257 actions.push_back (_("Save and close"));
258 switch (ask_about_saving_session (actions)) {
264 _session->save_state ("");
272 meterbridge->hide ();
273 theme_manager->hide ();
274 audio_port_matrix->hide();
275 midi_port_matrix->hide();
276 route_params->hide();
279 second_connection.disconnect ();
280 point_one_second_connection.disconnect ();
281 point_zero_something_second_connection.disconnect();
284 meter_box.remove(*editor_meter);
287 editor_meter_peak_display.hide();
290 ActionManager::set_sensitive (ActionManager::session_sensitive_actions, false);
292 rec_button.set_sensitive (false);
294 WM::Manager::instance().set_session ((ARDOUR::Session*) 0);
296 if (ARDOUR_UI::instance()->video_timeline) {
297 ARDOUR_UI::instance()->video_timeline->close_session();
303 /* drop everything attached to the blink signal */
310 session_loaded = false;
312 update_buffer_load ();
318 _hide_splash (gpointer arg)
320 ((ARDOUR_UI*)arg)->hide_splash();
325 ARDOUR_UI::goto_editor_window ()
327 if (splash && splash->is_visible()) {
328 // in 2 seconds, hide the splash screen
329 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 2000);
332 editor->show_window ();
334 /* mixer should now be on top */
335 WM::Manager::instance().set_transient_for (editor);
336 _mixer_on_top = false;
340 ARDOUR_UI::goto_mixer_window ()
342 Glib::RefPtr<Gdk::Window> win;
343 Glib::RefPtr<Gdk::Screen> screen;
346 win = editor->get_window ();
350 screen = win->get_screen();
352 screen = Gdk::Screen::get_default();
355 if (g_getenv ("ARDOUR_LOVES_STUPID_TINY_SCREENS") == 0 && screen && screen->get_height() < 700) {
356 Gtk::MessageDialog msg (_("This screen is not tall enough to display the mixer window"));
361 mixer->show_window ();
363 /* mixer should now be on top */
364 WM::Manager::instance().set_transient_for (mixer);
365 _mixer_on_top = true;
369 ARDOUR_UI::toggle_mixer_window ()
371 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("toggle-mixer"));
376 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
378 if (tact->get_active()) {
379 goto_mixer_window ();
386 ARDOUR_UI::toggle_meterbridge ()
388 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("toggle-meterbridge"));
393 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
395 if (tact->get_active()) {
396 meterbridge->show_window ();
398 meterbridge->hide_window (NULL);
403 ARDOUR_UI::toggle_editor_mixer ()
405 bool obscuring = false;
406 /* currently, if windows are on different
407 screens then we do nothing; but in the
408 future we may want to bring the window
409 to the front or something, so I'm leaving this
410 variable for future use
412 bool same_screen = true;
414 if (editor && mixer) {
416 /* remeber: Screen != Monitor (Screen is a separately rendered
417 * continuous geometry that make include 1 or more monitors.
420 if (editor->get_screen() != mixer->get_screen() && (mixer->get_screen() != 0) && (editor->get_screen() != 0)) {
421 // different screens, so don't do anything
424 // they are on the same screen, see if they are obscuring each other
429 editor->get_position (ex, ey);
430 editor->get_size (ew, eh);
432 mixer->get_position (mx, my);
433 mixer->get_size (mw, mh);
449 if (gdk_rectangle_intersect (&e, &m, &r)) {
455 if (mixer && !mixer->not_visible() && mixer->property_has_toplevel_focus()) {
456 if (obscuring && same_screen) {
457 goto_editor_window();
459 } else if (editor && !editor->not_visible() && editor->property_has_toplevel_focus()) {
460 if (obscuring && same_screen) {
463 } else if (mixer && mixer->not_visible()) {
464 if (obscuring && same_screen) {
465 goto_mixer_window ();
467 } else if (editor && editor->not_visible()) {
468 if (obscuring && same_screen) {
469 goto_editor_window ();
471 } else if (obscuring && same_screen) {
472 //it's unclear what to do here, so just do the opposite of what we did last time (old behavior)
474 goto_editor_window ();
476 goto_mixer_window ();
482 ARDOUR_UI::new_midi_tracer_window ()
484 RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("NewMIDITracer"));
489 std::list<MidiTracer*>::iterator i = _midi_tracer_windows.begin ();
490 while (i != _midi_tracer_windows.end() && (*i)->get_visible() == true) {
494 if (i == _midi_tracer_windows.end()) {
495 /* all our MIDITracer windows are visible; make a new one */
496 MidiTracer* t = new MidiTracer ();
498 _midi_tracer_windows.push_back (t);
500 /* re-use the hidden one */
506 ARDOUR_UI::create_bundle_manager ()
508 return new BundleManager (_session);
512 ARDOUR_UI::create_add_video_dialog ()
514 return new AddVideoDialog (_session);
518 ARDOUR_UI::create_session_option_editor ()
520 return new SessionOptionEditor (_session);
524 ARDOUR_UI::create_big_clock_window ()
526 return new BigClockWindow (*big_clock);
530 ARDOUR_UI::handle_locations_change (Location *)
533 if (_session->locations()->num_range_markers()) {
534 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, true);
536 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, false);
542 ARDOUR_UI::main_window_state_event_handler (GdkEventWindowState* ev, bool window_was_editor)
544 if (window_was_editor) {
546 if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
547 (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
548 if (big_clock_window) {
549 big_clock_window->set_transient_for (*editor);
555 if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
556 (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
557 if (big_clock_window) {
558 big_clock_window->set_transient_for (*mixer);
567 ARDOUR_UI::editor_meter_peak_button_release (GdkEventButton* ev)
569 if (ev->button == 1 && Gtkmm2ext::Keyboard::modifier_state_equals (ev->state, Gtkmm2ext::Keyboard::PrimaryModifier|Gtkmm2ext::Keyboard::TertiaryModifier)) {
570 ArdourMeter::ResetAllPeakDisplays ();
571 } else if (ev->button == 1 && Gtkmm2ext::Keyboard::modifier_state_equals (ev->state, Gtkmm2ext::Keyboard::PrimaryModifier)) {
572 if (_session->master_out()) {
573 ArdourMeter::ResetGroupPeakDisplays (_session->master_out()->route_group());
575 } else if (_session->master_out()) {
576 ArdourMeter::ResetRoutePeakDisplays (_session->master_out().get());
582 ARDOUR_UI::toggle_mixer_space()
584 Glib::RefPtr<Action> act = ActionManager::get_action ("Common", "ToggleMaximalMixer");
587 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
588 if (tact->get_active()) {
589 mixer->maximise_mixer_space ();
591 mixer->restore_mixer_space ();