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_something_second_connection = Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::every_point_zero_something_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_zero_something_second_connection.disconnect();
228 ActionManager::set_sensitive (ActionManager::session_sensitive_actions, false);
230 rec_button.set_sensitive (false);
232 WM::Manager::instance().set_session ((ARDOUR::Session*) 0);
233 ARDOUR_UI::instance()->video_timeline->close_session();
238 /* drop everything attached to the blink signal */
245 session_loaded = false;
247 update_buffer_load ();
253 _hide_splash (gpointer arg)
255 ((ARDOUR_UI*)arg)->hide_splash();
260 ARDOUR_UI::goto_editor_window ()
262 if (splash && splash->is_visible()) {
263 // in 2 seconds, hide the splash screen
264 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 2000);
267 editor->show_window ();
269 /* mixer should now be on top */
270 WM::Manager::instance().set_transient_for (editor);
271 _mixer_on_top = false;
275 ARDOUR_UI::goto_mixer_window ()
277 Glib::RefPtr<Gdk::Window> win;
278 Glib::RefPtr<Gdk::Screen> screen;
281 win = editor->get_window ();
285 screen = win->get_screen();
287 screen = Gdk::Screen::get_default();
290 if (screen && screen->get_height() < 700) {
291 Gtk::MessageDialog msg (_("This screen is not tall enough to display the mixer window"));
296 mixer->show_window ();
298 /* mixer should now be on top */
299 WM::Manager::instance().set_transient_for (mixer);
300 _mixer_on_top = true;
304 ARDOUR_UI::toggle_mixer_window ()
306 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("toggle-mixer"));
311 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
313 if (tact->get_active()) {
314 goto_mixer_window ();
321 ARDOUR_UI::toggle_meterbridge ()
323 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("toggle-meterbridge"));
328 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
330 if (tact->get_active()) {
331 meterbridge->show_window ();
333 meterbridge->hide_window (NULL);
338 ARDOUR_UI::toggle_editor_mixer ()
340 bool obscuring = false;
341 /* currently, if windows are on different
342 screens then we do nothing; but in the
343 future we may want to bring the window
344 to the front or something, so I'm leaving this
345 variable for future use
347 bool same_screen = true;
349 if (editor && mixer) {
351 /* remeber: Screen != Monitor (Screen is a separately rendered
352 * continuous geometry that make include 1 or more monitors.
355 if (editor->get_screen() != mixer->get_screen() && (mixer->get_screen() != 0) && (editor->get_screen() != 0)) {
356 // different screens, so don't do anything
359 // they are on the same screen, see if they are obscuring each other
364 editor->get_position (ex, ey);
365 editor->get_size (ew, eh);
367 mixer->get_position (mx, my);
368 mixer->get_size (mw, mh);
384 if (gdk_rectangle_intersect (&e, &m, &r)) {
390 if (mixer && !mixer->not_visible() && mixer->property_has_toplevel_focus()) {
391 if (obscuring && same_screen) {
392 goto_editor_window();
394 } else if (editor && !editor->not_visible() && editor->property_has_toplevel_focus()) {
395 if (obscuring && same_screen) {
398 } else if (mixer && mixer->not_visible()) {
399 if (obscuring && same_screen) {
400 goto_mixer_window ();
402 } else if (editor && editor->not_visible()) {
403 if (obscuring && same_screen) {
404 goto_editor_window ();
406 } else if (obscuring && same_screen) {
407 //it's unclear what to do here, so just do the opposite of what we did last time (old behavior)
409 goto_editor_window ();
411 goto_mixer_window ();
417 ARDOUR_UI::new_midi_tracer_window ()
419 RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("NewMIDITracer"));
424 std::list<MidiTracer*>::iterator i = _midi_tracer_windows.begin ();
425 while (i != _midi_tracer_windows.end() && (*i)->get_visible() == true) {
429 if (i == _midi_tracer_windows.end()) {
430 /* all our MIDITracer windows are visible; make a new one */
431 MidiTracer* t = new MidiTracer ();
433 _midi_tracer_windows.push_back (t);
435 /* re-use the hidden one */
441 ARDOUR_UI::create_bundle_manager ()
443 return new BundleManager (_session);
447 ARDOUR_UI::create_add_video_dialog ()
449 return new AddVideoDialog (_session);
453 ARDOUR_UI::create_session_option_editor ()
455 return new SessionOptionEditor (_session);
459 ARDOUR_UI::create_big_clock_window ()
461 return new BigClockWindow (*big_clock);
465 ARDOUR_UI::handle_locations_change (Location *)
468 if (_session->locations()->num_range_markers()) {
469 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, true);
471 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, false);
477 ARDOUR_UI::main_window_state_event_handler (GdkEventWindowState* ev, bool window_was_editor)
479 if (window_was_editor) {
481 if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
482 (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
483 if (big_clock_window) {
484 big_clock_window->set_transient_for (*editor);
490 if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
491 (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
492 if (big_clock_window) {
493 big_clock_window->set_transient_for (*mixer);