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"
35 #include "add_route_dialog.h"
36 #include "add_video_dialog.h"
37 #include "ardour_ui.h"
38 #include "big_clock_window.h"
39 #include "bundle_manager.h"
40 #include "global_port_matrix.h"
41 #include "gui_object.h"
42 #include "gui_thread.h"
43 #include "keyeditor.h"
44 #include "location_ui.h"
45 #include "main_clock.h"
46 #include "meter_patterns.h"
47 #include "midi_tracer.h"
49 #include "public_editor.h"
50 #include "rc_option_editor.h"
51 #include "route_params_ui.h"
52 #include "shuttle_control.h"
53 #include "session_option_editor.h"
54 #include "speaker_dialog.h"
57 #include "theme_manager.h"
58 #include "time_info_box.h"
62 using namespace ARDOUR;
66 using namespace Gtkmm2ext;
69 ARDOUR_UI::set_session (Session *s)
71 SessionHandlePtr::set_session (s);
75 WM::Manager::instance().set_session (s);
76 /* Session option editor cannot exist across change-of-session */
77 session_option_editor.drop_window ();
78 /* Ditto for AddVideoDialog */
79 add_video_dialog.drop_window ();
83 const XMLNode* node = _session->extra_xml (X_("UI"));
86 const XMLNodeList& children = node->children();
87 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
88 if ((*i)->name() == GUIObjectState::xml_node_name) {
89 gui_object_state->load (**i);
95 WM::Manager::instance().set_session (s);
97 AutomationWatch::instance().set_session (s);
100 shuttle_box->set_session (s);
103 primary_clock->set_session (s);
104 secondary_clock->set_session (s);
105 big_clock->set_session (s);
106 time_info_box->set_session (s);
107 video_timeline->set_session (s);
109 /* sensitize menu bar options that are now valid */
111 ActionManager::set_sensitive (ActionManager::session_sensitive_actions, true);
112 ActionManager::set_sensitive (ActionManager::write_sensitive_actions, _session->writable());
114 if (_session->locations()->num_range_markers()) {
115 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, true);
117 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, false);
120 if (!_session->monitor_out()) {
121 Glib::RefPtr<Action> act = ActionManager::get_action (X_("options"), X_("SoloViaBus"));
123 act->set_sensitive (false);
127 /* allow wastebasket flush again */
129 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
131 act->set_sensitive (true);
134 /* there are never any selections on startup */
136 ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, false);
137 ActionManager::set_sensitive (ActionManager::track_selection_sensitive_actions, false);
138 ActionManager::set_sensitive (ActionManager::line_selection_sensitive_actions, false);
139 ActionManager::set_sensitive (ActionManager::point_selection_sensitive_actions, false);
140 ActionManager::set_sensitive (ActionManager::playlist_selection_sensitive_actions, false);
142 rec_button.set_sensitive (true);
144 solo_alert_button.set_active (_session->soloing());
146 setup_session_options ();
148 Blink.connect (sigc::mem_fun(*this, &ARDOUR_UI::transport_rec_enable_blink));
149 Blink.connect (sigc::mem_fun(*this, &ARDOUR_UI::solo_blink));
150 Blink.connect (sigc::mem_fun(*this, &ARDOUR_UI::sync_blink));
151 Blink.connect (sigc::mem_fun(*this, &ARDOUR_UI::audition_blink));
152 Blink.connect (sigc::mem_fun(*this, &ARDOUR_UI::feedback_blink));
154 _session->RecordStateChanged.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::record_state_changed, this), gui_context());
155 _session->StepEditStatusChange.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::step_edit_status_change, this, _1), gui_context());
156 _session->TransportStateChange.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::map_transport_state, this), gui_context());
157 _session->DirtyChanged.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_autosave, this), gui_context());
159 _session->Xrun.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::xrun_handler, this, _1), gui_context());
160 _session->SoloActive.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::soloing_changed, this, _1), gui_context());
161 _session->AuditionActive.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::auditioning_changed, this, _1), gui_context());
162 _session->locations()->added.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::handle_locations_change, this, _1), gui_context());
163 _session->locations()->removed.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::handle_locations_change, this, _1), gui_context());
164 _session->config.ParameterChanged.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_parameter_changed, this, _1), gui_context ());
166 #ifdef HAVE_JACK_SESSION
167 engine->JackSessionEvent.connect (*_session, MISSING_INVALIDATOR, boost::bind (&Session::jack_session_event, _session, _1), gui_context());
170 /* Clocks are on by default after we are connected to a session, so show that here.
173 connect_dependents_to_session (s);
175 /* listen to clock mode changes. don't do this earlier because otherwise as the clocks
176 restore their modes or are explicitly set, we will cause the "new" mode to be saved
177 back to the session XML ("Extra") state.
180 AudioClock::ModeChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::store_clock_modes));
182 Glib::signal_idle().connect (sigc::mem_fun (*this, &ARDOUR_UI::first_idle));
187 map_transport_state ();
189 second_connection = Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::every_second), 1000);
190 point_one_second_connection = Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::every_point_one_seconds), 100);
191 point_zero_something_second_connection = Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::every_point_zero_something_seconds), 40);
196 meter_box.remove(*editor_meter);
201 if (_session && _session->master_out()) {
202 editor_meter = new LevelMeterHBox(_session);
203 editor_meter->set_meter (_session->master_out()->shared_peak_meter().get());
204 editor_meter->clear_meters();
205 editor_meter->set_type (_session->master_out()->meter_type());
206 editor_meter->setup_meters (30, 12, 6);
207 meter_box.pack_start(*editor_meter);
209 ArdourMeter::ResetAllPeakDisplays.connect (sigc::mem_fun(*this, &ARDOUR_UI::reset_peak_display));
210 ArdourMeter::ResetRoutePeakDisplays.connect (sigc::mem_fun(*this, &ARDOUR_UI::reset_route_peak_display));
211 ArdourMeter::ResetGroupPeakDisplays.connect (sigc::mem_fun(*this, &ARDOUR_UI::reset_group_peak_display));
217 ARDOUR_UI::unload_session (bool hide_stuff)
220 ARDOUR_UI::instance()->video_timeline->sync_session_state();
223 if (_session && _session->dirty()) {
224 std::vector<std::string> actions;
225 actions.push_back (_("Don't close"));
226 actions.push_back (_("Just close"));
227 actions.push_back (_("Save and close"));
228 switch (ask_about_saving_session (actions)) {
234 _session->save_state ("");
242 meterbridge->hide ();
243 theme_manager->hide ();
244 audio_port_matrix->hide();
245 midi_port_matrix->hide();
246 route_params->hide();
249 second_connection.disconnect ();
250 point_one_second_connection.disconnect ();
251 point_zero_something_second_connection.disconnect();
254 meter_box.remove(*editor_meter);
259 ActionManager::set_sensitive (ActionManager::session_sensitive_actions, false);
261 rec_button.set_sensitive (false);
263 WM::Manager::instance().set_session ((ARDOUR::Session*) 0);
264 ARDOUR_UI::instance()->video_timeline->close_session();
269 /* drop everything attached to the blink signal */
276 session_loaded = false;
278 update_buffer_load ();
284 _hide_splash (gpointer arg)
286 ((ARDOUR_UI*)arg)->hide_splash();
291 ARDOUR_UI::goto_editor_window ()
293 if (splash && splash->is_visible()) {
294 // in 2 seconds, hide the splash screen
295 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 2000);
298 editor->show_window ();
300 /* mixer should now be on top */
301 WM::Manager::instance().set_transient_for (editor);
302 _mixer_on_top = false;
306 ARDOUR_UI::goto_mixer_window ()
308 Glib::RefPtr<Gdk::Window> win;
309 Glib::RefPtr<Gdk::Screen> screen;
312 win = editor->get_window ();
316 screen = win->get_screen();
318 screen = Gdk::Screen::get_default();
321 if (screen && screen->get_height() < 700) {
322 Gtk::MessageDialog msg (_("This screen is not tall enough to display the mixer window"));
327 mixer->show_window ();
329 /* mixer should now be on top */
330 WM::Manager::instance().set_transient_for (mixer);
331 _mixer_on_top = true;
335 ARDOUR_UI::toggle_mixer_window ()
337 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("toggle-mixer"));
342 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
344 if (tact->get_active()) {
345 goto_mixer_window ();
352 ARDOUR_UI::toggle_meterbridge ()
354 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("toggle-meterbridge"));
359 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
361 if (tact->get_active()) {
362 meterbridge->show_window ();
364 meterbridge->hide_window (NULL);
369 ARDOUR_UI::toggle_editor_mixer ()
371 bool obscuring = false;
372 /* currently, if windows are on different
373 screens then we do nothing; but in the
374 future we may want to bring the window
375 to the front or something, so I'm leaving this
376 variable for future use
378 bool same_screen = true;
380 if (editor && mixer) {
382 /* remeber: Screen != Monitor (Screen is a separately rendered
383 * continuous geometry that make include 1 or more monitors.
386 if (editor->get_screen() != mixer->get_screen() && (mixer->get_screen() != 0) && (editor->get_screen() != 0)) {
387 // different screens, so don't do anything
390 // they are on the same screen, see if they are obscuring each other
395 editor->get_position (ex, ey);
396 editor->get_size (ew, eh);
398 mixer->get_position (mx, my);
399 mixer->get_size (mw, mh);
415 if (gdk_rectangle_intersect (&e, &m, &r)) {
421 if (mixer && !mixer->not_visible() && mixer->property_has_toplevel_focus()) {
422 if (obscuring && same_screen) {
423 goto_editor_window();
425 } else if (editor && !editor->not_visible() && editor->property_has_toplevel_focus()) {
426 if (obscuring && same_screen) {
429 } else if (mixer && mixer->not_visible()) {
430 if (obscuring && same_screen) {
431 goto_mixer_window ();
433 } else if (editor && editor->not_visible()) {
434 if (obscuring && same_screen) {
435 goto_editor_window ();
437 } else if (obscuring && same_screen) {
438 //it's unclear what to do here, so just do the opposite of what we did last time (old behavior)
440 goto_editor_window ();
442 goto_mixer_window ();
448 ARDOUR_UI::new_midi_tracer_window ()
450 RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("NewMIDITracer"));
455 std::list<MidiTracer*>::iterator i = _midi_tracer_windows.begin ();
456 while (i != _midi_tracer_windows.end() && (*i)->get_visible() == true) {
460 if (i == _midi_tracer_windows.end()) {
461 /* all our MIDITracer windows are visible; make a new one */
462 MidiTracer* t = new MidiTracer ();
464 _midi_tracer_windows.push_back (t);
466 /* re-use the hidden one */
472 ARDOUR_UI::create_bundle_manager ()
474 return new BundleManager (_session);
478 ARDOUR_UI::create_add_video_dialog ()
480 return new AddVideoDialog (_session);
484 ARDOUR_UI::create_session_option_editor ()
486 return new SessionOptionEditor (_session);
490 ARDOUR_UI::create_big_clock_window ()
492 return new BigClockWindow (*big_clock);
496 ARDOUR_UI::handle_locations_change (Location *)
499 if (_session->locations()->num_range_markers()) {
500 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, true);
502 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, false);
508 ARDOUR_UI::main_window_state_event_handler (GdkEventWindowState* ev, bool window_was_editor)
510 if (window_was_editor) {
512 if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
513 (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
514 if (big_clock_window) {
515 big_clock_window->set_transient_for (*editor);
521 if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
522 (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
523 if (big_clock_window) {
524 big_clock_window->set_transient_for (*mixer);