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