fix merge with master
[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 "meter_patterns.h"
43 #include "midi_tracer.h"
44 #include "mixer_ui.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"
51 #include "splash.h"
52 #include "sfdb_ui.h"
53 #include "theme_manager.h"
54 #include "time_info_box.h"
55
56 #include <gtkmm2ext/keyboard.h>
57
58 #include "i18n.h"
59
60 using namespace ARDOUR;
61 using namespace PBD;
62 using namespace Glib;
63 using namespace Gtk;
64 using namespace Gtkmm2ext;
65
66 void
67 ARDOUR_UI::set_session (Session *s)
68 {
69         SessionHandlePtr::set_session (s);
70
71
72         if (!_session) {
73                 WM::Manager::instance().set_session (s);
74                 /* Session option editor cannot exist across change-of-session */
75                 session_option_editor.drop_window ();
76                 /* Ditto for AddVideoDialog */
77                 add_video_dialog.drop_window ();
78                 return;
79         }
80
81         const XMLNode* node = _session->extra_xml (X_("UI"));
82
83         if (node) {
84                 const XMLNodeList& children = node->children();
85                 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
86                         if ((*i)->name() == GUIObjectState::xml_node_name) {
87                                 gui_object_state->load (**i);
88                                 break;
89                         }
90                 }
91         }
92
93         WM::Manager::instance().set_session (s);
94
95         AutomationWatch::instance().set_session (s);
96
97         if (shuttle_box) {
98                 shuttle_box->set_session (s);
99         }
100
101         primary_clock->set_session (s);
102         secondary_clock->set_session (s);
103         big_clock->set_session (s);
104         time_info_box->set_session (s);
105         video_timeline->set_session (s);
106
107         /* sensitize menu bar options that are now valid */
108
109         ActionManager::set_sensitive (ActionManager::session_sensitive_actions, true);
110         ActionManager::set_sensitive (ActionManager::write_sensitive_actions, _session->writable());
111
112         if (_session->locations()->num_range_markers()) {
113                 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, true);
114         } else {
115                 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, false);
116         }
117
118         if (!_session->monitor_out()) {
119                 Glib::RefPtr<Action> act = ActionManager::get_action (X_("options"), X_("SoloViaBus"));
120                 if (act) {
121                         act->set_sensitive (false);
122                 }
123         }
124
125         /* allow wastebasket flush again */
126
127         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
128         if (act) {
129                 act->set_sensitive (true);
130         }
131
132         /* there are never any selections on startup */
133
134         ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, false);
135         ActionManager::set_sensitive (ActionManager::track_selection_sensitive_actions, false);
136         ActionManager::set_sensitive (ActionManager::line_selection_sensitive_actions, false);
137         ActionManager::set_sensitive (ActionManager::point_selection_sensitive_actions, false);
138         ActionManager::set_sensitive (ActionManager::playlist_selection_sensitive_actions, false);
139
140         rec_button.set_sensitive (true);
141
142         solo_alert_button.set_active (_session->soloing());
143
144         setup_session_options ();
145
146         Blink.connect (sigc::mem_fun(*this, &ARDOUR_UI::transport_rec_enable_blink));
147         Blink.connect (sigc::mem_fun(*this, &ARDOUR_UI::solo_blink));
148         Blink.connect (sigc::mem_fun(*this, &ARDOUR_UI::sync_blink));
149         Blink.connect (sigc::mem_fun(*this, &ARDOUR_UI::audition_blink));
150         Blink.connect (sigc::mem_fun(*this, &ARDOUR_UI::feedback_blink));
151
152         _session->RecordStateChanged.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::record_state_changed, this), gui_context());
153         _session->StepEditStatusChange.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::step_edit_status_change, this, _1), gui_context());
154         _session->TransportStateChange.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::map_transport_state, this), gui_context());
155         _session->DirtyChanged.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_autosave, this), gui_context());
156
157         _session->Xrun.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::xrun_handler, this, _1), gui_context());
158         _session->SoloActive.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::soloing_changed, this, _1), gui_context());
159         _session->AuditionActive.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::auditioning_changed, this, _1), gui_context());
160         _session->locations()->added.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::handle_locations_change, this, _1), gui_context());
161         _session->locations()->removed.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::handle_locations_change, this, _1), gui_context());
162         _session->config.ParameterChanged.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_parameter_changed, this, _1), gui_context ());
163
164         /* Clocks are on by default after we are connected to a session, so show that here.
165         */
166
167         connect_dependents_to_session (s);
168
169         /* listen to clock mode changes. don't do this earlier because otherwise as the clocks
170            restore their modes or are explicitly set, we will cause the "new" mode to be saved
171            back to the session XML ("Extra") state.
172          */
173
174         AudioClock::ModeChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::store_clock_modes));
175
176         Glib::signal_idle().connect (sigc::mem_fun (*this, &ARDOUR_UI::first_idle));
177
178         start_clocking ();
179         start_blinking ();
180
181         map_transport_state ();
182
183         second_connection = Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::every_second), 1000);
184         point_one_second_connection = Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::every_point_one_seconds), 100);
185         point_zero_something_second_connection = Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::every_point_zero_something_seconds), 40);
186
187         update_format ();
188
189         if (editor_meter) {
190                 meter_box.remove(*editor_meter);
191                 delete editor_meter;
192                 editor_meter = 0;
193                 editor_meter_peak_display.hide();
194         }
195
196         if (_session && _session->master_out()) {
197                 editor_meter = new LevelMeterHBox(_session);
198                 editor_meter->set_meter (_session->master_out()->shared_peak_meter().get());
199                 editor_meter->clear_meters();
200                 editor_meter->set_type (_session->master_out()->meter_type());
201                 editor_meter->setup_meters (30, 12, 6);
202                 editor_meter->show();
203                 meter_box.pack_start(*editor_meter);
204
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));
208
209                 editor_meter_peak_display.set_name ("meterbridge peakindicator");
210                 editor_meter_peak_display.set_elements((ArdourButton::Element) (ArdourButton::Edge|ArdourButton::Body));
211                 editor_meter_peak_display.unset_flags (Gtk::CAN_FOCUS);
212                 editor_meter_peak_display.set_size_request(6, -1);
213                 editor_meter_peak_display.set_corner_radius(2);
214
215                 editor_meter_max_peak = -INFINITY;
216                 editor_meter_peak_display.signal_button_release_event().connect (sigc::mem_fun(*this, &ARDOUR_UI::editor_meter_peak_button_release), false);
217
218                 if (Config->get_show_editor_meter()) {
219                         meter_box.show();
220                         editor_meter_peak_display.show();
221                 } else {
222                         meter_box.hide();
223                         editor_meter_peak_display.hide();
224                 }
225         }
226
227 }
228
229 int
230 ARDOUR_UI::unload_session (bool hide_stuff)
231 {
232         if (_session) {
233                 ARDOUR_UI::instance()->video_timeline->sync_session_state();
234         }
235
236         if (_session && _session->dirty()) {
237                 std::vector<std::string> actions;
238                 actions.push_back (_("Don't close"));
239                 actions.push_back (_("Just close"));
240                 actions.push_back (_("Save and close"));
241                 switch (ask_about_saving_session (actions)) {
242                 case -1:
243                         // cancel
244                         return 1;
245
246                 case 1:
247                         _session->save_state ("");
248                         break;
249                 }
250         }
251
252         if (hide_stuff) {
253                 editor->hide ();
254                 mixer->hide ();
255                 meterbridge->hide ();
256                 theme_manager->hide ();
257                 audio_port_matrix->hide();
258                 midi_port_matrix->hide();
259                 route_params->hide();
260         }
261
262         second_connection.disconnect ();
263         point_one_second_connection.disconnect ();
264         point_zero_something_second_connection.disconnect();
265
266         if (editor_meter) {
267                 meter_box.remove(*editor_meter);
268                 delete editor_meter;
269                 editor_meter = 0;
270                 editor_meter_peak_display.hide();
271         }
272
273         ActionManager::set_sensitive (ActionManager::session_sensitive_actions, false);
274
275         rec_button.set_sensitive (false);
276
277         WM::Manager::instance().set_session ((ARDOUR::Session*) 0);
278
279         if (ARDOUR_UI::instance()->video_timeline) {
280                 ARDOUR_UI::instance()->video_timeline->close_session();
281         }
282
283         stop_blinking ();
284         stop_clocking ();
285
286         /* drop everything attached to the blink signal */
287
288         Blink.clear ();
289
290         delete _session;
291         _session = 0;
292
293         session_loaded = false;
294
295         update_buffer_load ();
296
297         return 0;
298 }
299
300 static bool
301 _hide_splash (gpointer arg)
302 {
303         ((ARDOUR_UI*)arg)->hide_splash();
304         return false;
305 }
306
307 void
308 ARDOUR_UI::goto_editor_window ()
309 {
310         if (splash && splash->is_visible()) {
311                 // in 2 seconds, hide the splash screen
312                 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 2000);
313         }
314
315         editor->show_window ();
316         editor->present ();
317         /* mixer should now be on top */
318         WM::Manager::instance().set_transient_for (editor);
319         _mixer_on_top = false;
320 }
321
322 void
323 ARDOUR_UI::goto_mixer_window ()
324 {
325         Glib::RefPtr<Gdk::Window> win;
326         Glib::RefPtr<Gdk::Screen> screen;
327         
328         if (editor) {
329                 win = editor->get_window ();
330         }
331
332         if (win) {
333                 screen = win->get_screen();
334         } else {
335                 screen = Gdk::Screen::get_default();
336         }
337         
338         if (g_getenv ("ARDOUR_LOVES_STUPID_TINY_SCREENS") == 0 && screen && screen->get_height() < 700) {
339                 Gtk::MessageDialog msg (_("This screen is not tall enough to display the mixer window"));
340                 msg.run ();
341                 return;
342         }
343
344         mixer->show_window ();
345         mixer->present ();
346         /* mixer should now be on top */
347         WM::Manager::instance().set_transient_for (mixer);
348         _mixer_on_top = true;
349 }
350
351 void
352 ARDOUR_UI::toggle_mixer_window ()
353 {
354         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("toggle-mixer"));
355         if (!act) {
356                 return;
357         }
358
359         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
360
361         if (tact->get_active()) {
362                 goto_mixer_window ();
363         } else {
364                 mixer->hide ();
365         }
366 }
367
368 void
369 ARDOUR_UI::toggle_meterbridge ()
370 {
371         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("toggle-meterbridge"));
372         if (!act) {
373                 return;
374         }
375
376         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
377
378         if (tact->get_active()) {
379                 meterbridge->show_window ();
380         } else {
381                 meterbridge->hide_window (NULL);
382         }
383 }
384
385 void
386 ARDOUR_UI::toggle_editor_mixer ()
387 {
388         bool obscuring = false;
389         /* currently, if windows are on different
390            screens then we do nothing; but in the
391            future we may want to bring the window 
392            to the front or something, so I'm leaving this 
393            variable for future use
394         */
395         bool same_screen = true; 
396         
397         if (editor && mixer) {
398
399                 /* remeber: Screen != Monitor (Screen is a separately rendered
400                  * continuous geometry that make include 1 or more monitors.
401                  */
402                 
403                 if (editor->get_screen() != mixer->get_screen() && (mixer->get_screen() != 0) && (editor->get_screen() != 0)) {
404                         // different screens, so don't do anything
405                         same_screen = false;
406                 } else {
407                         // they are on the same screen, see if they are obscuring each other
408
409                         gint ex, ey, ew, eh;
410                         gint mx, my, mw, mh;
411
412                         editor->get_position (ex, ey);
413                         editor->get_size (ew, eh);
414
415                         mixer->get_position (mx, my);
416                         mixer->get_size (mw, mh);
417
418                         GdkRectangle e;
419                         GdkRectangle m;
420                         GdkRectangle r;
421
422                         e.x = ex;
423                         e.y = ey;
424                         e.width = ew;
425                         e.height = eh;
426
427                         m.x = mx;
428                         m.y = my;
429                         m.width = mw;
430                         m.height = mh;
431
432                         if (gdk_rectangle_intersect (&e, &m, &r)) {
433                                 obscuring = true;
434                         }
435                 }
436         }
437
438         if (mixer && !mixer->not_visible() && mixer->property_has_toplevel_focus()) {
439                 if (obscuring && same_screen) {
440                         goto_editor_window();
441                 }
442         } else if (editor && !editor->not_visible() && editor->property_has_toplevel_focus()) {
443                 if (obscuring && same_screen) {
444                         goto_mixer_window();
445                 }
446         } else if (mixer && mixer->not_visible()) {
447                 if (obscuring && same_screen) {
448                         goto_mixer_window ();
449                 }
450         } else if (editor && editor->not_visible()) {
451                 if (obscuring && same_screen) {
452                         goto_editor_window ();
453                 }
454         } else if (obscuring && same_screen) {
455                 //it's unclear what to do here, so just do the opposite of what we did last time  (old behavior)
456                 if (_mixer_on_top) {
457                         goto_editor_window ();
458                 } else {
459                         goto_mixer_window ();
460                 }
461         }
462 }
463
464 void
465 ARDOUR_UI::new_midi_tracer_window ()
466 {
467         RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("NewMIDITracer"));
468         if (!act) {
469                 return;
470         }
471
472         std::list<MidiTracer*>::iterator i = _midi_tracer_windows.begin ();
473         while (i != _midi_tracer_windows.end() && (*i)->get_visible() == true) {
474                 ++i;
475         }
476
477         if (i == _midi_tracer_windows.end()) {
478                 /* all our MIDITracer windows are visible; make a new one */
479                 MidiTracer* t = new MidiTracer ();
480                 t->show_all ();
481                 _midi_tracer_windows.push_back (t);
482         } else {
483                 /* re-use the hidden one */
484                 (*i)->show_all ();
485         }
486 }
487
488 BundleManager*
489 ARDOUR_UI::create_bundle_manager ()
490 {
491         return new BundleManager (_session);
492 }
493
494 AddVideoDialog*
495 ARDOUR_UI::create_add_video_dialog ()
496 {
497         return new AddVideoDialog (_session);
498 }
499
500 SessionOptionEditor*
501 ARDOUR_UI::create_session_option_editor ()
502 {
503         return new SessionOptionEditor (_session);
504 }
505
506 BigClockWindow*
507 ARDOUR_UI::create_big_clock_window ()
508 {
509         return new BigClockWindow (*big_clock);
510 }
511
512 void
513 ARDOUR_UI::handle_locations_change (Location *)
514 {
515         if (_session) {
516                 if (_session->locations()->num_range_markers()) {
517                         ActionManager::set_sensitive (ActionManager::range_sensitive_actions, true);
518                 } else {
519                         ActionManager::set_sensitive (ActionManager::range_sensitive_actions, false);
520                 }
521         }
522 }
523
524 bool
525 ARDOUR_UI::main_window_state_event_handler (GdkEventWindowState* ev, bool window_was_editor)
526 {
527         if (window_was_editor) {
528
529                 if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
530                     (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
531                         if (big_clock_window) {
532                                 big_clock_window->set_transient_for (*editor);
533                         }
534                 }
535
536         } else {
537
538                 if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
539                     (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
540                         if (big_clock_window) {
541                                 big_clock_window->set_transient_for (*mixer);
542                         }
543                 }
544         }
545
546         return false;
547 }
548
549 bool
550 ARDOUR_UI::editor_meter_peak_button_release (GdkEventButton* ev)
551 {
552         if (ev->button == 1 && Gtkmm2ext::Keyboard::modifier_state_equals (ev->state, Gtkmm2ext::Keyboard::PrimaryModifier|Gtkmm2ext::Keyboard::TertiaryModifier)) {
553                 ArdourMeter::ResetAllPeakDisplays ();
554         } else if (ev->button == 1 && Gtkmm2ext::Keyboard::modifier_state_equals (ev->state, Gtkmm2ext::Keyboard::PrimaryModifier)) {
555                 if (_session->master_out()) {
556                         ArdourMeter::ResetGroupPeakDisplays (_session->master_out()->route_group());
557                 }
558         } else if (_session->master_out()) {
559                 ArdourMeter::ResetRoutePeakDisplays (_session->master_out().get());
560         }
561         return true;
562 }