Add option to disable blinking alert buttons.
[ardour.git] / gtk2_ardour / monitor_section.cc
1 /*
2   Copyright (C) 2012 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 #include <gdkmm/pixbuf.h>
21
22 #include "pbd/compose.h"
23 #include "pbd/error.h"
24 #include "pbd/replace_all.h"
25
26 #include "gtkmm2ext/bindable_button.h"
27 #include "gtkmm2ext/tearoff.h"
28 #include "gtkmm2ext/actions.h"
29 #include "gtkmm2ext/utils.h"
30
31 #include <gtkmm/menu.h>
32 #include <gtkmm/menuitem.h>
33
34 #include "ardour/amp.h"
35 #include "ardour/audioengine.h"
36 #include "ardour/monitor_processor.h"
37 #include "ardour/port.h"
38 #include "ardour/route.h"
39 #include "ardour/solo_isolate_control.h"
40 #include "ardour/user_bundle.h"
41 #include "ardour/plugin_manager.h"
42
43 #include "ardour_ui.h"
44 #include "gui_thread.h"
45 #include "mixer_ui.h"
46 #include "monitor_section.h"
47 #include "public_editor.h"
48 #include "timers.h"
49 #include "tooltips.h"
50 #include "ui_config.h"
51 #include "utils.h"
52
53 #include "pbd/i18n.h"
54
55 using namespace ARDOUR;
56 using namespace ARDOUR_UI_UTILS;
57 using namespace Gtk;
58 using namespace Gtkmm2ext;
59 using namespace PBD;
60 using namespace std;
61
62 Glib::RefPtr<ActionGroup> MonitorSection::monitor_actions;
63 Gtkmm2ext::ActionMap MonitorSection::myactions (X_("monitor section"));
64 Gtkmm2ext::Bindings* MonitorSection::bindings = 0;
65
66 #define PX_SCALE(px) std::max((float)px, rintf((float)px * UIConfiguration::instance().get_ui_scale()))
67
68 MonitorSection::MonitorSection (Session* s)
69         : SessionHandlePtr (s)
70         , RouteUI (s)
71         , _tearoff (0)
72         , channel_table (0)
73         , channel_table_viewport (*channel_table_scroller.get_hadjustment()
74                                   , *channel_table_scroller.get_vadjustment ())
75         , gain_control (0)
76         , dim_control (0)
77         , solo_boost_control (0)
78         , solo_cut_control (0)
79         , gain_display (0)
80         , dim_display (0)
81         , solo_boost_display (0)
82         , solo_cut_display (0)
83         , _output_selector (0)
84         , solo_in_place_button (_("SiP"), ArdourButton::led_default_elements)
85         , afl_button (_("AFL"), ArdourButton::led_default_elements)
86         , pfl_button (_("PFL"), ArdourButton::led_default_elements)
87         , exclusive_solo_button (ArdourButton::led_default_elements)
88         , solo_mute_override_button (ArdourButton::led_default_elements)
89         , toggle_processorbox_button (ArdourButton::default_elements)
90         , _inhibit_solo_model_update (false)
91         , _ui_initialized (false)
92 {
93
94         using namespace Menu_Helpers;
95
96         Glib::RefPtr<Action> act;
97
98         if (!monitor_actions) {
99                 register_actions ();
100                 load_bindings ();
101         }
102
103         channel_size_group = SizeGroup::create (SIZE_GROUP_HORIZONTAL);
104
105         set_data ("ardour-bindings", bindings);
106
107         _plugin_selector = new PluginSelector (PluginManager::instance());
108         insert_box = new ProcessorBox (_session, boost::bind (&MonitorSection::plugin_selector, this), _rr_selection, 0);
109         insert_box->set_no_show_all ();
110         insert_box->show ();
111         // TODO allow keyboard shortcuts in ProcessorBox
112
113         set_session (s);
114
115         /* Rude Solo  & Solo Isolated */
116         rude_solo_button.set_text (_("Soloing"));
117         rude_solo_button.set_name ("rude solo");
118         rude_solo_button.show ();
119
120         rude_iso_button.set_text (_("Isolated"));
121         rude_iso_button.set_name ("rude isolate");
122         rude_iso_button.show ();
123
124         rude_audition_button.set_text (_("Auditioning"));
125         rude_audition_button.set_name ("rude audition");
126         rude_audition_button.show ();
127
128         Timers::blink_connect (sigc::mem_fun (*this, &MonitorSection::do_blink));
129
130         act = ActionManager::get_action (X_("Main"), X_("cancel-solo"));
131         rude_solo_button.set_related_action (act);
132         UI::instance()->set_tip (rude_solo_button, _("When active, something is soloed.\nClick to de-solo everything"));
133
134         rude_iso_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_isolate), false);
135         UI::instance()->set_tip (rude_iso_button, _("When active, something is solo-isolated.\nClick to de-isolate everything"));
136
137         rude_audition_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_audition), false);
138         UI::instance()->set_tip (rude_audition_button, _("When active, auditioning is active.\nClick to stop the audition"));
139
140         /* SIP, AFL, PFL radio */
141
142         solo_in_place_button.set_name ("monitor section solo model");
143         afl_button.set_name ("monitor section solo model");
144         pfl_button.set_name ("monitor section solo model");
145
146         solo_in_place_button.set_led_left (true);
147         afl_button.set_led_left (true);
148         pfl_button.set_led_left (true);
149
150         solo_in_place_button.show ();
151         afl_button.show ();
152         pfl_button.show ();
153
154         act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
155         set_tooltip (solo_in_place_button, _("Solo controls affect solo-in-place"));
156         if (act) {
157                 solo_in_place_button.set_related_action (act);
158         }
159
160         act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
161         set_tooltip (afl_button, _("Solo controls toggle after-fader-listen"));
162         if (act) {
163                 afl_button.set_related_action (act);
164         }
165
166         act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
167         set_tooltip (pfl_button, _("Solo controls toggle pre-fader-listen"));
168         if (act) {
169                 pfl_button.set_related_action (act);
170         }
171
172         /* Solo option buttons */
173         exclusive_solo_button.set_text (_("Excl. Solo"));
174         exclusive_solo_button.set_name (X_("monitor section solo option"));
175         set_tooltip (&exclusive_solo_button, _("Exclusive solo means that only 1 solo is active at a time"));
176
177         act = ActionManager::get_action (X_("Monitor"), X_("toggle-exclusive-solo"));
178         if (act) {
179                 exclusive_solo_button.set_related_action (act);
180         }
181
182         solo_mute_override_button.set_text (_("Solo ยป Mute"));
183         solo_mute_override_button.set_name (X_("monitor section solo option"));
184         set_tooltip (&solo_mute_override_button, _("If enabled, solo will override mute\n(a soloed & muted track or bus will be audible)"));
185
186         act = ActionManager::get_action (X_("Monitor"), X_("toggle-mute-overrides-solo"));
187         if (act) {
188                 solo_mute_override_button.set_related_action (act);
189         }
190
191         /* Processor Box hide/shos */
192         toggle_processorbox_button.set_text (_("Processors"));
193         toggle_processorbox_button.set_name (X_("monitor section processors toggle"));
194         set_tooltip (&toggle_processorbox_button, _("Allow one to add monitor effect processors"));
195
196         proctoggle = ActionManager::get_action (X_("Monitor"), X_("toggle-monitor-processor-box"));
197         toggle_processorbox_button.set_related_action (proctoggle);
198
199         /* Knobs */
200         Label* solo_boost_label;
201         Label* solo_cut_label;
202         Label* dim_label;
203
204         /* Solo Boost Knob */
205
206         solo_boost_control = new ArdourKnob ();
207         solo_boost_control->set_name("monitor section knob");
208         solo_boost_control->set_size_request (PX_SCALE(36), PX_SCALE(36));
209         set_tooltip (*solo_boost_control, _("Gain increase for soloed signals (0dB is normal)"));
210
211         solo_boost_display = new ArdourDisplay ();
212         solo_boost_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
213         solo_boost_display->add_controllable_preset(_("0 dB"), 0.0);
214         solo_boost_display->add_controllable_preset(_("3 dB"), 3.0);
215         solo_boost_display->add_controllable_preset(_("6 dB"), 6.0);
216         solo_boost_display->add_controllable_preset(_("10 dB"), 10.0);
217
218         solo_boost_label = manage (new Label (_("Solo Boost")));
219
220         /* Solo (SiP) cut */
221
222         solo_cut_control = new ArdourKnob ();
223         solo_cut_control->set_name ("monitor section knob");
224         solo_cut_control->set_size_request (PX_SCALE(36), PX_SCALE(36));
225         set_tooltip (*solo_cut_control, _("Gain reduction non-soloed signals\nA value above -inf dB causes \"solo-in-front\""));
226
227         solo_cut_display = new ArdourDisplay ();
228         solo_cut_display->set_name("monitor section dropdown"); // XXX
229         solo_cut_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
230         solo_cut_display->add_controllable_preset(_("0 dB"), 0.0);
231         solo_cut_display->add_controllable_preset(_("-6 dB"), -6.0);
232         solo_cut_display->add_controllable_preset(_("-12 dB"), -12.0);
233         solo_cut_display->add_controllable_preset(_("-20 dB"), -20.0);
234         solo_cut_display->add_controllable_preset(_("OFF"), -1200.0);
235
236         solo_cut_label = manage (new Label (_("SiP Cut")));
237
238         /* Dim */
239
240         dim_control = new ArdourKnob (ArdourKnob::default_elements, ArdourKnob::Detent);
241         dim_control->set_name ("monitor section knob");
242         dim_control->set_size_request (PX_SCALE(36), PX_SCALE(36));
243         set_tooltip (*dim_control, _("Gain reduction to use when dimming monitor outputs"));
244
245         dim_display = new ArdourDisplay ();
246         dim_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
247         dim_display->add_controllable_preset(_("0 dB"), 0.0);
248         dim_display->add_controllable_preset(_("-3 dB"), -3.0);
249         dim_display->add_controllable_preset(_("-6 dB"), -6.0);
250         dim_display->add_controllable_preset(_("-12 dB"), -12.0);
251         dim_display->add_controllable_preset(_("-20 dB"), -20.0);
252
253         dim_label = manage (new Label (_("Dim")));
254
255         // mute button
256         cut_all_button.set_text (_("Mute"));
257         cut_all_button.set_name ("mute button");
258         cut_all_button.set_size_request (-1, PX_SCALE(30));
259         cut_all_button.show ();
260
261         act = ActionManager::get_action (X_("Monitor"), X_("monitor-cut-all"));
262         if (act) {
263                 cut_all_button.set_related_action (act);
264         }
265
266         // dim button
267         dim_all_button.set_text (_("Dim"));
268         dim_all_button.set_name ("monitor section dim");
269         dim_all_button.set_size_request (-1, PX_SCALE(25));
270         act = ActionManager::get_action (X_("Monitor"), X_("monitor-dim-all"));
271         if (act) {
272                 dim_all_button.set_related_action (act);
273         }
274
275         // mono button
276         mono_button.set_text (_("Mono"));
277         mono_button.set_name ("monitor section mono");
278         mono_button.set_size_request (-1, PX_SCALE(25));
279         act = ActionManager::get_action (X_("Monitor"), X_("monitor-mono"));
280         if (act) {
281                 mono_button.set_related_action (act);
282         }
283
284         /* Gain */
285
286         gain_control = new ArdourKnob (ArdourKnob::default_elements, ArdourKnob::Detent);
287         gain_control->set_name("monitor section knob");
288         gain_control->set_size_request (PX_SCALE(60), PX_SCALE(60));
289
290         gain_display = new ArdourDisplay ();
291         gain_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
292         gain_display->add_controllable_preset(_("0 dB"), 0.0);
293         gain_display->add_controllable_preset(_("-3 dB"), -3.0);
294         gain_display->add_controllable_preset(_("-6 dB"), -6.0);
295         gain_display->add_controllable_preset(_("-12 dB"), -12.0);
296         gain_display->add_controllable_preset(_("-20 dB"), -20.0);
297         gain_display->add_controllable_preset(_("-30 dB"), -30.0);
298
299         Label* output_label = manage (new Label (_("Output")));
300         output_label->set_name (X_("MonitorSectionLabel"));
301
302         output_button = new ArdourButton ();
303         output_button->set_text (_("Output"));
304         output_button->set_name (X_("monitor section cut")); // XXX
305         output_button->set_text_ellipsize (Pango::ELLIPSIZE_MIDDLE);
306         output_button->set_layout_ellipsize_width (PX_SCALE(128) * PANGO_SCALE);
307
308         channel_table_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
309         channel_table_scroller.set_size_request (-1, PX_SCALE(150));
310         channel_table_scroller.set_shadow_type (Gtk::SHADOW_NONE);
311         channel_table_scroller.show ();
312         channel_table_scroller.add (channel_table_viewport);
313
314         channel_size_group->add_widget (channel_table_header);
315         channel_table_header.resize (1, 5);
316
317         Label* l1 = manage (new Label (X_("  ")));
318         l1->set_name (X_("MonitorSectionLabel"));
319         channel_table_header.attach (*l1, 0, 1, 0, 1, EXPAND|FILL);
320
321         l1 = manage (new Label (_("Mute")));
322         l1->set_name (X_("MonitorSectionLabel"));
323         channel_table_header.attach (*l1, 1, 2, 0, 1, EXPAND|FILL);
324
325         l1 = manage (new Label (_("Dim")));
326         l1->set_name (X_("MonitorSectionLabel"));
327         channel_table_header.attach (*l1, 2, 3, 0, 1, EXPAND|FILL);
328
329         l1 = manage (new Label (_("Solo")));
330         l1->set_name (X_("MonitorSectionLabel"));
331         channel_table_header.attach (*l1, 3, 4, 0, 1, EXPAND|FILL);
332
333         l1 = manage (new Label (_("Inv")));
334         l1->set_name (X_("MonitorSectionLabel"));
335         channel_table_header.attach (*l1, 4, 5, 0, 1, EXPAND|FILL);
336
337         channel_table_header.show ();
338
339
340         /****************************************************************************
341          * LAYOUT  top to bottom
342          */
343
344         // solo, iso information
345         HBox* rude_box = manage (new HBox);
346         rude_box->set_spacing (PX_SCALE(4));
347         rude_box->set_homogeneous (true);
348         rude_box->pack_start (rude_solo_button, true, true);
349         rude_box->pack_start (rude_iso_button, true, true);
350
351         // solo options (right align)
352         HBox* tbx1 = manage (new HBox);
353         tbx1->pack_end (exclusive_solo_button, false, false);
354
355         HBox* tbx2 = manage (new HBox);
356         tbx2->pack_end (solo_mute_override_button, false, false);
357
358         HBox* tbx3 = manage (new HBox);
359         tbx3->pack_end (toggle_processorbox_button, false, false);
360
361         HBox* tbx0 = manage (new HBox); // space
362
363         // combined solo mode (Sip, AFL, PFL) & solo options
364         Table *solo_tbl = manage (new Table);
365         solo_tbl->attach (solo_in_place_button,   0, 1, 0, 1, EXPAND|FILL, SHRINK, 0, 2);
366         solo_tbl->attach (pfl_button,             0, 1, 1, 2, EXPAND|FILL, SHRINK, 0, 2);
367         solo_tbl->attach (afl_button,             0, 1, 2, 3, EXPAND|FILL, SHRINK, 0, 2);
368         solo_tbl->attach (*tbx0,                  1, 2, 0, 3, EXPAND|FILL, SHRINK, 2, 2);
369         solo_tbl->attach (*tbx1,                  2, 3, 0, 1, EXPAND|FILL, SHRINK, 0, 2);
370         solo_tbl->attach (*tbx2,                  2, 3, 1, 2, EXPAND|FILL, SHRINK, 0, 2);
371         solo_tbl->attach (*tbx3,                  2, 3, 2, 3, EXPAND|FILL, SHRINK, 0, 2);
372
373         // boost, cut, dim  volume control
374         Table *level_tbl = manage (new Table);
375         level_tbl->attach (*solo_boost_label,    0, 2, 0, 1, EXPAND|FILL, SHRINK, 1, 2);
376         level_tbl->attach (*solo_boost_control,  0, 2, 1, 2, EXPAND|FILL, SHRINK, 1, 2);
377         level_tbl->attach (*solo_boost_display,  0, 2, 2, 3, EXPAND     , SHRINK, 1, 2);
378
379         level_tbl->attach (*solo_cut_label,      2, 4, 0, 1, EXPAND|FILL, SHRINK, 1, 2);
380         level_tbl->attach (*solo_cut_control,    2, 4, 1, 2, EXPAND|FILL, SHRINK, 1, 2);
381         level_tbl->attach (*solo_cut_display,    2, 4, 2, 3, EXPAND     , SHRINK, 1, 2);
382
383         level_tbl->attach (*dim_label,           1, 3, 3, 4, EXPAND|FILL, SHRINK, 1, 2);
384         level_tbl->attach (*dim_control,         1, 3, 4, 5, EXPAND|FILL, SHRINK, 1, 2);
385         level_tbl->attach (*dim_display,         1, 3, 5, 6, EXPAND     , SHRINK, 1, 2);
386
387         // mono, dim
388         HBox* mono_dim_box = manage (new HBox);
389         mono_dim_box->set_spacing (PX_SCALE(4));
390         mono_dim_box->set_homogeneous (true);
391         mono_dim_box->pack_start (mono_button, true, true);
392         mono_dim_box->pack_end (dim_all_button, true, true);
393
394         // master gain
395         Label* spin_label = manage (new Label (_("Monitor")));
396         VBox* spin_packer = manage (new VBox);
397         spin_packer->set_spacing (PX_SCALE(2));
398         spin_packer->pack_start (*spin_label, false, false);
399         spin_packer->pack_start (*gain_control, false, false);
400         spin_packer->pack_start (*gain_display, false, false);
401
402         master_packer.pack_start (*spin_packer, true, false);
403
404         // combined gain section (channels, mute, dim)
405         VBox* lower_packer = manage (new VBox);
406         lower_packer->pack_start (channel_table_header, false, false, PX_SCALE(0));
407         lower_packer->pack_start (channel_table_packer, false, false, PX_SCALE(8));
408         lower_packer->pack_start (*mono_dim_box,        false, false, PX_SCALE(2));
409         lower_packer->pack_start (cut_all_button,       false, false, PX_SCALE(2));
410
411         // calc height of mixer scrollbar
412         int scrollbar_height = 0;
413         {
414                 Gtk::Window window (WINDOW_TOPLEVEL);
415                 HScrollbar scrollbar;
416                 window.add (scrollbar);
417                 scrollbar.set_name ("MixerWindow");
418                 scrollbar.ensure_style();
419                 Gtk::Requisition requisition(scrollbar.size_request ());
420                 scrollbar_height = requisition.height;
421         }
422
423         // output port select
424         VBox* out_packer = manage (new VBox);
425         out_packer->set_spacing (PX_SCALE(2));
426         out_packer->pack_start (*output_label, false, false);
427         out_packer->pack_start (*output_button, false, false);
428
429         /****************************************************************************
430          * TOP LEVEL LAYOUT
431          */
432         vpacker.set_border_width (PX_SCALE(3));
433         vpacker.pack_start (*rude_box,            false, false, PX_SCALE(3));
434         vpacker.pack_start (rude_audition_button, false, false, 0);
435         vpacker.pack_start (*solo_tbl,            false, false, PX_SCALE(8));
436         vpacker.pack_start (*insert_box,          true,  true,  PX_SCALE(8));
437         vpacker.pack_start (*level_tbl,           false, false, PX_SCALE(8));
438         vpacker.pack_start (*lower_packer,        false, false, PX_SCALE(8));
439         vpacker.pack_start (master_packer,        false, false, PX_SCALE(10));
440         vpacker.pack_end   (*out_packer,          false, false,
441 #ifdef MIXBUS
442                         scrollbar_height - 2 /* no outer frame */
443 #else
444                         scrollbar_height + 2 /* frame borders */
445 #endif
446                         );
447
448         hpacker.set_spacing (0);
449         hpacker.pack_start (vpacker, true, true);
450
451         add (hpacker);
452
453         gain_control->show_all ();
454         gain_display->show_all ();
455         dim_control->show_all ();
456         dim_display->show_all();
457         solo_boost_control->show_all ();
458         solo_boost_display->show_all();
459
460         mono_dim_box->show ();
461         spin_packer->show ();
462         master_packer.show ();
463
464         rude_box->show();
465         solo_tbl->show_all();
466         level_tbl->show();
467         lower_packer->show ();
468         out_packer->show ();
469
470         vpacker.show ();
471         hpacker.show ();
472
473         map_state ();
474         assign_controllables ();
475
476         output_button->signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::output_press), false);
477         output_button->signal_button_release_event().connect (sigc::mem_fun(*this, &MonitorSection::output_release), false);
478
479         signal_enter_notify_event().connect (sigc::mem_fun (*this, &MonitorSection::enter_handler));
480         signal_leave_notify_event().connect (sigc::mem_fun (*this, &MonitorSection::leave_handler));
481         set_flags (CAN_FOCUS);
482
483         _tearoff = new TearOff (*this);
484
485         if (!UIConfiguration::instance().get_floating_monitor_section()) {
486                 /* if torn off, make this a normal window
487                  * (default is WINDOW_TYPE_HINT_UTILITY in libs/gtkmm2ext/tearoff.cc)
488                  */
489                 _tearoff->tearoff_window().set_type_hint (Gdk::WINDOW_TYPE_HINT_NORMAL);
490         }
491         _tearoff->tearoff_window().set_title (X_("Monitor"));
492         _tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), (Gtk::Window*) &_tearoff->tearoff_window()), false);
493
494         update_output_display ();
495         update_processor_box ();
496         _ui_initialized = true;
497
498         /* catch changes that affect us */
499         AudioEngine::instance()->PortConnectedOrDisconnected.connect (
500                 *this, invalidator (*this), boost::bind (&MonitorSection::port_connected_or_disconnected, this, _1, _3), gui_context ()
501                 );
502         Config->ParameterChanged.connect (config_connection, invalidator (*this), boost::bind (&MonitorSection::parameter_changed, this, _1), gui_context());
503 }
504
505 MonitorSection::~MonitorSection ()
506 {
507         for (ChannelButtons::iterator i = _channel_buttons.begin(); i != _channel_buttons.end(); ++i) {
508                 delete *i;
509         }
510
511         _channel_buttons.clear ();
512         output_changed_connections.drop_connections ();
513
514         delete insert_box; insert_box = 0;
515         delete output_button; output_button = 0;
516         delete gain_control; gain_control = 0;
517         delete gain_display; gain_display = 0;
518         delete dim_control; dim_control = 0;
519         delete dim_display; dim_display = 0;
520         delete solo_boost_control; solo_boost_control = 0;
521         delete solo_boost_display; solo_boost_display = 0;
522         delete solo_cut_control; solo_cut_control = 0;
523         delete solo_cut_display; solo_cut_display = 0;
524         delete _tearoff; _tearoff = 0;
525         delete _output_selector; _output_selector = 0;
526         delete channel_table; channel_table = 0;
527 }
528
529 bool
530 MonitorSection::enter_handler (GdkEventCrossing* ev)
531 {
532         grab_focus ();
533         return false;
534 }
535
536 bool
537 MonitorSection::leave_handler (GdkEventCrossing* ev)
538 {
539         switch (ev->detail) {
540         case GDK_NOTIFY_INFERIOR:
541                 return false;
542         default:
543                 break;
544         }
545
546         /* cancel focus if we're not torn off. With X11 WM's that do
547          * focus-follows-mouse, focus will be taken from us anyway.
548          */
549
550         Widget* top = get_toplevel();
551
552         if (top->is_toplevel() && top != &_tearoff->tearoff_window()) {
553                 Window* win = dynamic_cast<Window*> (top);
554                 gtk_window_set_focus (win->gobj(), 0);
555         }
556
557         return false;
558 }
559
560 void
561 MonitorSection::update_processor_box ()
562 {
563         bool show_processor_box = Glib::RefPtr<ToggleAction>::cast_dynamic (proctoggle)->get_active ();
564
565         if (count_processors () > 0 && !show_processor_box) {
566                 toggle_processorbox_button.set_name (X_("monitor section processors present"));
567         } else {
568                 toggle_processorbox_button.set_name (X_("monitor section processors toggle"));
569         }
570
571         if (insert_box->is_visible() == show_processor_box) {
572                 return;
573         }
574
575         if (show_processor_box) {
576                 if (master_packer.get_parent()) {
577                         master_packer.get_parent()->remove (master_packer);
578                 }
579                 insert_box->show();
580                 vpacker.pack_start (master_packer,        false, false, PX_SCALE(10));
581         } else {
582                 if (master_packer.get_parent()) {
583                         master_packer.get_parent()->remove (master_packer);
584                 }
585                 insert_box->hide();
586                 vpacker.pack_start (master_packer,        true,  false, PX_SCALE(10));
587         }
588 }
589
590 void
591 MonitorSection::set_session (Session* s)
592 {
593         RouteUI::set_session (s);
594         _plugin_selector->set_session (_session);
595
596         if (_session) {
597
598                 _route = _session->monitor_out ();
599
600                 if (_route) {
601                         /* session with monitor section */
602                         _monitor = _route->monitor_control ();
603                         assign_controllables ();
604                         _route->output()->changed.connect (output_changed_connections, invalidator (*this),
605                                                                                         boost::bind (&MonitorSection::update_output_display, this),
606                                                                                         gui_context());
607                         insert_box->set_route (_route);
608                         _route->processors_changed.connect (*this, invalidator (*this), boost::bind (&MonitorSection::processors_changed, this, _1), gui_context());
609                         _route->output()->PortCountChanged.connect (output_changed_connections, invalidator (*this), boost::bind (&MonitorSection::populate_buttons, this), gui_context());
610                         if (_ui_initialized) {
611                                 update_processor_box ();
612                         }
613                 } else {
614                         /* session with no monitor section */
615                         output_changed_connections.drop_connections();
616                         _monitor.reset ();
617                         _route.reset ();
618                         delete _output_selector;
619                         _output_selector = 0;
620                 }
621
622                 populate_buttons ();
623
624         } else {
625                 /* no session */
626
627                 output_changed_connections.drop_connections();
628                 _monitor.reset ();
629                 _route.reset ();
630                 control_connections.drop_connections ();
631                 rude_iso_button.unset_active_state ();
632                 rude_solo_button.unset_active_state ();
633                 delete _output_selector;
634                 _output_selector = 0;
635
636                 assign_controllables ();
637         }
638 }
639
640 MonitorSection::ChannelButtonSet::ChannelButtonSet ()
641 {
642         cut.set_name (X_("mute button"));
643         dim.set_name (X_("monitor section dim"));
644         solo.set_name (X_("solo button"));
645         invert.set_name (X_("invert button"));
646
647         cut.unset_flags (Gtk::CAN_FOCUS);
648         dim.unset_flags (Gtk::CAN_FOCUS);
649         solo.unset_flags (Gtk::CAN_FOCUS);
650         invert.unset_flags (Gtk::CAN_FOCUS);
651 }
652
653 void
654 MonitorSection::populate_buttons ()
655 {
656         if (!_monitor) {
657                 return;
658         }
659
660         if (channel_table) {
661                 channel_size_group->remove_widget (*channel_table);
662                 delete channel_table;
663         }
664
665         channel_table = new Gtk::Table();
666
667         channel_table->set_col_spacings (6);
668         channel_table->set_row_spacings (6);
669         channel_table->set_homogeneous (true);
670
671         channel_size_group->add_widget (*channel_table);
672         channel_table->show ();
673         table_hpacker.pack_start (*channel_table, true, true);
674
675         for (ChannelButtons::iterator i = _channel_buttons.begin(); i != _channel_buttons.end(); ++i) {
676                 delete *i;
677         }
678         _channel_buttons.clear ();
679
680         Glib::RefPtr<Action> act;
681         uint32_t nchans = _monitor->output_streams().n_audio();
682
683         channel_table->resize (nchans, 5);
684
685         const uint32_t row_offset = 0;
686
687         for (uint32_t i = 0; i < nchans; ++i) {
688
689                 string l;
690                 char buf[64];
691
692                 if (nchans == 2) {
693                         if (i == 0) {
694                                 l = "L";
695                         } else {
696                                 l = "R";
697                         }
698                 } else {
699                         char buf[32];
700                         snprintf (buf, sizeof (buf), "%d", i+1);
701                         l = buf;
702                 }
703
704                 Label* label = manage (new Label (l));
705                 channel_table->attach (*label, 0, 1, i+row_offset, i+row_offset+1, EXPAND|FILL);
706
707                 ChannelButtonSet* cbs = new ChannelButtonSet;
708
709                 _channel_buttons.push_back (cbs);
710
711                 channel_table->attach (cbs->cut, 1, 2, i+row_offset, i+row_offset+1, EXPAND|FILL);
712                 channel_table->attach (cbs->dim, 2, 3, i+row_offset, i+row_offset+1, EXPAND|FILL);
713                 channel_table->attach (cbs->solo, 3, 4, i+row_offset, i+row_offset+1, EXPAND|FILL);
714                 channel_table->attach (cbs->invert, 4, 5, i+row_offset, i+row_offset+1, EXPAND|FILL);
715
716                 snprintf (buf, sizeof (buf), "monitor-cut-%u", i);
717                 act = ActionManager::get_action (X_("Monitor"), buf);
718                 if (act) {
719                         cbs->cut.set_related_action (act);
720                 }
721
722                 snprintf (buf, sizeof (buf), "monitor-dim-%u", i);
723                 act = ActionManager::get_action (X_("Monitor"), buf);
724                 if (act) {
725                         cbs->dim.set_related_action (act);
726                 }
727
728                 snprintf (buf, sizeof (buf), "monitor-solo-%u", i);
729                 act = ActionManager::get_action (X_("Monitor"), buf);
730                 if (act) {
731                         cbs->solo.set_related_action (act);
732                 }
733
734                 snprintf (buf, sizeof (buf), "monitor-invert-%u", i);
735                 act = ActionManager::get_action (X_("Monitor"), buf);
736                 if (act) {
737                         cbs->invert.set_related_action (act);
738                 }
739         }
740
741         channel_table->show_all ();
742
743         if (channel_table_scroller.get_parent()) {
744                 /* scroller is packed, so remove it */
745                 channel_table_packer.remove (channel_table_scroller);
746         }
747
748         if (table_hpacker.get_parent () == &channel_table_packer) {
749                 /* this occurs when the table hpacker is directly
750                          packed, so remove it.
751                          */
752                 channel_table_packer.remove (table_hpacker);
753         } else if (table_hpacker.get_parent()) {
754                 channel_table_viewport.remove ();
755         }
756
757         if (nchans > 7) {
758                 /* put the table into a scrolled window, and then put
759                  * that into the channel vpacker, after the table header
760                  */
761                 channel_table_viewport.add (table_hpacker);
762                 channel_table_packer.pack_start (channel_table_scroller, true, true);
763                 channel_table_viewport.show ();
764                 channel_table_scroller.show ();
765
766         } else {
767                 /* just put the channel table itself into the channel
768                  * vpacker, after the table header
769                  */
770                 channel_table_packer.pack_start (table_hpacker, true, true);
771                 channel_table_scroller.hide ();
772         }
773         table_hpacker.show ();
774         channel_table->show ();
775 }
776
777 void
778 MonitorSection::toggle_exclusive_solo ()
779 {
780         if (!_monitor) {
781                 return;
782         }
783
784         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "toggle-exclusive-solo");
785         if (act) {
786                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
787                 Config->set_exclusive_solo (tact->get_active());
788         }
789
790 }
791
792 void
793 MonitorSection::toggle_mute_overrides_solo ()
794 {
795         if (!_monitor) {
796                 return;
797         }
798
799         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "toggle-mute-overrides-solo");
800         if (act) {
801                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
802                 Config->set_solo_mute_override (tact->get_active());
803         }
804 }
805
806 void
807 MonitorSection::dim_all ()
808 {
809         if (!_monitor) {
810                 return;
811         }
812
813         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
814         if (act) {
815                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
816                 _monitor->set_dim_all (tact->get_active());
817         }
818
819 }
820
821 void
822 MonitorSection::cut_all ()
823 {
824         if (!_monitor) {
825                 return;
826         }
827
828         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
829         if (act) {
830                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
831                 _monitor->set_cut_all (tact->get_active());
832         }
833 }
834
835 void
836 MonitorSection::mono ()
837 {
838         if (!_monitor) {
839                 return;
840         }
841
842         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
843         if (act) {
844                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
845                 _monitor->set_mono (tact->get_active());
846         }
847 }
848
849 void
850 MonitorSection::cut_channel (uint32_t chn)
851 {
852         if (!_monitor) {
853                 return;
854         }
855
856         char buf[64];
857         snprintf (buf, sizeof (buf), "monitor-cut-%u", chn);
858
859         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
860         if (act) {
861                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
862                 _monitor->set_cut (chn, tact->get_active());
863         }
864 }
865
866 void
867 MonitorSection::dim_channel (uint32_t chn)
868 {
869         if (!_monitor) {
870                 return;
871         }
872
873         char buf[64];
874         snprintf (buf, sizeof (buf), "monitor-dim-%u", chn);
875
876         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
877         if (act) {
878                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
879                 _monitor->set_dim (chn, tact->get_active());
880         }
881
882 }
883
884 void
885 MonitorSection::solo_channel (uint32_t chn)
886 {
887         if (!_monitor) {
888                 return;
889         }
890
891         char buf[64];
892         snprintf (buf, sizeof (buf), "monitor-solo-%u", chn);
893
894         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
895         if (act) {
896                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
897                 _monitor->set_solo (chn, tact->get_active());
898         }
899
900 }
901
902 void
903 MonitorSection::invert_channel (uint32_t chn)
904 {
905         if (!_monitor) {
906                 return;
907         }
908
909         char buf[64];
910         snprintf (buf, sizeof (buf), "monitor-invert-%u", chn);
911
912         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
913         if (act) {
914                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
915                 _monitor->set_polarity (chn, tact->get_active());
916         }
917 }
918
919 void
920 MonitorSection::register_actions ()
921 {
922         string action_name;
923         string action_descr;
924         Glib::RefPtr<Action> act;
925
926         monitor_actions = myactions.create_action_group (X_("Monitor"));
927
928         myactions.register_toggle_action (monitor_actions, "monitor-mono", _("Switch monitor to mono"),
929                         sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), MonitorMono));
930
931         myactions.register_toggle_action (monitor_actions, "monitor-cut-all", _("Cut monitor"),
932                         sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), MonitorCutAll));
933
934         myactions.register_toggle_action (monitor_actions, "monitor-dim-all", _("Dim monitor"),
935                         sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), MonitorDimAll));
936
937         act = myactions.register_toggle_action (monitor_actions, "toggle-exclusive-solo", _("Toggle exclusive solo mode"),
938                         sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), ToggleExclusiveSolo));
939
940         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
941         tact->set_active (Config->get_exclusive_solo());
942
943         act = myactions.register_toggle_action (monitor_actions, "toggle-mute-overrides-solo", _("Toggle mute overrides solo mode"),
944                         sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), ToggleMuteOverridesSolo));
945
946         tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
947         tact->set_active (Config->get_solo_mute_override());
948
949         for (uint32_t chn = 0; chn < 16; ++chn) {
950
951                 action_name = string_compose (X_("monitor-cut-%1"), chn);
952                 action_descr = string_compose (_("Cut monitor channel %1"), chn);
953                 myactions.register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
954                                 sigc::bind (sigc::ptr_fun (action_proxy1), CutChannel, chn));
955
956                 action_name = string_compose (X_("monitor-dim-%1"), chn);
957                 action_descr = string_compose (_("Dim monitor channel %1"), chn);
958                 myactions.register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
959                                 sigc::bind (sigc::ptr_fun (action_proxy1), DimChannel, chn));
960
961                 action_name = string_compose (X_("monitor-solo-%1"), chn);
962                 action_descr = string_compose (_("Solo monitor channel %1"), chn);
963                 myactions.register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
964                                 sigc::bind (sigc::ptr_fun (action_proxy1), SoloChannel, chn));
965
966                 action_name = string_compose (X_("monitor-invert-%1"), chn);
967                 action_descr = string_compose (_("Invert monitor channel %1"), chn);
968                 myactions.register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
969                                 sigc::bind (sigc::ptr_fun (action_proxy1), InvertChannel, chn));
970
971         }
972
973
974         Glib::RefPtr<ActionGroup> solo_actions = myactions.create_action_group (X_("Solo"));
975         RadioAction::Group solo_group;
976
977         myactions.register_radio_action (solo_actions, solo_group, "solo-use-in-place", _("In-place solo"),
978                         sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), SoloUseInPlace));
979         myactions.register_radio_action (solo_actions, solo_group, "solo-use-afl", _("After Fade Listen (AFL) solo"),
980                         sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), SoloUseAFL));
981         myactions.register_radio_action (solo_actions, solo_group, "solo-use-pfl", _("Pre Fade Listen (PFL) solo"),
982                         sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), SoloUsePFL));
983
984         myactions.register_toggle_action (monitor_actions, "toggle-monitor-processor-box", _("Toggle Monitor Section Processor Box"),
985                         sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), ToggleMonitorProcessorBox));
986
987 }
988
989 void
990 MonitorSection::solo_use_in_place ()
991 {
992         /* this is driven by a toggle on a radio group, and so is invoked twice,
993                  once for the item that became inactive and once for the one that became
994                  active.
995                  */
996
997         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
998
999         if (act) {
1000                 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1001                 if (ract) {
1002                         if (!ract->get_active ()) {
1003                                 /* We are turning SiP off, which means that AFL or PFL will be turned on
1004                                          shortly; don't update the solo model in the mean time, as if the currently
1005                                          configured listen position is not the one that is about to be turned on,
1006                                          things will go wrong.
1007                                          */
1008                                 _inhibit_solo_model_update = true;
1009                         }
1010                         Config->set_solo_control_is_listen_control (!ract->get_active());
1011                         _inhibit_solo_model_update = false;
1012                 }
1013         }
1014 }
1015
1016 void
1017 MonitorSection::solo_use_afl ()
1018 {
1019         /* this is driven by a toggle on a radio group, and so is invoked twice,
1020                  once for the item that became inactive and once for the one that became
1021                  active.
1022                  */
1023
1024         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
1025         if (act) {
1026                 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1027                 if (ract) {
1028                         if (ract->get_active()) {
1029                                 Config->set_solo_control_is_listen_control (true);
1030                                 Config->set_listen_position (AfterFaderListen);
1031                         }
1032                 }
1033         }
1034 }
1035
1036 void
1037 MonitorSection::solo_use_pfl ()
1038 {
1039         /* this is driven by a toggle on a radio group, and so is invoked twice,
1040            once for the item that became inactive and once for the one that became
1041            active.
1042         */
1043
1044         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
1045         if (act) {
1046                 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1047                 if (ract) {
1048                         if (ract->get_active()) {
1049                                 Config->set_solo_control_is_listen_control (true);
1050                                 Config->set_listen_position (PreFaderListen);
1051                         }
1052                 }
1053         }
1054 }
1055
1056 void
1057 MonitorSection::update_solo_model ()
1058 {
1059         if (_inhibit_solo_model_update) {
1060                 return;
1061         }
1062
1063         const char* action_name = 0;
1064         Glib::RefPtr<Action> act;
1065
1066         if (Config->get_solo_control_is_listen_control()) {
1067                 switch (Config->get_listen_position()) {
1068                         case AfterFaderListen:
1069                                 action_name = X_("solo-use-afl");
1070                                 break;
1071                         case PreFaderListen:
1072                                 action_name = X_("solo-use-pfl");
1073                                 break;
1074                 }
1075         } else {
1076                 action_name = X_("solo-use-in-place");
1077         }
1078
1079         act = ActionManager::get_action (X_("Solo"), action_name);
1080         if (act) {
1081
1082                 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1083                 if (ract) {
1084                         /* because these are radio buttons, one of them will be
1085                                  active no matter what. to trigger a change in the
1086                                  action so that the view picks it up, toggle it.
1087                                  */
1088                         if (ract->get_active()) {
1089                                 ract->set_active (false);
1090                         }
1091                         ract->set_active (true);
1092                 }
1093
1094         }
1095 }
1096
1097 void
1098 MonitorSection::map_state ()
1099 {
1100         if (!_route || !_monitor) {
1101                 return;
1102         }
1103
1104         Glib::RefPtr<Action> act;
1105
1106         update_solo_model ();
1107
1108         act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
1109         if (act) {
1110                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1111                 if (tact) {
1112                         tact->set_active (_monitor->cut_all());
1113                 }
1114         }
1115
1116         act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
1117         if (act) {
1118                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1119                 if (tact) {
1120                         tact->set_active (_monitor->dim_all());
1121                 }
1122         }
1123
1124         act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
1125         if (act) {
1126                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1127                 if (tact) {
1128                         tact->set_active (_monitor->mono());
1129                 }
1130         }
1131
1132         uint32_t nchans = _monitor->output_streams().n_audio();
1133
1134         assert (nchans == _channel_buttons.size ());
1135
1136         for (uint32_t n = 0; n < nchans; ++n) {
1137
1138                 char action_name[32];
1139
1140                 snprintf (action_name, sizeof (action_name), "monitor-cut-%u", n);
1141                 act = ActionManager::get_action (X_("Monitor"), action_name);
1142                 if (act) {
1143                         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1144                         if (tact) {
1145                                 tact->set_active (_monitor->cut (n));
1146                         }
1147                 }
1148
1149                 snprintf (action_name, sizeof (action_name), "monitor-dim-%u", n);
1150                 act = ActionManager::get_action (X_("Monitor"), action_name);
1151                 if (act) {
1152                         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1153                         if (tact) {
1154                                 tact->set_active (_monitor->dimmed (n));
1155                         }
1156                 }
1157
1158                 snprintf (action_name, sizeof (action_name), "monitor-solo-%u", n);
1159                 act = ActionManager::get_action (X_("Monitor"), action_name);
1160                 if (act) {
1161                         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1162                         if (tact) {
1163                                 tact->set_active (_monitor->soloed (n));
1164                         }
1165                 }
1166
1167                 snprintf (action_name, sizeof (action_name), "monitor-invert-%u", n);
1168                 act = ActionManager::get_action (X_("Monitor"), action_name);
1169                 if (act) {
1170                         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1171                         if (tact) {
1172                                 tact->set_active (_monitor->inverted (n));
1173                         }
1174                 }
1175         }
1176 }
1177
1178 void
1179 MonitorSection::do_blink (bool onoff)
1180 {
1181         if (!UIConfiguration::instance().get_blink_alert_indicators ()) {
1182                 onoff = true;
1183         }
1184
1185         solo_blink (onoff);
1186         audition_blink (onoff);
1187 }
1188
1189 void
1190 MonitorSection::audition_blink (bool onoff)
1191 {
1192         if (_session == 0) {
1193                 return;
1194         }
1195
1196         if (_session->is_auditioning()) {
1197                 rude_audition_button.set_active (onoff);
1198         } else {
1199                 rude_audition_button.set_active (false);
1200         }
1201 }
1202
1203 void
1204 MonitorSection::solo_blink (bool onoff)
1205 {
1206         if (_session == 0) {
1207                 return;
1208         }
1209
1210         if (_session->soloing() || _session->listening()) {
1211                 rude_solo_button.set_active (onoff);
1212
1213                 if (_session->soloing()) {
1214                         if (_session->solo_isolated()) {
1215                                 rude_iso_button.set_active (onoff);
1216                         } else {
1217                                 rude_iso_button.set_active (false);
1218                         }
1219                 }
1220
1221         } else {
1222                 rude_solo_button.set_active (false);
1223                 rude_iso_button.set_active (false);
1224         }
1225 }
1226
1227 bool
1228 MonitorSection::cancel_isolate (GdkEventButton*)
1229 {
1230         if (_session) {
1231                 boost::shared_ptr<RouteList> rl (_session->get_routes ());
1232                 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_isolate_control), 0.0, Controllable::NoGroup);
1233         }
1234
1235         return true;
1236 }
1237
1238 bool
1239 MonitorSection::cancel_audition (GdkEventButton*)
1240 {
1241         if (_session) {
1242                 _session->cancel_audition();
1243         }
1244         return true;
1245 }
1246
1247 #define SYNCHRONIZE_TOGGLE_ACTION(action, value) \
1248         if (action) { \
1249                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(action); \
1250                 if (tact && tact->get_active() != value) { \
1251                         tact->set_active(value); \
1252                 } \
1253         }
1254
1255 void
1256 MonitorSection::parameter_changed (std::string name)
1257 {
1258         if (name == "solo-control-is-listen-control") {
1259                 update_solo_model ();
1260         } else if (name == "listen-position") {
1261                 update_solo_model ();
1262         } else if (name == "solo-mute-override") {
1263                 SYNCHRONIZE_TOGGLE_ACTION(
1264                                 ActionManager::get_action (X_("Monitor"), "toggle-mute-overrides-solo"),
1265                                 Config->get_solo_mute_override ())
1266         } else if (name == "exclusive-solo") {
1267                 SYNCHRONIZE_TOGGLE_ACTION(
1268                                 ActionManager::get_action (X_("Monitor"), "toggle-exclusive-solo"),
1269                                 Config->get_exclusive_solo ())
1270         }
1271 }
1272
1273 void
1274 MonitorSection::assign_controllables ()
1275 {
1276         boost::shared_ptr<Controllable> none;
1277
1278         if (!gain_control) {
1279                 /* too early - GUI controls not set up yet */
1280                 return;
1281         }
1282
1283         if (_session) {
1284                 solo_cut_control->set_controllable (_session->solo_cut_control());
1285                 solo_cut_display->set_controllable (_session->solo_cut_control());
1286         } else {
1287                 solo_cut_control->set_controllable (none);
1288                 solo_cut_display->set_controllable (none);
1289         }
1290
1291         if (_route) {
1292                 gain_control->set_controllable (_route->gain_control());
1293                 gain_display->set_controllable (_route->gain_control());
1294         } else {
1295                 gain_control->set_controllable (none);
1296         }
1297
1298         if (_monitor) {
1299
1300                 cut_all_button.set_controllable (_monitor->cut_control());
1301                 cut_all_button.watch ();
1302                 dim_all_button.set_controllable (_monitor->dim_control());
1303                 dim_all_button.watch ();
1304                 mono_button.set_controllable (_monitor->mono_control());
1305                 mono_button.watch ();
1306
1307                 dim_control->set_controllable (_monitor->dim_level_control ());
1308                 dim_display->set_controllable (_monitor->dim_level_control ());
1309                 solo_boost_control->set_controllable (_monitor->solo_boost_control ());
1310                 solo_boost_display->set_controllable (_monitor->solo_boost_control ());
1311
1312         } else {
1313
1314                 cut_all_button.set_controllable (none);
1315                 dim_all_button.set_controllable (none);
1316                 mono_button.set_controllable (none);
1317
1318                 dim_control->set_controllable (none);
1319                 dim_display->set_controllable (none);
1320                 solo_boost_control->set_controllable (none);
1321                 solo_boost_display->set_controllable (none);
1322         }
1323 }
1324
1325 string
1326 MonitorSection::state_id() const
1327 {
1328         return "monitor-section";
1329 }
1330
1331 void
1332 MonitorSection::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1333 {
1334         using namespace Menu_Helpers;
1335
1336         if (b->ports_are_inputs() == false || b->nchannels() != _route->n_outputs() || *b == *_route->input()->bundle()) {
1337                 return;
1338         }
1339
1340         list<boost::shared_ptr<Bundle> >::iterator i = output_menu_bundles.begin ();
1341         while (i != output_menu_bundles.end() && b->has_same_ports (*i) == false) {
1342                 ++i;
1343         }
1344
1345         if (i != output_menu_bundles.end()) {
1346                 return;
1347         }
1348
1349         output_menu_bundles.push_back (b);
1350
1351         MenuList& citems = output_menu.items();
1352
1353         std::string n = b->name ();
1354         replace_all (n, "_", " ");
1355
1356         citems.push_back (MenuElem (n, sigc::bind (sigc::mem_fun(*this, &MonitorSection::bundle_output_chosen), b)));
1357 }
1358
1359 void
1360 MonitorSection::bundle_output_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1361 {
1362
1363         ARDOUR::BundleList current = _route->output()->bundles_connected ();
1364
1365         if (std::find (current.begin(), current.end(), c) == current.end()) {
1366                 _route->output()->connect_ports_to_bundle (c, true, this);
1367         } else {
1368                 _route->output()->disconnect_ports_from_bundle (c, this);
1369         }
1370 }
1371
1372 gint
1373 MonitorSection::output_release (GdkEventButton *ev)
1374 {
1375         switch (ev->button) {
1376         case 3:
1377                 edit_output_configuration ();
1378                 break;
1379         }
1380
1381         return false;
1382 }
1383
1384 struct RouteCompareByName {
1385         bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
1386                 return a->name().compare (b->name()) < 0;
1387         }
1388 };
1389
1390 gint
1391 MonitorSection::output_press (GdkEventButton *ev)
1392 {
1393         using namespace Menu_Helpers;
1394         if (!_session) {
1395                 MessageDialog msg (_("No session - no I/O changes are possible"));
1396                 msg.run ();
1397                 return true;
1398         }
1399
1400         MenuList& citems = output_menu.items();
1401         switch (ev->button) {
1402
1403         case 3:
1404                 return false;  //wait for the mouse-up to pop the dialog
1405
1406         case 1:
1407         {
1408                 output_menu.set_name ("ArdourContextMenu");
1409                 citems.clear ();
1410                 output_menu_bundles.clear ();
1411
1412                 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(this), &MonitorSection::disconnect_output)));
1413
1414                 citems.push_back (SeparatorElem());
1415                 uint32_t const n_with_separator = citems.size ();
1416
1417                 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1418
1419                 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
1420
1421                 /* give user bundles first chance at being in the menu */
1422
1423                 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1424                         if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
1425                                 maybe_add_bundle_to_output_menu (*i, current);
1426                         }
1427                 }
1428
1429                 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1430                         if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
1431                                 maybe_add_bundle_to_output_menu (*i, current);
1432                         }
1433                 }
1434
1435                 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
1436                 RouteList copy = *routes;
1437                 copy.sort (RouteCompareByName ());
1438                 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
1439                         maybe_add_bundle_to_output_menu ((*i)->output()->bundle(), current);
1440                 }
1441
1442                 if (citems.size() == n_with_separator) {
1443                         /* no routes added; remove the separator */
1444                         citems.pop_back ();
1445                 }
1446
1447                 citems.push_back (SeparatorElem());
1448                 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(this), &MonitorSection::edit_output_configuration)));
1449
1450                 output_menu.popup (1, ev->time);
1451                 break;
1452         }
1453
1454         default:
1455                 break;
1456         }
1457         return TRUE;
1458 }
1459
1460 void
1461 MonitorSection::update_output_display ()
1462 {
1463         if (!_route || !_monitor || _session->deletion_in_progress()) {
1464                 return;
1465         }
1466
1467         uint32_t io_count;
1468         uint32_t io_index;
1469         boost::shared_ptr<Port> port;
1470         vector<string> port_connections;
1471
1472         uint32_t total_connection_count = 0;
1473         uint32_t io_connection_count = 0;
1474         uint32_t ardour_connection_count = 0;
1475         uint32_t system_connection_count = 0;
1476         uint32_t other_connection_count = 0;
1477
1478         ostringstream label;
1479
1480         bool have_label = false;
1481         bool each_io_has_one_connection = true;
1482
1483         string connection_name;
1484         string ardour_track_name;
1485         string other_connection_type;
1486         string system_ports;
1487         string system_port;
1488
1489         ostringstream tooltip;
1490         char * tooltip_cstr;
1491
1492         io_count = _route->n_outputs().n_total();
1493         tooltip << string_compose (_("<b>OUTPUT</b> from %1"), Gtkmm2ext::markup_escape_text (_route->name()));
1494
1495
1496         for (io_index = 0; io_index < io_count; ++io_index) {
1497
1498                 port = _route->output()->nth (io_index);
1499
1500                 //ignore any port connections that don't match our DataType
1501                 if (port->type() != DataType::AUDIO) {
1502                         continue;
1503                 }
1504
1505                 port_connections.clear ();
1506                 port->get_connections(port_connections);
1507                 io_connection_count = 0;
1508
1509                 if (!port_connections.empty()) {
1510                         for (vector<string>::iterator i = port_connections.begin(); i != port_connections.end(); ++i) {
1511                                 string pn = "";
1512                                 string& connection_name (*i);
1513
1514                                 if (connection_name.find("system:") == 0) {
1515                                         pn = AudioEngine::instance()->get_pretty_name_by_name (connection_name);
1516                                 }
1517
1518                                 if (io_connection_count == 0) {
1519                                         tooltip << endl << Gtkmm2ext::markup_escape_text (port->name().substr(port->name().find("/") + 1))
1520                                                 << " -> "
1521                                                 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1522                                 } else {
1523                                         tooltip << ", "
1524                                                 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1525                                 }
1526
1527                                 if (connection_name.find(RouteUI::program_port_prefix) == 0) {
1528                                         if (ardour_track_name.empty()) {
1529                                                 // "ardour:Master/in 1" -> "ardour:Master/"
1530                                                 string::size_type slash = connection_name.find("/");
1531                                                 if (slash != string::npos) {
1532                                                         ardour_track_name = connection_name.substr(0, slash + 1);
1533                                                 }
1534                                         }
1535
1536                                         if (connection_name.find(ardour_track_name) == 0) {
1537                                                 ++ardour_connection_count;
1538                                         }
1539                                 } else if (!pn.empty()) {
1540                                         if (system_ports.empty()) {
1541                                                 system_ports += pn;
1542                                         } else {
1543                                                 system_ports += "/" + pn;
1544                                         }
1545                                         if (connection_name.find("system:") == 0) {
1546                                                 ++system_connection_count;
1547                                         }
1548                                 } else if (connection_name.find("system:") == 0) {
1549                                         // "system:playback_123" -> "123"
1550                                         system_port = connection_name.substr(16);
1551                                         if (system_ports.empty()) {
1552                                                 system_ports += system_port;
1553                                         } else {
1554                                                 system_ports += "/" + system_port;
1555                                         }
1556
1557                                         ++system_connection_count;
1558                                 } else {
1559                                         if (other_connection_type.empty()) {
1560                                                 // "jamin:in 1" -> "jamin:"
1561                                                 other_connection_type = connection_name.substr(0, connection_name.find(":") + 1);
1562                                         }
1563
1564                                         if (connection_name.find(other_connection_type) == 0) {
1565                                                 ++other_connection_count;
1566                                         }
1567                                 }
1568
1569                                 ++total_connection_count;
1570                                 ++io_connection_count;
1571                         }
1572                 }
1573
1574                 if (io_connection_count != 1) {
1575                         each_io_has_one_connection = false;
1576                 }
1577         }
1578
1579         if (total_connection_count == 0) {
1580                 tooltip << endl << _("Disconnected");
1581         }
1582
1583         tooltip_cstr = new char[tooltip.str().size() + 1];
1584         strcpy(tooltip_cstr, tooltip.str().c_str());
1585
1586         set_tooltip (output_button, tooltip_cstr, "");
1587
1588         if (each_io_has_one_connection) {
1589                 if (total_connection_count == ardour_connection_count) {
1590                         // all connections are to the same track in ardour
1591                         // "ardour:Master/" -> "Master"
1592                         string::size_type slash = ardour_track_name.find("/");
1593                         if (slash != string::npos) {
1594                                 label << ardour_track_name.substr(7, slash - 7);
1595                                 have_label = true;
1596                         }
1597                 } else if (total_connection_count == system_connection_count) {
1598                         // all connections are to system ports
1599                         label << system_ports;
1600                         have_label = true;
1601                 } else if (total_connection_count == other_connection_count) {
1602                         // all connections are to the same external program eg jamin
1603                         // "jamin:" -> "jamin"
1604                         label << other_connection_type.substr(0, other_connection_type.size() - 1);
1605                         have_label = true;
1606                 }
1607         }
1608
1609         if (!have_label) {
1610                 if (total_connection_count == 0) {
1611                         // Disconnected
1612                         label << "-";
1613                 } else {
1614                         // Odd configuration
1615                         label << "*" << total_connection_count << "*";
1616                 }
1617         }
1618
1619         output_button->set_text (label.str());
1620 }
1621
1622 void
1623 MonitorSection::disconnect_output ()
1624 {
1625         if (_route) {
1626                 _route->output()->disconnect(this);
1627         }
1628 }
1629
1630 void
1631 MonitorSection::edit_output_configuration ()
1632 {
1633         if (_output_selector == 0) {
1634                 _output_selector = new MonitorSelectorWindow (_session, _route->output());
1635         }
1636         _output_selector->present ();
1637 }
1638
1639 void
1640 MonitorSection::port_connected_or_disconnected (boost::weak_ptr<Port> wa, boost::weak_ptr<Port> wb)
1641 {
1642         if (!_route) {
1643                 return;
1644         }
1645         boost::shared_ptr<Port> a = wa.lock ();
1646         boost::shared_ptr<Port> b = wb.lock ();
1647         if ((a && _route->output()->has_port (a)) || (b && _route->output()->has_port (b))) {
1648                 update_output_display ();
1649         }
1650 }
1651
1652 void
1653 MonitorSection::load_bindings ()
1654 {
1655         bindings = Bindings::get_bindings (X_("Monitor Section"), myactions);
1656 }
1657
1658 void
1659 MonitorSection::help_count_processors (boost::weak_ptr<Processor> p, uint32_t* cnt) const
1660 {
1661         boost::shared_ptr<Processor> processor (p.lock ());
1662         if (!processor || !processor->display_to_user()) {
1663                 return;
1664         }
1665         if (boost::dynamic_pointer_cast<Amp>(processor)) {
1666                 return;
1667         }
1668         ++(*cnt);
1669 }
1670
1671 uint32_t
1672 MonitorSection::count_processors ()
1673 {
1674         uint32_t processor_count = 0;
1675         if (_route) {
1676                 _route->foreach_processor (sigc::bind (sigc::mem_fun (*this, &MonitorSection::help_count_processors), &processor_count));
1677         }
1678         return processor_count;
1679 }
1680
1681 void
1682 MonitorSection::processors_changed (ARDOUR::RouteProcessorChange)
1683 {
1684         update_processor_box ();
1685 }
1686
1687 void
1688 MonitorSection::action_proxy0 (enum MonitorActions action)
1689 {
1690         MonitorSection* ms = Mixer_UI::instance()->monitor_section ();
1691         if (!ms) {
1692                 return;
1693         }
1694         switch (action) {
1695                 case MonitorMono:
1696                         ms->mono ();
1697                         break;
1698                 case MonitorCutAll:
1699                         ms->cut_all ();
1700                         break;
1701                 case MonitorDimAll:
1702                         ms->dim_all ();
1703                         break;
1704                 case ToggleExclusiveSolo:
1705                         ms->toggle_exclusive_solo ();
1706                         break;
1707                 case ToggleMuteOverridesSolo:
1708                         ms->toggle_mute_overrides_solo ();
1709                         break;
1710                 case SoloUseInPlace:
1711                         ms->solo_use_in_place ();
1712                         break;
1713                 case SoloUseAFL:
1714                         ms->solo_use_afl ();
1715                         break;
1716                 case SoloUsePFL:
1717                         ms->solo_use_pfl ();
1718                         break;
1719                 case ToggleMonitorProcessorBox:
1720                         ms->update_processor_box ();
1721                         break;
1722         }
1723 }
1724
1725 void
1726 MonitorSection::action_proxy1 (enum ChannelActions action, uint32_t chn)
1727 {
1728         MonitorSection* ms = Mixer_UI::instance()->monitor_section ();
1729         if (!ms) {
1730                 return;
1731         }
1732         switch (action) {
1733                 case CutChannel:
1734                         ms->cut_channel (chn);
1735                         break;
1736                 case DimChannel:
1737                         ms->dim_channel (chn);
1738                         break;
1739                 case SoloChannel:
1740                         ms->solo_channel (chn);
1741                         break;
1742                 case InvertChannel:
1743                         ms->invert_channel (chn);
1744                         break;
1745         }
1746 }