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);
109 location_ui->set_session (s);
111 /* sensitize menu bar options that are now valid */
113 ActionManager::set_sensitive (ActionManager::session_sensitive_actions, true);
114 ActionManager::set_sensitive (ActionManager::write_sensitive_actions, _session->writable());
116 if (_session->locations()->num_range_markers()) {
117 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, true);
119 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, false);
122 if (!_session->monitor_out()) {
123 Glib::RefPtr<Action> act = ActionManager::get_action (X_("options"), X_("SoloViaBus"));
125 act->set_sensitive (false);
129 /* allow wastebasket flush again */
131 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
133 act->set_sensitive (true);
136 /* there are never any selections on startup */
138 ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, false);
139 ActionManager::set_sensitive (ActionManager::track_selection_sensitive_actions, false);
140 ActionManager::set_sensitive (ActionManager::line_selection_sensitive_actions, false);
141 ActionManager::set_sensitive (ActionManager::point_selection_sensitive_actions, false);
142 ActionManager::set_sensitive (ActionManager::playlist_selection_sensitive_actions, false);
144 rec_button.set_sensitive (true);
146 solo_alert_button.set_active (_session->soloing());
148 setup_session_options ();
150 Blink.connect (sigc::mem_fun(*this, &ARDOUR_UI::transport_rec_enable_blink));
151 Blink.connect (sigc::mem_fun(*this, &ARDOUR_UI::solo_blink));
152 Blink.connect (sigc::mem_fun(*this, &ARDOUR_UI::sync_blink));
153 Blink.connect (sigc::mem_fun(*this, &ARDOUR_UI::audition_blink));
154 Blink.connect (sigc::mem_fun(*this, &ARDOUR_UI::feedback_blink));
156 _session->RecordStateChanged.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::record_state_changed, this), gui_context());
157 _session->StepEditStatusChange.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::step_edit_status_change, this, _1), gui_context());
158 _session->TransportStateChange.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::map_transport_state, this), gui_context());
159 _session->DirtyChanged.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_autosave, this), gui_context());
161 _session->Xrun.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::xrun_handler, this, _1), gui_context());
162 _session->SoloActive.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::soloing_changed, this, _1), gui_context());
163 _session->AuditionActive.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::auditioning_changed, this, _1), gui_context());
164 _session->locations()->added.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::handle_locations_change, this, _1), gui_context());
165 _session->locations()->removed.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::handle_locations_change, this, _1), gui_context());
166 _session->config.ParameterChanged.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_parameter_changed, this, _1), gui_context ());
168 #ifdef HAVE_JACK_SESSION
169 engine->JackSessionEvent.connect (*_session, MISSING_INVALIDATOR, boost::bind (&Session::jack_session_event, _session, _1), gui_context());
172 /* Clocks are on by default after we are connected to a session, so show that here.
175 connect_dependents_to_session (s);
177 /* listen to clock mode changes. don't do this earlier because otherwise as the clocks
178 restore their modes or are explicitly set, we will cause the "new" mode to be saved
179 back to the session XML ("Extra") state.
182 AudioClock::ModeChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::store_clock_modes));
184 Glib::signal_idle().connect (sigc::mem_fun (*this, &ARDOUR_UI::first_idle));
189 map_transport_state ();
191 second_connection = Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::every_second), 1000);
192 point_one_second_connection = Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::every_point_one_seconds), 100);
193 point_zero_one_second_connection = Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::every_point_zero_one_seconds), 40);
199 ARDOUR_UI::unload_session (bool hide_stuff)
202 ARDOUR_UI::instance()->video_timeline->sync_session_state();
205 if (_session && _session->dirty()) {
206 std::vector<std::string> actions;
207 actions.push_back (_("Don't close"));
208 actions.push_back (_("Just close"));
209 actions.push_back (_("Save and close"));
210 switch (ask_about_saving_session (actions)) {
216 _session->save_state ("");
224 theme_manager->hide ();
227 second_connection.disconnect ();
228 point_one_second_connection.disconnect ();
229 point_oh_five_second_connection.disconnect ();
230 point_zero_one_second_connection.disconnect();
232 ActionManager::set_sensitive (ActionManager::session_sensitive_actions, false);
234 rec_button.set_sensitive (false);
236 ARDOUR_UI::instance()->video_timeline->close_session();
241 /* drop everything attached to the blink signal */
248 session_loaded = false;
250 update_buffer_load ();
256 _hide_splash (gpointer arg)
258 ((ARDOUR_UI*)arg)->hide_splash();
263 ARDOUR_UI::goto_editor_window ()
265 if (splash && splash->is_visible()) {
266 // in 2 seconds, hide the splash screen
267 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 2000);
270 editor->show_window ();
272 /* mixer should now be on top */
273 WM::Manager::instance().set_transient_for (editor);
274 _mixer_on_top = false;
278 ARDOUR_UI::goto_mixer_window ()
280 Glib::RefPtr<Gdk::Window> win;
281 Glib::RefPtr<Gdk::Screen> screen;
284 win = editor->get_window ();
288 screen = win->get_screen();
290 screen = Gdk::Screen::get_default();
293 if (screen && screen->get_height() < 700) {
294 Gtk::MessageDialog msg (_("This screen is not tall enough to display the mixer window"));
299 mixer->show_window ();
301 /* mixer should now be on top */
302 WM::Manager::instance().set_transient_for (mixer);
303 _mixer_on_top = true;
307 ARDOUR_UI::toggle_mixer_window ()
309 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("toggle-mixer"));
314 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
316 if (tact->get_active()) {
317 goto_mixer_window ();
324 ARDOUR_UI::toggle_editor_mixer ()
326 bool obscuring = false;
327 /* currently, if windows are on different
328 screens then we do nothing; but in the
329 future we may want to bring the window
330 to the front or something, so I'm leaving this
331 variable for future use
333 bool same_screen = true;
335 if (editor && mixer) {
337 /* remeber: Screen != Monitor (Screen is a separately rendered
338 * continuous geometry that make include 1 or more monitors.
341 if (editor->get_screen() != mixer->get_screen() && (mixer->get_screen() != 0) && (editor->get_screen() != 0)) {
342 // different screens, so don't do anything
345 // they are on the same screen, see if they are obscuring each other
350 editor->get_position (ex, ey);
351 editor->get_size (ew, eh);
353 mixer->get_position (mx, my);
354 mixer->get_size (mw, mh);
370 if (gdk_rectangle_intersect (&e, &m, &r)) {
376 if (mixer && !mixer->not_visible() && mixer->property_has_toplevel_focus()) {
377 if (obscuring && same_screen) {
378 goto_editor_window();
380 } else if (editor && !editor->not_visible() && editor->property_has_toplevel_focus()) {
381 if (obscuring && same_screen) {
384 } else if (mixer && mixer->not_visible()) {
385 if (obscuring && same_screen) {
386 goto_mixer_window ();
388 } else if (editor && editor->not_visible()) {
389 if (obscuring && same_screen) {
390 goto_editor_window ();
392 } else if (obscuring && same_screen) {
393 //it's unclear what to do here, so just do the opposite of what we did last time (old behavior)
395 goto_editor_window ();
397 goto_mixer_window ();
403 ARDOUR_UI::new_midi_tracer_window ()
405 RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("NewMIDITracer"));
410 std::list<MidiTracer*>::iterator i = _midi_tracer_windows.begin ();
411 while (i != _midi_tracer_windows.end() && (*i)->get_visible() == true) {
415 if (i == _midi_tracer_windows.end()) {
416 /* all our MIDITracer windows are visible; make a new one */
417 MidiTracer* t = new MidiTracer ();
419 _midi_tracer_windows.push_back (t);
421 /* re-use the hidden one */
427 ARDOUR_UI::create_bundle_manager ()
429 return new BundleManager (_session);
433 ARDOUR_UI::create_add_video_dialog ()
435 return new AddVideoDialog (_session);
439 ARDOUR_UI::create_session_option_editor ()
441 return new SessionOptionEditor (_session);
445 ARDOUR_UI::create_big_clock_window ()
447 return new BigClockWindow (*big_clock);
451 ARDOUR_UI::handle_locations_change (Location *)
454 if (_session->locations()->num_range_markers()) {
455 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, true);
457 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, false);
463 ARDOUR_UI::main_window_state_event_handler (GdkEventWindowState* ev, bool window_was_editor)
465 if (window_was_editor) {
467 if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
468 (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
469 if (big_clock_window) {
470 big_clock_window->set_transient_for (*editor);
476 if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
477 (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
478 if (big_clock_window) {
479 big_clock_window->set_transient_for (*mixer);