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