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);
189 if (meter_box.get_parent()) {
190 transport_tearoff_hbox.remove (meter_box);
191 transport_tearoff_hbox.remove (editor_meter_peak_display);
195 meter_box.remove(*editor_meter);
198 editor_meter_peak_display.hide();
201 if (meter_box.get_parent()) {
202 transport_tearoff_hbox.remove (meter_box);
203 transport_tearoff_hbox.remove (editor_meter_peak_display);
207 _session->master_out() &&
208 _session->master_out()->n_outputs().n(DataType::AUDIO) > 0) {
210 if (!ARDOUR::Profile->get_trx()) {
211 editor_meter = new LevelMeterHBox(_session);
212 editor_meter->set_meter (_session->master_out()->shared_peak_meter().get());
213 editor_meter->clear_meters();
214 editor_meter->set_type (_session->master_out()->meter_type());
215 editor_meter->setup_meters (30, 12, 6);
216 editor_meter->show();
217 meter_box.pack_start(*editor_meter);
220 ArdourMeter::ResetAllPeakDisplays.connect (sigc::mem_fun(*this, &ARDOUR_UI::reset_peak_display));
221 ArdourMeter::ResetRoutePeakDisplays.connect (sigc::mem_fun(*this, &ARDOUR_UI::reset_route_peak_display));
222 ArdourMeter::ResetGroupPeakDisplays.connect (sigc::mem_fun(*this, &ARDOUR_UI::reset_group_peak_display));
224 editor_meter_peak_display.set_name ("meterbridge peakindicator");
225 editor_meter_peak_display.unset_flags (Gtk::CAN_FOCUS);
226 editor_meter_peak_display.set_size_request(10, -1);
227 editor_meter_peak_display.set_corner_radius(1);
229 editor_meter_max_peak = -INFINITY;
230 editor_meter_peak_display.signal_button_release_event().connect (sigc::mem_fun(*this, &ARDOUR_UI::editor_meter_peak_button_release), false);
232 if (Config->get_show_editor_meter() && !ARDOUR::Profile->get_trx()) {
233 transport_tearoff_hbox.pack_start (meter_box, false, false);
234 transport_tearoff_hbox.pack_start (editor_meter_peak_display, false, false);
236 editor_meter_peak_display.show();
242 ARDOUR_UI::unload_session (bool hide_stuff)
245 ARDOUR_UI::instance()->video_timeline->sync_session_state();
248 if (_session && _session->dirty()) {
249 std::vector<std::string> actions;
250 actions.push_back (_("Don't close"));
251 actions.push_back (_("Just close"));
252 actions.push_back (_("Save and close"));
253 switch (ask_about_saving_session (actions)) {
259 _session->save_state ("");
267 meterbridge->hide ();
268 theme_manager->hide ();
269 audio_port_matrix->hide();
270 midi_port_matrix->hide();
271 route_params->hide();
274 second_connection.disconnect ();
275 point_one_second_connection.disconnect ();
276 point_zero_something_second_connection.disconnect();
279 meter_box.remove(*editor_meter);
282 editor_meter_peak_display.hide();
285 ActionManager::set_sensitive (ActionManager::session_sensitive_actions, false);
287 rec_button.set_sensitive (false);
289 WM::Manager::instance().set_session ((ARDOUR::Session*) 0);
291 if (ARDOUR_UI::instance()->video_timeline) {
292 ARDOUR_UI::instance()->video_timeline->close_session();
298 /* drop everything attached to the blink signal */
305 session_loaded = false;
307 update_buffer_load ();
313 _hide_splash (gpointer arg)
315 ((ARDOUR_UI*)arg)->hide_splash();
320 ARDOUR_UI::goto_editor_window ()
322 if (splash && splash->is_visible()) {
323 // in 2 seconds, hide the splash screen
324 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 2000);
327 editor->show_window ();
329 /* mixer should now be on top */
330 WM::Manager::instance().set_transient_for (editor);
331 _mixer_on_top = false;
335 ARDOUR_UI::goto_mixer_window ()
337 Glib::RefPtr<Gdk::Window> win;
338 Glib::RefPtr<Gdk::Screen> screen;
341 win = editor->get_window ();
345 screen = win->get_screen();
347 screen = Gdk::Screen::get_default();
350 if (g_getenv ("ARDOUR_LOVES_STUPID_TINY_SCREENS") == 0 && screen && screen->get_height() < 700) {
351 Gtk::MessageDialog msg (_("This screen is not tall enough to display the mixer window"));
356 mixer->show_window ();
358 /* mixer should now be on top */
359 WM::Manager::instance().set_transient_for (mixer);
360 _mixer_on_top = true;
364 ARDOUR_UI::toggle_mixer_window ()
366 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("toggle-mixer"));
371 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
373 if (tact->get_active()) {
374 goto_mixer_window ();
381 ARDOUR_UI::toggle_meterbridge ()
383 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("toggle-meterbridge"));
388 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
390 if (tact->get_active()) {
391 meterbridge->show_window ();
393 meterbridge->hide_window (NULL);
398 ARDOUR_UI::toggle_editor_mixer ()
400 bool obscuring = false;
401 /* currently, if windows are on different
402 screens then we do nothing; but in the
403 future we may want to bring the window
404 to the front or something, so I'm leaving this
405 variable for future use
407 bool same_screen = true;
409 if (editor && mixer) {
411 /* remeber: Screen != Monitor (Screen is a separately rendered
412 * continuous geometry that make include 1 or more monitors.
415 if (editor->get_screen() != mixer->get_screen() && (mixer->get_screen() != 0) && (editor->get_screen() != 0)) {
416 // different screens, so don't do anything
419 // they are on the same screen, see if they are obscuring each other
424 editor->get_position (ex, ey);
425 editor->get_size (ew, eh);
427 mixer->get_position (mx, my);
428 mixer->get_size (mw, mh);
444 if (gdk_rectangle_intersect (&e, &m, &r)) {
450 if (mixer && !mixer->not_visible() && mixer->property_has_toplevel_focus()) {
451 if (obscuring && same_screen) {
452 goto_editor_window();
454 } else if (editor && !editor->not_visible() && editor->property_has_toplevel_focus()) {
455 if (obscuring && same_screen) {
458 } else if (mixer && mixer->not_visible()) {
459 if (obscuring && same_screen) {
460 goto_mixer_window ();
462 } else if (editor && editor->not_visible()) {
463 if (obscuring && same_screen) {
464 goto_editor_window ();
466 } else if (obscuring && same_screen) {
467 //it's unclear what to do here, so just do the opposite of what we did last time (old behavior)
469 goto_editor_window ();
471 goto_mixer_window ();
477 ARDOUR_UI::new_midi_tracer_window ()
479 RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("NewMIDITracer"));
484 std::list<MidiTracer*>::iterator i = _midi_tracer_windows.begin ();
485 while (i != _midi_tracer_windows.end() && (*i)->get_visible() == true) {
489 if (i == _midi_tracer_windows.end()) {
490 /* all our MIDITracer windows are visible; make a new one */
491 MidiTracer* t = new MidiTracer ();
493 _midi_tracer_windows.push_back (t);
495 /* re-use the hidden one */
501 ARDOUR_UI::create_bundle_manager ()
503 return new BundleManager (_session);
507 ARDOUR_UI::create_add_video_dialog ()
509 return new AddVideoDialog (_session);
513 ARDOUR_UI::create_session_option_editor ()
515 return new SessionOptionEditor (_session);
519 ARDOUR_UI::create_big_clock_window ()
521 return new BigClockWindow (*big_clock);
525 ARDOUR_UI::handle_locations_change (Location *)
528 if (_session->locations()->num_range_markers()) {
529 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, true);
531 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, false);
537 ARDOUR_UI::main_window_state_event_handler (GdkEventWindowState* ev, bool window_was_editor)
539 if (window_was_editor) {
541 if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
542 (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
543 if (big_clock_window) {
544 big_clock_window->set_transient_for (*editor);
550 if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
551 (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
552 if (big_clock_window) {
553 big_clock_window->set_transient_for (*mixer);
562 ARDOUR_UI::editor_meter_peak_button_release (GdkEventButton* ev)
564 if (ev->button == 1 && Gtkmm2ext::Keyboard::modifier_state_equals (ev->state, Gtkmm2ext::Keyboard::PrimaryModifier|Gtkmm2ext::Keyboard::TertiaryModifier)) {
565 ArdourMeter::ResetAllPeakDisplays ();
566 } else if (ev->button == 1 && Gtkmm2ext::Keyboard::modifier_state_equals (ev->state, Gtkmm2ext::Keyboard::PrimaryModifier)) {
567 if (_session->master_out()) {
568 ArdourMeter::ResetGroupPeakDisplays (_session->master_out()->route_group());
570 } else if (_session->master_out()) {
571 ArdourMeter::ResetRoutePeakDisplays (_session->master_out().get());
577 ARDOUR_UI::toggle_mixer_space()
579 Glib::RefPtr<Action> act = ActionManager::get_action ("Common", "ToggleMaximalMixer");
582 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
583 if (tact->get_active()) {
584 mixer->maximise_mixer_space ();
586 mixer->restore_mixer_space ();