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);
186 set_fps_timeout_connection();
190 if (meter_box.get_parent()) {
191 transport_tearoff_hbox.remove (meter_box);
192 transport_tearoff_hbox.remove (editor_meter_peak_display);
196 meter_box.remove(*editor_meter);
199 editor_meter_peak_display.hide();
202 if (meter_box.get_parent()) {
203 transport_tearoff_hbox.remove (meter_box);
204 transport_tearoff_hbox.remove (editor_meter_peak_display);
208 _session->master_out() &&
209 _session->master_out()->n_outputs().n(DataType::AUDIO) > 0) {
211 if (!ARDOUR::Profile->get_trx()) {
212 editor_meter = new LevelMeterHBox(_session);
213 editor_meter->set_meter (_session->master_out()->shared_peak_meter().get());
214 editor_meter->clear_meters();
215 editor_meter->set_type (_session->master_out()->meter_type());
216 editor_meter->setup_meters (30, 12, 6);
217 editor_meter->show();
218 meter_box.pack_start(*editor_meter);
221 ArdourMeter::ResetAllPeakDisplays.connect (sigc::mem_fun(*this, &ARDOUR_UI::reset_peak_display));
222 ArdourMeter::ResetRoutePeakDisplays.connect (sigc::mem_fun(*this, &ARDOUR_UI::reset_route_peak_display));
223 ArdourMeter::ResetGroupPeakDisplays.connect (sigc::mem_fun(*this, &ARDOUR_UI::reset_group_peak_display));
225 editor_meter_peak_display.set_name ("meterbridge peakindicator");
226 editor_meter_peak_display.unset_flags (Gtk::CAN_FOCUS);
227 editor_meter_peak_display.set_size_request(8, -1);
228 editor_meter_peak_display.set_corner_radius(3);
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();
278 fps_connection.disconnect();
281 meter_box.remove(*editor_meter);
284 editor_meter_peak_display.hide();
287 ActionManager::set_sensitive (ActionManager::session_sensitive_actions, false);
289 rec_button.set_sensitive (false);
291 WM::Manager::instance().set_session ((ARDOUR::Session*) 0);
293 if (ARDOUR_UI::instance()->video_timeline) {
294 ARDOUR_UI::instance()->video_timeline->close_session();
300 /* drop everything attached to the blink signal */
307 session_loaded = false;
309 update_buffer_load ();
315 _hide_splash (gpointer arg)
317 ((ARDOUR_UI*)arg)->hide_splash();
322 ARDOUR_UI::goto_editor_window ()
324 if (splash && splash->is_visible()) {
325 // in 2 seconds, hide the splash screen
326 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 2000);
329 editor->show_window ();
331 /* mixer should now be on top */
332 WM::Manager::instance().set_transient_for (editor);
333 _mixer_on_top = false;
337 ARDOUR_UI::goto_mixer_window ()
339 Glib::RefPtr<Gdk::Window> win;
340 Glib::RefPtr<Gdk::Screen> screen;
343 win = editor->get_window ();
347 screen = win->get_screen();
349 screen = Gdk::Screen::get_default();
352 if (g_getenv ("ARDOUR_LOVES_STUPID_TINY_SCREENS") == 0 && screen && screen->get_height() < 700) {
353 Gtk::MessageDialog msg (_("This screen is not tall enough to display the mixer window"));
358 mixer->show_window ();
360 /* mixer should now be on top */
361 WM::Manager::instance().set_transient_for (mixer);
362 _mixer_on_top = true;
366 ARDOUR_UI::toggle_mixer_window ()
368 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("toggle-mixer"));
373 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
375 if (tact->get_active()) {
376 goto_mixer_window ();
383 ARDOUR_UI::toggle_meterbridge ()
385 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("toggle-meterbridge"));
390 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
392 if (tact->get_active()) {
393 meterbridge->show_window ();
395 meterbridge->hide_window (NULL);
400 ARDOUR_UI::toggle_editor_mixer ()
402 bool obscuring = false;
403 /* currently, if windows are on different
404 screens then we do nothing; but in the
405 future we may want to bring the window
406 to the front or something, so I'm leaving this
407 variable for future use
409 bool same_screen = true;
411 if (editor && mixer) {
413 /* remeber: Screen != Monitor (Screen is a separately rendered
414 * continuous geometry that make include 1 or more monitors.
417 if (editor->get_screen() != mixer->get_screen() && (mixer->get_screen() != 0) && (editor->get_screen() != 0)) {
418 // different screens, so don't do anything
421 // they are on the same screen, see if they are obscuring each other
426 editor->get_position (ex, ey);
427 editor->get_size (ew, eh);
429 mixer->get_position (mx, my);
430 mixer->get_size (mw, mh);
446 if (gdk_rectangle_intersect (&e, &m, &r)) {
452 if (mixer && !mixer->not_visible() && mixer->property_has_toplevel_focus()) {
453 if (obscuring && same_screen) {
454 goto_editor_window();
456 } else if (editor && !editor->not_visible() && editor->property_has_toplevel_focus()) {
457 if (obscuring && same_screen) {
460 } else if (mixer && mixer->not_visible()) {
461 if (obscuring && same_screen) {
462 goto_mixer_window ();
464 } else if (editor && editor->not_visible()) {
465 if (obscuring && same_screen) {
466 goto_editor_window ();
468 } else if (obscuring && same_screen) {
469 //it's unclear what to do here, so just do the opposite of what we did last time (old behavior)
471 goto_editor_window ();
473 goto_mixer_window ();
479 ARDOUR_UI::new_midi_tracer_window ()
481 RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("NewMIDITracer"));
486 std::list<MidiTracer*>::iterator i = _midi_tracer_windows.begin ();
487 while (i != _midi_tracer_windows.end() && (*i)->get_visible() == true) {
491 if (i == _midi_tracer_windows.end()) {
492 /* all our MIDITracer windows are visible; make a new one */
493 MidiTracer* t = new MidiTracer ();
495 _midi_tracer_windows.push_back (t);
497 /* re-use the hidden one */
503 ARDOUR_UI::create_bundle_manager ()
505 return new BundleManager (_session);
509 ARDOUR_UI::create_add_video_dialog ()
511 return new AddVideoDialog (_session);
515 ARDOUR_UI::create_session_option_editor ()
517 return new SessionOptionEditor (_session);
521 ARDOUR_UI::create_big_clock_window ()
523 return new BigClockWindow (*big_clock);
527 ARDOUR_UI::handle_locations_change (Location *)
530 if (_session->locations()->num_range_markers()) {
531 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, true);
533 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, false);
539 ARDOUR_UI::main_window_state_event_handler (GdkEventWindowState* ev, bool window_was_editor)
541 if (window_was_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 (*editor);
552 if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
553 (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
554 if (big_clock_window) {
555 big_clock_window->set_transient_for (*mixer);
564 ARDOUR_UI::editor_meter_peak_button_release (GdkEventButton* ev)
566 if (ev->button == 1 && Gtkmm2ext::Keyboard::modifier_state_equals (ev->state, Gtkmm2ext::Keyboard::PrimaryModifier|Gtkmm2ext::Keyboard::TertiaryModifier)) {
567 ArdourMeter::ResetAllPeakDisplays ();
568 } else if (ev->button == 1 && Gtkmm2ext::Keyboard::modifier_state_equals (ev->state, Gtkmm2ext::Keyboard::PrimaryModifier)) {
569 if (_session->master_out()) {
570 ArdourMeter::ResetGroupPeakDisplays (_session->master_out()->route_group());
572 } else if (_session->master_out()) {
573 ArdourMeter::ResetRoutePeakDisplays (_session->master_out().get());
579 ARDOUR_UI::toggle_mixer_space()
581 Glib::RefPtr<Action> act = ActionManager::get_action ("Common", "ToggleMaximalMixer");
584 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
585 if (tact->get_active()) {
586 mixer->maximise_mixer_space ();
588 mixer->restore_mixer_space ();