clean up video related messages
[ardour.git] / gtk2_ardour / ardour_ui_dialogs.cc
1 /*
2     Copyright (C) 2000 Paul Davis
3
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.
8
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.
13
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.
17
18 */
19
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.
24 */
25
26 #include "ardour/session.h"
27 #include "ardour/audioengine.h"
28 #include "ardour/automation_watch.h"
29
30 #include "actions.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"
43 #include "mixer_ui.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"
50 #include "splash.h"
51 #include "sfdb_ui.h"
52 #include "theme_manager.h"
53 #include "time_info_box.h"
54
55 #include "i18n.h"
56
57 using namespace ARDOUR;
58 using namespace PBD;
59 using namespace Glib;
60 using namespace Gtk;
61 using namespace Gtkmm2ext;
62
63 void
64 ARDOUR_UI::set_session (Session *s)
65 {
66         SessionHandlePtr::set_session (s);
67
68
69         if (!_session) {
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 ();
75                 return;
76         }
77
78         const XMLNode* node = _session->extra_xml (X_("UI"));
79
80         if (node) {
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);
85                                 break;
86                         }
87                 }
88         }
89
90         WM::Manager::instance().set_session (s);
91
92         AutomationWatch::instance().set_session (s);
93
94         if (shuttle_box) {
95                 shuttle_box->set_session (s);
96         }
97
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);
103
104         /* sensitize menu bar options that are now valid */
105
106         ActionManager::set_sensitive (ActionManager::session_sensitive_actions, true);
107         ActionManager::set_sensitive (ActionManager::write_sensitive_actions, _session->writable());
108
109         if (_session->locations()->num_range_markers()) {
110                 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, true);
111         } else {
112                 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, false);
113         }
114
115         if (!_session->monitor_out()) {
116                 Glib::RefPtr<Action> act = ActionManager::get_action (X_("options"), X_("SoloViaBus"));
117                 if (act) {
118                         act->set_sensitive (false);
119                 }
120         }
121
122         /* allow wastebasket flush again */
123
124         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
125         if (act) {
126                 act->set_sensitive (true);
127         }
128
129         /* there are never any selections on startup */
130
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);
136
137         rec_button.set_sensitive (true);
138
139         solo_alert_button.set_active (_session->soloing());
140
141         setup_session_options ();
142
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));
148
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());
153
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 ());
160
161 #ifdef HAVE_JACK_SESSION
162         engine->JackSessionEvent.connect (*_session, MISSING_INVALIDATOR, boost::bind (&Session::jack_session_event, _session, _1), gui_context());
163 #endif
164
165         /* Clocks are on by default after we are connected to a session, so show that here.
166         */
167
168         connect_dependents_to_session (s);
169
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.
173          */
174
175         AudioClock::ModeChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::store_clock_modes));
176
177         Glib::signal_idle().connect (sigc::mem_fun (*this, &ARDOUR_UI::first_idle));
178
179         start_clocking ();
180         start_blinking ();
181
182         map_transport_state ();
183
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);
187
188         update_format ();
189 }
190
191 int
192 ARDOUR_UI::unload_session (bool hide_stuff)
193 {
194         if (_session) {
195                 ARDOUR_UI::instance()->video_timeline->sync_session_state();
196         }
197
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)) {
204                 case -1:
205                         // cancel
206                         return 1;
207
208                 case 1:
209                         _session->save_state ("");
210                         break;
211                 }
212         }
213
214         if (hide_stuff) {
215                 editor->hide ();
216                 mixer->hide ();
217                 meterbridge->hide ();
218                 theme_manager->hide ();
219                 audio_port_matrix->hide();
220                 midi_port_matrix->hide();
221                 route_params->hide();
222         }
223
224         second_connection.disconnect ();
225         point_one_second_connection.disconnect ();
226         point_zero_something_second_connection.disconnect();
227
228         ActionManager::set_sensitive (ActionManager::session_sensitive_actions, false);
229
230         rec_button.set_sensitive (false);
231
232         WM::Manager::instance().set_session ((ARDOUR::Session*) 0);
233         ARDOUR_UI::instance()->video_timeline->close_session();
234
235         stop_blinking ();
236         stop_clocking ();
237
238         /* drop everything attached to the blink signal */
239
240         Blink.clear ();
241
242         delete _session;
243         _session = 0;
244
245         session_loaded = false;
246
247         update_buffer_load ();
248
249         return 0;
250 }
251
252 static bool
253 _hide_splash (gpointer arg)
254 {
255         ((ARDOUR_UI*)arg)->hide_splash();
256         return false;
257 }
258
259 void
260 ARDOUR_UI::goto_editor_window ()
261 {
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);
265         }
266
267         editor->show_window ();
268         editor->present ();
269         /* mixer should now be on top */
270         WM::Manager::instance().set_transient_for (editor);
271         _mixer_on_top = false;
272 }
273
274 void
275 ARDOUR_UI::goto_mixer_window ()
276 {
277         Glib::RefPtr<Gdk::Window> win;
278         Glib::RefPtr<Gdk::Screen> screen;
279         
280         if (editor) {
281                 win = editor->get_window ();
282         }
283
284         if (win) {
285                 screen = win->get_screen();
286         } else {
287                 screen = Gdk::Screen::get_default();
288         }
289         
290         if (screen && screen->get_height() < 700) {
291                 Gtk::MessageDialog msg (_("This screen is not tall enough to display the mixer window"));
292                 msg.run ();
293                 return;
294         }
295
296         mixer->show_window ();
297         mixer->present ();
298         /* mixer should now be on top */
299         WM::Manager::instance().set_transient_for (mixer);
300         _mixer_on_top = true;
301 }
302
303 void
304 ARDOUR_UI::toggle_mixer_window ()
305 {
306         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("toggle-mixer"));
307         if (!act) {
308                 return;
309         }
310
311         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
312
313         if (tact->get_active()) {
314                 goto_mixer_window ();
315         } else {
316                 mixer->hide ();
317         }
318 }
319
320 void
321 ARDOUR_UI::toggle_meterbridge ()
322 {
323         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("toggle-meterbridge"));
324         if (!act) {
325                 return;
326         }
327
328         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
329
330         if (tact->get_active()) {
331                 meterbridge->show_window ();
332         } else {
333                 meterbridge->hide_window (NULL);
334         }
335 }
336
337 void
338 ARDOUR_UI::toggle_editor_mixer ()
339 {
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
346         */
347         bool same_screen = true; 
348         
349         if (editor && mixer) {
350
351                 /* remeber: Screen != Monitor (Screen is a separately rendered
352                  * continuous geometry that make include 1 or more monitors.
353                  */
354                 
355                 if (editor->get_screen() != mixer->get_screen() && (mixer->get_screen() != 0) && (editor->get_screen() != 0)) {
356                         // different screens, so don't do anything
357                         same_screen = false;
358                 } else {
359                         // they are on the same screen, see if they are obscuring each other
360
361                         gint ex, ey, ew, eh;
362                         gint mx, my, mw, mh;
363
364                         editor->get_position (ex, ey);
365                         editor->get_size (ew, eh);
366
367                         mixer->get_position (mx, my);
368                         mixer->get_size (mw, mh);
369
370                         GdkRectangle e;
371                         GdkRectangle m;
372                         GdkRectangle r;
373
374                         e.x = ex;
375                         e.y = ey;
376                         e.width = ew;
377                         e.height = eh;
378
379                         m.x = mx;
380                         m.y = my;
381                         m.width = mw;
382                         m.height = mh;
383
384                         if (gdk_rectangle_intersect (&e, &m, &r)) {
385                                 obscuring = true;
386                         }
387                 }
388         }
389
390         if (mixer && !mixer->not_visible() && mixer->property_has_toplevel_focus()) {
391                 if (obscuring && same_screen) {
392                         goto_editor_window();
393                 }
394         } else if (editor && !editor->not_visible() && editor->property_has_toplevel_focus()) {
395                 if (obscuring && same_screen) {
396                         goto_mixer_window();
397                 }
398         } else if (mixer && mixer->not_visible()) {
399                 if (obscuring && same_screen) {
400                         goto_mixer_window ();
401                 }
402         } else if (editor && editor->not_visible()) {
403                 if (obscuring && same_screen) {
404                         goto_editor_window ();
405                 }
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)
408                 if (_mixer_on_top) {
409                         goto_editor_window ();
410                 } else {
411                         goto_mixer_window ();
412                 }
413         }
414 }
415
416 void
417 ARDOUR_UI::new_midi_tracer_window ()
418 {
419         RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("NewMIDITracer"));
420         if (!act) {
421                 return;
422         }
423
424         std::list<MidiTracer*>::iterator i = _midi_tracer_windows.begin ();
425         while (i != _midi_tracer_windows.end() && (*i)->get_visible() == true) {
426                 ++i;
427         }
428
429         if (i == _midi_tracer_windows.end()) {
430                 /* all our MIDITracer windows are visible; make a new one */
431                 MidiTracer* t = new MidiTracer ();
432                 t->show_all ();
433                 _midi_tracer_windows.push_back (t);
434         } else {
435                 /* re-use the hidden one */
436                 (*i)->show_all ();
437         }
438 }
439
440 BundleManager*
441 ARDOUR_UI::create_bundle_manager ()
442 {
443         return new BundleManager (_session);
444 }
445
446 AddVideoDialog*
447 ARDOUR_UI::create_add_video_dialog ()
448 {
449         return new AddVideoDialog (_session);
450 }
451
452 SessionOptionEditor*
453 ARDOUR_UI::create_session_option_editor ()
454 {
455         return new SessionOptionEditor (_session);
456 }
457
458 BigClockWindow*
459 ARDOUR_UI::create_big_clock_window ()
460 {
461         return new BigClockWindow (*big_clock);
462 }
463
464 void
465 ARDOUR_UI::handle_locations_change (Location *)
466 {
467         if (_session) {
468                 if (_session->locations()->num_range_markers()) {
469                         ActionManager::set_sensitive (ActionManager::range_sensitive_actions, true);
470                 } else {
471                         ActionManager::set_sensitive (ActionManager::range_sensitive_actions, false);
472                 }
473         }
474 }
475
476 bool
477 ARDOUR_UI::main_window_state_event_handler (GdkEventWindowState* ev, bool window_was_editor)
478 {
479         if (window_was_editor) {
480
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);
485                         }
486                 }
487
488         } else {
489
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);
494                         }
495                 }
496         }
497
498         return false;
499 }