Fix thinkos in cubasish theme
[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         }
237
238         if (editor_meter_table.get_parent()) {
239                 transport_hbox.remove (editor_meter_table);
240         }
241         if (editor_meter_peak_display.get_parent ()) {
242                 editor_meter_table.remove (editor_meter_peak_display);
243         }
244
245         if (_session &&
246             _session->master_out() &&
247             _session->master_out()->n_outputs().n(DataType::AUDIO) > 0) {
248
249                 editor_meter = new LevelMeterHBox(_session);
250                 editor_meter->set_meter (_session->master_out()->shared_peak_meter().get());
251                 editor_meter->clear_meters();
252                 editor_meter->setup_meters (30, 10, 6);
253                 editor_meter->show();
254
255                 editor_meter_table.set_spacings(3);
256                 editor_meter_table.attach(*editor_meter,             0,1, 0,1, FILL, EXPAND|FILL, 0, 1);
257                 editor_meter_table.attach(editor_meter_peak_display, 0,1, 1,2, FILL, SHRINK, 0, 0);
258
259                 editor_meter->show();
260                 editor_meter_peak_display.show();
261
262                 ArdourMeter::ResetAllPeakDisplays.connect (sigc::mem_fun(*this, &ARDOUR_UI::reset_peak_display));
263                 ArdourMeter::ResetRoutePeakDisplays.connect (sigc::mem_fun(*this, &ARDOUR_UI::reset_route_peak_display));
264                 ArdourMeter::ResetGroupPeakDisplays.connect (sigc::mem_fun(*this, &ARDOUR_UI::reset_group_peak_display));
265
266                 editor_meter_peak_display.set_name ("meterbridge peakindicator");
267                 editor_meter_peak_display.unset_flags (Gtk::CAN_FOCUS);
268                 editor_meter_peak_display.set_size_request (-1, std::max (5.f, std::min (12.f, rintf (8.f * UIConfiguration::instance().get_ui_scale()))) );
269                 editor_meter_peak_display.set_corner_radius (1.0);
270
271                 editor_meter_max_peak = -INFINITY;
272                 editor_meter_peak_display.signal_button_release_event().connect (sigc::mem_fun(*this, &ARDOUR_UI::editor_meter_peak_button_release), false);
273
274                 repack_transport_hbox ();
275         }
276
277         update_title ();
278 }
279
280 int
281 ARDOUR_UI::unload_session (bool hide_stuff)
282 {
283         if (_session) {
284                 ARDOUR_UI::instance()->video_timeline->sync_session_state();
285
286                 /* Unconditionally save session-specific GUI settings:
287                  * Playhead position, zoom/scroll with stationary PH,
288                  * window and pane positions, etc.
289                  *
290                  * While many GUI operations immediately cause an instant.xml
291                  * save, changing the playhead-pos in particular does not,
292                  * nor mark the session dirty.
293                  */
294                 save_ardour_state ();
295         }
296
297         if (_session && _session->dirty()) {
298                 std::vector<std::string> actions;
299                 actions.push_back (_("Don't close"));
300                 actions.push_back (_("Just close"));
301                 actions.push_back (_("Save and close"));
302                 switch (ask_about_saving_session (actions)) {
303                 case -1:
304                         // cancel
305                         return 1;
306
307                 case 1:
308                         _session->save_state ("");
309                         break;
310                 }
311         }
312
313         {
314                 // tear down session specific CPI (owned by rc_config_editor which can remain)
315                 ControlProtocolManager& m = ControlProtocolManager::instance ();
316                 for (std::list<ControlProtocolInfo*>::iterator i = m.control_protocol_info.begin(); i != m.control_protocol_info.end(); ++i) {
317                         if (*i && (*i)->protocol && (*i)->protocol->has_editor ()) {
318                                 (*i)->protocol->tear_down_gui ();
319                         }
320                 }
321         }
322
323         if (hide_stuff) {
324                 close_all_dialogs ();
325                 editor->hide ();
326                 mixer->hide ();
327                 meterbridge->hide ();
328                 audio_port_matrix->hide();
329                 midi_port_matrix->hide();
330                 route_params->hide();
331         }
332
333         second_connection.disconnect ();
334         point_one_second_connection.disconnect ();
335         point_zero_something_second_connection.disconnect();
336         fps_connection.disconnect();
337
338         if (editor_meter) {
339                 editor_meter_table.remove(*editor_meter);
340                 delete editor_meter;
341                 editor_meter = 0;
342                 editor_meter_peak_display.hide();
343         }
344
345         ActionManager::set_sensitive (ActionManager::session_sensitive_actions, false);
346
347         WM::Manager::instance().set_session ((ARDOUR::Session*) 0);
348
349         if (ARDOUR_UI::instance()->video_timeline) {
350                 ARDOUR_UI::instance()->video_timeline->close_session();
351         }
352
353         stop_clocking ();
354
355         /* drop everything attached to the blink signal */
356
357         blink_connection.disconnect ();
358
359         ARDOUR::Session* session_to_delete = _session;
360         _session = 0;
361         delete session_to_delete;
362
363         update_title ();
364
365         return 0;
366 }
367
368 void
369 ARDOUR_UI::toggle_editor_and_mixer ()
370 {
371         if (editor->tabbed() && mixer->tabbed()) {
372                 /* both in the same window */
373                 if (_tabs.get_current_page() == _tabs.page_num (editor->contents())) {
374                         _tabs.set_current_page (_tabs.page_num (mixer->contents()));
375                 } else if (_tabs.get_current_page() == _tabs.page_num (mixer->contents())) {
376                         _tabs.set_current_page (_tabs.page_num (editor->contents()));
377                 } else {
378                         /* go to mixer */
379                         _tabs.set_current_page (_tabs.page_num (mixer->contents()));
380                 }
381                 return;
382         }
383
384
385         if (editor->tabbed() && !mixer->tabbed()) {
386                 /* editor is tabbed, mixer is not */
387
388                 Gtk::Window* mwin = mixer->current_toplevel ();
389
390                 if (!mwin) {
391                         /* mixer's own window doesn't exist */
392                         mixer->make_visible ();
393                 } else if (!mwin->is_mapped ()) {
394                         /* mixer's own window exists but isn't mapped */
395                         mixer->make_visible ();
396                 } else {
397                         /* mixer window is mapped, editor is visible as tab */
398                         Gtk::Widget* f = mwin->get_focus();
399                         if (f && f->has_focus()) {
400                                 /* mixer has focus, switch to editor */
401                                 editor->make_visible ();
402                         } else {
403                                 mixer->make_visible ();
404                         }
405                 }
406                 return;
407         }
408
409         if (!editor->tabbed() && mixer->tabbed()) {
410                 /* mixer is tabbed, editor is not */
411
412                 Gtk::Window* ewin = editor->current_toplevel ();
413
414                 if (!ewin) {
415                         /* mixer's own window doesn't exist */
416                         editor->make_visible ();
417                 } else if (!ewin->is_mapped ()) {
418                         /* editor's own window exists but isn't mapped */
419                         editor->make_visible ();
420                 } else {
421                         /* editor window is mapped, mixer is visible as tab */
422                         Gtk::Widget* f = ewin->get_focus();
423                         if (f && f->has_focus()) {
424                                 /* editor has focus, switch to mixer */
425                                 mixer->make_visible ();
426                         } else {
427                                 editor->make_visible ();
428                         }
429                 }
430                 return;
431         }
432 }
433
434 void
435 ARDOUR_UI::step_up_through_tabs ()
436 {
437         std::vector<Tabbable*> candidates;
438
439         /* this list must match the order of visibility buttons */
440
441         if (!editor->window_visible()) {
442                 candidates.push_back (editor);
443         }
444
445         if (!mixer->window_visible()) {
446                 candidates.push_back (mixer);
447         }
448
449         if (!rc_option_editor->window_visible()) {
450                 candidates.push_back (rc_option_editor);
451         }
452
453         if (candidates.size() < 2) {
454                 /* nothing to be done with zero or one visible in tabs */
455                 return;
456         }
457
458         std::vector<Tabbable*>::iterator prev = candidates.end();
459         std::vector<Tabbable*>::iterator i;
460         Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page ());
461
462         for (i = candidates.begin(); i != candidates.end(); ++i) {
463                 if (w == &(*i)->contents()) {
464                         if (prev != candidates.end()) {
465                                 _tabs.set_current_page (_tabs.page_num ((*prev)->contents()));
466                         } else {
467                                 _tabs.set_current_page (_tabs.page_num (candidates.back()->contents()));
468                         }
469                         return;
470                 }
471                 prev = i;
472         }
473 }
474
475 void
476 ARDOUR_UI::step_down_through_tabs ()
477 {
478         std::vector<Tabbable*> candidates;
479
480         /* this list must match the order of visibility buttons */
481
482         if (!editor->window_visible()) {
483                 candidates.push_back (editor);
484         }
485
486         if (!mixer->window_visible()) {
487                 candidates.push_back (mixer);
488         }
489
490         if (!rc_option_editor->window_visible()) {
491                 candidates.push_back (rc_option_editor);
492         }
493
494         if (candidates.size() < 2) {
495                 /* nothing to be done with zero or one visible in tabs */
496                 return;
497         }
498
499         std::vector<Tabbable*>::reverse_iterator next = candidates.rend();
500         std::vector<Tabbable*>::reverse_iterator i;
501         Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page ());
502
503         for (i = candidates.rbegin(); i != candidates.rend(); ++i) {
504                 if (w == &(*i)->contents()) {
505                         if (next != candidates.rend()) {
506                                 _tabs.set_current_page (_tabs.page_num ((*next)->contents()));
507                         } else {
508                                 _tabs.set_current_page (_tabs.page_num (candidates.front()->contents()));
509                         }
510                         break;
511                 }
512                 next = i;
513         }
514 }
515
516 void
517 ARDOUR_UI::key_change_tabbable_visibility (Tabbable* t)
518 {
519         if (!t) {
520                 return;
521         }
522
523         if (t->tabbed()) {
524                 _tabs.set_current_page (_tabs.page_num (t->contents()));
525         } else if (!t->fully_visible()) {
526                 t->make_visible ();
527         } else {
528                 _main_window.present ();
529         }
530 }
531
532 void
533 ARDOUR_UI::button_change_tabbable_visibility (Tabbable* t)
534 {
535         /* For many/most users, clicking a button in the main window will make it
536            the main/front/key window, which will change any stacking relationship they
537            were trying to modify by clicking on the button in the first
538            place. This button-aware method knows that click on
539            a button designed to show/hide a Tabbable that has its own window
540            will have made that window be obscured (as the main window comes to
541            the front). We therefore *hide* the Tabbable's window if it is even
542            partially visible, believing that this is likely because the
543            Tabbable window used to be front, the user clicked to change that,
544            and before we even get here, the main window has become front.
545         */
546
547         if (!t) {
548                 return;
549         }
550
551         if (t->tabbed()) {
552                 _tabs.set_current_page (_tabs.page_num (t->contents()));
553         } else if (t->visible()) {
554                 t->hide();
555         } else {
556                 t->make_visible ();
557         }
558 }
559
560 void
561 ARDOUR_UI::show_tabbable (Tabbable* t)
562 {
563         if (!t) {
564                 return;
565         }
566
567         t->make_visible ();
568 }
569
570 void
571 ARDOUR_UI::hide_tabbable (Tabbable* t)
572 {
573         if (!t) {
574                 return;
575         }
576         t->make_invisible ();
577 }
578
579 void
580 ARDOUR_UI::attach_tabbable (Tabbable* t)
581 {
582         if (!t) {
583                 return;
584         }
585
586         t->attach ();
587 }
588
589 void
590 ARDOUR_UI::detach_tabbable (Tabbable* t)
591 {
592         if (!t) {
593                 return;
594         }
595         t->detach ();
596 }
597
598 void
599 ARDOUR_UI::tabs_page_added (Widget*,guint)
600 {
601         if (_tabs.get_n_pages() > 1) {
602
603                 std::vector<TargetEntry> drag_target_entries;
604                 drag_target_entries.push_back (TargetEntry ("tabbable"));
605
606                 editor_visibility_button.drag_source_set (drag_target_entries);
607                 mixer_visibility_button.drag_source_set (drag_target_entries);
608                 prefs_visibility_button.drag_source_set (drag_target_entries);
609
610                 editor_visibility_button.drag_source_set_icon (Gtkmm2ext::pixbuf_from_string (editor->name(),
611                                                                                               Pango::FontDescription ("Sans 24"),
612                                                                                               0, 0,
613                                                                                               Gdk::Color ("red")));
614                 mixer_visibility_button.drag_source_set_icon (Gtkmm2ext::pixbuf_from_string (mixer->name(),
615                                                                                              Pango::FontDescription ("Sans 24"),
616                                                                                              0, 0,
617                                                                                              Gdk::Color ("red")));
618                 prefs_visibility_button.drag_source_set_icon (Gtkmm2ext::pixbuf_from_string (rc_option_editor->name(),
619                                                                                              Pango::FontDescription ("Sans 24"),
620                                                                                              0, 0,
621                                                                                              Gdk::Color ("red")));
622         }
623 }
624
625 void
626 ARDOUR_UI::tabs_page_removed (Widget*, guint)
627 {
628         if (_tabs.get_n_pages() < 2) {
629                 editor_visibility_button.drag_source_unset ();
630                 mixer_visibility_button.drag_source_unset ();
631                 prefs_visibility_button.drag_source_unset ();
632         }
633 }
634
635 void
636 ARDOUR_UI::tabs_switch (GtkNotebookPage*, guint page)
637 {
638         if (editor && (page == (guint) _tabs.page_num (editor->contents()))) {
639                 editor_visibility_button.set_active_state (Gtkmm2ext::ImplicitActive);
640
641                 if (mixer && (mixer->tabbed() || mixer->tabbed_by_default())) {
642                         mixer_visibility_button.set_active_state (Gtkmm2ext::Off);
643                 }
644
645                 if (rc_option_editor && (rc_option_editor->tabbed() || rc_option_editor->tabbed_by_default())) {
646                         prefs_visibility_button.set_active_state (Gtkmm2ext::Off);
647                 }
648         } else if (mixer && (page == (guint) _tabs.page_num (mixer->contents()))) {
649
650                 if (editor && (editor->tabbed() || editor->tabbed_by_default())) {
651                         editor_visibility_button.set_active_state (Gtkmm2ext::Off);
652                 }
653
654                 mixer_visibility_button.set_active_state (Gtkmm2ext::ImplicitActive);
655
656                 if (rc_option_editor && (rc_option_editor->tabbed() || rc_option_editor->tabbed_by_default())) {
657                         prefs_visibility_button.set_active_state (Gtkmm2ext::Off);
658                 }
659
660         } else if (page == (guint) _tabs.page_num (rc_option_editor->contents())) {
661
662                 if (editor && (editor->tabbed() || editor->tabbed_by_default())) {
663                         editor_visibility_button.set_active_state (Gtkmm2ext::Off);
664                 }
665
666                 if (mixer && (mixer->tabbed() || mixer->tabbed_by_default())) {
667                         mixer_visibility_button.set_active_state (Gtkmm2ext::Off);
668                 }
669
670                 prefs_visibility_button.set_active_state (Gtkmm2ext::ImplicitActive);
671         }
672
673 }
674
675 void
676 ARDOUR_UI::tabbable_state_change (Tabbable& t)
677 {
678         std::vector<std::string> insensitive_action_names;
679         std::vector<std::string> sensitive_action_names;
680         std::vector<std::string> active_action_names;
681         std::vector<std::string> inactive_action_names;
682         Glib::RefPtr<Action> action;
683         std::string downcased_name = downcase (t.name());
684         enum ViewState {
685                 Tabbed,
686                 Windowed,
687                 Hidden
688         };
689         ViewState vs;
690
691         if (t.tabbed()) {
692
693                 insensitive_action_names.push_back (string_compose ("attach-%1", downcased_name));
694                 sensitive_action_names.push_back (string_compose ("show-%1", downcased_name));
695                 sensitive_action_names.push_back (string_compose ("detach-%1", downcased_name));
696                 sensitive_action_names.push_back (string_compose ("hide-%1", downcased_name));
697
698                 vs = Tabbed;
699
700         } else if (t.tabbed_by_default ()) {
701
702                 insensitive_action_names.push_back (string_compose ("attach-%1", downcased_name));
703                 insensitive_action_names.push_back (string_compose ("hide-%1", downcased_name));
704                 sensitive_action_names.push_back (string_compose ("show-%1", downcased_name));
705                 sensitive_action_names.push_back (string_compose ("detach-%1", downcased_name));
706
707                 vs = Hidden;
708
709         } else if (t.window_visible()) {
710
711                 insensitive_action_names.push_back (string_compose ("detach-%1", downcased_name));
712                 sensitive_action_names.push_back (string_compose ("show-%1", downcased_name));
713                 sensitive_action_names.push_back (string_compose ("attach-%1", downcased_name));
714                 sensitive_action_names.push_back (string_compose ("hide-%1", downcased_name));
715
716                 active_action_names.push_back (string_compose ("show-%1", downcased_name));
717                 inactive_action_names.push_back (string_compose ("hide-%1", downcased_name));
718
719                 vs = Windowed;
720
721         } else {
722
723                 /* not currently visible. allow user to retab it or just make
724                  * it visible.
725                  */
726
727                 insensitive_action_names.push_back (string_compose ("detach-%1", downcased_name));
728                 insensitive_action_names.push_back (string_compose ("hide-%1", downcased_name));
729                 sensitive_action_names.push_back (string_compose ("show-%1", downcased_name));
730                 sensitive_action_names.push_back (string_compose ("attach-%1", downcased_name));
731
732                 active_action_names.push_back (string_compose ("hide-%1", downcased_name));
733                 inactive_action_names.push_back (string_compose ("show-%1", downcased_name));
734
735                 vs = Hidden;
736         }
737
738         for (std::vector<std::string>::iterator s = insensitive_action_names.begin(); s != insensitive_action_names.end(); ++s) {
739                 action = ActionManager::get_action (X_("Common"), (*s).c_str(), false);
740                 if (action) {
741                         action->set_sensitive (false);
742                 }
743         }
744
745         for (std::vector<std::string>::iterator s = sensitive_action_names.begin(); s != sensitive_action_names.end(); ++s) {
746                 action = ActionManager::get_action (X_("Common"), (*s).c_str(), false);
747                 if (action) {
748                         action->set_sensitive (true);
749                 }
750         }
751
752         ArdourButton* vis_button = 0;
753         std::vector<ArdourButton*> other_vis_buttons;
754
755         if (&t == editor) {
756                 vis_button = &editor_visibility_button;
757                 other_vis_buttons.push_back (&mixer_visibility_button);
758                 other_vis_buttons.push_back (&prefs_visibility_button);
759         } else if (&t == mixer) {
760                 vis_button = &mixer_visibility_button;
761                 other_vis_buttons.push_back (&editor_visibility_button);
762                 other_vis_buttons.push_back (&prefs_visibility_button);
763         } else if (&t == rc_option_editor) {
764                 vis_button = &prefs_visibility_button;
765                 other_vis_buttons.push_back (&editor_visibility_button);
766                 other_vis_buttons.push_back (&mixer_visibility_button);
767         }
768
769         if (!vis_button) {
770                 return;
771         }
772
773         switch (vs) {
774         case Tabbed:
775                 vis_button->set_active_state (Gtkmm2ext::ImplicitActive);
776                 break;
777         case Windowed:
778                 vis_button->set_active_state (Gtkmm2ext::ExplicitActive);
779                 break;
780         case Hidden:
781                 vis_button->set_active_state (Gtkmm2ext::Off);
782                 break;
783         }
784
785         for (std::vector<ArdourButton*>::iterator b = other_vis_buttons.begin(); b != other_vis_buttons.end(); ++b) {
786                 (*b)->set_active_state (Gtkmm2ext::Off);
787         }
788 }
789
790 void
791 ARDOUR_UI::toggle_meterbridge ()
792 {
793         assert (editor && mixer && meterbridge);
794
795         bool show = false;
796         bool obscuring = false;
797
798         if (meterbridge->not_visible ()) {
799                 show = true;
800         } else if ((editor->window_visible() && ARDOUR_UI_UTILS::windows_overlap (editor->own_window(), meterbridge)) ||
801                    (mixer->window_visible () && ARDOUR_UI_UTILS::windows_overlap (mixer->own_window(), meterbridge))) {
802                 obscuring = true;
803         }
804
805         if (obscuring && ((editor->own_window() && editor->own_window()->property_has_toplevel_focus()) ||
806                           (mixer->own_window() && mixer->own_window()->property_has_toplevel_focus()))) {
807                 show = true;
808         }
809
810         if (show) {
811                 meterbridge->show_window ();
812                 meterbridge->present ();
813                 meterbridge->raise ();
814         } else {
815                 meterbridge->hide_window (NULL);
816         }
817 }
818
819 void
820 ARDOUR_UI::toggle_luawindow ()
821 {
822         assert (editor && luawindow);
823
824         bool show = false;
825
826         if (luawindow->not_visible ()) {
827                 show = true;
828         }
829         // TODO check overlap
830
831         if (show) {
832                 luawindow->show_window ();
833                 luawindow->present ();
834                 luawindow->raise ();
835         } else {
836                 luawindow->hide_window (NULL);
837         }
838 }
839
840
841 void
842 ARDOUR_UI::new_midi_tracer_window ()
843 {
844         RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("NewMIDITracer"));
845         if (!act) {
846                 return;
847         }
848
849         std::list<MidiTracer*>::iterator i = _midi_tracer_windows.begin ();
850         while (i != _midi_tracer_windows.end() && (*i)->get_visible() == true) {
851                 ++i;
852         }
853
854         if (i == _midi_tracer_windows.end()) {
855                 /* all our MIDITracer windows are visible; make a new one */
856                 MidiTracer* t = new MidiTracer ();
857                 t->show_all ();
858                 _midi_tracer_windows.push_back (t);
859         } else {
860                 /* re-use the hidden one */
861                 (*i)->show_all ();
862         }
863 }
864
865 KeyEditor*
866 ARDOUR_UI::create_key_editor ()
867 {
868         KeyEditor* kedit = new KeyEditor;
869
870         for (std::list<Bindings*>::iterator b = Bindings::bindings.begin(); b != Bindings::bindings.end(); ++b) {
871                 kedit->add_tab ((*b)->name(), **b);
872         }
873
874         return kedit;
875 }
876
877 BundleManager*
878 ARDOUR_UI::create_bundle_manager ()
879 {
880         return new BundleManager (_session);
881 }
882
883 AddVideoDialog*
884 ARDOUR_UI::create_add_video_dialog ()
885 {
886         return new AddVideoDialog (_session);
887 }
888
889 SessionOptionEditor*
890 ARDOUR_UI::create_session_option_editor ()
891 {
892         return new SessionOptionEditor (_session);
893 }
894
895 BigClockWindow*
896 ARDOUR_UI::create_big_clock_window ()
897 {
898         return new BigClockWindow (*big_clock);
899 }
900
901 BigTransportWindow*
902 ARDOUR_UI::create_big_transport_window ()
903 {
904         BigTransportWindow* btw = new BigTransportWindow ();
905         btw->set_session (_session);
906         return btw;
907 }
908
909 VirtualKeyboardWindow*
910 ARDOUR_UI::create_virtual_keyboard_window ()
911 {
912         VirtualKeyboardWindow* vkbd = new VirtualKeyboardWindow ();
913         vkbd->set_session (_session);
914         return vkbd;
915 }
916
917 void
918 ARDOUR_UI::handle_locations_change (Location *)
919 {
920         if (_session) {
921                 if (_session->locations()->num_range_markers()) {
922                         ActionManager::set_sensitive (ActionManager::range_sensitive_actions, true);
923                 } else {
924                         ActionManager::set_sensitive (ActionManager::range_sensitive_actions, false);
925                 }
926         }
927 }
928
929 bool
930 ARDOUR_UI::tabbed_window_state_event_handler (GdkEventWindowState* ev, void* object)
931 {
932         if (object == editor) {
933
934                 if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
935                     (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
936                         if (big_clock_window) {
937                                 big_clock_window->set_transient_for (*editor->own_window());
938                         }
939                         if (big_transport_window) {
940                                 big_transport_window->set_transient_for (*editor->own_window());
941                         }
942                         if (virtual_keyboard_window) {
943                                 virtual_keyboard_window->set_transient_for (*editor->own_window());
944                         }
945                 }
946
947         } else if (object == mixer) {
948
949                 if ((ev->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) &&
950                     (ev->new_window_state & GDK_WINDOW_STATE_FULLSCREEN)) {
951                         if (big_clock_window) {
952                                 big_clock_window->set_transient_for (*mixer->own_window());
953                         }
954                         if (big_transport_window) {
955                                 big_transport_window->set_transient_for (*mixer->own_window());
956                         }
957                         if (virtual_keyboard_window) {
958                                 virtual_keyboard_window->set_transient_for (*mixer->own_window());
959                         }
960                 }
961         }
962
963         return false;
964 }
965
966 bool
967 ARDOUR_UI::editor_meter_peak_button_release (GdkEventButton* ev)
968 {
969         if (ev->button == 1) {
970                 ArdourMeter::ResetAllPeakDisplays ();
971         }
972         return false;
973 }
974
975 void
976 ARDOUR_UI::toggle_mixer_space()
977 {
978         Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action ("Common", "ToggleMaximalMixer");
979         if (tact->get_active()) {
980                 mixer->maximise_mixer_space ();
981         } else {
982                 mixer->restore_mixer_space ();
983         }
984 }