fix conflicts caused by meterbridge merge
[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_one_second_connection = Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::every_point_zero_one_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_oh_five_second_connection.disconnect ();
227         point_zero_one_second_connection.disconnect();
228
229         ActionManager::set_sensitive (ActionManager::session_sensitive_actions, false);
230
231         rec_button.set_sensitive (false);
232
233         WM::Manager::instance().set_session ((ARDOUR::Session*) 0);
234         ARDOUR_UI::instance()->video_timeline->close_session();
235
236         stop_blinking ();
237         stop_clocking ();
238
239         /* drop everything attached to the blink signal */
240
241         Blink.clear ();
242
243         delete _session;
244         _session = 0;
245
246         session_loaded = false;
247
248         update_buffer_load ();
249
250         return 0;
251 }
252
253 static bool
254 _hide_splash (gpointer arg)
255 {
256         ((ARDOUR_UI*)arg)->hide_splash();
257         return false;
258 }
259
260 void
261 ARDOUR_UI::goto_editor_window ()
262 {
263         if (splash && splash->is_visible()) {
264                 // in 2 seconds, hide the splash screen
265                 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 2000);
266         }
267
268         editor->show_window ();
269         editor->present ();
270         /* mixer should now be on top */
271         WM::Manager::instance().set_transient_for (editor);
272         _mixer_on_top = false;
273 }
274
275 void
276 ARDOUR_UI::goto_mixer_window ()
277 {
278         Glib::RefPtr<Gdk::Window> win;
279         Glib::RefPtr<Gdk::Screen> screen;
280         
281         if (editor) {
282                 win = editor->get_window ();
283         }
284
285         if (win) {
286                 screen = win->get_screen();
287         } else {
288                 screen = Gdk::Screen::get_default();
289         }
290         
291         if (screen && screen->get_height() < 700) {
292                 Gtk::MessageDialog msg (_("This screen is not tall enough to display the mixer window"));
293                 msg.run ();
294                 return;
295         }
296
297         mixer->show_window ();
298         mixer->present ();
299         /* mixer should now be on top */
300         WM::Manager::instance().set_transient_for (mixer);
301         _mixer_on_top = true;
302 }
303
304 void
305 ARDOUR_UI::toggle_mixer_window ()
306 {
307         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("toggle-mixer"));
308         if (!act) {
309                 return;
310         }
311
312         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
313
314         if (tact->get_active()) {
315                 goto_mixer_window ();
316         } else {
317                 mixer->hide ();
318         }
319 }
320
321 void
322 ARDOUR_UI::toggle_meterbridge ()
323 {
324         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("toggle-meterbridge"));
325         if (!act) {
326                 return;
327         }
328
329         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
330
331         if (tact->get_active()) {
332                 meterbridge->show_window ();
333         } else {
334                 meterbridge->hide_window (NULL);
335         }
336 }
337
338 void
339 ARDOUR_UI::toggle_editor_mixer ()
340 {
341         bool obscuring = false;
342         /* currently, if windows are on different
343            screens then we do nothing; but in the
344            future we may want to bring the window 
345            to the front or something, so I'm leaving this 
346            variable for future use
347         */
348         bool same_screen = true; 
349         
350         if (editor && mixer) {
351
352                 /* remeber: Screen != Monitor (Screen is a separately rendered
353                  * continuous geometry that make include 1 or more monitors.
354                  */
355                 
356                 if (editor->get_screen() != mixer->get_screen() && (mixer->get_screen() != 0) && (editor->get_screen() != 0)) {
357                         // different screens, so don't do anything
358                         same_screen = false;
359                 } else {
360                         // they are on the same screen, see if they are obscuring each other
361
362                         gint ex, ey, ew, eh;
363                         gint mx, my, mw, mh;
364
365                         editor->get_position (ex, ey);
366                         editor->get_size (ew, eh);
367
368                         mixer->get_position (mx, my);
369                         mixer->get_size (mw, mh);
370
371                         GdkRectangle e;
372                         GdkRectangle m;
373                         GdkRectangle r;
374
375                         e.x = ex;
376                         e.y = ey;
377                         e.width = ew;
378                         e.height = eh;
379
380                         m.x = mx;
381                         m.y = my;
382                         m.width = mw;
383                         m.height = mh;
384
385                         if (gdk_rectangle_intersect (&e, &m, &r)) {
386                                 obscuring = true;
387                         }
388                 }
389         }
390
391         if (mixer && !mixer->not_visible() && mixer->property_has_toplevel_focus()) {
392                 if (obscuring && same_screen) {
393                         goto_editor_window();
394                 }
395         } else if (editor && !editor->not_visible() && editor->property_has_toplevel_focus()) {
396                 if (obscuring && same_screen) {
397                         goto_mixer_window();
398                 }
399         } else if (mixer && mixer->not_visible()) {
400                 if (obscuring && same_screen) {
401                         goto_mixer_window ();
402                 }
403         } else if (editor && editor->not_visible()) {
404                 if (obscuring && same_screen) {
405                         goto_editor_window ();
406                 }
407         } else if (obscuring && same_screen) {
408                 //it's unclear what to do here, so just do the opposite of what we did last time  (old behavior)
409                 if (_mixer_on_top) {
410                         goto_editor_window ();
411                 } else {
412                         goto_mixer_window ();
413                 }
414         }
415 }
416
417 void
418 ARDOUR_UI::new_midi_tracer_window ()
419 {
420         RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("NewMIDITracer"));
421         if (!act) {
422                 return;
423         }
424
425         std::list<MidiTracer*>::iterator i = _midi_tracer_windows.begin ();
426         while (i != _midi_tracer_windows.end() && (*i)->get_visible() == true) {
427                 ++i;
428         }
429
430         if (i == _midi_tracer_windows.end()) {
431                 /* all our MIDITracer windows are visible; make a new one */
432                 MidiTracer* t = new MidiTracer ();
433                 t->show_all ();
434                 _midi_tracer_windows.push_back (t);
435         } else {
436                 /* re-use the hidden one */
437                 (*i)->show_all ();
438         }
439 }
440
441 BundleManager*
442 ARDOUR_UI::create_bundle_manager ()
443 {
444         return new BundleManager (_session);
445 }
446
447 AddVideoDialog*
448 ARDOUR_UI::create_add_video_dialog ()
449 {
450         return new AddVideoDialog (_session);
451 }
452
453 SessionOptionEditor*
454 ARDOUR_UI::create_session_option_editor ()
455 {
456         return new SessionOptionEditor (_session);
457 }
458
459 BigClockWindow*
460 ARDOUR_UI::create_big_clock_window ()
461 {
462         return new BigClockWindow (*big_clock);
463 }
464
465 void
466 ARDOUR_UI::handle_locations_change (Location *)
467 {
468         if (_session) {
469                 if (_session->locations()->num_range_markers()) {
470                         ActionManager::set_sensitive (ActionManager::range_sensitive_actions, true);
471                 } else {
472                         ActionManager::set_sensitive (ActionManager::range_sensitive_actions, false);
473                 }
474         }
475 }
476
477 bool
478 ARDOUR_UI::main_window_state_event_handler (GdkEventWindowState* ev, bool window_was_editor)
479 {
480         if (window_was_editor) {
481
482                 if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
483                     (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
484                         if (big_clock_window) {
485                                 big_clock_window->set_transient_for (*editor);
486                         }
487                 }
488
489         } else {
490
491                 if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
492                     (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
493                         if (big_clock_window) {
494                                 big_clock_window->set_transient_for (*mixer);
495                         }
496                 }
497         }
498
499         return false;
500 }