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();
197 && _session->master_out()
198 && _session->master_out()->n_outputs().n(DataType::AUDIO) > 0) {
199 editor_meter = new LevelMeterHBox(_session);
200 editor_meter->set_meter (_session->master_out()->shared_peak_meter().get());
201 editor_meter->clear_meters();
202 editor_meter->set_type (_session->master_out()->meter_type());
203 editor_meter->setup_meters (30, 12, 6);
204 editor_meter->show();
205 meter_box.pack_start(*editor_meter);
207 ArdourMeter::ResetAllPeakDisplays.connect (sigc::mem_fun(*this, &ARDOUR_UI::reset_peak_display));
208 ArdourMeter::ResetRoutePeakDisplays.connect (sigc::mem_fun(*this, &ARDOUR_UI::reset_route_peak_display));
209 ArdourMeter::ResetGroupPeakDisplays.connect (sigc::mem_fun(*this, &ARDOUR_UI::reset_group_peak_display));
211 editor_meter_peak_display.set_name ("meterbridge peakindicator");
212 editor_meter_peak_display.set_elements((ArdourButton::Element) (ArdourButton::Edge|ArdourButton::Body));
213 editor_meter_peak_display.unset_flags (Gtk::CAN_FOCUS);
214 editor_meter_peak_display.set_size_request(6, -1);
215 editor_meter_peak_display.set_corner_radius(2);
217 editor_meter_max_peak = -INFINITY;
218 editor_meter_peak_display.signal_button_release_event().connect (sigc::mem_fun(*this, &ARDOUR_UI::editor_meter_peak_button_release), false);
220 if (Config->get_show_editor_meter()) {
221 transport_tearoff_hbox.pack_start (meter_box, false, false);
222 transport_tearoff_hbox.pack_start (editor_meter_peak_display, false, false);
224 editor_meter_peak_display.show();
225 } else if (meter_box.get_parent()) {
226 transport_tearoff_hbox.remove (meter_box);
227 transport_tearoff_hbox.remove (editor_meter_peak_display);
229 } else if (meter_box.get_parent()) {
230 transport_tearoff_hbox.remove (meter_box);
231 transport_tearoff_hbox.remove (editor_meter_peak_display);
237 ARDOUR_UI::unload_session (bool hide_stuff)
240 ARDOUR_UI::instance()->video_timeline->sync_session_state();
243 if (_session && _session->dirty()) {
244 std::vector<std::string> actions;
245 actions.push_back (_("Don't close"));
246 actions.push_back (_("Just close"));
247 actions.push_back (_("Save and close"));
248 switch (ask_about_saving_session (actions)) {
254 _session->save_state ("");
262 meterbridge->hide ();
263 theme_manager->hide ();
264 audio_port_matrix->hide();
265 midi_port_matrix->hide();
266 route_params->hide();
269 second_connection.disconnect ();
270 point_one_second_connection.disconnect ();
271 point_zero_something_second_connection.disconnect();
274 meter_box.remove(*editor_meter);
277 editor_meter_peak_display.hide();
280 ActionManager::set_sensitive (ActionManager::session_sensitive_actions, false);
282 rec_button.set_sensitive (false);
284 WM::Manager::instance().set_session ((ARDOUR::Session*) 0);
286 if (ARDOUR_UI::instance()->video_timeline) {
287 ARDOUR_UI::instance()->video_timeline->close_session();
293 /* drop everything attached to the blink signal */
300 session_loaded = false;
302 update_buffer_load ();
308 _hide_splash (gpointer arg)
310 ((ARDOUR_UI*)arg)->hide_splash();
315 ARDOUR_UI::goto_editor_window ()
317 if (splash && splash->is_visible()) {
318 // in 2 seconds, hide the splash screen
319 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 2000);
322 editor->show_window ();
324 /* mixer should now be on top */
325 WM::Manager::instance().set_transient_for (editor);
326 _mixer_on_top = false;
330 ARDOUR_UI::goto_mixer_window ()
332 Glib::RefPtr<Gdk::Window> win;
333 Glib::RefPtr<Gdk::Screen> screen;
336 win = editor->get_window ();
340 screen = win->get_screen();
342 screen = Gdk::Screen::get_default();
345 if (g_getenv ("ARDOUR_LOVES_STUPID_TINY_SCREENS") == 0 && screen && screen->get_height() < 700) {
346 Gtk::MessageDialog msg (_("This screen is not tall enough to display the mixer window"));
351 mixer->show_window ();
353 /* mixer should now be on top */
354 WM::Manager::instance().set_transient_for (mixer);
355 _mixer_on_top = true;
359 ARDOUR_UI::toggle_mixer_window ()
361 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("toggle-mixer"));
366 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
368 if (tact->get_active()) {
369 goto_mixer_window ();
376 ARDOUR_UI::toggle_meterbridge ()
378 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("toggle-meterbridge"));
383 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
385 if (tact->get_active()) {
386 meterbridge->show_window ();
388 meterbridge->hide_window (NULL);
393 ARDOUR_UI::toggle_editor_mixer ()
395 bool obscuring = false;
396 /* currently, if windows are on different
397 screens then we do nothing; but in the
398 future we may want to bring the window
399 to the front or something, so I'm leaving this
400 variable for future use
402 bool same_screen = true;
404 if (editor && mixer) {
406 /* remeber: Screen != Monitor (Screen is a separately rendered
407 * continuous geometry that make include 1 or more monitors.
410 if (editor->get_screen() != mixer->get_screen() && (mixer->get_screen() != 0) && (editor->get_screen() != 0)) {
411 // different screens, so don't do anything
414 // they are on the same screen, see if they are obscuring each other
419 editor->get_position (ex, ey);
420 editor->get_size (ew, eh);
422 mixer->get_position (mx, my);
423 mixer->get_size (mw, mh);
439 if (gdk_rectangle_intersect (&e, &m, &r)) {
445 if (mixer && !mixer->not_visible() && mixer->property_has_toplevel_focus()) {
446 if (obscuring && same_screen) {
447 goto_editor_window();
449 } else if (editor && !editor->not_visible() && editor->property_has_toplevel_focus()) {
450 if (obscuring && same_screen) {
453 } else if (mixer && mixer->not_visible()) {
454 if (obscuring && same_screen) {
455 goto_mixer_window ();
457 } else if (editor && editor->not_visible()) {
458 if (obscuring && same_screen) {
459 goto_editor_window ();
461 } else if (obscuring && same_screen) {
462 //it's unclear what to do here, so just do the opposite of what we did last time (old behavior)
464 goto_editor_window ();
466 goto_mixer_window ();
472 ARDOUR_UI::new_midi_tracer_window ()
474 RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("NewMIDITracer"));
479 std::list<MidiTracer*>::iterator i = _midi_tracer_windows.begin ();
480 while (i != _midi_tracer_windows.end() && (*i)->get_visible() == true) {
484 if (i == _midi_tracer_windows.end()) {
485 /* all our MIDITracer windows are visible; make a new one */
486 MidiTracer* t = new MidiTracer ();
488 _midi_tracer_windows.push_back (t);
490 /* re-use the hidden one */
496 ARDOUR_UI::create_bundle_manager ()
498 return new BundleManager (_session);
502 ARDOUR_UI::create_add_video_dialog ()
504 return new AddVideoDialog (_session);
508 ARDOUR_UI::create_session_option_editor ()
510 return new SessionOptionEditor (_session);
514 ARDOUR_UI::create_big_clock_window ()
516 return new BigClockWindow (*big_clock);
520 ARDOUR_UI::handle_locations_change (Location *)
523 if (_session->locations()->num_range_markers()) {
524 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, true);
526 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, false);
532 ARDOUR_UI::main_window_state_event_handler (GdkEventWindowState* ev, bool window_was_editor)
534 if (window_was_editor) {
536 if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
537 (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
538 if (big_clock_window) {
539 big_clock_window->set_transient_for (*editor);
545 if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
546 (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
547 if (big_clock_window) {
548 big_clock_window->set_transient_for (*mixer);
557 ARDOUR_UI::editor_meter_peak_button_release (GdkEventButton* ev)
559 if (ev->button == 1 && Gtkmm2ext::Keyboard::modifier_state_equals (ev->state, Gtkmm2ext::Keyboard::PrimaryModifier|Gtkmm2ext::Keyboard::TertiaryModifier)) {
560 ArdourMeter::ResetAllPeakDisplays ();
561 } else if (ev->button == 1 && Gtkmm2ext::Keyboard::modifier_state_equals (ev->state, Gtkmm2ext::Keyboard::PrimaryModifier)) {
562 if (_session->master_out()) {
563 ArdourMeter::ResetGroupPeakDisplays (_session->master_out()->route_group());
565 } else if (_session->master_out()) {
566 ArdourMeter::ResetRoutePeakDisplays (_session->master_out().get());