a variety of fixes aimed at preventing crashes caused by the (global) port matrix...
[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 "ardour_ui.h"
33 #include "bundle_manager.h"
34 #include "global_port_matrix.h"
35 #include "gui_object.h"
36 #include "gui_thread.h"
37 #include "keyeditor.h"
38 #include "location_ui.h"
39 #include "main_clock.h"
40 #include "midi_tracer.h"
41 #include "mixer_ui.h"
42 #include "public_editor.h"
43 #include "rc_option_editor.h"
44 #include "route_params_ui.h"
45 #include "shuttle_control.h"
46 #include "session_option_editor.h"
47 #include "speaker_dialog.h"
48 #include "sfdb_ui.h"
49 #include "theme_manager.h"
50 #include "time_info_box.h"
51
52 #include "i18n.h"
53
54 using namespace ARDOUR;
55 using namespace PBD;
56 using namespace Glib;
57 using namespace Gtk;
58 using namespace Gtkmm2ext;
59
60 void
61 ARDOUR_UI::set_session (Session *s)
62 {
63         SessionHandlePtr::set_session (s);
64
65         for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) {
66                 GlobalPortMatrixWindow* w;
67                 if ((w = _global_port_matrix[*i]->get()) != 0) {
68                         w->set_session (s);
69                 }
70         }
71
72         if (!_session) {
73                 return;
74         }
75
76         const XMLNode* node = _session->extra_xml (X_("UI"));
77
78         if (node) {
79                 const XMLNodeList& children = node->children();
80                 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
81                         if ((*i)->name() == GUIObjectState::xml_node_name) {
82                                 gui_object_state->load (**i);
83                                 break;
84                         }
85                 }
86         }
87
88         AutomationWatch::instance().set_session (s);
89
90         if (location_ui->get()) {
91                 location_ui->get()->set_session(s);
92         }
93
94         if (speaker_config_window->get()) {
95                 speaker_config_window->get()->set_speakers (s->get_speakers());
96         }
97
98         if (route_params) {
99                 route_params->set_session (s);
100         }
101
102         if (add_route_dialog) {
103                 add_route_dialog->set_session (s);
104         }
105
106         if (session_option_editor) {
107                 session_option_editor->set_session (s);
108         }
109
110         if (shuttle_box) {
111                 shuttle_box->set_session (s);
112         }
113
114         for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) {
115                 if (_global_port_matrix[*i]->get()) {
116                         _global_port_matrix[*i]->get()->set_session (_session);
117                 }
118         }
119
120         primary_clock->set_session (s);
121         secondary_clock->set_session (s);
122         big_clock->set_session (s);
123         time_info_box->set_session (s);
124
125         /* sensitize menu bar options that are now valid */
126
127         ActionManager::set_sensitive (ActionManager::session_sensitive_actions, true);
128         ActionManager::set_sensitive (ActionManager::write_sensitive_actions, _session->writable());
129
130         if (_session->locations()->num_range_markers()) {
131                 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, true);
132         } else {
133                 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, false);
134         }
135
136         if (!_session->monitor_out()) {
137                 Glib::RefPtr<Action> act = ActionManager::get_action (X_("options"), X_("SoloViaBus"));
138                 if (act) {
139                         act->set_sensitive (false);
140                 }
141         }
142
143         /* allow wastebasket flush again */
144
145         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
146         if (act) {
147                 act->set_sensitive (true);
148         }
149
150         /* there are never any selections on startup */
151
152         ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, false);
153         ActionManager::set_sensitive (ActionManager::track_selection_sensitive_actions, false);
154         ActionManager::set_sensitive (ActionManager::line_selection_sensitive_actions, false);
155         ActionManager::set_sensitive (ActionManager::point_selection_sensitive_actions, false);
156         ActionManager::set_sensitive (ActionManager::playlist_selection_sensitive_actions, false);
157
158         rec_button.set_sensitive (true);
159
160         solo_alert_button.set_active (_session->soloing());
161
162         setup_session_options ();
163
164         Blink.connect (sigc::mem_fun(*this, &ARDOUR_UI::transport_rec_enable_blink));
165         Blink.connect (sigc::mem_fun(*this, &ARDOUR_UI::solo_blink));
166         Blink.connect (sigc::mem_fun(*this, &ARDOUR_UI::sync_blink));
167         Blink.connect (sigc::mem_fun(*this, &ARDOUR_UI::audition_blink));
168         Blink.connect (sigc::mem_fun(*this, &ARDOUR_UI::feedback_blink));
169
170         _session->RecordStateChanged.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::record_state_changed, this), gui_context());
171         _session->StepEditStatusChange.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::step_edit_status_change, this, _1), gui_context());
172         _session->TransportStateChange.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::map_transport_state, this), gui_context());
173         _session->DirtyChanged.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_autosave, this), gui_context());
174
175         _session->Xrun.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::xrun_handler, this, _1), gui_context());
176         _session->SoloActive.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::soloing_changed, this, _1), gui_context());
177         _session->AuditionActive.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::auditioning_changed, this, _1), gui_context());
178         _session->locations()->added.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::handle_locations_change, this, _1), gui_context());
179         _session->locations()->removed.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::handle_locations_change, this, _1), gui_context());
180         _session->config.ParameterChanged.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_parameter_changed, this, _1), gui_context ());
181
182 #ifdef HAVE_JACK_SESSION
183         engine->JackSessionEvent.connect (*_session, MISSING_INVALIDATOR, boost::bind (&Session::jack_session_event, _session, _1), gui_context());
184 #endif
185
186         /* Clocks are on by default after we are connected to a session, so show that here.
187         */
188
189         connect_dependents_to_session (s);
190
191         /* listen to clock mode changes. don't do this earlier because otherwise as the clocks
192            restore their modes or are explicitly set, we will cause the "new" mode to be saved
193            back to the session XML ("Extra") state.
194          */
195
196         AudioClock::ModeChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::store_clock_modes));
197
198         Glib::signal_idle().connect (sigc::mem_fun (*this, &ARDOUR_UI::first_idle));
199
200         start_clocking ();
201         start_blinking ();
202
203         map_transport_state ();
204
205         second_connection = Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::every_second), 1000);
206         point_one_second_connection = Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::every_point_one_seconds), 100);
207         point_zero_one_second_connection = Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::every_point_zero_one_seconds), 40);
208
209         update_format ();
210 }
211
212 int
213 ARDOUR_UI::unload_session (bool hide_stuff)
214 {
215         if (_session && _session->dirty()) {
216                 std::vector<std::string> actions;
217                 actions.push_back (_("Don't close"));
218                 actions.push_back (_("Just close"));
219                 actions.push_back (_("Save and close"));
220                 switch (ask_about_saving_session (actions)) {
221                 case -1:
222                         // cancel
223                         return 1;
224
225                 case 1:
226                         _session->save_state ("");
227                         break;
228                 }
229         }
230
231         if (hide_stuff) {
232                 editor->hide ();
233                 mixer->hide ();
234                 theme_manager->hide ();
235         }
236
237         second_connection.disconnect ();
238         point_one_second_connection.disconnect ();
239         point_oh_five_second_connection.disconnect ();
240         point_zero_one_second_connection.disconnect();
241
242         ActionManager::set_sensitive (ActionManager::session_sensitive_actions, false);
243
244         rec_button.set_sensitive (false);
245
246         stop_blinking ();
247         stop_clocking ();
248
249         /* drop everything attached to the blink signal */
250
251         Blink.clear ();
252
253         delete _session;
254         _session = 0;
255
256         session_loaded = false;
257
258         update_buffer_load ();
259
260         return 0;
261 }
262
263 void
264 ARDOUR_UI::toggle_big_clock_window ()
265 {
266         RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleBigClock"));
267         if (act) {
268                 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
269
270                 if (tact->get_active()) {
271                         big_clock_window->get()->show_all ();
272                         big_clock_window->get()->present ();
273                 } else {
274                         big_clock_window->get()->hide ();
275                 }
276         }
277 }
278
279 void
280 ARDOUR_UI::toggle_speaker_config_window ()
281 {
282         RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("toggle-speaker-config"));
283         if (act) {
284                 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
285
286                 if (tact->get_active()) {
287                         speaker_config_window->get()->show_all ();
288                         speaker_config_window->get()->present ();
289                 } else {
290                         speaker_config_window->get()->hide ();
291                 }
292         }
293 }
294
295 void
296 ARDOUR_UI::new_midi_tracer_window ()
297 {
298         RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("NewMIDITracer"));
299         if (!act) {
300                 return;
301         }
302
303         std::list<MidiTracer*>::iterator i = _midi_tracer_windows.begin ();
304         while (i != _midi_tracer_windows.end() && (*i)->get_visible() == true) {
305                 ++i;
306         }
307
308         if (i == _midi_tracer_windows.end()) {
309                 /* all our MIDITracer windows are visible; make a new one */
310                 MidiTracer* t = new MidiTracer ();
311                 manage_window (*t);
312                 t->show_all ();
313                 _midi_tracer_windows.push_back (t);
314         } else {
315                 /* re-use the hidden one */
316                 (*i)->show_all ();
317         }
318 }
319
320 void
321 ARDOUR_UI::toggle_rc_options_window ()
322 {
323         if (rc_option_editor == 0) {
324                 rc_option_editor = new RCOptionEditor;
325                 rc_option_editor->signal_unmap().connect(sigc::bind (sigc::ptr_fun(&ActionManager::uncheck_toggleaction), X_("<Actions>/Common/ToggleRCOptionsEditor")));
326                 rc_option_editor->set_session (_session);
327         }
328
329         RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleRCOptionsEditor"));
330         if (act) {
331                 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
332
333                 if (tact->get_active()) {
334                         rc_option_editor->show_all ();
335                         rc_option_editor->present ();
336                 } else {
337                         rc_option_editor->hide ();
338                 }
339         }
340 }
341
342 void
343 ARDOUR_UI::toggle_session_options_window ()
344 {
345         if (session_option_editor == 0) {
346                 session_option_editor = new SessionOptionEditor (_session);
347                 session_option_editor->signal_unmap().connect(sigc::bind (sigc::ptr_fun(&ActionManager::uncheck_toggleaction), X_("<Actions>/Common/ToggleSessionOptionsEditor")));
348         }
349
350         RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleSessionOptionsEditor"));
351         if (act) {
352                 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic (act);
353
354                 if (tact->get_active()) {
355                         session_option_editor->show_all ();
356                         session_option_editor->present ();
357                 } else {
358                         session_option_editor->hide ();
359                 }
360         }
361 }
362
363 int
364 ARDOUR_UI::create_location_ui ()
365 {
366         if (location_ui->get() == 0) {
367                 location_ui->set (new LocationUIWindow ());
368                 location_ui->get()->set_session (_session);
369                 location_ui->get()->signal_unmap().connect (sigc::bind (sigc::ptr_fun(&ActionManager::uncheck_toggleaction), X_("<Actions>/Common/ToggleLocations")));
370         }
371         return 0;
372 }
373
374 void
375 ARDOUR_UI::toggle_location_window ()
376 {
377         if (create_location_ui()) {
378                 return;
379         }
380
381         RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleLocations"));
382         if (act) {
383                 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
384
385                 if (tact->get_active()) {
386                         location_ui->get()->show_all ();
387                         location_ui->get()->present ();
388                 } else {
389                         location_ui->get()->hide ();
390                 }
391         }
392 }
393
394 void
395 ARDOUR_UI::toggle_key_editor ()
396 {
397         if (key_editor == 0) {
398                 key_editor = new KeyEditor;
399                 key_editor->signal_unmap().connect (sigc::bind (sigc::ptr_fun(&ActionManager::uncheck_toggleaction), X_("<Actions>/Common/ToggleKeyEditor")));
400         }
401
402         RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleKeyEditor"));
403         if (act) {
404                 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
405
406                 if (tact->get_active()) {
407                         key_editor->show_all ();
408                         key_editor->present ();
409                 } else {
410                         key_editor->hide ();
411                 }
412         }
413 }
414
415 void
416 ARDOUR_UI::toggle_theme_manager ()
417 {
418         RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleThemeManager"));
419         if (act) {
420                 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
421
422                 if (tact->get_active()) {
423                         theme_manager->show_all ();
424                         theme_manager->present ();
425                 } else {
426                         theme_manager->hide ();
427                 }
428         }
429 }
430
431 void
432 ARDOUR_UI::create_bundle_manager ()
433 {
434         if (bundle_manager == 0) {
435                 bundle_manager = new BundleManager (_session);
436                 bundle_manager->signal_unmap().connect (sigc::bind (sigc::ptr_fun (&ActionManager::uncheck_toggleaction), X_("<Actions>/Common/ToggleBundleManager")));
437         }
438 }
439
440 void
441 ARDOUR_UI::toggle_bundle_manager ()
442 {
443         create_bundle_manager ();
444
445         RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleBundleManager"));
446         if (act) {
447                 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic (act);
448
449                 if (tact->get_active()) {
450                         bundle_manager->show_all ();
451                         bundle_manager->present ();
452                 } else {
453                         bundle_manager->hide ();
454                 }
455         }
456 }
457
458 int
459 ARDOUR_UI::create_route_params ()
460 {
461         if (route_params == 0) {
462                 route_params = new RouteParams_UI ();
463                 route_params->set_session (_session);
464                 route_params->signal_unmap().connect (sigc::bind(sigc::ptr_fun(&ActionManager::uncheck_toggleaction), X_("<Actions>/Common/ToggleInspector")));
465         }
466         return 0;
467 }
468
469 void
470 ARDOUR_UI::toggle_route_params_window ()
471 {
472         if (create_route_params ()) {
473                 return;
474         }
475
476         RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleInspector"));
477         if (act) {
478                 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
479
480                 if (tact->get_active()) {
481                         route_params->show_all ();
482                         route_params->present ();
483                 } else {
484                         route_params->hide ();
485                 }
486         }
487 }
488
489 void
490 ARDOUR_UI::handle_locations_change (Location *)
491 {
492         if (_session) {
493                 if (_session->locations()->num_range_markers()) {
494                         ActionManager::set_sensitive (ActionManager::range_sensitive_actions, true);
495                 } else {
496                         ActionManager::set_sensitive (ActionManager::range_sensitive_actions, false);
497                 }
498         }
499 }
500
501 bool
502 ARDOUR_UI::main_window_state_event_handler (GdkEventWindowState* ev, bool window_was_editor)
503 {
504         if (window_was_editor) {
505
506                 if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
507                     (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
508                         float_big_clock (editor);
509                 }
510
511         } else {
512
513                 if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
514                     (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
515                         float_big_clock (mixer);
516                 }
517         }
518
519         return false;
520 }