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();
201 && _session->master_out()
202 && _session->master_out()->n_outputs().n(DataType::AUDIO) > 0) {
203 editor_meter = new LevelMeterHBox(_session);
204 editor_meter->set_meter (_session->master_out()->shared_peak_meter().get());
205 editor_meter->clear_meters();
206 editor_meter->set_type (_session->master_out()->meter_type());
207 editor_meter->setup_meters (30, 12, 6);
208 editor_meter->show();
209 meter_box.pack_start(*editor_meter);
211 ArdourMeter::ResetAllPeakDisplays.connect (sigc::mem_fun(*this, &ARDOUR_UI::reset_peak_display));
212 ArdourMeter::ResetRoutePeakDisplays.connect (sigc::mem_fun(*this, &ARDOUR_UI::reset_route_peak_display));
213 ArdourMeter::ResetGroupPeakDisplays.connect (sigc::mem_fun(*this, &ARDOUR_UI::reset_group_peak_display));
215 editor_meter_peak_display.set_name ("meterbridge peakindicator");
216 editor_meter_peak_display.set_elements((ArdourButton::Element) (ArdourButton::Edge|ArdourButton::Body));
217 editor_meter_peak_display.unset_flags (Gtk::CAN_FOCUS);
218 editor_meter_peak_display.set_size_request(6, -1);
219 editor_meter_peak_display.set_corner_radius(2);
221 editor_meter_max_peak = -INFINITY;
222 editor_meter_peak_display.signal_button_release_event().connect (sigc::mem_fun(*this, &ARDOUR_UI::editor_meter_peak_button_release), false);
224 if (Config->get_show_editor_meter()) {
225 transport_tearoff_hbox.pack_start (meter_box, false, false);
226 transport_tearoff_hbox.pack_start (editor_meter_peak_display, false, false);
228 editor_meter_peak_display.show();
229 } else if (meter_box.get_parent()) {
230 transport_tearoff_hbox.remove (meter_box);
231 transport_tearoff_hbox.remove (editor_meter_peak_display);
233 } else if (meter_box.get_parent()) {
234 transport_tearoff_hbox.remove (meter_box);
235 transport_tearoff_hbox.remove (editor_meter_peak_display);
241 ARDOUR_UI::unload_session (bool hide_stuff)
244 ARDOUR_UI::instance()->video_timeline->sync_session_state();
247 if (_session && _session->dirty()) {
248 std::vector<std::string> actions;
249 actions.push_back (_("Don't close"));
250 actions.push_back (_("Just close"));
251 actions.push_back (_("Save and close"));
252 switch (ask_about_saving_session (actions)) {
258 _session->save_state ("");
266 meterbridge->hide ();
267 theme_manager->hide ();
268 audio_port_matrix->hide();
269 midi_port_matrix->hide();
270 route_params->hide();
273 second_connection.disconnect ();
274 point_one_second_connection.disconnect ();
275 point_zero_something_second_connection.disconnect();
278 meter_box.remove(*editor_meter);
281 editor_meter_peak_display.hide();
284 ActionManager::set_sensitive (ActionManager::session_sensitive_actions, false);
286 rec_button.set_sensitive (false);
288 WM::Manager::instance().set_session ((ARDOUR::Session*) 0);
290 if (ARDOUR_UI::instance()->video_timeline) {
291 ARDOUR_UI::instance()->video_timeline->close_session();
297 /* drop everything attached to the blink signal */
304 session_loaded = false;
306 update_buffer_load ();
312 _hide_splash (gpointer arg)
314 ((ARDOUR_UI*)arg)->hide_splash();
319 ARDOUR_UI::goto_editor_window ()
321 if (splash && splash->is_visible()) {
322 // in 2 seconds, hide the splash screen
323 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 2000);
326 editor->show_window ();
328 /* mixer should now be on top */
329 WM::Manager::instance().set_transient_for (editor);
330 _mixer_on_top = false;
334 ARDOUR_UI::goto_mixer_window ()
336 Glib::RefPtr<Gdk::Window> win;
337 Glib::RefPtr<Gdk::Screen> screen;
340 win = editor->get_window ();
344 screen = win->get_screen();
346 screen = Gdk::Screen::get_default();
349 if (g_getenv ("ARDOUR_LOVES_STUPID_TINY_SCREENS") == 0 && screen && screen->get_height() < 700) {
350 Gtk::MessageDialog msg (_("This screen is not tall enough to display the mixer window"));
355 mixer->show_window ();
357 /* mixer should now be on top */
358 WM::Manager::instance().set_transient_for (mixer);
359 _mixer_on_top = true;
363 ARDOUR_UI::toggle_mixer_window ()
365 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("toggle-mixer"));
370 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
372 if (tact->get_active()) {
373 goto_mixer_window ();
380 ARDOUR_UI::toggle_meterbridge ()
382 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("toggle-meterbridge"));
387 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
389 if (tact->get_active()) {
390 meterbridge->show_window ();
392 meterbridge->hide_window (NULL);
397 ARDOUR_UI::toggle_editor_mixer ()
399 bool obscuring = false;
400 /* currently, if windows are on different
401 screens then we do nothing; but in the
402 future we may want to bring the window
403 to the front or something, so I'm leaving this
404 variable for future use
406 bool same_screen = true;
408 if (editor && mixer) {
410 /* remeber: Screen != Monitor (Screen is a separately rendered
411 * continuous geometry that make include 1 or more monitors.
414 if (editor->get_screen() != mixer->get_screen() && (mixer->get_screen() != 0) && (editor->get_screen() != 0)) {
415 // different screens, so don't do anything
418 // they are on the same screen, see if they are obscuring each other
423 editor->get_position (ex, ey);
424 editor->get_size (ew, eh);
426 mixer->get_position (mx, my);
427 mixer->get_size (mw, mh);
443 if (gdk_rectangle_intersect (&e, &m, &r)) {
449 if (mixer && !mixer->not_visible() && mixer->property_has_toplevel_focus()) {
450 if (obscuring && same_screen) {
451 goto_editor_window();
453 } else if (editor && !editor->not_visible() && editor->property_has_toplevel_focus()) {
454 if (obscuring && same_screen) {
457 } else if (mixer && mixer->not_visible()) {
458 if (obscuring && same_screen) {
459 goto_mixer_window ();
461 } else if (editor && editor->not_visible()) {
462 if (obscuring && same_screen) {
463 goto_editor_window ();
465 } else if (obscuring && same_screen) {
466 //it's unclear what to do here, so just do the opposite of what we did last time (old behavior)
468 goto_editor_window ();
470 goto_mixer_window ();
476 ARDOUR_UI::new_midi_tracer_window ()
478 RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("NewMIDITracer"));
483 std::list<MidiTracer*>::iterator i = _midi_tracer_windows.begin ();
484 while (i != _midi_tracer_windows.end() && (*i)->get_visible() == true) {
488 if (i == _midi_tracer_windows.end()) {
489 /* all our MIDITracer windows are visible; make a new one */
490 MidiTracer* t = new MidiTracer ();
492 _midi_tracer_windows.push_back (t);
494 /* re-use the hidden one */
500 ARDOUR_UI::create_bundle_manager ()
502 return new BundleManager (_session);
506 ARDOUR_UI::create_add_video_dialog ()
508 return new AddVideoDialog (_session);
512 ARDOUR_UI::create_session_option_editor ()
514 return new SessionOptionEditor (_session);
518 ARDOUR_UI::create_big_clock_window ()
520 return new BigClockWindow (*big_clock);
524 ARDOUR_UI::handle_locations_change (Location *)
527 if (_session->locations()->num_range_markers()) {
528 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, true);
530 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, false);
536 ARDOUR_UI::main_window_state_event_handler (GdkEventWindowState* ev, bool window_was_editor)
538 if (window_was_editor) {
540 if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
541 (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
542 if (big_clock_window) {
543 big_clock_window->set_transient_for (*editor);
549 if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
550 (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
551 if (big_clock_window) {
552 big_clock_window->set_transient_for (*mixer);
561 ARDOUR_UI::editor_meter_peak_button_release (GdkEventButton* ev)
563 if (ev->button == 1 && Gtkmm2ext::Keyboard::modifier_state_equals (ev->state, Gtkmm2ext::Keyboard::PrimaryModifier|Gtkmm2ext::Keyboard::TertiaryModifier)) {
564 ArdourMeter::ResetAllPeakDisplays ();
565 } else if (ev->button == 1 && Gtkmm2ext::Keyboard::modifier_state_equals (ev->state, Gtkmm2ext::Keyboard::PrimaryModifier)) {
566 if (_session->master_out()) {
567 ArdourMeter::ResetGroupPeakDisplays (_session->master_out()->route_group());
569 } else if (_session->master_out()) {
570 ArdourMeter::ResetRoutePeakDisplays (_session->master_out().get());