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 "meterbridge.h"
46 #include "meter_patterns.h"
47 #include "midi_tracer.h"
49 #include "public_editor.h"
50 #include "rc_option_editor.h"
51 #include "route_params_ui.h"
52 #include "shuttle_control.h"
53 #include "session_option_editor.h"
54 #include "speaker_dialog.h"
57 #include "theme_manager.h"
58 #include "time_info_box.h"
61 #include <gtkmm2ext/keyboard.h>
65 using namespace ARDOUR;
69 using namespace Gtkmm2ext;
72 ARDOUR_UI::set_session (Session *s)
74 SessionHandlePtr::set_session (s);
77 WM::Manager::instance().set_session (s);
78 /* Session option editor cannot exist across change-of-session */
79 session_option_editor.drop_window ();
80 /* Ditto for AddVideoDialog */
81 add_video_dialog.drop_window ();
85 const XMLNode* node = _session->extra_xml (X_("UI"));
88 const XMLNodeList& children = node->children();
89 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
90 if ((*i)->name() == GUIObjectState::xml_node_name) {
91 gui_object_state->load (**i);
97 WM::Manager::instance().set_session (s);
99 AutomationWatch::instance().set_session (s);
102 shuttle_box->set_session (s);
105 primary_clock->set_session (s);
106 secondary_clock->set_session (s);
107 big_clock->set_session (s);
108 time_info_box->set_session (s);
109 video_timeline->set_session (s);
111 /* sensitize menu bar options that are now valid */
113 ActionManager::set_sensitive (ActionManager::session_sensitive_actions, true);
114 ActionManager::set_sensitive (ActionManager::write_sensitive_actions, _session->writable());
116 if (_session->locations()->num_range_markers()) {
117 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, true);
119 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, false);
122 if (!_session->monitor_out()) {
123 Glib::RefPtr<Action> act = ActionManager::get_action (X_("options"), X_("SoloViaBus"));
125 act->set_sensitive (false);
129 /* allow wastebasket flush again */
131 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
133 act->set_sensitive (true);
136 /* there are never any selections on startup */
138 ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, false);
139 ActionManager::set_sensitive (ActionManager::track_selection_sensitive_actions, false);
140 ActionManager::set_sensitive (ActionManager::line_selection_sensitive_actions, false);
141 ActionManager::set_sensitive (ActionManager::point_selection_sensitive_actions, false);
142 ActionManager::set_sensitive (ActionManager::playlist_selection_sensitive_actions, false);
144 rec_button.set_sensitive (true);
146 solo_alert_button.set_active (_session->soloing());
148 setup_session_options ();
150 blink_connection = Timers::blink_connect (sigc::mem_fun(*this, &ARDOUR_UI::blink_handler));
152 _session->SaveSessionRequested.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::save_session_at_its_request, this, _1), gui_context());
153 _session->RecordStateChanged.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::record_state_changed, this), gui_context());
154 _session->StepEditStatusChange.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::step_edit_status_change, this, _1), gui_context());
155 _session->TransportStateChange.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::map_transport_state, this), gui_context());
156 _session->DirtyChanged.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_autosave, this), gui_context());
158 _session->Xrun.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::xrun_handler, this, _1), gui_context());
159 _session->SoloActive.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::soloing_changed, this, _1), gui_context());
160 _session->AuditionActive.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::auditioning_changed, this, _1), gui_context());
161 _session->locations()->added.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::handle_locations_change, this, _1), gui_context());
162 _session->locations()->removed.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::handle_locations_change, this, _1), gui_context());
163 _session->config.ParameterChanged.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_parameter_changed, this, _1), gui_context ());
165 /* Clocks are on by default after we are connected to a session, so show that here.
168 connect_dependents_to_session (s);
170 /* listen to clock mode changes. don't do this earlier because otherwise as the clocks
171 restore their modes or are explicitly set, we will cause the "new" mode to be saved
172 back to the session XML ("Extra") state.
175 AudioClock::ModeChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::store_clock_modes));
177 Glib::signal_idle().connect (sigc::mem_fun (*this, &ARDOUR_UI::first_idle));
181 map_transport_state ();
183 second_connection = Timers::second_connect (sigc::mem_fun(*this, &ARDOUR_UI::every_second));
184 point_one_second_connection = Timers::rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::every_point_one_seconds));
185 point_zero_something_second_connection = Timers::super_rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::every_point_zero_something_seconds));
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 (std::max(9.f, rintf(8.f * UIConfiguration::instance().get_ui_scale())), -1);
228 editor_meter_peak_display.set_corner_radius (3.0);
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 (UIConfiguration::instance().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 ("");
266 // tear down session specific CPI (owned by rc_config_editor which can remain)
267 ControlProtocolManager& m = ControlProtocolManager::instance ();
268 for (std::list<ControlProtocolInfo*>::iterator i = m.control_protocol_info.begin(); i != m.control_protocol_info.end(); ++i) {
269 if (*i && (*i)->protocol && (*i)->protocol->has_editor ()) {
270 (*i)->protocol->tear_down_gui ();
278 meterbridge->hide ();
279 audio_port_matrix->hide();
280 midi_port_matrix->hide();
281 route_params->hide();
284 second_connection.disconnect ();
285 point_one_second_connection.disconnect ();
286 point_zero_something_second_connection.disconnect();
287 fps_connection.disconnect();
290 meter_box.remove(*editor_meter);
293 editor_meter_peak_display.hide();
296 ActionManager::set_sensitive (ActionManager::session_sensitive_actions, false);
298 rec_button.set_sensitive (false);
300 WM::Manager::instance().set_session ((ARDOUR::Session*) 0);
302 if (ARDOUR_UI::instance()->video_timeline) {
303 ARDOUR_UI::instance()->video_timeline->close_session();
308 /* drop everything attached to the blink signal */
310 blink_connection.disconnect ();
315 session_loaded = false;
317 update_buffer_load ();
323 _hide_splash (gpointer arg)
325 ((ARDOUR_UI*)arg)->hide_splash();
330 ARDOUR_UI::goto_editor_window ()
332 if (splash && splash->is_visible()) {
333 // in 2 seconds, hide the splash screen
334 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 2000);
337 editor->show_window ();
339 /* mixer should now be on top */
340 if (UIConfiguration::instance().get_transients_follow_front()) {
341 WM::Manager::instance().set_transient_for (editor);
343 _mixer_on_top = false;
347 ARDOUR_UI::goto_mixer_window ()
349 Glib::RefPtr<Gdk::Window> win;
350 Glib::RefPtr<Gdk::Screen> screen;
353 win = editor->get_window ();
357 screen = win->get_screen();
359 screen = Gdk::Screen::get_default();
362 if (g_getenv ("ARDOUR_LOVES_STUPID_TINY_SCREENS") == 0 && screen && screen->get_height() < 700) {
363 Gtk::MessageDialog msg (_("This screen is not tall enough to display the mixer window"));
368 mixer->show_window ();
370 /* mixer should now be on top */
371 if (UIConfiguration::instance().get_transients_follow_front()) {
372 WM::Manager::instance().set_transient_for (mixer);
374 _mixer_on_top = true;
378 ARDOUR_UI::toggle_mixer_window ()
380 /* thse windows are created in ARDOUR_UI::setup_windows()
381 * it should be impossible to get here with any of them being NULL
383 assert (editor && mixer && meterbridge);
386 bool obscuring = false;
388 if (mixer->not_visible ()) {
391 else if ( (!editor->not_visible () && ARDOUR_UI_UTILS::windows_overlap (editor, mixer))
392 || (!meterbridge->not_visible () && ARDOUR_UI_UTILS::windows_overlap (meterbridge, mixer))
397 if (obscuring && (editor->property_has_toplevel_focus() || meterbridge->property_has_toplevel_focus())) {
402 goto_mixer_window ();
409 ARDOUR_UI::toggle_meterbridge ()
411 assert (editor && mixer && meterbridge);
414 bool obscuring = false;
416 if (meterbridge->not_visible ()) {
419 else if ( (!editor->not_visible() && ARDOUR_UI_UTILS::windows_overlap (editor, meterbridge))
420 || (!mixer->not_visible () && ARDOUR_UI_UTILS::windows_overlap (meterbridge, mixer))
425 if (obscuring && (editor->property_has_toplevel_focus() || mixer->property_has_toplevel_focus())) {
430 meterbridge->show_window ();
431 meterbridge->present ();
432 meterbridge->raise ();
434 meterbridge->hide_window (NULL);
439 ARDOUR_UI::toggle_editor_mixer ()
441 bool obscuring = false;
443 if (editor && mixer) {
444 if (ARDOUR_UI_UTILS::windows_overlap (editor, mixer)) {
449 if (mixer && !mixer->not_visible() && mixer->property_has_toplevel_focus()) {
451 goto_editor_window();
453 } else if (editor && !editor->not_visible() && editor->property_has_toplevel_focus()) {
457 } else if (mixer && mixer->not_visible()) {
459 goto_mixer_window ();
461 } else if (editor && editor->not_visible()) {
463 goto_editor_window ();
465 } else if (obscuring) {
466 //it's unclear what to do here, so just do the opposite of what we did last time (old behavior)
468 goto_editor_window ();
470 goto_mixer_window ();
476 ARDOUR_UI::new_midi_tracer_window ()
478 RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("NewMIDITracer"));
483 std::list<MidiTracer*>::iterator i = _midi_tracer_windows.begin ();
484 while (i != _midi_tracer_windows.end() && (*i)->get_visible() == true) {
488 if (i == _midi_tracer_windows.end()) {
489 /* all our MIDITracer windows are visible; make a new one */
490 MidiTracer* t = new MidiTracer ();
492 _midi_tracer_windows.push_back (t);
494 /* re-use the hidden one */
500 ARDOUR_UI::create_bundle_manager ()
502 return new BundleManager (_session);
506 ARDOUR_UI::create_add_video_dialog ()
508 return new AddVideoDialog (_session);
512 ARDOUR_UI::create_session_option_editor ()
514 return new SessionOptionEditor (_session);
518 ARDOUR_UI::create_big_clock_window ()
520 return new BigClockWindow (*big_clock);
524 ARDOUR_UI::handle_locations_change (Location *)
527 if (_session->locations()->num_range_markers()) {
528 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, true);
530 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, false);
536 ARDOUR_UI::main_window_state_event_handler (GdkEventWindowState* ev, bool window_was_editor)
538 if (window_was_editor) {
540 if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
541 (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
542 if (big_clock_window) {
543 big_clock_window->set_transient_for (*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 (*mixer);
561 ARDOUR_UI::editor_meter_peak_button_release (GdkEventButton* ev)
563 if (ev->button == 1 && Gtkmm2ext::Keyboard::modifier_state_equals (ev->state, Gtkmm2ext::Keyboard::PrimaryModifier|Gtkmm2ext::Keyboard::TertiaryModifier)) {
564 ArdourMeter::ResetAllPeakDisplays ();
565 } else if (ev->button == 1 && Gtkmm2ext::Keyboard::modifier_state_equals (ev->state, Gtkmm2ext::Keyboard::PrimaryModifier)) {
566 if (_session->master_out()) {
567 ArdourMeter::ResetGroupPeakDisplays (_session->master_out()->route_group());
569 } else if (_session->master_out()) {
570 ArdourMeter::ResetRoutePeakDisplays (_session->master_out().get());
576 ARDOUR_UI::toggle_mixer_space()
578 Glib::RefPtr<Action> act = ActionManager::get_action ("Common", "ToggleMaximalMixer");
581 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
582 if (tact->get_active()) {
583 mixer->maximise_mixer_space ();
585 mixer->restore_mixer_space ();
591 ARDOUR_UI::toggle_mixer_list()
593 Glib::RefPtr<Action> act = ActionManager::get_action ("Common", "ToggleMixerList");
596 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
597 mixer->show_mixer_list (tact->get_active());