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"
59 #include <gtkmm2ext/keyboard.h>
63 using namespace ARDOUR;
67 using namespace Gtkmm2ext;
70 ARDOUR_UI::set_session (Session *s)
72 SessionHandlePtr::set_session (s);
75 WM::Manager::instance().set_session (s);
76 /* Session option editor cannot exist across change-of-session */
77 session_option_editor.drop_window ();
78 /* Ditto for AddVideoDialog */
79 add_video_dialog.drop_window ();
83 const XMLNode* node = _session->extra_xml (X_("UI"));
86 const XMLNodeList& children = node->children();
87 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
88 if ((*i)->name() == GUIObjectState::xml_node_name) {
89 gui_object_state->load (**i);
95 WM::Manager::instance().set_session (s);
97 AutomationWatch::instance().set_session (s);
100 shuttle_box->set_session (s);
103 primary_clock->set_session (s);
104 secondary_clock->set_session (s);
105 big_clock->set_session (s);
106 time_info_box->set_session (s);
107 video_timeline->set_session (s);
109 /* sensitize menu bar options that are now valid */
111 ActionManager::set_sensitive (ActionManager::session_sensitive_actions, true);
112 ActionManager::set_sensitive (ActionManager::write_sensitive_actions, _session->writable());
114 if (_session->locations()->num_range_markers()) {
115 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, true);
117 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, false);
120 if (!_session->monitor_out()) {
121 Glib::RefPtr<Action> act = ActionManager::get_action (X_("options"), X_("SoloViaBus"));
123 act->set_sensitive (false);
127 /* allow wastebasket flush again */
129 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
131 act->set_sensitive (true);
134 /* there are never any selections on startup */
136 ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, false);
137 ActionManager::set_sensitive (ActionManager::track_selection_sensitive_actions, false);
138 ActionManager::set_sensitive (ActionManager::line_selection_sensitive_actions, false);
139 ActionManager::set_sensitive (ActionManager::point_selection_sensitive_actions, false);
140 ActionManager::set_sensitive (ActionManager::playlist_selection_sensitive_actions, false);
142 rec_button.set_sensitive (true);
144 solo_alert_button.set_active (_session->soloing());
146 setup_session_options ();
148 Blink.connect (sigc::mem_fun(*this, &ARDOUR_UI::transport_rec_enable_blink));
149 Blink.connect (sigc::mem_fun(*this, &ARDOUR_UI::solo_blink));
150 Blink.connect (sigc::mem_fun(*this, &ARDOUR_UI::sync_blink));
151 Blink.connect (sigc::mem_fun(*this, &ARDOUR_UI::audition_blink));
152 Blink.connect (sigc::mem_fun(*this, &ARDOUR_UI::feedback_blink));
154 _session->RecordStateChanged.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::record_state_changed, this), gui_context());
155 _session->StepEditStatusChange.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::step_edit_status_change, this, _1), gui_context());
156 _session->TransportStateChange.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::map_transport_state, this), gui_context());
157 _session->DirtyChanged.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_autosave, this), gui_context());
159 _session->Xrun.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::xrun_handler, this, _1), gui_context());
160 _session->SoloActive.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::soloing_changed, this, _1), gui_context());
161 _session->AuditionActive.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::auditioning_changed, this, _1), gui_context());
162 _session->locations()->added.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::handle_locations_change, this, _1), gui_context());
163 _session->locations()->removed.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::handle_locations_change, this, _1), gui_context());
164 _session->config.ParameterChanged.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_parameter_changed, this, _1), gui_context ());
166 /* Clocks are on by default after we are connected to a session, so show that here.
169 connect_dependents_to_session (s);
171 /* listen to clock mode changes. don't do this earlier because otherwise as the clocks
172 restore their modes or are explicitly set, we will cause the "new" mode to be saved
173 back to the session XML ("Extra") state.
176 AudioClock::ModeChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::store_clock_modes));
178 Glib::signal_idle().connect (sigc::mem_fun (*this, &ARDOUR_UI::first_idle));
183 map_transport_state ();
185 second_connection = Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::every_second), 1000);
186 point_one_second_connection = Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::every_point_one_seconds), 100);
187 point_zero_something_second_connection = Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::every_point_zero_something_seconds), 40);
188 set_fps_timeout_connection();
192 if (meter_box.get_parent()) {
193 transport_tearoff_hbox.remove (meter_box);
194 transport_tearoff_hbox.remove (editor_meter_peak_display);
198 meter_box.remove(*editor_meter);
201 editor_meter_peak_display.hide();
204 if (meter_box.get_parent()) {
205 transport_tearoff_hbox.remove (meter_box);
206 transport_tearoff_hbox.remove (editor_meter_peak_display);
210 _session->master_out() &&
211 _session->master_out()->n_outputs().n(DataType::AUDIO) > 0) {
213 if (!ARDOUR::Profile->get_trx()) {
214 editor_meter = new LevelMeterHBox(_session);
215 editor_meter->set_meter (_session->master_out()->shared_peak_meter().get());
216 editor_meter->clear_meters();
217 editor_meter->set_type (_session->master_out()->meter_type());
218 editor_meter->setup_meters (30, 12, 6);
219 editor_meter->show();
220 meter_box.pack_start(*editor_meter);
223 ArdourMeter::ResetAllPeakDisplays.connect (sigc::mem_fun(*this, &ARDOUR_UI::reset_peak_display));
224 ArdourMeter::ResetRoutePeakDisplays.connect (sigc::mem_fun(*this, &ARDOUR_UI::reset_route_peak_display));
225 ArdourMeter::ResetGroupPeakDisplays.connect (sigc::mem_fun(*this, &ARDOUR_UI::reset_group_peak_display));
227 editor_meter_peak_display.set_name ("meterbridge peakindicator");
228 editor_meter_peak_display.unset_flags (Gtk::CAN_FOCUS);
229 editor_meter_peak_display.set_size_request(8, -1);
230 editor_meter_peak_display.set_corner_radius(3);
232 editor_meter_max_peak = -INFINITY;
233 editor_meter_peak_display.signal_button_release_event().connect (sigc::mem_fun(*this, &ARDOUR_UI::editor_meter_peak_button_release), false);
235 if (Config->get_show_editor_meter() && !ARDOUR::Profile->get_trx()) {
236 transport_tearoff_hbox.pack_start (meter_box, false, false);
237 transport_tearoff_hbox.pack_start (editor_meter_peak_display, false, false);
239 editor_meter_peak_display.show();
245 ARDOUR_UI::unload_session (bool hide_stuff)
248 ARDOUR_UI::instance()->video_timeline->sync_session_state();
251 if (_session && _session->dirty()) {
252 std::vector<std::string> actions;
253 actions.push_back (_("Don't close"));
254 actions.push_back (_("Just close"));
255 actions.push_back (_("Save and close"));
256 switch (ask_about_saving_session (actions)) {
262 _session->save_state ("");
268 // tear down session specific CPI (owned by rc_config_editor which can remain)
269 ControlProtocolManager& m = ControlProtocolManager::instance ();
270 for (std::list<ControlProtocolInfo*>::iterator i = m.control_protocol_info.begin(); i != m.control_protocol_info.end(); ++i) {
271 if (*i && (*i)->protocol && (*i)->protocol->has_editor ()) {
272 (*i)->protocol->tear_down_gui ();
280 meterbridge->hide ();
281 theme_manager->hide ();
282 audio_port_matrix->hide();
283 midi_port_matrix->hide();
284 route_params->hide();
287 second_connection.disconnect ();
288 point_one_second_connection.disconnect ();
289 point_zero_something_second_connection.disconnect();
290 fps_connection.disconnect();
293 meter_box.remove(*editor_meter);
296 editor_meter_peak_display.hide();
299 ActionManager::set_sensitive (ActionManager::session_sensitive_actions, false);
301 rec_button.set_sensitive (false);
303 WM::Manager::instance().set_session ((ARDOUR::Session*) 0);
305 if (ARDOUR_UI::instance()->video_timeline) {
306 ARDOUR_UI::instance()->video_timeline->close_session();
312 /* drop everything attached to the blink signal */
319 session_loaded = false;
321 update_buffer_load ();
327 _hide_splash (gpointer arg)
329 ((ARDOUR_UI*)arg)->hide_splash();
334 ARDOUR_UI::goto_editor_window ()
336 if (splash && splash->is_visible()) {
337 // in 2 seconds, hide the splash screen
338 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 2000);
341 editor->show_window ();
343 /* mixer should now be on top */
344 WM::Manager::instance().set_transient_for (editor);
345 _mixer_on_top = false;
349 ARDOUR_UI::goto_mixer_window ()
351 Glib::RefPtr<Gdk::Window> win;
352 Glib::RefPtr<Gdk::Screen> screen;
355 win = editor->get_window ();
359 screen = win->get_screen();
361 screen = Gdk::Screen::get_default();
364 if (g_getenv ("ARDOUR_LOVES_STUPID_TINY_SCREENS") == 0 && screen && screen->get_height() < 700) {
365 Gtk::MessageDialog msg (_("This screen is not tall enough to display the mixer window"));
370 mixer->show_window ();
372 /* mixer should now be on top */
373 WM::Manager::instance().set_transient_for (mixer);
374 _mixer_on_top = true;
378 ARDOUR_UI::toggle_mixer_window ()
380 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("toggle-mixer"));
385 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
387 if (tact->get_active()) {
388 goto_mixer_window ();
395 ARDOUR_UI::toggle_meterbridge ()
397 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("toggle-meterbridge"));
402 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
404 if (tact->get_active()) {
405 meterbridge->show_window ();
407 meterbridge->hide_window (NULL);
412 ARDOUR_UI::toggle_editor_mixer ()
414 bool obscuring = false;
415 /* currently, if windows are on different
416 screens then we do nothing; but in the
417 future we may want to bring the window
418 to the front or something, so I'm leaving this
419 variable for future use
421 bool same_screen = true;
423 if (editor && mixer) {
425 /* remeber: Screen != Monitor (Screen is a separately rendered
426 * continuous geometry that make include 1 or more monitors.
429 if (editor->get_screen() != mixer->get_screen() && (mixer->get_screen() != 0) && (editor->get_screen() != 0)) {
430 // different screens, so don't do anything
433 // they are on the same screen, see if they are obscuring each other
438 editor->get_position (ex, ey);
439 editor->get_size (ew, eh);
441 mixer->get_position (mx, my);
442 mixer->get_size (mw, mh);
458 if (gdk_rectangle_intersect (&e, &m, &r)) {
464 if (mixer && !mixer->not_visible() && mixer->property_has_toplevel_focus()) {
465 if (obscuring && same_screen) {
466 goto_editor_window();
468 } else if (editor && !editor->not_visible() && editor->property_has_toplevel_focus()) {
469 if (obscuring && same_screen) {
472 } else if (mixer && mixer->not_visible()) {
473 if (obscuring && same_screen) {
474 goto_mixer_window ();
476 } else if (editor && editor->not_visible()) {
477 if (obscuring && same_screen) {
478 goto_editor_window ();
480 } else if (obscuring && same_screen) {
481 //it's unclear what to do here, so just do the opposite of what we did last time (old behavior)
483 goto_editor_window ();
485 goto_mixer_window ();
491 ARDOUR_UI::new_midi_tracer_window ()
493 RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("NewMIDITracer"));
498 std::list<MidiTracer*>::iterator i = _midi_tracer_windows.begin ();
499 while (i != _midi_tracer_windows.end() && (*i)->get_visible() == true) {
503 if (i == _midi_tracer_windows.end()) {
504 /* all our MIDITracer windows are visible; make a new one */
505 MidiTracer* t = new MidiTracer ();
507 _midi_tracer_windows.push_back (t);
509 /* re-use the hidden one */
515 ARDOUR_UI::create_bundle_manager ()
517 return new BundleManager (_session);
521 ARDOUR_UI::create_add_video_dialog ()
523 return new AddVideoDialog (_session);
527 ARDOUR_UI::create_session_option_editor ()
529 return new SessionOptionEditor (_session);
533 ARDOUR_UI::create_big_clock_window ()
535 return new BigClockWindow (*big_clock);
539 ARDOUR_UI::handle_locations_change (Location *)
542 if (_session->locations()->num_range_markers()) {
543 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, true);
545 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, false);
551 ARDOUR_UI::main_window_state_event_handler (GdkEventWindowState* ev, bool window_was_editor)
553 if (window_was_editor) {
555 if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
556 (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
557 if (big_clock_window) {
558 big_clock_window->set_transient_for (*editor);
564 if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
565 (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
566 if (big_clock_window) {
567 big_clock_window->set_transient_for (*mixer);
576 ARDOUR_UI::editor_meter_peak_button_release (GdkEventButton* ev)
578 if (ev->button == 1 && Gtkmm2ext::Keyboard::modifier_state_equals (ev->state, Gtkmm2ext::Keyboard::PrimaryModifier|Gtkmm2ext::Keyboard::TertiaryModifier)) {
579 ArdourMeter::ResetAllPeakDisplays ();
580 } else if (ev->button == 1 && Gtkmm2ext::Keyboard::modifier_state_equals (ev->state, Gtkmm2ext::Keyboard::PrimaryModifier)) {
581 if (_session->master_out()) {
582 ArdourMeter::ResetGroupPeakDisplays (_session->master_out()->route_group());
584 } else if (_session->master_out()) {
585 ArdourMeter::ResetRoutePeakDisplays (_session->master_out().get());
591 ARDOUR_UI::toggle_mixer_space()
593 Glib::RefPtr<Action> act = ActionManager::get_action ("Common", "ToggleMaximalMixer");
596 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
597 if (tact->get_active()) {
598 mixer->maximise_mixer_space ();
600 mixer->restore_mixer_space ();