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