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 "meter_patterns.h"
43 #include "midi_tracer.h"
45 #include "public_editor.h"
46 #include "rc_option_editor.h"
47 #include "route_params_ui.h"
48 #include "shuttle_control.h"
49 #include "session_option_editor.h"
50 #include "speaker_dialog.h"
53 #include "theme_manager.h"
54 #include "time_info_box.h"
58 using namespace ARDOUR;
62 using namespace Gtkmm2ext;
65 ARDOUR_UI::set_session (Session *s)
67 SessionHandlePtr::set_session (s);
71 WM::Manager::instance().set_session (s);
72 /* Session option editor cannot exist across change-of-session */
73 session_option_editor.drop_window ();
74 /* Ditto for AddVideoDialog */
75 add_video_dialog.drop_window ();
79 const XMLNode* node = _session->extra_xml (X_("UI"));
82 const XMLNodeList& children = node->children();
83 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
84 if ((*i)->name() == GUIObjectState::xml_node_name) {
85 gui_object_state->load (**i);
91 WM::Manager::instance().set_session (s);
93 AutomationWatch::instance().set_session (s);
96 shuttle_box->set_session (s);
99 primary_clock->set_session (s);
100 secondary_clock->set_session (s);
101 big_clock->set_session (s);
102 time_info_box->set_session (s);
103 video_timeline->set_session (s);
105 /* sensitize menu bar options that are now valid */
107 ActionManager::set_sensitive (ActionManager::session_sensitive_actions, true);
108 ActionManager::set_sensitive (ActionManager::write_sensitive_actions, _session->writable());
110 if (_session->locations()->num_range_markers()) {
111 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, true);
113 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, false);
116 if (!_session->monitor_out()) {
117 Glib::RefPtr<Action> act = ActionManager::get_action (X_("options"), X_("SoloViaBus"));
119 act->set_sensitive (false);
123 /* allow wastebasket flush again */
125 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
127 act->set_sensitive (true);
130 /* there are never any selections on startup */
132 ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, false);
133 ActionManager::set_sensitive (ActionManager::track_selection_sensitive_actions, false);
134 ActionManager::set_sensitive (ActionManager::line_selection_sensitive_actions, false);
135 ActionManager::set_sensitive (ActionManager::point_selection_sensitive_actions, false);
136 ActionManager::set_sensitive (ActionManager::playlist_selection_sensitive_actions, false);
138 rec_button.set_sensitive (true);
140 solo_alert_button.set_active (_session->soloing());
142 setup_session_options ();
144 Blink.connect (sigc::mem_fun(*this, &ARDOUR_UI::transport_rec_enable_blink));
145 Blink.connect (sigc::mem_fun(*this, &ARDOUR_UI::solo_blink));
146 Blink.connect (sigc::mem_fun(*this, &ARDOUR_UI::sync_blink));
147 Blink.connect (sigc::mem_fun(*this, &ARDOUR_UI::audition_blink));
148 Blink.connect (sigc::mem_fun(*this, &ARDOUR_UI::feedback_blink));
150 _session->RecordStateChanged.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::record_state_changed, this), gui_context());
151 _session->StepEditStatusChange.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::step_edit_status_change, this, _1), gui_context());
152 _session->TransportStateChange.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::map_transport_state, this), gui_context());
153 _session->DirtyChanged.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_autosave, this), gui_context());
155 _session->Xrun.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::xrun_handler, this, _1), gui_context());
156 _session->SoloActive.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::soloing_changed, this, _1), gui_context());
157 _session->AuditionActive.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::auditioning_changed, this, _1), gui_context());
158 _session->locations()->added.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::handle_locations_change, this, _1), gui_context());
159 _session->locations()->removed.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::handle_locations_change, this, _1), gui_context());
160 _session->config.ParameterChanged.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_parameter_changed, this, _1), gui_context ());
162 #ifdef HAVE_JACK_SESSION
163 engine->JackSessionEvent.connect (*_session, MISSING_INVALIDATOR, boost::bind (&Session::jack_session_event, _session, _1), gui_context());
166 /* Clocks are on by default after we are connected to a session, so show that here.
169 connect_dependents_to_session (s);
171 /* listen to clock mode changes. don't do this earlier because otherwise as the clocks
172 restore their modes or are explicitly set, we will cause the "new" mode to be saved
173 back to the session XML ("Extra") state.
176 AudioClock::ModeChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::store_clock_modes));
178 Glib::signal_idle().connect (sigc::mem_fun (*this, &ARDOUR_UI::first_idle));
183 map_transport_state ();
185 second_connection = Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::every_second), 1000);
186 point_one_second_connection = Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::every_point_one_seconds), 100);
187 point_zero_something_second_connection = Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::every_point_zero_something_seconds), 40);
192 meter_box.remove(*editor_meter);
197 if (_session && _session->master_out()) {
198 editor_meter = new LevelMeterHBox(_session);
199 editor_meter->set_meter (_session->master_out()->shared_peak_meter().get());
200 editor_meter->clear_meters();
201 editor_meter->set_type (_session->master_out()->meter_type());
202 editor_meter->setup_meters (30, 12, 6);
203 meter_box.pack_start(*editor_meter);
205 ArdourMeter::ResetAllPeakDisplays.connect (sigc::mem_fun(*this, &ARDOUR_UI::reset_peak_display));
206 ArdourMeter::ResetRoutePeakDisplays.connect (sigc::mem_fun(*this, &ARDOUR_UI::reset_route_peak_display));
207 ArdourMeter::ResetGroupPeakDisplays.connect (sigc::mem_fun(*this, &ARDOUR_UI::reset_group_peak_display));
213 ARDOUR_UI::unload_session (bool hide_stuff)
216 ARDOUR_UI::instance()->video_timeline->sync_session_state();
219 if (_session && _session->dirty()) {
220 std::vector<std::string> actions;
221 actions.push_back (_("Don't close"));
222 actions.push_back (_("Just close"));
223 actions.push_back (_("Save and close"));
224 switch (ask_about_saving_session (actions)) {
230 _session->save_state ("");
238 meterbridge->hide ();
239 theme_manager->hide ();
240 audio_port_matrix->hide();
241 midi_port_matrix->hide();
242 route_params->hide();
245 second_connection.disconnect ();
246 point_one_second_connection.disconnect ();
247 point_zero_something_second_connection.disconnect();
250 meter_box.remove(*editor_meter);
255 ActionManager::set_sensitive (ActionManager::session_sensitive_actions, false);
257 rec_button.set_sensitive (false);
259 WM::Manager::instance().set_session ((ARDOUR::Session*) 0);
260 ARDOUR_UI::instance()->video_timeline->close_session();
265 /* drop everything attached to the blink signal */
272 session_loaded = false;
274 update_buffer_load ();
280 _hide_splash (gpointer arg)
282 ((ARDOUR_UI*)arg)->hide_splash();
287 ARDOUR_UI::goto_editor_window ()
289 if (splash && splash->is_visible()) {
290 // in 2 seconds, hide the splash screen
291 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 2000);
294 editor->show_window ();
296 /* mixer should now be on top */
297 WM::Manager::instance().set_transient_for (editor);
298 _mixer_on_top = false;
302 ARDOUR_UI::goto_mixer_window ()
304 Glib::RefPtr<Gdk::Window> win;
305 Glib::RefPtr<Gdk::Screen> screen;
308 win = editor->get_window ();
312 screen = win->get_screen();
314 screen = Gdk::Screen::get_default();
317 if (screen && screen->get_height() < 700) {
318 Gtk::MessageDialog msg (_("This screen is not tall enough to display the mixer window"));
323 mixer->show_window ();
325 /* mixer should now be on top */
326 WM::Manager::instance().set_transient_for (mixer);
327 _mixer_on_top = true;
331 ARDOUR_UI::toggle_mixer_window ()
333 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("toggle-mixer"));
338 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
340 if (tact->get_active()) {
341 goto_mixer_window ();
348 ARDOUR_UI::toggle_meterbridge ()
350 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("toggle-meterbridge"));
355 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
357 if (tact->get_active()) {
358 meterbridge->show_window ();
360 meterbridge->hide_window (NULL);
365 ARDOUR_UI::toggle_editor_mixer ()
367 bool obscuring = false;
368 /* currently, if windows are on different
369 screens then we do nothing; but in the
370 future we may want to bring the window
371 to the front or something, so I'm leaving this
372 variable for future use
374 bool same_screen = true;
376 if (editor && mixer) {
378 /* remeber: Screen != Monitor (Screen is a separately rendered
379 * continuous geometry that make include 1 or more monitors.
382 if (editor->get_screen() != mixer->get_screen() && (mixer->get_screen() != 0) && (editor->get_screen() != 0)) {
383 // different screens, so don't do anything
386 // they are on the same screen, see if they are obscuring each other
391 editor->get_position (ex, ey);
392 editor->get_size (ew, eh);
394 mixer->get_position (mx, my);
395 mixer->get_size (mw, mh);
411 if (gdk_rectangle_intersect (&e, &m, &r)) {
417 if (mixer && !mixer->not_visible() && mixer->property_has_toplevel_focus()) {
418 if (obscuring && same_screen) {
419 goto_editor_window();
421 } else if (editor && !editor->not_visible() && editor->property_has_toplevel_focus()) {
422 if (obscuring && same_screen) {
425 } else if (mixer && mixer->not_visible()) {
426 if (obscuring && same_screen) {
427 goto_mixer_window ();
429 } else if (editor && editor->not_visible()) {
430 if (obscuring && same_screen) {
431 goto_editor_window ();
433 } else if (obscuring && same_screen) {
434 //it's unclear what to do here, so just do the opposite of what we did last time (old behavior)
436 goto_editor_window ();
438 goto_mixer_window ();
444 ARDOUR_UI::new_midi_tracer_window ()
446 RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("NewMIDITracer"));
451 std::list<MidiTracer*>::iterator i = _midi_tracer_windows.begin ();
452 while (i != _midi_tracer_windows.end() && (*i)->get_visible() == true) {
456 if (i == _midi_tracer_windows.end()) {
457 /* all our MIDITracer windows are visible; make a new one */
458 MidiTracer* t = new MidiTracer ();
460 _midi_tracer_windows.push_back (t);
462 /* re-use the hidden one */
468 ARDOUR_UI::create_bundle_manager ()
470 return new BundleManager (_session);
474 ARDOUR_UI::create_add_video_dialog ()
476 return new AddVideoDialog (_session);
480 ARDOUR_UI::create_session_option_editor ()
482 return new SessionOptionEditor (_session);
486 ARDOUR_UI::create_big_clock_window ()
488 return new BigClockWindow (*big_clock);
492 ARDOUR_UI::handle_locations_change (Location *)
495 if (_session->locations()->num_range_markers()) {
496 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, true);
498 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, false);
504 ARDOUR_UI::main_window_state_event_handler (GdkEventWindowState* ev, bool window_was_editor)
506 if (window_was_editor) {
508 if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
509 (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
510 if (big_clock_window) {
511 big_clock_window->set_transient_for (*editor);
517 if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
518 (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
519 if (big_clock_window) {
520 big_clock_window->set_transient_for (*mixer);