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