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"
32 #include "add_route_dialog.h"
33 #include "add_video_dialog.h"
34 #include "ardour_ui.h"
35 #include "big_clock_window.h"
36 #include "bundle_manager.h"
37 #include "global_port_matrix.h"
38 #include "gui_object.h"
39 #include "gui_thread.h"
40 #include "keyeditor.h"
41 #include "location_ui.h"
42 #include "main_clock.h"
43 #include "meter_patterns.h"
44 #include "midi_tracer.h"
46 #include "public_editor.h"
47 #include "rc_option_editor.h"
48 #include "route_params_ui.h"
49 #include "shuttle_control.h"
50 #include "session_option_editor.h"
51 #include "speaker_dialog.h"
54 #include "theme_manager.h"
55 #include "time_info_box.h"
57 #include <gtkmm2ext/keyboard.h>
61 using namespace ARDOUR;
65 using namespace Gtkmm2ext;
68 ARDOUR_UI::set_session (Session *s)
70 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();
201 if (meter_box.get_parent()) {
202 transport_tearoff_hbox.remove (meter_box);
203 transport_tearoff_hbox.remove (editor_meter_peak_display);
207 _session->master_out() &&
208 _session->master_out()->n_outputs().n(DataType::AUDIO) > 0) {
210 if (!ARDOUR::Profile->get_trx()) {
211 editor_meter = new LevelMeterHBox(_session);
212 editor_meter->set_meter (_session->master_out()->shared_peak_meter().get());
213 editor_meter->clear_meters();
214 editor_meter->set_type (_session->master_out()->meter_type());
215 editor_meter->setup_meters (30, 12, 6);
216 editor_meter->show();
217 meter_box.pack_start(*editor_meter);
220 ArdourMeter::ResetAllPeakDisplays.connect (sigc::mem_fun(*this, &ARDOUR_UI::reset_peak_display));
221 ArdourMeter::ResetRoutePeakDisplays.connect (sigc::mem_fun(*this, &ARDOUR_UI::reset_route_peak_display));
222 ArdourMeter::ResetGroupPeakDisplays.connect (sigc::mem_fun(*this, &ARDOUR_UI::reset_group_peak_display));
224 editor_meter_peak_display.set_name ("meterbridge peakindicator");
225 editor_meter_peak_display.set_elements((ArdourButton::Element) (ArdourButton::Edge|ArdourButton::Body));
226 editor_meter_peak_display.unset_flags (Gtk::CAN_FOCUS);
227 editor_meter_peak_display.set_size_request(6, -1);
228 editor_meter_peak_display.set_corner_radius(2);
230 editor_meter_max_peak = -INFINITY;
231 editor_meter_peak_display.signal_button_release_event().connect (sigc::mem_fun(*this, &ARDOUR_UI::editor_meter_peak_button_release), false);
233 if (Config->get_show_editor_meter() && !ARDOUR::Profile->get_trx()) {
234 transport_tearoff_hbox.pack_start (meter_box, false, false);
235 transport_tearoff_hbox.pack_start (editor_meter_peak_display, false, false);
237 editor_meter_peak_display.show();
243 ARDOUR_UI::unload_session (bool hide_stuff)
246 ARDOUR_UI::instance()->video_timeline->sync_session_state();
249 if (_session && _session->dirty()) {
250 std::vector<std::string> actions;
251 actions.push_back (_("Don't close"));
252 actions.push_back (_("Just close"));
253 actions.push_back (_("Save and close"));
254 switch (ask_about_saving_session (actions)) {
260 _session->save_state ("");
268 meterbridge->hide ();
269 theme_manager->hide ();
270 audio_port_matrix->hide();
271 midi_port_matrix->hide();
272 route_params->hide();
275 second_connection.disconnect ();
276 point_one_second_connection.disconnect ();
277 point_zero_something_second_connection.disconnect();
280 meter_box.remove(*editor_meter);
283 editor_meter_peak_display.hide();
286 ActionManager::set_sensitive (ActionManager::session_sensitive_actions, false);
288 rec_button.set_sensitive (false);
290 WM::Manager::instance().set_session ((ARDOUR::Session*) 0);
292 if (ARDOUR_UI::instance()->video_timeline) {
293 ARDOUR_UI::instance()->video_timeline->close_session();
299 /* drop everything attached to the blink signal */
306 session_loaded = false;
308 update_buffer_load ();
314 _hide_splash (gpointer arg)
316 ((ARDOUR_UI*)arg)->hide_splash();
321 ARDOUR_UI::goto_editor_window ()
323 if (splash && splash->is_visible()) {
324 // in 2 seconds, hide the splash screen
325 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 2000);
328 editor->show_window ();
330 /* mixer should now be on top */
331 WM::Manager::instance().set_transient_for (editor);
332 _mixer_on_top = false;
336 ARDOUR_UI::goto_mixer_window ()
338 Glib::RefPtr<Gdk::Window> win;
339 Glib::RefPtr<Gdk::Screen> screen;
342 win = editor->get_window ();
346 screen = win->get_screen();
348 screen = Gdk::Screen::get_default();
351 if (g_getenv ("ARDOUR_LOVES_STUPID_TINY_SCREENS") == 0 && screen && screen->get_height() < 700) {
352 Gtk::MessageDialog msg (_("This screen is not tall enough to display the mixer window"));
357 mixer->show_window ();
359 /* mixer should now be on top */
360 WM::Manager::instance().set_transient_for (mixer);
361 _mixer_on_top = true;
365 ARDOUR_UI::toggle_mixer_window ()
367 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("toggle-mixer"));
372 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
374 if (tact->get_active()) {
375 goto_mixer_window ();
382 ARDOUR_UI::toggle_meterbridge ()
384 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("toggle-meterbridge"));
389 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
391 if (tact->get_active()) {
392 meterbridge->show_window ();
394 meterbridge->hide_window (NULL);
399 ARDOUR_UI::toggle_editor_mixer ()
401 bool obscuring = false;
402 /* currently, if windows are on different
403 screens then we do nothing; but in the
404 future we may want to bring the window
405 to the front or something, so I'm leaving this
406 variable for future use
408 bool same_screen = true;
410 if (editor && mixer) {
412 /* remeber: Screen != Monitor (Screen is a separately rendered
413 * continuous geometry that make include 1 or more monitors.
416 if (editor->get_screen() != mixer->get_screen() && (mixer->get_screen() != 0) && (editor->get_screen() != 0)) {
417 // different screens, so don't do anything
420 // they are on the same screen, see if they are obscuring each other
425 editor->get_position (ex, ey);
426 editor->get_size (ew, eh);
428 mixer->get_position (mx, my);
429 mixer->get_size (mw, mh);
445 if (gdk_rectangle_intersect (&e, &m, &r)) {
451 if (mixer && !mixer->not_visible() && mixer->property_has_toplevel_focus()) {
452 if (obscuring && same_screen) {
453 goto_editor_window();
455 } else if (editor && !editor->not_visible() && editor->property_has_toplevel_focus()) {
456 if (obscuring && same_screen) {
459 } else if (mixer && mixer->not_visible()) {
460 if (obscuring && same_screen) {
461 goto_mixer_window ();
463 } else if (editor && editor->not_visible()) {
464 if (obscuring && same_screen) {
465 goto_editor_window ();
467 } else if (obscuring && same_screen) {
468 //it's unclear what to do here, so just do the opposite of what we did last time (old behavior)
470 goto_editor_window ();
472 goto_mixer_window ();
478 ARDOUR_UI::new_midi_tracer_window ()
480 RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("NewMIDITracer"));
485 std::list<MidiTracer*>::iterator i = _midi_tracer_windows.begin ();
486 while (i != _midi_tracer_windows.end() && (*i)->get_visible() == true) {
490 if (i == _midi_tracer_windows.end()) {
491 /* all our MIDITracer windows are visible; make a new one */
492 MidiTracer* t = new MidiTracer ();
494 _midi_tracer_windows.push_back (t);
496 /* re-use the hidden one */
502 ARDOUR_UI::create_bundle_manager ()
504 return new BundleManager (_session);
508 ARDOUR_UI::create_add_video_dialog ()
510 return new AddVideoDialog (_session);
514 ARDOUR_UI::create_session_option_editor ()
516 return new SessionOptionEditor (_session);
520 ARDOUR_UI::create_big_clock_window ()
522 return new BigClockWindow (*big_clock);
526 ARDOUR_UI::handle_locations_change (Location *)
529 if (_session->locations()->num_range_markers()) {
530 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, true);
532 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, false);
538 ARDOUR_UI::main_window_state_event_handler (GdkEventWindowState* ev, bool window_was_editor)
540 if (window_was_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 (*editor);
551 if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
552 (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
553 if (big_clock_window) {
554 big_clock_window->set_transient_for (*mixer);
563 ARDOUR_UI::editor_meter_peak_button_release (GdkEventButton* ev)
565 if (ev->button == 1 && Gtkmm2ext::Keyboard::modifier_state_equals (ev->state, Gtkmm2ext::Keyboard::PrimaryModifier|Gtkmm2ext::Keyboard::TertiaryModifier)) {
566 ArdourMeter::ResetAllPeakDisplays ();
567 } else if (ev->button == 1 && Gtkmm2ext::Keyboard::modifier_state_equals (ev->state, Gtkmm2ext::Keyboard::PrimaryModifier)) {
568 if (_session->master_out()) {
569 ArdourMeter::ResetGroupPeakDisplays (_session->master_out()->route_group());
571 } else if (_session->master_out()) {
572 ArdourMeter::ResetRoutePeakDisplays (_session->master_out().get());
578 ARDOUR_UI::toggle_mixer_space()
580 Glib::RefPtr<Action> act = ActionManager::get_action ("Common", "ToggleMaximalMixer");
583 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
584 if (tact->get_active()) {
585 mixer->maximise_mixer_space ();
587 mixer->restore_mixer_space ();