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 if (audio_port_matrix) {
69 audio_port_matrix->set_session (s);
72 if (midi_port_matrix) {
73 midi_port_matrix->set_session (s);
78 /* Session option editor cannot exist across change-of-session */
79 session_option_editor.drop_window ();
80 /* Ditto for AddVideoDialog */
81 add_video_dialog.drop_window ();
85 const XMLNode* node = _session->extra_xml (X_("UI"));
88 const XMLNodeList& children = node->children();
89 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
90 if ((*i)->name() == GUIObjectState::xml_node_name) {
91 gui_object_state->load (**i);
97 AutomationWatch::instance().set_session (s);
98 WM::Manager::instance().set_session (s);
101 shuttle_box->set_session (s);
104 primary_clock->set_session (s);
105 secondary_clock->set_session (s);
106 big_clock->set_session (s);
107 time_info_box->set_session (s);
108 video_timeline->set_session (s);
110 /* sensitize menu bar options that are now valid */
112 ActionManager::set_sensitive (ActionManager::session_sensitive_actions, true);
113 ActionManager::set_sensitive (ActionManager::write_sensitive_actions, _session->writable());
115 if (_session->locations()->num_range_markers()) {
116 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, true);
118 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, false);
121 if (!_session->monitor_out()) {
122 Glib::RefPtr<Action> act = ActionManager::get_action (X_("options"), X_("SoloViaBus"));
124 act->set_sensitive (false);
128 /* allow wastebasket flush again */
130 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
132 act->set_sensitive (true);
135 /* there are never any selections on startup */
137 ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, false);
138 ActionManager::set_sensitive (ActionManager::track_selection_sensitive_actions, false);
139 ActionManager::set_sensitive (ActionManager::line_selection_sensitive_actions, false);
140 ActionManager::set_sensitive (ActionManager::point_selection_sensitive_actions, false);
141 ActionManager::set_sensitive (ActionManager::playlist_selection_sensitive_actions, false);
143 rec_button.set_sensitive (true);
145 solo_alert_button.set_active (_session->soloing());
147 setup_session_options ();
149 Blink.connect (sigc::mem_fun(*this, &ARDOUR_UI::transport_rec_enable_blink));
150 Blink.connect (sigc::mem_fun(*this, &ARDOUR_UI::solo_blink));
151 Blink.connect (sigc::mem_fun(*this, &ARDOUR_UI::sync_blink));
152 Blink.connect (sigc::mem_fun(*this, &ARDOUR_UI::audition_blink));
153 Blink.connect (sigc::mem_fun(*this, &ARDOUR_UI::feedback_blink));
155 _session->RecordStateChanged.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::record_state_changed, this), gui_context());
156 _session->StepEditStatusChange.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::step_edit_status_change, this, _1), gui_context());
157 _session->TransportStateChange.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::map_transport_state, this), gui_context());
158 _session->DirtyChanged.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_autosave, this), gui_context());
160 _session->Xrun.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::xrun_handler, this, _1), gui_context());
161 _session->SoloActive.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::soloing_changed, this, _1), gui_context());
162 _session->AuditionActive.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::auditioning_changed, this, _1), gui_context());
163 _session->locations()->added.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::handle_locations_change, this, _1), gui_context());
164 _session->locations()->removed.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::handle_locations_change, this, _1), gui_context());
165 _session->config.ParameterChanged.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_parameter_changed, this, _1), gui_context ());
167 #ifdef HAVE_JACK_SESSION
168 engine->JackSessionEvent.connect (*_session, MISSING_INVALIDATOR, boost::bind (&Session::jack_session_event, _session, _1), gui_context());
171 /* Clocks are on by default after we are connected to a session, so show that here.
174 connect_dependents_to_session (s);
176 /* listen to clock mode changes. don't do this earlier because otherwise as the clocks
177 restore their modes or are explicitly set, we will cause the "new" mode to be saved
178 back to the session XML ("Extra") state.
181 AudioClock::ModeChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::store_clock_modes));
183 Glib::signal_idle().connect (sigc::mem_fun (*this, &ARDOUR_UI::first_idle));
188 map_transport_state ();
190 second_connection = Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::every_second), 1000);
191 point_one_second_connection = Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::every_point_one_seconds), 100);
192 point_zero_one_second_connection = Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::every_point_zero_one_seconds), 40);
198 ARDOUR_UI::unload_session (bool hide_stuff)
201 ARDOUR_UI::instance()->video_timeline->sync_session_state();
204 if (_session && _session->dirty()) {
205 std::vector<std::string> actions;
206 actions.push_back (_("Don't close"));
207 actions.push_back (_("Just close"));
208 actions.push_back (_("Save and close"));
209 switch (ask_about_saving_session (actions)) {
215 _session->save_state ("");
223 theme_manager->hide ();
226 second_connection.disconnect ();
227 point_one_second_connection.disconnect ();
228 point_oh_five_second_connection.disconnect ();
229 point_zero_one_second_connection.disconnect();
231 ActionManager::set_sensitive (ActionManager::session_sensitive_actions, false);
233 rec_button.set_sensitive (false);
235 ARDOUR_UI::instance()->video_timeline->close_session();
240 /* drop everything attached to the blink signal */
247 session_loaded = false;
249 update_buffer_load ();
255 _hide_splash (gpointer arg)
257 ((ARDOUR_UI*)arg)->hide_splash();
262 ARDOUR_UI::goto_editor_window ()
264 if (splash && splash->is_visible()) {
265 // in 2 seconds, hide the splash screen
266 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 2000);
269 editor->show_window ();
271 /* mixer should now be on top */
272 WM::Manager::instance().set_transient_for (editor);
273 _mixer_on_top = false;
277 ARDOUR_UI::goto_mixer_window ()
279 Glib::RefPtr<Gdk::Window> win;
280 Glib::RefPtr<Gdk::Screen> screen;
283 win = editor->get_window ();
287 screen = win->get_screen();
289 screen = Gdk::Screen::get_default();
292 if (screen && screen->get_height() < 700) {
293 Gtk::MessageDialog msg (_("This screen is not tall enough to display the mixer window"));
298 mixer->show_window ();
300 /* mixer should now be on top */
301 WM::Manager::instance().set_transient_for (mixer);
302 _mixer_on_top = true;
306 ARDOUR_UI::toggle_mixer_window ()
308 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("toggle-mixer"));
313 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
315 if (tact->get_active()) {
316 goto_mixer_window ();
323 ARDOUR_UI::toggle_editor_mixer ()
325 bool obscuring = false;
326 /* currently, if windows are on different
327 screens then we do nothing; but in the
328 future we may want to bring the window
329 to the front or something, so I'm leaving this
330 variable for future use
332 bool same_screen = true;
334 if (editor && mixer) {
336 /* remeber: Screen != Monitor (Screen is a separately rendered
337 * continuous geometry that make include 1 or more monitors.
340 if (editor->get_screen() != mixer->get_screen() && (mixer->get_screen() != 0) && (editor->get_screen() != 0)) {
341 // different screens, so don't do anything
344 // they are on the same screen, see if they are obscuring each other
349 editor->get_position (ex, ey);
350 editor->get_size (ew, eh);
352 mixer->get_position (mx, my);
353 mixer->get_size (mw, mh);
369 if (gdk_rectangle_intersect (&e, &m, &r)) {
375 if (mixer && !mixer->not_visible() && mixer->property_has_toplevel_focus()) {
376 if (obscuring && same_screen) {
377 goto_editor_window();
379 } else if (editor && !editor->not_visible() && editor->property_has_toplevel_focus()) {
380 if (obscuring && same_screen) {
383 } else if (mixer && mixer->not_visible()) {
384 if (obscuring && same_screen) {
385 goto_mixer_window ();
387 } else if (editor && editor->not_visible()) {
388 if (obscuring && same_screen) {
389 goto_editor_window ();
391 } else if (obscuring && same_screen) {
392 //it's unclear what to do here, so just do the opposite of what we did last time (old behavior)
394 goto_editor_window ();
396 goto_mixer_window ();
402 ARDOUR_UI::new_midi_tracer_window ()
404 RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("NewMIDITracer"));
409 std::list<MidiTracer*>::iterator i = _midi_tracer_windows.begin ();
410 while (i != _midi_tracer_windows.end() && (*i)->get_visible() == true) {
414 if (i == _midi_tracer_windows.end()) {
415 /* all our MIDITracer windows are visible; make a new one */
416 MidiTracer* t = new MidiTracer ();
418 _midi_tracer_windows.push_back (t);
420 /* re-use the hidden one */
426 ARDOUR_UI::create_bundle_manager ()
428 return new BundleManager (_session);
432 ARDOUR_UI::create_add_video_dialog ()
434 return new AddVideoDialog (_session);
438 ARDOUR_UI::create_session_option_editor ()
440 return new SessionOptionEditor (_session);
444 ARDOUR_UI::create_big_clock_window ()
446 return new BigClockWindow (*big_clock);
450 ARDOUR_UI::handle_locations_change (Location *)
453 if (_session->locations()->num_range_markers()) {
454 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, true);
456 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, false);
462 ARDOUR_UI::main_window_state_event_handler (GdkEventWindowState* ev, bool window_was_editor)
464 if (window_was_editor) {
466 if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
467 (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
468 if (big_clock_window) {
469 big_clock_window->set_transient_for (*editor);
475 if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
476 (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
477 if (big_clock_window) {
478 big_clock_window->set_transient_for (*mixer);