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