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