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/session.h"
27 #include "ardour/audioengine.h"
28 #include "ardour/automation_watch.h"
35 #include "add_route_dialog.h"
36 #include "add_video_dialog.h"
37 #include "ardour_ui.h"
38 #include "big_clock_window.h"
39 #include "bundle_manager.h"
40 #include "global_port_matrix.h"
41 #include "gui_object.h"
42 #include "gui_thread.h"
43 #include "keyeditor.h"
44 #include "location_ui.h"
45 #include "main_clock.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"
61 using namespace ARDOUR;
65 using namespace Gtkmm2ext;
68 ARDOUR_UI::set_session (Session *s)
70 SessionHandlePtr::set_session (s);
74 WM::Manager::instance().set_session (s);
75 /* Session option editor cannot exist across change-of-session */
76 session_option_editor.drop_window ();
77 /* Ditto for AddVideoDialog */
78 add_video_dialog.drop_window ();
82 const XMLNode* node = _session->extra_xml (X_("UI"));
85 const XMLNodeList& children = node->children();
86 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
87 if ((*i)->name() == GUIObjectState::xml_node_name) {
88 gui_object_state->load (**i);
94 WM::Manager::instance().set_session (s);
96 AutomationWatch::instance().set_session (s);
99 shuttle_box->set_session (s);
102 primary_clock->set_session (s);
103 secondary_clock->set_session (s);
104 big_clock->set_session (s);
105 time_info_box->set_session (s);
106 video_timeline->set_session (s);
108 /* sensitize menu bar options that are now valid */
110 ActionManager::set_sensitive (ActionManager::session_sensitive_actions, true);
111 ActionManager::set_sensitive (ActionManager::write_sensitive_actions, _session->writable());
113 if (_session->locations()->num_range_markers()) {
114 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, true);
116 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, false);
119 if (!_session->monitor_out()) {
120 Glib::RefPtr<Action> act = ActionManager::get_action (X_("options"), X_("SoloViaBus"));
122 act->set_sensitive (false);
126 /* allow wastebasket flush again */
128 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
130 act->set_sensitive (true);
133 /* there are never any selections on startup */
135 ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, false);
136 ActionManager::set_sensitive (ActionManager::track_selection_sensitive_actions, false);
137 ActionManager::set_sensitive (ActionManager::line_selection_sensitive_actions, false);
138 ActionManager::set_sensitive (ActionManager::point_selection_sensitive_actions, false);
139 ActionManager::set_sensitive (ActionManager::playlist_selection_sensitive_actions, false);
141 rec_button.set_sensitive (true);
143 solo_alert_button.set_active (_session->soloing());
145 setup_session_options ();
147 Blink.connect (sigc::mem_fun(*this, &ARDOUR_UI::transport_rec_enable_blink));
148 Blink.connect (sigc::mem_fun(*this, &ARDOUR_UI::solo_blink));
149 Blink.connect (sigc::mem_fun(*this, &ARDOUR_UI::sync_blink));
150 Blink.connect (sigc::mem_fun(*this, &ARDOUR_UI::audition_blink));
151 Blink.connect (sigc::mem_fun(*this, &ARDOUR_UI::feedback_blink));
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 #ifdef HAVE_JACK_SESSION
166 engine->JackSessionEvent.connect (*_session, MISSING_INVALIDATOR, boost::bind (&Session::jack_session_event, _session, _1), gui_context());
169 /* Clocks are on by default after we are connected to a session, so show that here.
172 connect_dependents_to_session (s);
174 /* listen to clock mode changes. don't do this earlier because otherwise as the clocks
175 restore their modes or are explicitly set, we will cause the "new" mode to be saved
176 back to the session XML ("Extra") state.
179 AudioClock::ModeChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::store_clock_modes));
181 Glib::signal_idle().connect (sigc::mem_fun (*this, &ARDOUR_UI::first_idle));
186 map_transport_state ();
188 second_connection = Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::every_second), 1000);
189 point_one_second_connection = Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::every_point_one_seconds), 100);
190 point_zero_something_second_connection = Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::every_point_zero_something_seconds), 40);
196 ARDOUR_UI::unload_session (bool hide_stuff)
199 ARDOUR_UI::instance()->video_timeline->sync_session_state();
202 if (_session && _session->dirty()) {
203 std::vector<std::string> actions;
204 actions.push_back (_("Don't close"));
205 actions.push_back (_("Just close"));
206 actions.push_back (_("Save and close"));
207 switch (ask_about_saving_session (actions)) {
213 _session->save_state ("");
221 meterbridge->hide ();
222 theme_manager->hide ();
223 audio_port_matrix->hide();
224 midi_port_matrix->hide();
225 route_params->hide();
228 second_connection.disconnect ();
229 point_one_second_connection.disconnect ();
230 point_zero_something_second_connection.disconnect();
232 ActionManager::set_sensitive (ActionManager::session_sensitive_actions, false);
234 rec_button.set_sensitive (false);
236 WM::Manager::instance().set_session ((ARDOUR::Session*) 0);
237 ARDOUR_UI::instance()->video_timeline->close_session();
242 /* drop everything attached to the blink signal */
249 session_loaded = false;
251 update_buffer_load ();
257 _hide_splash (gpointer arg)
259 ((ARDOUR_UI*)arg)->hide_splash();
264 ARDOUR_UI::goto_editor_window ()
266 if (splash && splash->is_visible()) {
267 // in 2 seconds, hide the splash screen
268 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 2000);
271 editor->show_window ();
273 /* mixer should now be on top */
274 WM::Manager::instance().set_transient_for (editor);
275 _mixer_on_top = false;
279 ARDOUR_UI::goto_mixer_window ()
281 Glib::RefPtr<Gdk::Window> win;
282 Glib::RefPtr<Gdk::Screen> screen;
285 win = editor->get_window ();
289 screen = win->get_screen();
291 screen = Gdk::Screen::get_default();
294 if (screen && screen->get_height() < 700) {
295 Gtk::MessageDialog msg (_("This screen is not tall enough to display the mixer window"));
300 mixer->show_window ();
302 /* mixer should now be on top */
303 WM::Manager::instance().set_transient_for (mixer);
304 _mixer_on_top = true;
308 ARDOUR_UI::toggle_mixer_window ()
310 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("toggle-mixer"));
315 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
317 if (tact->get_active()) {
318 goto_mixer_window ();
325 ARDOUR_UI::toggle_meterbridge ()
327 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("toggle-meterbridge"));
332 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
334 if (tact->get_active()) {
335 meterbridge->show_window ();
337 meterbridge->hide_window (NULL);
342 ARDOUR_UI::toggle_editor_mixer ()
344 bool obscuring = false;
345 /* currently, if windows are on different
346 screens then we do nothing; but in the
347 future we may want to bring the window
348 to the front or something, so I'm leaving this
349 variable for future use
351 bool same_screen = true;
353 if (editor && mixer) {
355 /* remeber: Screen != Monitor (Screen is a separately rendered
356 * continuous geometry that make include 1 or more monitors.
359 if (editor->get_screen() != mixer->get_screen() && (mixer->get_screen() != 0) && (editor->get_screen() != 0)) {
360 // different screens, so don't do anything
363 // they are on the same screen, see if they are obscuring each other
368 editor->get_position (ex, ey);
369 editor->get_size (ew, eh);
371 mixer->get_position (mx, my);
372 mixer->get_size (mw, mh);
388 if (gdk_rectangle_intersect (&e, &m, &r)) {
394 if (mixer && !mixer->not_visible() && mixer->property_has_toplevel_focus()) {
395 if (obscuring && same_screen) {
396 goto_editor_window();
398 } else if (editor && !editor->not_visible() && editor->property_has_toplevel_focus()) {
399 if (obscuring && same_screen) {
402 } else if (mixer && mixer->not_visible()) {
403 if (obscuring && same_screen) {
404 goto_mixer_window ();
406 } else if (editor && editor->not_visible()) {
407 if (obscuring && same_screen) {
408 goto_editor_window ();
410 } else if (obscuring && same_screen) {
411 //it's unclear what to do here, so just do the opposite of what we did last time (old behavior)
413 goto_editor_window ();
415 goto_mixer_window ();
421 ARDOUR_UI::new_midi_tracer_window ()
423 RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("NewMIDITracer"));
428 std::list<MidiTracer*>::iterator i = _midi_tracer_windows.begin ();
429 while (i != _midi_tracer_windows.end() && (*i)->get_visible() == true) {
433 if (i == _midi_tracer_windows.end()) {
434 /* all our MIDITracer windows are visible; make a new one */
435 MidiTracer* t = new MidiTracer ();
437 _midi_tracer_windows.push_back (t);
439 /* re-use the hidden one */
445 ARDOUR_UI::create_bundle_manager ()
447 return new BundleManager (_session);
451 ARDOUR_UI::create_add_video_dialog ()
453 return new AddVideoDialog (_session);
457 ARDOUR_UI::create_session_option_editor ()
459 return new SessionOptionEditor (_session);
463 ARDOUR_UI::create_big_clock_window ()
465 return new BigClockWindow (*big_clock);
469 ARDOUR_UI::handle_locations_change (Location *)
472 if (_session->locations()->num_range_markers()) {
473 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, true);
475 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, false);
481 ARDOUR_UI::main_window_state_event_handler (GdkEventWindowState* ev, bool window_was_editor)
483 if (window_was_editor) {
485 if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
486 (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
487 if (big_clock_window) {
488 big_clock_window->set_transient_for (*editor);
494 if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
495 (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
496 if (big_clock_window) {
497 big_clock_window->set_transient_for (*mixer);