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 #ifndef PLATFORM_WINDOWS
188 point_zero_something_second_connection = Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::every_point_zero_something_seconds), 40);
190 set_fps_timeout_connection();
194 if (meter_box.get_parent()) {
195 transport_tearoff_hbox.remove (meter_box);
196 transport_tearoff_hbox.remove (editor_meter_peak_display);
200 meter_box.remove(*editor_meter);
203 editor_meter_peak_display.hide();
206 if (meter_box.get_parent()) {
207 transport_tearoff_hbox.remove (meter_box);
208 transport_tearoff_hbox.remove (editor_meter_peak_display);
212 _session->master_out() &&
213 _session->master_out()->n_outputs().n(DataType::AUDIO) > 0) {
215 if (!ARDOUR::Profile->get_trx()) {
216 editor_meter = new LevelMeterHBox(_session);
217 editor_meter->set_meter (_session->master_out()->shared_peak_meter().get());
218 editor_meter->clear_meters();
219 editor_meter->set_type (_session->master_out()->meter_type());
220 editor_meter->setup_meters (30, 12, 6);
221 editor_meter->show();
222 meter_box.pack_start(*editor_meter);
225 ArdourMeter::ResetAllPeakDisplays.connect (sigc::mem_fun(*this, &ARDOUR_UI::reset_peak_display));
226 ArdourMeter::ResetRoutePeakDisplays.connect (sigc::mem_fun(*this, &ARDOUR_UI::reset_route_peak_display));
227 ArdourMeter::ResetGroupPeakDisplays.connect (sigc::mem_fun(*this, &ARDOUR_UI::reset_group_peak_display));
229 editor_meter_peak_display.set_name ("meterbridge peakindicator");
230 editor_meter_peak_display.unset_flags (Gtk::CAN_FOCUS);
231 editor_meter_peak_display.set_size_request(8, -1);
232 editor_meter_peak_display.set_corner_radius(3);
234 editor_meter_max_peak = -INFINITY;
235 editor_meter_peak_display.signal_button_release_event().connect (sigc::mem_fun(*this, &ARDOUR_UI::editor_meter_peak_button_release), false);
237 if (Config->get_show_editor_meter() && !ARDOUR::Profile->get_trx()) {
238 transport_tearoff_hbox.pack_start (meter_box, false, false);
239 transport_tearoff_hbox.pack_start (editor_meter_peak_display, false, false);
241 editor_meter_peak_display.show();
247 ARDOUR_UI::unload_session (bool hide_stuff)
250 ARDOUR_UI::instance()->video_timeline->sync_session_state();
253 if (_session && _session->dirty()) {
254 std::vector<std::string> actions;
255 actions.push_back (_("Don't close"));
256 actions.push_back (_("Just close"));
257 actions.push_back (_("Save and close"));
258 switch (ask_about_saving_session (actions)) {
264 _session->save_state ("");
270 // tear down session specific CPI (owned by rc_config_editor which can remain)
271 ControlProtocolManager& m = ControlProtocolManager::instance ();
272 for (std::list<ControlProtocolInfo*>::iterator i = m.control_protocol_info.begin(); i != m.control_protocol_info.end(); ++i) {
273 if (*i && (*i)->protocol && (*i)->protocol->has_editor ()) {
274 (*i)->protocol->tear_down_gui ();
282 meterbridge->hide ();
283 theme_manager->hide ();
284 audio_port_matrix->hide();
285 midi_port_matrix->hide();
286 route_params->hide();
289 second_connection.disconnect ();
290 point_one_second_connection.disconnect ();
291 #ifndef PLATFORM_WINDOWS
292 point_zero_something_second_connection.disconnect();
294 fps_connection.disconnect();
297 meter_box.remove(*editor_meter);
300 editor_meter_peak_display.hide();
303 ActionManager::set_sensitive (ActionManager::session_sensitive_actions, false);
305 rec_button.set_sensitive (false);
307 WM::Manager::instance().set_session ((ARDOUR::Session*) 0);
309 if (ARDOUR_UI::instance()->video_timeline) {
310 ARDOUR_UI::instance()->video_timeline->close_session();
316 /* drop everything attached to the blink signal */
323 session_loaded = false;
325 update_buffer_load ();
331 _hide_splash (gpointer arg)
333 ((ARDOUR_UI*)arg)->hide_splash();
338 ARDOUR_UI::goto_editor_window ()
340 if (splash && splash->is_visible()) {
341 // in 2 seconds, hide the splash screen
342 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 2000);
345 editor->show_window ();
347 /* mixer should now be on top */
348 WM::Manager::instance().set_transient_for (editor);
349 _mixer_on_top = false;
353 ARDOUR_UI::goto_mixer_window ()
355 Glib::RefPtr<Gdk::Window> win;
356 Glib::RefPtr<Gdk::Screen> screen;
359 win = editor->get_window ();
363 screen = win->get_screen();
365 screen = Gdk::Screen::get_default();
368 if (g_getenv ("ARDOUR_LOVES_STUPID_TINY_SCREENS") == 0 && screen && screen->get_height() < 700) {
369 Gtk::MessageDialog msg (_("This screen is not tall enough to display the mixer window"));
374 mixer->show_window ();
376 /* mixer should now be on top */
377 WM::Manager::instance().set_transient_for (mixer);
378 _mixer_on_top = true;
382 ARDOUR_UI::toggle_mixer_window ()
384 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("toggle-mixer"));
389 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
391 if (tact->get_active()) {
392 goto_mixer_window ();
399 ARDOUR_UI::toggle_meterbridge ()
401 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("toggle-meterbridge"));
406 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
408 if (tact->get_active()) {
409 meterbridge->show_window ();
411 meterbridge->hide_window (NULL);
416 ARDOUR_UI::toggle_editor_mixer ()
418 bool obscuring = false;
419 /* currently, if windows are on different
420 screens then we do nothing; but in the
421 future we may want to bring the window
422 to the front or something, so I'm leaving this
423 variable for future use
425 bool same_screen = true;
427 if (editor && mixer) {
429 /* remeber: Screen != Monitor (Screen is a separately rendered
430 * continuous geometry that make include 1 or more monitors.
433 if (editor->get_screen() != mixer->get_screen() && (mixer->get_screen() != 0) && (editor->get_screen() != 0)) {
434 // different screens, so don't do anything
437 // they are on the same screen, see if they are obscuring each other
442 editor->get_position (ex, ey);
443 editor->get_size (ew, eh);
445 mixer->get_position (mx, my);
446 mixer->get_size (mw, mh);
462 if (gdk_rectangle_intersect (&e, &m, &r)) {
468 if (mixer && !mixer->not_visible() && mixer->property_has_toplevel_focus()) {
469 if (obscuring && same_screen) {
470 goto_editor_window();
472 } else if (editor && !editor->not_visible() && editor->property_has_toplevel_focus()) {
473 if (obscuring && same_screen) {
476 } else if (mixer && mixer->not_visible()) {
477 if (obscuring && same_screen) {
478 goto_mixer_window ();
480 } else if (editor && editor->not_visible()) {
481 if (obscuring && same_screen) {
482 goto_editor_window ();
484 } else if (obscuring && same_screen) {
485 //it's unclear what to do here, so just do the opposite of what we did last time (old behavior)
487 goto_editor_window ();
489 goto_mixer_window ();
495 ARDOUR_UI::new_midi_tracer_window ()
497 RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("NewMIDITracer"));
502 std::list<MidiTracer*>::iterator i = _midi_tracer_windows.begin ();
503 while (i != _midi_tracer_windows.end() && (*i)->get_visible() == true) {
507 if (i == _midi_tracer_windows.end()) {
508 /* all our MIDITracer windows are visible; make a new one */
509 MidiTracer* t = new MidiTracer ();
511 _midi_tracer_windows.push_back (t);
513 /* re-use the hidden one */
519 ARDOUR_UI::create_bundle_manager ()
521 return new BundleManager (_session);
525 ARDOUR_UI::create_add_video_dialog ()
527 return new AddVideoDialog (_session);
531 ARDOUR_UI::create_session_option_editor ()
533 return new SessionOptionEditor (_session);
537 ARDOUR_UI::create_big_clock_window ()
539 return new BigClockWindow (*big_clock);
543 ARDOUR_UI::handle_locations_change (Location *)
546 if (_session->locations()->num_range_markers()) {
547 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, true);
549 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, false);
555 ARDOUR_UI::main_window_state_event_handler (GdkEventWindowState* ev, bool window_was_editor)
557 if (window_was_editor) {
559 if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
560 (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
561 if (big_clock_window) {
562 big_clock_window->set_transient_for (*editor);
568 if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
569 (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
570 if (big_clock_window) {
571 big_clock_window->set_transient_for (*mixer);
580 ARDOUR_UI::editor_meter_peak_button_release (GdkEventButton* ev)
582 if (ev->button == 1 && Gtkmm2ext::Keyboard::modifier_state_equals (ev->state, Gtkmm2ext::Keyboard::PrimaryModifier|Gtkmm2ext::Keyboard::TertiaryModifier)) {
583 ArdourMeter::ResetAllPeakDisplays ();
584 } else if (ev->button == 1 && Gtkmm2ext::Keyboard::modifier_state_equals (ev->state, Gtkmm2ext::Keyboard::PrimaryModifier)) {
585 if (_session->master_out()) {
586 ArdourMeter::ResetGroupPeakDisplays (_session->master_out()->route_group());
588 } else if (_session->master_out()) {
589 ArdourMeter::ResetRoutePeakDisplays (_session->master_out().get());
595 ARDOUR_UI::toggle_mixer_space()
597 Glib::RefPtr<Action> act = ActionManager::get_action ("Common", "ToggleMaximalMixer");
600 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
601 if (tact->get_active()) {
602 mixer->maximise_mixer_space ();
604 mixer->restore_mixer_space ();