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