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);
189 if (meter_box.get_parent()) {
190 transport_tearoff_hbox.remove (meter_box);
191 transport_tearoff_hbox.remove (editor_meter_peak_display);
195 meter_box.remove(*editor_meter);
198 editor_meter_peak_display.hide();
202 && _session->master_out()
203 && _session->master_out()->n_outputs().n(DataType::AUDIO) > 0) {
204 editor_meter = new LevelMeterHBox(_session);
205 editor_meter->set_meter (_session->master_out()->shared_peak_meter().get());
206 editor_meter->clear_meters();
207 editor_meter->set_type (_session->master_out()->meter_type());
208 editor_meter->setup_meters (30, 12, 6);
209 editor_meter->show();
210 meter_box.pack_start(*editor_meter);
212 ArdourMeter::ResetAllPeakDisplays.connect (sigc::mem_fun(*this, &ARDOUR_UI::reset_peak_display));
213 ArdourMeter::ResetRoutePeakDisplays.connect (sigc::mem_fun(*this, &ARDOUR_UI::reset_route_peak_display));
214 ArdourMeter::ResetGroupPeakDisplays.connect (sigc::mem_fun(*this, &ARDOUR_UI::reset_group_peak_display));
216 editor_meter_peak_display.set_name ("meterbridge peakindicator");
217 editor_meter_peak_display.set_elements((ArdourButton::Element) (ArdourButton::Edge|ArdourButton::Body));
218 editor_meter_peak_display.unset_flags (Gtk::CAN_FOCUS);
219 editor_meter_peak_display.set_size_request(6, -1);
220 editor_meter_peak_display.set_corner_radius(2);
222 editor_meter_max_peak = -INFINITY;
223 editor_meter_peak_display.signal_button_release_event().connect (sigc::mem_fun(*this, &ARDOUR_UI::editor_meter_peak_button_release), false);
225 if (Config->get_show_editor_meter()) {
226 transport_tearoff_hbox.pack_start (meter_box, false, false);
227 transport_tearoff_hbox.pack_start (editor_meter_peak_display, false, false);
229 editor_meter_peak_display.show();
235 ARDOUR_UI::unload_session (bool hide_stuff)
238 ARDOUR_UI::instance()->video_timeline->sync_session_state();
241 if (_session && _session->dirty()) {
242 std::vector<std::string> actions;
243 actions.push_back (_("Don't close"));
244 actions.push_back (_("Just close"));
245 actions.push_back (_("Save and close"));
246 switch (ask_about_saving_session (actions)) {
252 _session->save_state ("");
260 meterbridge->hide ();
261 theme_manager->hide ();
262 audio_port_matrix->hide();
263 midi_port_matrix->hide();
264 route_params->hide();
267 second_connection.disconnect ();
268 point_one_second_connection.disconnect ();
269 point_zero_something_second_connection.disconnect();
272 meter_box.remove(*editor_meter);
275 editor_meter_peak_display.hide();
278 ActionManager::set_sensitive (ActionManager::session_sensitive_actions, false);
280 rec_button.set_sensitive (false);
282 WM::Manager::instance().set_session ((ARDOUR::Session*) 0);
284 if (ARDOUR_UI::instance()->video_timeline) {
285 ARDOUR_UI::instance()->video_timeline->close_session();
291 /* drop everything attached to the blink signal */
298 session_loaded = false;
300 update_buffer_load ();
306 _hide_splash (gpointer arg)
308 ((ARDOUR_UI*)arg)->hide_splash();
313 ARDOUR_UI::goto_editor_window ()
315 if (splash && splash->is_visible()) {
316 // in 2 seconds, hide the splash screen
317 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 2000);
320 editor->show_window ();
322 /* mixer should now be on top */
323 WM::Manager::instance().set_transient_for (editor);
324 _mixer_on_top = false;
328 ARDOUR_UI::goto_mixer_window ()
330 Glib::RefPtr<Gdk::Window> win;
331 Glib::RefPtr<Gdk::Screen> screen;
334 win = editor->get_window ();
338 screen = win->get_screen();
340 screen = Gdk::Screen::get_default();
343 if (g_getenv ("ARDOUR_LOVES_STUPID_TINY_SCREENS") == 0 && screen && screen->get_height() < 700) {
344 Gtk::MessageDialog msg (_("This screen is not tall enough to display the mixer window"));
349 mixer->show_window ();
351 /* mixer should now be on top */
352 WM::Manager::instance().set_transient_for (mixer);
353 _mixer_on_top = true;
357 ARDOUR_UI::toggle_mixer_window ()
359 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("toggle-mixer"));
364 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
366 if (tact->get_active()) {
367 goto_mixer_window ();
374 ARDOUR_UI::toggle_meterbridge ()
376 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("toggle-meterbridge"));
381 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
383 if (tact->get_active()) {
384 meterbridge->show_window ();
386 meterbridge->hide_window (NULL);
391 ARDOUR_UI::toggle_editor_mixer ()
393 bool obscuring = false;
394 /* currently, if windows are on different
395 screens then we do nothing; but in the
396 future we may want to bring the window
397 to the front or something, so I'm leaving this
398 variable for future use
400 bool same_screen = true;
402 if (editor && mixer) {
404 /* remeber: Screen != Monitor (Screen is a separately rendered
405 * continuous geometry that make include 1 or more monitors.
408 if (editor->get_screen() != mixer->get_screen() && (mixer->get_screen() != 0) && (editor->get_screen() != 0)) {
409 // different screens, so don't do anything
412 // they are on the same screen, see if they are obscuring each other
417 editor->get_position (ex, ey);
418 editor->get_size (ew, eh);
420 mixer->get_position (mx, my);
421 mixer->get_size (mw, mh);
437 if (gdk_rectangle_intersect (&e, &m, &r)) {
443 if (mixer && !mixer->not_visible() && mixer->property_has_toplevel_focus()) {
444 if (obscuring && same_screen) {
445 goto_editor_window();
447 } else if (editor && !editor->not_visible() && editor->property_has_toplevel_focus()) {
448 if (obscuring && same_screen) {
451 } else if (mixer && mixer->not_visible()) {
452 if (obscuring && same_screen) {
453 goto_mixer_window ();
455 } else if (editor && editor->not_visible()) {
456 if (obscuring && same_screen) {
457 goto_editor_window ();
459 } else if (obscuring && same_screen) {
460 //it's unclear what to do here, so just do the opposite of what we did last time (old behavior)
462 goto_editor_window ();
464 goto_mixer_window ();
470 ARDOUR_UI::new_midi_tracer_window ()
472 RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("NewMIDITracer"));
477 std::list<MidiTracer*>::iterator i = _midi_tracer_windows.begin ();
478 while (i != _midi_tracer_windows.end() && (*i)->get_visible() == true) {
482 if (i == _midi_tracer_windows.end()) {
483 /* all our MIDITracer windows are visible; make a new one */
484 MidiTracer* t = new MidiTracer ();
486 _midi_tracer_windows.push_back (t);
488 /* re-use the hidden one */
494 ARDOUR_UI::create_bundle_manager ()
496 return new BundleManager (_session);
500 ARDOUR_UI::create_add_video_dialog ()
502 return new AddVideoDialog (_session);
506 ARDOUR_UI::create_session_option_editor ()
508 return new SessionOptionEditor (_session);
512 ARDOUR_UI::create_big_clock_window ()
514 return new BigClockWindow (*big_clock);
518 ARDOUR_UI::handle_locations_change (Location *)
521 if (_session->locations()->num_range_markers()) {
522 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, true);
524 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, false);
530 ARDOUR_UI::main_window_state_event_handler (GdkEventWindowState* ev, bool window_was_editor)
532 if (window_was_editor) {
534 if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
535 (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
536 if (big_clock_window) {
537 big_clock_window->set_transient_for (*editor);
543 if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
544 (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
545 if (big_clock_window) {
546 big_clock_window->set_transient_for (*mixer);
555 ARDOUR_UI::editor_meter_peak_button_release (GdkEventButton* ev)
557 if (ev->button == 1 && Gtkmm2ext::Keyboard::modifier_state_equals (ev->state, Gtkmm2ext::Keyboard::PrimaryModifier|Gtkmm2ext::Keyboard::TertiaryModifier)) {
558 ArdourMeter::ResetAllPeakDisplays ();
559 } else if (ev->button == 1 && Gtkmm2ext::Keyboard::modifier_state_equals (ev->state, Gtkmm2ext::Keyboard::PrimaryModifier)) {
560 if (_session->master_out()) {
561 ArdourMeter::ResetGroupPeakDisplays (_session->master_out()->route_group());
563 } else if (_session->master_out()) {
564 ArdourMeter::ResetRoutePeakDisplays (_session->master_out().get());