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"
31 #include "add_route_dialog.h"
32 #include "add_video_dialog.h"
33 #include "ardour_ui.h"
34 #include "big_clock_window.h"
35 #include "bundle_manager.h"
36 #include "global_port_matrix.h"
37 #include "gui_object.h"
38 #include "gui_thread.h"
39 #include "keyeditor.h"
40 #include "location_ui.h"
41 #include "main_clock.h"
42 #include "midi_tracer.h"
44 #include "public_editor.h"
45 #include "rc_option_editor.h"
46 #include "route_params_ui.h"
47 #include "shuttle_control.h"
48 #include "session_option_editor.h"
49 #include "speaker_dialog.h"
52 #include "theme_manager.h"
53 #include "time_info_box.h"
57 using namespace ARDOUR;
61 using namespace Gtkmm2ext;
64 ARDOUR_UI::set_session (Session *s)
66 SessionHandlePtr::set_session (s);
68 WM::Manager::instance().set_session (s);
71 /* Session option editor cannot exist across change-of-session */
72 session_option_editor.drop_window ();
73 /* Ditto for AddVideoDialog */
74 add_video_dialog.drop_window ();
78 const XMLNode* node = _session->extra_xml (X_("UI"));
81 const XMLNodeList& children = node->children();
82 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
83 if ((*i)->name() == GUIObjectState::xml_node_name) {
84 gui_object_state->load (**i);
90 AutomationWatch::instance().set_session (s);
93 shuttle_box->set_session (s);
96 primary_clock->set_session (s);
97 secondary_clock->set_session (s);
98 big_clock->set_session (s);
99 time_info_box->set_session (s);
100 video_timeline->set_session (s);
102 /* sensitize menu bar options that are now valid */
104 ActionManager::set_sensitive (ActionManager::session_sensitive_actions, true);
105 ActionManager::set_sensitive (ActionManager::write_sensitive_actions, _session->writable());
107 if (_session->locations()->num_range_markers()) {
108 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, true);
110 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, false);
113 if (!_session->monitor_out()) {
114 Glib::RefPtr<Action> act = ActionManager::get_action (X_("options"), X_("SoloViaBus"));
116 act->set_sensitive (false);
120 /* allow wastebasket flush again */
122 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
124 act->set_sensitive (true);
127 /* there are never any selections on startup */
129 ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, false);
130 ActionManager::set_sensitive (ActionManager::track_selection_sensitive_actions, false);
131 ActionManager::set_sensitive (ActionManager::line_selection_sensitive_actions, false);
132 ActionManager::set_sensitive (ActionManager::point_selection_sensitive_actions, false);
133 ActionManager::set_sensitive (ActionManager::playlist_selection_sensitive_actions, false);
135 rec_button.set_sensitive (true);
137 solo_alert_button.set_active (_session->soloing());
139 setup_session_options ();
141 Blink.connect (sigc::mem_fun(*this, &ARDOUR_UI::transport_rec_enable_blink));
142 Blink.connect (sigc::mem_fun(*this, &ARDOUR_UI::solo_blink));
143 Blink.connect (sigc::mem_fun(*this, &ARDOUR_UI::sync_blink));
144 Blink.connect (sigc::mem_fun(*this, &ARDOUR_UI::audition_blink));
145 Blink.connect (sigc::mem_fun(*this, &ARDOUR_UI::feedback_blink));
147 _session->RecordStateChanged.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::record_state_changed, this), gui_context());
148 _session->StepEditStatusChange.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::step_edit_status_change, this, _1), gui_context());
149 _session->TransportStateChange.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::map_transport_state, this), gui_context());
150 _session->DirtyChanged.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_autosave, this), gui_context());
152 _session->Xrun.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::xrun_handler, this, _1), gui_context());
153 _session->SoloActive.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::soloing_changed, this, _1), gui_context());
154 _session->AuditionActive.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::auditioning_changed, this, _1), gui_context());
155 _session->locations()->added.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::handle_locations_change, this, _1), gui_context());
156 _session->locations()->removed.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::handle_locations_change, this, _1), gui_context());
157 _session->config.ParameterChanged.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_parameter_changed, this, _1), gui_context ());
159 #ifdef HAVE_JACK_SESSION
160 engine->JackSessionEvent.connect (*_session, MISSING_INVALIDATOR, boost::bind (&Session::jack_session_event, _session, _1), gui_context());
163 /* Clocks are on by default after we are connected to a session, so show that here.
166 connect_dependents_to_session (s);
168 /* listen to clock mode changes. don't do this earlier because otherwise as the clocks
169 restore their modes or are explicitly set, we will cause the "new" mode to be saved
170 back to the session XML ("Extra") state.
173 AudioClock::ModeChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::store_clock_modes));
175 Glib::signal_idle().connect (sigc::mem_fun (*this, &ARDOUR_UI::first_idle));
180 map_transport_state ();
182 second_connection = Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::every_second), 1000);
183 point_one_second_connection = Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::every_point_one_seconds), 100);
184 point_zero_one_second_connection = Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::every_point_zero_one_seconds), 40);
190 ARDOUR_UI::unload_session (bool hide_stuff)
193 ARDOUR_UI::instance()->video_timeline->sync_session_state();
196 if (_session && _session->dirty()) {
197 std::vector<std::string> actions;
198 actions.push_back (_("Don't close"));
199 actions.push_back (_("Just close"));
200 actions.push_back (_("Save and close"));
201 switch (ask_about_saving_session (actions)) {
207 _session->save_state ("");
215 theme_manager->hide ();
216 audio_port_matrix->hide();
217 midi_port_matrix->hide();
218 route_params->hide();
221 second_connection.disconnect ();
222 point_one_second_connection.disconnect ();
223 point_oh_five_second_connection.disconnect ();
224 point_zero_one_second_connection.disconnect();
226 ActionManager::set_sensitive (ActionManager::session_sensitive_actions, false);
228 rec_button.set_sensitive (false);
230 ARDOUR_UI::instance()->video_timeline->close_session();
235 /* drop everything attached to the blink signal */
242 session_loaded = false;
244 update_buffer_load ();
250 _hide_splash (gpointer arg)
252 ((ARDOUR_UI*)arg)->hide_splash();
257 ARDOUR_UI::goto_editor_window ()
259 if (splash && splash->is_visible()) {
260 // in 2 seconds, hide the splash screen
261 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 2000);
264 editor->show_window ();
266 /* mixer should now be on top */
267 WM::Manager::instance().set_transient_for (editor);
268 _mixer_on_top = false;
272 ARDOUR_UI::goto_mixer_window ()
274 Glib::RefPtr<Gdk::Window> win;
275 Glib::RefPtr<Gdk::Screen> screen;
278 win = editor->get_window ();
282 screen = win->get_screen();
284 screen = Gdk::Screen::get_default();
287 if (screen && screen->get_height() < 700) {
288 Gtk::MessageDialog msg (_("This screen is not tall enough to display the mixer window"));
293 mixer->show_window ();
295 /* mixer should now be on top */
296 WM::Manager::instance().set_transient_for (mixer);
297 _mixer_on_top = true;
301 ARDOUR_UI::toggle_mixer_window ()
303 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("toggle-mixer"));
308 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
310 if (tact->get_active()) {
311 goto_mixer_window ();
318 ARDOUR_UI::toggle_meterbridge ()
320 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("toggle-meterbridge"));
325 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
327 if (tact->get_active()) {
328 meterbridge->show_window ();
330 meterbridge->hide ();
335 ARDOUR_UI::toggle_editor_mixer ()
337 bool obscuring = false;
338 /* currently, if windows are on different
339 screens then we do nothing; but in the
340 future we may want to bring the window
341 to the front or something, so I'm leaving this
342 variable for future use
344 bool same_screen = true;
346 if (editor && mixer) {
348 /* remeber: Screen != Monitor (Screen is a separately rendered
349 * continuous geometry that make include 1 or more monitors.
352 if (editor->get_screen() != mixer->get_screen() && (mixer->get_screen() != 0) && (editor->get_screen() != 0)) {
353 // different screens, so don't do anything
356 // they are on the same screen, see if they are obscuring each other
361 editor->get_position (ex, ey);
362 editor->get_size (ew, eh);
364 mixer->get_position (mx, my);
365 mixer->get_size (mw, mh);
381 if (gdk_rectangle_intersect (&e, &m, &r)) {
387 if (mixer && !mixer->not_visible() && mixer->property_has_toplevel_focus()) {
388 if (obscuring && same_screen) {
389 goto_editor_window();
391 } else if (editor && !editor->not_visible() && editor->property_has_toplevel_focus()) {
392 if (obscuring && same_screen) {
395 } else if (mixer && mixer->not_visible()) {
396 if (obscuring && same_screen) {
397 goto_mixer_window ();
399 } else if (editor && editor->not_visible()) {
400 if (obscuring && same_screen) {
401 goto_editor_window ();
403 } else if (obscuring && same_screen) {
404 //it's unclear what to do here, so just do the opposite of what we did last time (old behavior)
406 goto_editor_window ();
408 goto_mixer_window ();
414 ARDOUR_UI::new_midi_tracer_window ()
416 RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("NewMIDITracer"));
421 std::list<MidiTracer*>::iterator i = _midi_tracer_windows.begin ();
422 while (i != _midi_tracer_windows.end() && (*i)->get_visible() == true) {
426 if (i == _midi_tracer_windows.end()) {
427 /* all our MIDITracer windows are visible; make a new one */
428 MidiTracer* t = new MidiTracer ();
430 _midi_tracer_windows.push_back (t);
432 /* re-use the hidden one */
438 ARDOUR_UI::create_bundle_manager ()
440 return new BundleManager (_session);
444 ARDOUR_UI::create_add_video_dialog ()
446 return new AddVideoDialog (_session);
450 ARDOUR_UI::create_session_option_editor ()
452 return new SessionOptionEditor (_session);
456 ARDOUR_UI::create_big_clock_window ()
458 return new BigClockWindow (*big_clock);
462 ARDOUR_UI::handle_locations_change (Location *)
465 if (_session->locations()->num_range_markers()) {
466 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, true);
468 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, false);
474 ARDOUR_UI::main_window_state_event_handler (GdkEventWindowState* ev, bool window_was_editor)
476 if (window_was_editor) {
478 if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
479 (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
480 if (big_clock_window) {
481 big_clock_window->set_transient_for (*editor);
487 if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
488 (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
489 if (big_clock_window) {
490 big_clock_window->set_transient_for (*mixer);