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