Enable Menu > Quit to work again after startup on macOS
[ardour.git] / gtk2_ardour / ardour_ui_dialogs.cc
1 /*
2  * Copyright (C) 2005-2006 Taybin Rutkin <taybin@taybin.com>
3  * Copyright (C) 2005-2018 Paul Davis <paul@linuxaudiosystems.com>
4  * Copyright (C) 2006-2016 David Robillard <d@drobilla.net>
5  * Copyright (C) 2006 Hans Fugal <hans@fugal.net>
6  * Copyright (C) 2006 Nick Mainsbridge <mainsbridge@gmail.com>
7  * Copyright (C) 2007-2012 Carl Hetherington <carl@carlh.net>
8  * Copyright (C) 2007-2015 Tim Mayberry <mojofunk@gmail.com>
9  * Copyright (C) 2007 Doug McLain <doug@nostar.net>
10  * Copyright (C) 2013-2019 Robin Gareus <robin@gareus.org>
11  * Copyright (C) 2014-2018 Ben Loftis <ben@harrisonconsoles.com>
12  *
13  * This program is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation; either version 2 of the License, or
16  * (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License along
24  * with this program; if not, write to the Free Software Foundation, Inc.,
25  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26  */
27
28 /* This file contains any ARDOUR_UI methods that require knowledge of
29    the various dialog boxes, and exists so that no compilation dependency
30    exists between the main ARDOUR_UI modules and their respective classes.
31    This is to cut down on the compile times.  It also helps with my sanity.
32 */
33
34 #include <vector>
35
36 #include <gtkmm/treemodelfilter.h>
37
38 #include "pbd/convert.h"
39
40 #include "ardour/audioengine.h"
41 #include "ardour/automation_watch.h"
42 #include "ardour/control_protocol_manager.h"
43 #include "ardour/profile.h"
44 #include "ardour/session.h"
45
46 #include "control_protocol/control_protocol.h"
47
48 #include "gtkmm2ext/keyboard.h"
49 #include "gtkmm2ext/utils.h"
50
51 #include "actions.h"
52 #include "add_route_dialog.h"
53 #include "add_video_dialog.h"
54 #include "ardour_ui.h"
55 #include "big_clock_window.h"
56 #include "big_transport_window.h"
57 #include "bundle_manager.h"
58 #include "global_port_matrix.h"
59 #include "gui_object.h"
60 #include "gui_thread.h"
61 #include "keyeditor.h"
62 #include "location_ui.h"
63 #include "lua_script_manager.h"
64 #include "luawindow.h"
65 #include "main_clock.h"
66 #include "meterbridge.h"
67 #include "meter_patterns.h"
68 #include "monitor_section.h"
69 #include "midi_tracer.h"
70 #include "mini_timeline.h"
71 #include "mixer_ui.h"
72 #include "plugin_dspload_window.h"
73 #include "public_editor.h"
74 #include "processor_box.h"
75 #include "rc_option_editor.h"
76 #include "route_params_ui.h"
77 #include "shuttle_control.h"
78 #include "session_option_editor.h"
79 #include "speaker_dialog.h"
80 #include "splash.h"
81 #include "sfdb_ui.h"
82 #include "time_info_box.h"
83 #include "timers.h"
84 #include "transport_masters_dialog.h"
85 #include "virtual_keyboard_window.h"
86
87 #include "pbd/i18n.h"
88
89 using namespace ARDOUR;
90 using namespace PBD;
91 using namespace Glib;
92 using namespace Gtk;
93 using namespace Gtkmm2ext;
94 using namespace ArdourWidgets;
95
96 void
97 ARDOUR_UI::set_session (Session *s)
98 {
99         SessionHandlePtr::set_session (s);
100
101         transport_ctrl.set_session (s);
102
103         if (big_transport_window) {
104                 big_transport_window->set_session (s);
105         }
106
107         if (virtual_keyboard_window) {
108                 virtual_keyboard_window->set_session (s);
109         }
110
111         if (!_session) {
112                 WM::Manager::instance().set_session (s);
113                 /* Session option editor cannot exist across change-of-session */
114                 session_option_editor.drop_window ();
115                 /* Ditto for AddVideoDialog */
116                 add_video_dialog.drop_window ();
117                 /* screensaver + layered button sensitivity */
118                 map_transport_state ();
119                 return;
120         }
121
122         const XMLNode* node = _session->extra_xml (X_("UI"));
123
124         if (node) {
125                 const XMLNodeList& children = node->children();
126                 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
127                         if ((*i)->name() == GUIObjectState::xml_node_name) {
128                                 gui_object_state->load (**i);
129                                 break;
130                         }
131                 }
132         }
133
134         WM::Manager::instance().set_session (s);
135
136         AutomationWatch::instance().set_session (s);
137
138         shuttle_box.set_session (s);
139         mini_timeline.set_session (s);
140         time_info_box->set_session (s);
141
142         primary_clock->set_session (s);
143         secondary_clock->set_session (s);
144         big_clock->set_session (s);
145         video_timeline->set_session (s);
146         lua_script_window->set_session (s);
147         plugin_dsp_load_window->set_session (s);
148         transport_masters_window->set_session (s);
149         rc_option_editor->set_session (s);
150
151         /* sensitize menu bar options that are now valid */
152
153         ActionManager::set_sensitive (ActionManager::session_sensitive_actions, true);
154         ActionManager::set_sensitive (ActionManager::write_sensitive_actions, _session->writable());
155
156         if (_session->locations()->num_range_markers()) {
157                 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, true);
158         } else {
159                 ActionManager::set_sensitive (ActionManager::range_sensitive_actions, false);
160         }
161
162         /* allow wastebasket flush again */
163
164         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
165         if (act) {
166                 act->set_sensitive (true);
167         }
168
169         /* there are never any selections on startup */
170
171         ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, false);
172         ActionManager::set_sensitive (ActionManager::track_selection_sensitive_actions, false);
173         ActionManager::set_sensitive (ActionManager::route_selection_sensitive_actions, false);
174         ActionManager::set_sensitive (ActionManager::bus_selection_sensitive_actions, false);
175         ActionManager::set_sensitive (ActionManager::vca_selection_sensitive_actions, false);
176         ActionManager::set_sensitive (ActionManager::stripable_selection_sensitive_actions, false);
177         ActionManager::set_sensitive (ActionManager::line_selection_sensitive_actions, false);
178         ActionManager::set_sensitive (ActionManager::point_selection_sensitive_actions, false);
179         ActionManager::set_sensitive (ActionManager::playlist_selection_sensitive_actions, false);
180
181         solo_alert_button.set_active (_session->soloing());
182
183         setup_session_options ();
184
185         blink_connection = Timers::blink_connect (sigc::mem_fun(*this, &ARDOUR_UI::blink_handler));
186
187         _session->SaveSessionRequested.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::save_session_at_its_request, this, _1), gui_context());
188         _session->StateSaved.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_title, this), gui_context());
189         _session->RecordStateChanged.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::record_state_changed, this), gui_context());
190         _session->TransportStateChange.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::map_transport_state, this), gui_context());
191         _session->DirtyChanged.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_dirty_changed, this), gui_context());
192
193         _session->Xrun.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::xrun_handler, this, _1), gui_context());
194         _session->SoloActive.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::soloing_changed, this, _1), gui_context());
195         _session->AuditionActive.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::auditioning_changed, this, _1), gui_context());
196         _session->locations()->added.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::handle_locations_change, this, _1), gui_context());
197         _session->locations()->removed.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::handle_locations_change, this, _1), gui_context());
198         _session->config.ParameterChanged.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_parameter_changed, this, _1), gui_context ());
199
200         _session->LatencyUpdated.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_latency_updated, this), gui_context());
201         session_latency_updated ();
202
203         /* Clocks are on by default after we are connected to a session, so show that here.
204         */
205
206         connect_dependents_to_session (s);
207
208         /* listen to clock mode changes. don't do this earlier because otherwise as the clocks
209            restore their modes or are explicitly set, we will cause the "new" mode to be saved
210            back to the session XML ("Extra") state.
211          */
212
213         AudioClock::ModeChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::store_clock_modes));
214
215         Glib::signal_idle().connect (sigc::mem_fun (*this, &ARDOUR_UI::first_idle));
216
217         start_clocking ();
218
219         map_transport_state ();
220
221         second_connection = Timers::second_connect (sigc::mem_fun(*this, &ARDOUR_UI::every_second));
222         point_one_second_connection = Timers::rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::every_point_one_seconds));
223         point_zero_something_second_connection = Timers::super_rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::every_point_zero_something_seconds));
224         set_fps_timeout_connection();
225
226         update_format ();
227
228         if (editor_meter_table.get_parent()) {
229                 transport_hbox.remove (editor_meter_table);
230         }
231
232         if (editor_meter) {
233                 editor_meter_table.remove(*editor_meter);
234                 delete editor_meter;
235                 editor_meter = 0;
236                 editor_meter_peak_display.hide();
237         }
238
239         if (editor_meter_table.get_parent()) {
240                 transport_hbox.remove (editor_meter_table);
241         }
242
243         if (_session &&
244             _session->master_out() &&
245             _session->master_out()->n_outputs().n(DataType::AUDIO) > 0) {
246
247                 editor_meter = new LevelMeterHBox(_session);
248                 editor_meter->set_meter (_session->master_out()->shared_peak_meter().get());
249                 editor_meter->clear_meters();
250                 editor_meter->setup_meters (30, 10, 6);
251                 editor_meter->show();
252
253                 editor_meter_table.set_spacings(3);
254                 editor_meter_table.attach(*editor_meter,             0,1, 0,1, FILL, FILL);
255                 editor_meter_table.attach(editor_meter_peak_display, 0,1, 1,2, FILL, EXPAND|FILL);
256
257                 editor_meter->show();
258                 editor_meter_peak_display.show();
259
260                 ArdourMeter::ResetAllPeakDisplays.connect (sigc::mem_fun(*this, &ARDOUR_UI::reset_peak_display));
261                 ArdourMeter::ResetRoutePeakDisplays.connect (sigc::mem_fun(*this, &ARDOUR_UI::reset_route_peak_display));
262                 ArdourMeter::ResetGroupPeakDisplays.connect (sigc::mem_fun(*this, &ARDOUR_UI::reset_group_peak_display));
263
264                 editor_meter_peak_display.set_name ("meterbridge peakindicator");
265                 editor_meter_peak_display.unset_flags (Gtk::CAN_FOCUS);
266                 editor_meter_peak_display.set_size_request (-1, std::max(6.f, rintf(5.f * UIConfiguration::instance().get_ui_scale())) );
267                 editor_meter_peak_display.set_corner_radius (3.0);
268
269                 editor_meter_max_peak = -INFINITY;
270                 editor_meter_peak_display.signal_button_release_event().connect (sigc::mem_fun(*this, &ARDOUR_UI::editor_meter_peak_button_release), false);
271
272                 repack_transport_hbox ();
273         }
274
275         update_title ();
276 }
277
278 int
279 ARDOUR_UI::unload_session (bool hide_stuff)
280 {
281         if (_session) {
282                 ARDOUR_UI::instance()->video_timeline->sync_session_state();
283         }
284
285         if (_session && _session->dirty()) {
286                 std::vector<std::string> actions;
287                 actions.push_back (_("Don't close"));
288                 actions.push_back (_("Just close"));
289                 actions.push_back (_("Save and close"));
290                 switch (ask_about_saving_session (actions)) {
291                 case -1:
292                         // cancel
293                         return 1;
294
295                 case 1:
296                         _session->save_state ("");
297                         break;
298                 }
299         }
300
301         {
302                 // tear down session specific CPI (owned by rc_config_editor which can remain)
303                 ControlProtocolManager& m = ControlProtocolManager::instance ();
304                 for (std::list<ControlProtocolInfo*>::iterator i = m.control_protocol_info.begin(); i != m.control_protocol_info.end(); ++i) {
305                         if (*i && (*i)->protocol && (*i)->protocol->has_editor ()) {
306                                 (*i)->protocol->tear_down_gui ();
307                         }
308                 }
309         }
310
311         if (hide_stuff) {
312                 close_all_dialogs ();
313                 editor->hide ();
314                 mixer->hide ();
315                 meterbridge->hide ();
316                 audio_port_matrix->hide();
317                 midi_port_matrix->hide();
318                 route_params->hide();
319         }
320
321         second_connection.disconnect ();
322         point_one_second_connection.disconnect ();
323         point_zero_something_second_connection.disconnect();
324         fps_connection.disconnect();
325
326         if (editor_meter) {
327                 editor_meter_table.remove(*editor_meter);
328                 delete editor_meter;
329                 editor_meter = 0;
330                 editor_meter_peak_display.hide();
331         }
332
333         ActionManager::set_sensitive (ActionManager::session_sensitive_actions, false);
334
335         WM::Manager::instance().set_session ((ARDOUR::Session*) 0);
336
337         if (ARDOUR_UI::instance()->video_timeline) {
338                 ARDOUR_UI::instance()->video_timeline->close_session();
339         }
340
341         stop_clocking ();
342
343         /* drop everything attached to the blink signal */
344
345         blink_connection.disconnect ();
346
347         ARDOUR::Session* session_to_delete = _session;
348         _session = 0;
349         delete session_to_delete;
350
351         update_title ();
352
353         return 0;
354 }
355
356 void
357 ARDOUR_UI::toggle_editor_and_mixer ()
358 {
359         if (editor->tabbed() && mixer->tabbed()) {
360                 /* both in the same window */
361                 if (_tabs.get_current_page() == _tabs.page_num (editor->contents())) {
362                         _tabs.set_current_page (_tabs.page_num (mixer->contents()));
363                 } else if (_tabs.get_current_page() == _tabs.page_num (mixer->contents())) {
364                         _tabs.set_current_page (_tabs.page_num (editor->contents()));
365                 } else {
366                         /* go to mixer */
367                         _tabs.set_current_page (_tabs.page_num (mixer->contents()));
368                 }
369                 return;
370         }
371
372
373         if (editor->tabbed() && !mixer->tabbed()) {
374                 /* editor is tabbed, mixer is not */
375
376                 Gtk::Window* mwin = mixer->current_toplevel ();
377
378                 if (!mwin) {
379                         /* mixer's own window doesn't exist */
380                         mixer->make_visible ();
381                 } else if (!mwin->is_mapped ()) {
382                         /* mixer's own window exists but isn't mapped */
383                         mixer->make_visible ();
384                 } else {
385                         /* mixer window is mapped, editor is visible as tab */
386                         Gtk::Widget* f = mwin->get_focus();
387                         if (f && f->has_focus()) {
388                                 /* mixer has focus, switch to editor */
389                                 editor->make_visible ();
390                         } else {
391                                 mixer->make_visible ();
392                         }
393                 }
394                 return;
395         }
396
397         if (!editor->tabbed() && mixer->tabbed()) {
398                 /* mixer is tabbed, editor is not */
399
400                 Gtk::Window* ewin = editor->current_toplevel ();
401
402                 if (!ewin) {
403                         /* mixer's own window doesn't exist */
404                         editor->make_visible ();
405                 } else if (!ewin->is_mapped ()) {
406                         /* editor's own window exists but isn't mapped */
407                         editor->make_visible ();
408                 } else {
409                         /* editor window is mapped, mixer is visible as tab */
410                         Gtk::Widget* f = ewin->get_focus();
411                         if (f && f->has_focus()) {
412                                 /* editor has focus, switch to mixer */
413                                 mixer->make_visible ();
414                         } else {
415                                 editor->make_visible ();
416                         }
417                 }
418                 return;
419         }
420 }
421
422 void
423 ARDOUR_UI::step_up_through_tabs ()
424 {
425         std::vector<Tabbable*> candidates;
426
427         /* this list must match the order of visibility buttons */
428
429         if (!editor->window_visible()) {
430                 candidates.push_back (editor);
431         }
432
433         if (!mixer->window_visible()) {
434                 candidates.push_back (mixer);
435         }
436
437         if (!rc_option_editor->window_visible()) {
438                 candidates.push_back (rc_option_editor);
439         }
440
441         if (candidates.size() < 2) {
442                 /* nothing to be done with zero or one visible in tabs */
443                 return;
444         }
445
446         std::vector<Tabbable*>::iterator prev = candidates.end();
447         std::vector<Tabbable*>::iterator i;
448         Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page ());
449
450         for (i = candidates.begin(); i != candidates.end(); ++i) {
451                 if (w == &(*i)->contents()) {
452                         if (prev != candidates.end()) {
453                                 _tabs.set_current_page (_tabs.page_num ((*prev)->contents()));
454                         } else {
455                                 _tabs.set_current_page (_tabs.page_num (candidates.back()->contents()));
456                         }
457                         return;
458                 }
459                 prev = i;
460         }
461 }
462
463 void
464 ARDOUR_UI::step_down_through_tabs ()
465 {
466         std::vector<Tabbable*> candidates;
467
468         /* this list must match the order of visibility buttons */
469
470         if (!editor->window_visible()) {
471                 candidates.push_back (editor);
472         }
473
474         if (!mixer->window_visible()) {
475                 candidates.push_back (mixer);
476         }
477
478         if (!rc_option_editor->window_visible()) {
479                 candidates.push_back (rc_option_editor);
480         }
481
482         if (candidates.size() < 2) {
483                 /* nothing to be done with zero or one visible in tabs */
484                 return;
485         }
486
487         std::vector<Tabbable*>::reverse_iterator next = candidates.rend();
488         std::vector<Tabbable*>::reverse_iterator i;
489         Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page ());
490
491         for (i = candidates.rbegin(); i != candidates.rend(); ++i) {
492                 if (w == &(*i)->contents()) {
493                         if (next != candidates.rend()) {
494                                 _tabs.set_current_page (_tabs.page_num ((*next)->contents()));
495                         } else {
496                                 _tabs.set_current_page (_tabs.page_num (candidates.front()->contents()));
497                         }
498                         break;
499                 }
500                 next = i;
501         }
502 }
503
504 void
505 ARDOUR_UI::key_change_tabbable_visibility (Tabbable* t)
506 {
507         if (!t) {
508                 return;
509         }
510
511         if (t->tabbed()) {
512                 _tabs.set_current_page (_tabs.page_num (t->contents()));
513         } else if (!t->fully_visible()) {
514                 t->make_visible ();
515         } else {
516                 _main_window.present ();
517         }
518 }
519
520 void
521 ARDOUR_UI::button_change_tabbable_visibility (Tabbable* t)
522 {
523         /* For many/most users, clicking a button in the main window will make it
524            the main/front/key window, which will change any stacking relationship they
525            were trying to modify by clicking on the button in the first
526            place. This button-aware method knows that click on
527            a button designed to show/hide a Tabbable that has its own window
528            will have made that window be obscured (as the main window comes to
529            the front). We therefore *hide* the Tabbable's window if it is even
530            partially visible, believing that this is likely because the
531            Tabbable window used to be front, the user clicked to change that,
532            and before we even get here, the main window has become front.
533         */
534
535         if (!t) {
536                 return;
537         }
538
539         if (t->tabbed()) {
540                 _tabs.set_current_page (_tabs.page_num (t->contents()));
541         } else if (t->visible()) {
542                 t->hide();
543         } else {
544                 t->make_visible ();
545         }
546 }
547
548 void
549 ARDOUR_UI::show_tabbable (Tabbable* t)
550 {
551         if (!t) {
552                 return;
553         }
554
555         t->make_visible ();
556 }
557
558 void
559 ARDOUR_UI::hide_tabbable (Tabbable* t)
560 {
561         if (!t) {
562                 return;
563         }
564         t->make_invisible ();
565 }
566
567 void
568 ARDOUR_UI::attach_tabbable (Tabbable* t)
569 {
570         if (!t) {
571                 return;
572         }
573
574         t->attach ();
575 }
576
577 void
578 ARDOUR_UI::detach_tabbable (Tabbable* t)
579 {
580         if (!t) {
581                 return;
582         }
583         t->detach ();
584 }
585
586 void
587 ARDOUR_UI::tabs_page_added (Widget*,guint)
588 {
589         if (_tabs.get_n_pages() > 1) {
590
591                 std::vector<TargetEntry> drag_target_entries;
592                 drag_target_entries.push_back (TargetEntry ("tabbable"));
593
594                 editor_visibility_button.drag_source_set (drag_target_entries);
595                 mixer_visibility_button.drag_source_set (drag_target_entries);
596                 prefs_visibility_button.drag_source_set (drag_target_entries);
597
598                 editor_visibility_button.drag_source_set_icon (Gtkmm2ext::pixbuf_from_string (editor->name(),
599                                                                                               Pango::FontDescription ("Sans 24"),
600                                                                                               0, 0,
601                                                                                               Gdk::Color ("red")));
602                 mixer_visibility_button.drag_source_set_icon (Gtkmm2ext::pixbuf_from_string (mixer->name(),
603                                                                                              Pango::FontDescription ("Sans 24"),
604                                                                                              0, 0,
605                                                                                              Gdk::Color ("red")));
606                 prefs_visibility_button.drag_source_set_icon (Gtkmm2ext::pixbuf_from_string (rc_option_editor->name(),
607                                                                                              Pango::FontDescription ("Sans 24"),
608                                                                                              0, 0,
609                                                                                              Gdk::Color ("red")));
610         }
611 }
612
613 void
614 ARDOUR_UI::tabs_page_removed (Widget*, guint)
615 {
616         if (_tabs.get_n_pages() < 2) {
617                 editor_visibility_button.drag_source_unset ();
618                 mixer_visibility_button.drag_source_unset ();
619                 prefs_visibility_button.drag_source_unset ();
620         }
621 }
622
623 void
624 ARDOUR_UI::tabs_switch (GtkNotebookPage*, guint page)
625 {
626         if (editor && (page == (guint) _tabs.page_num (editor->contents()))) {
627                 editor_visibility_button.set_active_state (Gtkmm2ext::ImplicitActive);
628
629                 if (mixer && (mixer->tabbed() || mixer->tabbed_by_default())) {
630                         mixer_visibility_button.set_active_state (Gtkmm2ext::Off);
631                 }
632
633                 if (rc_option_editor && (rc_option_editor->tabbed() || rc_option_editor->tabbed_by_default())) {
634                         prefs_visibility_button.set_active_state (Gtkmm2ext::Off);
635                 }
636         } else if (mixer && (page == (guint) _tabs.page_num (mixer->contents()))) {
637
638                 if (editor && (editor->tabbed() || editor->tabbed_by_default())) {
639                         editor_visibility_button.set_active_state (Gtkmm2ext::Off);
640                 }
641
642                 mixer_visibility_button.set_active_state (Gtkmm2ext::ImplicitActive);
643
644                 if (rc_option_editor && (rc_option_editor->tabbed() || rc_option_editor->tabbed_by_default())) {
645                         prefs_visibility_button.set_active_state (Gtkmm2ext::Off);
646                 }
647
648         } else if (page == (guint) _tabs.page_num (rc_option_editor->contents())) {
649
650                 if (editor && (editor->tabbed() || editor->tabbed_by_default())) {
651                         editor_visibility_button.set_active_state (Gtkmm2ext::Off);
652                 }
653
654                 if (mixer && (mixer->tabbed() || mixer->tabbed_by_default())) {
655                         mixer_visibility_button.set_active_state (Gtkmm2ext::Off);
656                 }
657
658                 prefs_visibility_button.set_active_state (Gtkmm2ext::ImplicitActive);
659         }
660
661 }
662
663 void
664 ARDOUR_UI::tabbable_state_change (Tabbable& t)
665 {
666         std::vector<std::string> insensitive_action_names;
667         std::vector<std::string> sensitive_action_names;
668         std::vector<std::string> active_action_names;
669         std::vector<std::string> inactive_action_names;
670         Glib::RefPtr<Action> action;
671         std::string downcased_name = downcase (t.name());
672         enum ViewState {
673                 Tabbed,
674                 Windowed,
675                 Hidden
676         };
677         ViewState vs;
678
679         if (t.tabbed()) {
680
681                 insensitive_action_names.push_back (string_compose ("attach-%1", downcased_name));
682                 sensitive_action_names.push_back (string_compose ("show-%1", downcased_name));
683                 sensitive_action_names.push_back (string_compose ("detach-%1", downcased_name));
684                 sensitive_action_names.push_back (string_compose ("hide-%1", downcased_name));
685
686                 vs = Tabbed;
687
688         } else if (t.tabbed_by_default ()) {
689
690                 insensitive_action_names.push_back (string_compose ("attach-%1", downcased_name));
691                 insensitive_action_names.push_back (string_compose ("hide-%1", downcased_name));
692                 sensitive_action_names.push_back (string_compose ("show-%1", downcased_name));
693                 sensitive_action_names.push_back (string_compose ("detach-%1", downcased_name));
694
695                 vs = Hidden;
696
697         } else if (t.window_visible()) {
698
699                 insensitive_action_names.push_back (string_compose ("detach-%1", downcased_name));
700                 sensitive_action_names.push_back (string_compose ("show-%1", downcased_name));
701                 sensitive_action_names.push_back (string_compose ("attach-%1", downcased_name));
702                 sensitive_action_names.push_back (string_compose ("hide-%1", downcased_name));
703
704                 active_action_names.push_back (string_compose ("show-%1", downcased_name));
705                 inactive_action_names.push_back (string_compose ("hide-%1", downcased_name));
706
707                 vs = Windowed;
708
709         } else {
710
711                 /* not currently visible. allow user to retab it or just make
712                  * it visible.
713                  */
714
715                 insensitive_action_names.push_back (string_compose ("detach-%1", downcased_name));
716                 insensitive_action_names.push_back (string_compose ("hide-%1", downcased_name));
717                 sensitive_action_names.push_back (string_compose ("show-%1", downcased_name));
718                 sensitive_action_names.push_back (string_compose ("attach-%1", downcased_name));
719
720                 active_action_names.push_back (string_compose ("hide-%1", downcased_name));
721                 inactive_action_names.push_back (string_compose ("show-%1", downcased_name));
722
723                 vs = Hidden;
724         }
725
726         for (std::vector<std::string>::iterator s = insensitive_action_names.begin(); s != insensitive_action_names.end(); ++s) {
727                 action = ActionManager::get_action (X_("Common"), (*s).c_str(), false);
728                 if (action) {
729                         action->set_sensitive (false);
730                 }
731         }
732
733         for (std::vector<std::string>::iterator s = sensitive_action_names.begin(); s != sensitive_action_names.end(); ++s) {
734                 action = ActionManager::get_action (X_("Common"), (*s).c_str(), false);
735                 if (action) {
736                         action->set_sensitive (true);
737                 }
738         }
739
740         ArdourButton* vis_button = 0;
741         std::vector<ArdourButton*> other_vis_buttons;
742
743         if (&t == editor) {
744                 vis_button = &editor_visibility_button;
745                 other_vis_buttons.push_back (&mixer_visibility_button);
746                 other_vis_buttons.push_back (&prefs_visibility_button);
747         } else if (&t == mixer) {
748                 vis_button = &mixer_visibility_button;
749                 other_vis_buttons.push_back (&editor_visibility_button);
750                 other_vis_buttons.push_back (&prefs_visibility_button);
751         } else if (&t == rc_option_editor) {
752                 vis_button = &prefs_visibility_button;
753                 other_vis_buttons.push_back (&editor_visibility_button);
754                 other_vis_buttons.push_back (&mixer_visibility_button);
755         }
756
757         if (!vis_button) {
758                 return;
759         }
760
761         switch (vs) {
762         case Tabbed:
763                 vis_button->set_active_state (Gtkmm2ext::ImplicitActive);
764                 break;
765         case Windowed:
766                 vis_button->set_active_state (Gtkmm2ext::ExplicitActive);
767                 break;
768         case Hidden:
769                 vis_button->set_active_state (Gtkmm2ext::Off);
770                 break;
771         }
772
773         for (std::vector<ArdourButton*>::iterator b = other_vis_buttons.begin(); b != other_vis_buttons.end(); ++b) {
774                 (*b)->set_active_state (Gtkmm2ext::Off);
775         }
776 }
777
778 void
779 ARDOUR_UI::toggle_meterbridge ()
780 {
781         assert (editor && mixer && meterbridge);
782
783         bool show = false;
784         bool obscuring = false;
785
786         if (meterbridge->not_visible ()) {
787                 show = true;
788         } else if ((editor->window_visible() && ARDOUR_UI_UTILS::windows_overlap (editor->own_window(), meterbridge)) ||
789                    (mixer->window_visible () && ARDOUR_UI_UTILS::windows_overlap (mixer->own_window(), meterbridge))) {
790                 obscuring = true;
791         }
792
793         if (obscuring && ((editor->own_window() && editor->own_window()->property_has_toplevel_focus()) ||
794                           (mixer->own_window() && mixer->own_window()->property_has_toplevel_focus()))) {
795                 show = true;
796         }
797
798         if (show) {
799                 meterbridge->show_window ();
800                 meterbridge->present ();
801                 meterbridge->raise ();
802         } else {
803                 meterbridge->hide_window (NULL);
804         }
805 }
806
807 void
808 ARDOUR_UI::toggle_luawindow ()
809 {
810         assert (editor && luawindow);
811
812         bool show = false;
813
814         if (luawindow->not_visible ()) {
815                 show = true;
816         }
817         // TODO check overlap
818
819         if (show) {
820                 luawindow->show_window ();
821                 luawindow->present ();
822                 luawindow->raise ();
823         } else {
824                 luawindow->hide_window (NULL);
825         }
826 }
827
828
829 void
830 ARDOUR_UI::new_midi_tracer_window ()
831 {
832         RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("NewMIDITracer"));
833         if (!act) {
834                 return;
835         }
836
837         std::list<MidiTracer*>::iterator i = _midi_tracer_windows.begin ();
838         while (i != _midi_tracer_windows.end() && (*i)->get_visible() == true) {
839                 ++i;
840         }
841
842         if (i == _midi_tracer_windows.end()) {
843                 /* all our MIDITracer windows are visible; make a new one */
844                 MidiTracer* t = new MidiTracer ();
845                 t->show_all ();
846                 _midi_tracer_windows.push_back (t);
847         } else {
848                 /* re-use the hidden one */
849                 (*i)->show_all ();
850         }
851 }
852
853 KeyEditor*
854 ARDOUR_UI::create_key_editor ()
855 {
856         KeyEditor* kedit = new KeyEditor;
857
858         for (std::list<Bindings*>::iterator b = Bindings::bindings.begin(); b != Bindings::bindings.end(); ++b) {
859                 kedit->add_tab ((*b)->name(), **b);
860         }
861
862         return kedit;
863 }
864
865 BundleManager*
866 ARDOUR_UI::create_bundle_manager ()
867 {
868         return new BundleManager (_session);
869 }
870
871 AddVideoDialog*
872 ARDOUR_UI::create_add_video_dialog ()
873 {
874         return new AddVideoDialog (_session);
875 }
876
877 SessionOptionEditor*
878 ARDOUR_UI::create_session_option_editor ()
879 {
880         return new SessionOptionEditor (_session);
881 }
882
883 BigClockWindow*
884 ARDOUR_UI::create_big_clock_window ()
885 {
886         return new BigClockWindow (*big_clock);
887 }
888
889 BigTransportWindow*
890 ARDOUR_UI::create_big_transport_window ()
891 {
892         BigTransportWindow* btw = new BigTransportWindow ();
893         btw->set_session (_session);
894         return btw;
895 }
896
897 VirtualKeyboardWindow*
898 ARDOUR_UI::create_virtual_keyboard_window ()
899 {
900         VirtualKeyboardWindow* vkbd = new VirtualKeyboardWindow ();
901         vkbd->set_session (_session);
902         return vkbd;
903 }
904
905 void
906 ARDOUR_UI::handle_locations_change (Location *)
907 {
908         if (_session) {
909                 if (_session->locations()->num_range_markers()) {
910                         ActionManager::set_sensitive (ActionManager::range_sensitive_actions, true);
911                 } else {
912                         ActionManager::set_sensitive (ActionManager::range_sensitive_actions, false);
913                 }
914         }
915 }
916
917 bool
918 ARDOUR_UI::tabbed_window_state_event_handler (GdkEventWindowState* ev, void* object)
919 {
920         if (object == editor) {
921
922                 if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
923                     (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
924                         if (big_clock_window) {
925                                 big_clock_window->set_transient_for (*editor->own_window());
926                         }
927                         if (big_transport_window) {
928                                 big_transport_window->set_transient_for (*editor->own_window());
929                         }
930                         if (virtual_keyboard_window) {
931                                 virtual_keyboard_window->set_transient_for (*editor->own_window());
932                         }
933                 }
934
935         } else if (object == mixer) {
936
937                 if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
938                     (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
939                         if (big_clock_window) {
940                                 big_clock_window->set_transient_for (*mixer->own_window());
941                         }
942                         if (big_transport_window) {
943                                 big_transport_window->set_transient_for (*mixer->own_window());
944                         }
945                         if (virtual_keyboard_window) {
946                                 virtual_keyboard_window->set_transient_for (*mixer->own_window());
947                         }
948                 }
949         }
950
951         return false;
952 }
953
954 bool
955 ARDOUR_UI::editor_meter_peak_button_release (GdkEventButton* ev)
956 {
957         if (ev->button == 1) {
958                 ArdourMeter::ResetAllPeakDisplays ();
959         }
960         return false;
961 }
962
963 void
964 ARDOUR_UI::toggle_mixer_space()
965 {
966         Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action ("Common", "ToggleMaximalMixer");
967         if (tact->get_active()) {
968                 mixer->maximise_mixer_space ();
969         } else {
970                 mixer->restore_mixer_space ();
971         }
972 }