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/control_protocol_manager.h"
29 #include "ardour/profile.h"
30 #include "ardour/session.h"
31 #include "control_protocol/control_protocol.h"
34 #include "add_route_dialog.h"
35 #include "add_video_dialog.h"
36 #include "ardour_ui.h"
37 #include "big_clock_window.h"
38 #include "bundle_manager.h"
39 #include "global_port_matrix.h"
40 #include "gui_object.h"
41 #include "gui_thread.h"
42 #include "keyeditor.h"
43 #include "location_ui.h"
44 #include "main_clock.h"
45 #include "meter_patterns.h"
46 #include "midi_tracer.h"
48 #include "public_editor.h"
49 #include "rc_option_editor.h"
50 #include "route_params_ui.h"
51 #include "shuttle_control.h"
52 #include "session_option_editor.h"
53 #include "speaker_dialog.h"
56 #include "theme_manager.h"
57 #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);
76 WM::Manager::instance().set_session (s);
77 /* Session option editor cannot exist across change-of-session */
78 session_option_editor.drop_window ();
79 /* Ditto for AddVideoDialog */
80 add_video_dialog.drop_window ();
84 const XMLNode* node = _session->extra_xml (X_("UI"));
87 const XMLNodeList& children = node->children();
88 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
89 if ((*i)->name() == GUIObjectState::xml_node_name) {
90 gui_object_state->load (**i);
96 WM::Manager::instance().set_session (s);
98 AutomationWatch::instance().set_session (s);
101 shuttle_box->set_session (s);
104 primary_clock->set_session (s);
105 secondary_clock->set_session (s);
106 big_clock->set_session (s);
107 time_info_box->set_session (s);
108 video_timeline->set_session (s);
110 /* sensitize menu bar options that are now valid */
112 ActionManager::set_sensitive (ActionManager::session_sensitive_actions, true);
113 ActionManager::set_sensitive (ActionManager::write_sensitive_actions, _session->writable());
115 if (_session->locations()->num_range_markers()) {
116 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, true);
118 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, false);
121 if (!_session->monitor_out()) {
122 Glib::RefPtr<Action> act = ActionManager::get_action (X_("options"), X_("SoloViaBus"));
124 act->set_sensitive (false);
128 /* allow wastebasket flush again */
130 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
132 act->set_sensitive (true);
135 /* there are never any selections on startup */
137 ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, false);
138 ActionManager::set_sensitive (ActionManager::track_selection_sensitive_actions, false);
139 ActionManager::set_sensitive (ActionManager::line_selection_sensitive_actions, false);
140 ActionManager::set_sensitive (ActionManager::point_selection_sensitive_actions, false);
141 ActionManager::set_sensitive (ActionManager::playlist_selection_sensitive_actions, false);
143 rec_button.set_sensitive (true);
145 solo_alert_button.set_active (_session->soloing());
147 setup_session_options ();
149 blink_connection = Timers::blink_connect (sigc::mem_fun(*this, &ARDOUR_UI::blink_handler));
151 _session->RecordStateChanged.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::record_state_changed, this), gui_context());
152 _session->StepEditStatusChange.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::step_edit_status_change, this, _1), gui_context());
153 _session->TransportStateChange.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::map_transport_state, this), gui_context());
154 _session->DirtyChanged.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_autosave, this), gui_context());
156 _session->Xrun.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::xrun_handler, this, _1), gui_context());
157 _session->SoloActive.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::soloing_changed, this, _1), gui_context());
158 _session->AuditionActive.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::auditioning_changed, this, _1), gui_context());
159 _session->locations()->added.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::handle_locations_change, this, _1), gui_context());
160 _session->locations()->removed.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::handle_locations_change, this, _1), gui_context());
161 _session->config.ParameterChanged.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_parameter_changed, this, _1), gui_context ());
163 /* Clocks are on by default after we are connected to a session, so show that here.
166 connect_dependents_to_session (s);
168 /* listen to clock mode changes. don't do this earlier because otherwise as the clocks
169 restore their modes or are explicitly set, we will cause the "new" mode to be saved
170 back to the session XML ("Extra") state.
173 AudioClock::ModeChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::store_clock_modes));
175 Glib::signal_idle().connect (sigc::mem_fun (*this, &ARDOUR_UI::first_idle));
179 map_transport_state ();
181 second_connection = Timers::second_connect (sigc::mem_fun(*this, &ARDOUR_UI::every_second));
182 point_one_second_connection = Timers::rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::every_point_one_seconds));
183 point_zero_something_second_connection = Timers::super_rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::every_point_zero_something_seconds));
184 set_fps_timeout_connection();
188 if (meter_box.get_parent()) {
189 transport_tearoff_hbox.remove (meter_box);
190 transport_tearoff_hbox.remove (editor_meter_peak_display);
194 meter_box.remove(*editor_meter);
197 editor_meter_peak_display.hide();
200 if (meter_box.get_parent()) {
201 transport_tearoff_hbox.remove (meter_box);
202 transport_tearoff_hbox.remove (editor_meter_peak_display);
206 _session->master_out() &&
207 _session->master_out()->n_outputs().n(DataType::AUDIO) > 0) {
209 if (!ARDOUR::Profile->get_trx()) {
210 editor_meter = new LevelMeterHBox(_session);
211 editor_meter->set_meter (_session->master_out()->shared_peak_meter().get());
212 editor_meter->clear_meters();
213 editor_meter->set_type (_session->master_out()->meter_type());
214 editor_meter->setup_meters (30, 12, 6);
215 editor_meter->show();
216 meter_box.pack_start(*editor_meter);
219 ArdourMeter::ResetAllPeakDisplays.connect (sigc::mem_fun(*this, &ARDOUR_UI::reset_peak_display));
220 ArdourMeter::ResetRoutePeakDisplays.connect (sigc::mem_fun(*this, &ARDOUR_UI::reset_route_peak_display));
221 ArdourMeter::ResetGroupPeakDisplays.connect (sigc::mem_fun(*this, &ARDOUR_UI::reset_group_peak_display));
223 editor_meter_peak_display.set_name ("meterbridge peakindicator");
224 editor_meter_peak_display.unset_flags (Gtk::CAN_FOCUS);
225 editor_meter_peak_display.set_size_request(8, -1);
226 editor_meter_peak_display.set_corner_radius(3);
228 editor_meter_max_peak = -INFINITY;
229 editor_meter_peak_display.signal_button_release_event().connect (sigc::mem_fun(*this, &ARDOUR_UI::editor_meter_peak_button_release), false);
231 if (ARDOUR_UI::config()->get_show_editor_meter() && !ARDOUR::Profile->get_trx()) {
232 transport_tearoff_hbox.pack_start (meter_box, false, false);
233 transport_tearoff_hbox.pack_start (editor_meter_peak_display, false, false);
235 editor_meter_peak_display.show();
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 ("");
264 // tear down session specific CPI (owned by rc_config_editor which can remain)
265 ControlProtocolManager& m = ControlProtocolManager::instance ();
266 for (std::list<ControlProtocolInfo*>::iterator i = m.control_protocol_info.begin(); i != m.control_protocol_info.end(); ++i) {
267 if (*i && (*i)->protocol && (*i)->protocol->has_editor ()) {
268 (*i)->protocol->tear_down_gui ();
276 meterbridge->hide ();
277 audio_port_matrix->hide();
278 midi_port_matrix->hide();
279 route_params->hide();
282 second_connection.disconnect ();
283 point_one_second_connection.disconnect ();
284 point_zero_something_second_connection.disconnect();
285 fps_connection.disconnect();
288 meter_box.remove(*editor_meter);
291 editor_meter_peak_display.hide();
294 ActionManager::set_sensitive (ActionManager::session_sensitive_actions, false);
296 rec_button.set_sensitive (false);
298 WM::Manager::instance().set_session ((ARDOUR::Session*) 0);
300 if (ARDOUR_UI::instance()->video_timeline) {
301 ARDOUR_UI::instance()->video_timeline->close_session();
306 /* drop everything attached to the blink signal */
308 blink_connection.disconnect ();
313 session_loaded = false;
315 update_buffer_load ();
321 _hide_splash (gpointer arg)
323 ((ARDOUR_UI*)arg)->hide_splash();
328 ARDOUR_UI::goto_editor_window ()
330 if (splash && splash->is_visible()) {
331 // in 2 seconds, hide the splash screen
332 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 2000);
335 editor->show_window ();
337 /* mixer should now be on top */
338 WM::Manager::instance().set_transient_for (editor);
339 _mixer_on_top = false;
343 ARDOUR_UI::goto_mixer_window ()
345 Glib::RefPtr<Gdk::Window> win;
346 Glib::RefPtr<Gdk::Screen> screen;
349 win = editor->get_window ();
353 screen = win->get_screen();
355 screen = Gdk::Screen::get_default();
358 if (g_getenv ("ARDOUR_LOVES_STUPID_TINY_SCREENS") == 0 && screen && screen->get_height() < 700) {
359 Gtk::MessageDialog msg (_("This screen is not tall enough to display the mixer window"));
364 mixer->show_window ();
366 /* mixer should now be on top */
367 WM::Manager::instance().set_transient_for (mixer);
368 _mixer_on_top = true;
372 ARDOUR_UI::toggle_mixer_window ()
374 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("toggle-mixer"));
379 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
381 if (tact->get_active()) {
382 goto_mixer_window ();
389 ARDOUR_UI::toggle_meterbridge ()
391 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("toggle-meterbridge"));
396 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
398 if (tact->get_active()) {
399 meterbridge->show_window ();
401 meterbridge->hide_window (NULL);
406 ARDOUR_UI::toggle_editor_mixer ()
408 bool obscuring = false;
409 /* currently, if windows are on different
410 screens then we do nothing; but in the
411 future we may want to bring the window
412 to the front or something, so I'm leaving this
413 variable for future use
415 bool same_screen = true;
417 if (editor && mixer) {
419 /* remeber: Screen != Monitor (Screen is a separately rendered
420 * continuous geometry that make include 1 or more monitors.
423 if (editor->get_screen() != mixer->get_screen() && (mixer->get_screen() != 0) && (editor->get_screen() != 0)) {
424 // different screens, so don't do anything
427 // they are on the same screen, see if they are obscuring each other
432 editor->get_position (ex, ey);
433 editor->get_size (ew, eh);
435 mixer->get_position (mx, my);
436 mixer->get_size (mw, mh);
452 if (gdk_rectangle_intersect (&e, &m, &r)) {
458 if (mixer && !mixer->not_visible() && mixer->property_has_toplevel_focus()) {
459 if (obscuring && same_screen) {
460 goto_editor_window();
462 } else if (editor && !editor->not_visible() && editor->property_has_toplevel_focus()) {
463 if (obscuring && same_screen) {
466 } else if (mixer && mixer->not_visible()) {
467 if (obscuring && same_screen) {
468 goto_mixer_window ();
470 } else if (editor && editor->not_visible()) {
471 if (obscuring && same_screen) {
472 goto_editor_window ();
474 } else if (obscuring && same_screen) {
475 //it's unclear what to do here, so just do the opposite of what we did last time (old behavior)
477 goto_editor_window ();
479 goto_mixer_window ();
485 ARDOUR_UI::new_midi_tracer_window ()
487 RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("NewMIDITracer"));
492 std::list<MidiTracer*>::iterator i = _midi_tracer_windows.begin ();
493 while (i != _midi_tracer_windows.end() && (*i)->get_visible() == true) {
497 if (i == _midi_tracer_windows.end()) {
498 /* all our MIDITracer windows are visible; make a new one */
499 MidiTracer* t = new MidiTracer ();
501 _midi_tracer_windows.push_back (t);
503 /* re-use the hidden one */
509 ARDOUR_UI::create_bundle_manager ()
511 return new BundleManager (_session);
515 ARDOUR_UI::create_add_video_dialog ()
517 return new AddVideoDialog (_session);
521 ARDOUR_UI::create_session_option_editor ()
523 return new SessionOptionEditor (_session);
527 ARDOUR_UI::create_big_clock_window ()
529 return new BigClockWindow (*big_clock);
533 ARDOUR_UI::handle_locations_change (Location *)
536 if (_session->locations()->num_range_markers()) {
537 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, true);
539 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, false);
545 ARDOUR_UI::main_window_state_event_handler (GdkEventWindowState* ev, bool window_was_editor)
547 if (window_was_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 (*editor);
558 if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
559 (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
560 if (big_clock_window) {
561 big_clock_window->set_transient_for (*mixer);
570 ARDOUR_UI::editor_meter_peak_button_release (GdkEventButton* ev)
572 if (ev->button == 1 && Gtkmm2ext::Keyboard::modifier_state_equals (ev->state, Gtkmm2ext::Keyboard::PrimaryModifier|Gtkmm2ext::Keyboard::TertiaryModifier)) {
573 ArdourMeter::ResetAllPeakDisplays ();
574 } else if (ev->button == 1 && Gtkmm2ext::Keyboard::modifier_state_equals (ev->state, Gtkmm2ext::Keyboard::PrimaryModifier)) {
575 if (_session->master_out()) {
576 ArdourMeter::ResetGroupPeakDisplays (_session->master_out()->route_group());
578 } else if (_session->master_out()) {
579 ArdourMeter::ResetRoutePeakDisplays (_session->master_out().get());
585 ARDOUR_UI::toggle_mixer_space()
587 Glib::RefPtr<Action> act = ActionManager::get_action ("Common", "ToggleMaximalMixer");
590 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
591 if (tact->get_active()) {
592 mixer->maximise_mixer_space ();
594 mixer->restore_mixer_space ();