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);
70 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 WM::Manager::instance().set_session (s);
92 AutomationWatch::instance().set_session (s);
95 shuttle_box->set_session (s);
98 primary_clock->set_session (s);
99 secondary_clock->set_session (s);
100 big_clock->set_session (s);
101 time_info_box->set_session (s);
102 video_timeline->set_session (s);
104 /* sensitize menu bar options that are now valid */
106 ActionManager::set_sensitive (ActionManager::session_sensitive_actions, true);
107 ActionManager::set_sensitive (ActionManager::write_sensitive_actions, _session->writable());
109 if (_session->locations()->num_range_markers()) {
110 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, true);
112 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, false);
115 if (!_session->monitor_out()) {
116 Glib::RefPtr<Action> act = ActionManager::get_action (X_("options"), X_("SoloViaBus"));
118 act->set_sensitive (false);
122 /* allow wastebasket flush again */
124 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
126 act->set_sensitive (true);
129 /* there are never any selections on startup */
131 ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, false);
132 ActionManager::set_sensitive (ActionManager::track_selection_sensitive_actions, false);
133 ActionManager::set_sensitive (ActionManager::line_selection_sensitive_actions, false);
134 ActionManager::set_sensitive (ActionManager::point_selection_sensitive_actions, false);
135 ActionManager::set_sensitive (ActionManager::playlist_selection_sensitive_actions, false);
137 rec_button.set_sensitive (true);
139 solo_alert_button.set_active (_session->soloing());
141 setup_session_options ();
143 Blink.connect (sigc::mem_fun(*this, &ARDOUR_UI::transport_rec_enable_blink));
144 Blink.connect (sigc::mem_fun(*this, &ARDOUR_UI::solo_blink));
145 Blink.connect (sigc::mem_fun(*this, &ARDOUR_UI::sync_blink));
146 Blink.connect (sigc::mem_fun(*this, &ARDOUR_UI::audition_blink));
147 Blink.connect (sigc::mem_fun(*this, &ARDOUR_UI::feedback_blink));
149 _session->RecordStateChanged.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::record_state_changed, this), gui_context());
150 _session->StepEditStatusChange.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::step_edit_status_change, this, _1), gui_context());
151 _session->TransportStateChange.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::map_transport_state, this), gui_context());
152 _session->DirtyChanged.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_autosave, this), gui_context());
154 _session->Xrun.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::xrun_handler, this, _1), gui_context());
155 _session->SoloActive.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::soloing_changed, this, _1), gui_context());
156 _session->AuditionActive.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::auditioning_changed, this, _1), gui_context());
157 _session->locations()->added.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::handle_locations_change, this, _1), gui_context());
158 _session->locations()->removed.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::handle_locations_change, this, _1), gui_context());
159 _session->config.ParameterChanged.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_parameter_changed, this, _1), gui_context ());
161 #ifdef HAVE_JACK_SESSION
162 engine->JackSessionEvent.connect (*_session, MISSING_INVALIDATOR, boost::bind (&Session::jack_session_event, _session, _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));
182 map_transport_state ();
184 second_connection = Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::every_second), 1000);
185 point_one_second_connection = Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::every_point_one_seconds), 100);
186 point_zero_one_second_connection = Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::every_point_zero_one_seconds), 40);
192 ARDOUR_UI::unload_session (bool hide_stuff)
195 ARDOUR_UI::instance()->video_timeline->sync_session_state();
198 if (_session && _session->dirty()) {
199 std::vector<std::string> actions;
200 actions.push_back (_("Don't close"));
201 actions.push_back (_("Just close"));
202 actions.push_back (_("Save and close"));
203 switch (ask_about_saving_session (actions)) {
209 _session->save_state ("");
217 meterbridge->hide ();
218 theme_manager->hide ();
219 audio_port_matrix->hide();
220 midi_port_matrix->hide();
221 route_params->hide();
224 second_connection.disconnect ();
225 point_one_second_connection.disconnect ();
226 point_oh_five_second_connection.disconnect ();
227 point_zero_one_second_connection.disconnect();
229 ActionManager::set_sensitive (ActionManager::session_sensitive_actions, false);
231 rec_button.set_sensitive (false);
233 WM::Manager::instance().set_session ((ARDOUR::Session*) 0);
234 ARDOUR_UI::instance()->video_timeline->close_session();
239 /* drop everything attached to the blink signal */
246 session_loaded = false;
248 update_buffer_load ();
254 _hide_splash (gpointer arg)
256 ((ARDOUR_UI*)arg)->hide_splash();
261 ARDOUR_UI::goto_editor_window ()
263 if (splash && splash->is_visible()) {
264 // in 2 seconds, hide the splash screen
265 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 2000);
268 editor->show_window ();
270 /* mixer should now be on top */
271 WM::Manager::instance().set_transient_for (editor);
272 _mixer_on_top = false;
276 ARDOUR_UI::goto_mixer_window ()
278 Glib::RefPtr<Gdk::Window> win;
279 Glib::RefPtr<Gdk::Screen> screen;
282 win = editor->get_window ();
286 screen = win->get_screen();
288 screen = Gdk::Screen::get_default();
291 if (screen && screen->get_height() < 700) {
292 Gtk::MessageDialog msg (_("This screen is not tall enough to display the mixer window"));
297 mixer->show_window ();
299 /* mixer should now be on top */
300 WM::Manager::instance().set_transient_for (mixer);
301 _mixer_on_top = true;
305 ARDOUR_UI::toggle_mixer_window ()
307 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("toggle-mixer"));
312 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
314 if (tact->get_active()) {
315 goto_mixer_window ();
322 ARDOUR_UI::toggle_meterbridge ()
324 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("toggle-meterbridge"));
329 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
331 if (tact->get_active()) {
332 meterbridge->show_window ();
334 meterbridge->hide_window (NULL);
339 ARDOUR_UI::toggle_editor_mixer ()
341 bool obscuring = false;
342 /* currently, if windows are on different
343 screens then we do nothing; but in the
344 future we may want to bring the window
345 to the front or something, so I'm leaving this
346 variable for future use
348 bool same_screen = true;
350 if (editor && mixer) {
352 /* remeber: Screen != Monitor (Screen is a separately rendered
353 * continuous geometry that make include 1 or more monitors.
356 if (editor->get_screen() != mixer->get_screen() && (mixer->get_screen() != 0) && (editor->get_screen() != 0)) {
357 // different screens, so don't do anything
360 // they are on the same screen, see if they are obscuring each other
365 editor->get_position (ex, ey);
366 editor->get_size (ew, eh);
368 mixer->get_position (mx, my);
369 mixer->get_size (mw, mh);
385 if (gdk_rectangle_intersect (&e, &m, &r)) {
391 if (mixer && !mixer->not_visible() && mixer->property_has_toplevel_focus()) {
392 if (obscuring && same_screen) {
393 goto_editor_window();
395 } else if (editor && !editor->not_visible() && editor->property_has_toplevel_focus()) {
396 if (obscuring && same_screen) {
399 } else if (mixer && mixer->not_visible()) {
400 if (obscuring && same_screen) {
401 goto_mixer_window ();
403 } else if (editor && editor->not_visible()) {
404 if (obscuring && same_screen) {
405 goto_editor_window ();
407 } else if (obscuring && same_screen) {
408 //it's unclear what to do here, so just do the opposite of what we did last time (old behavior)
410 goto_editor_window ();
412 goto_mixer_window ();
418 ARDOUR_UI::new_midi_tracer_window ()
420 RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("NewMIDITracer"));
425 std::list<MidiTracer*>::iterator i = _midi_tracer_windows.begin ();
426 while (i != _midi_tracer_windows.end() && (*i)->get_visible() == true) {
430 if (i == _midi_tracer_windows.end()) {
431 /* all our MIDITracer windows are visible; make a new one */
432 MidiTracer* t = new MidiTracer ();
434 _midi_tracer_windows.push_back (t);
436 /* re-use the hidden one */
442 ARDOUR_UI::create_bundle_manager ()
444 return new BundleManager (_session);
448 ARDOUR_UI::create_add_video_dialog ()
450 return new AddVideoDialog (_session);
454 ARDOUR_UI::create_session_option_editor ()
456 return new SessionOptionEditor (_session);
460 ARDOUR_UI::create_big_clock_window ()
462 return new BigClockWindow (*big_clock);
466 ARDOUR_UI::handle_locations_change (Location *)
469 if (_session->locations()->num_range_markers()) {
470 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, true);
472 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, false);
478 ARDOUR_UI::main_window_state_event_handler (GdkEventWindowState* ev, bool window_was_editor)
480 if (window_was_editor) {
482 if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
483 (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
484 if (big_clock_window) {
485 big_clock_window->set_transient_for (*editor);
491 if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
492 (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
493 if (big_clock_window) {
494 big_clock_window->set_transient_for (*mixer);