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