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