fc39115c33472a7835f9d7c06f873e281afcd01d
[ardour.git] / gtk2_ardour / mixer_ui.cc
1 /*
2     Copyright (C) 2000-2004 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 #ifdef WAF_BUILD
21 #include "gtk2ardour-config.h"
22 #endif
23
24 #include <algorithm>
25 #include <map>
26 #include <sigc++/bind.h>
27
28 #include <gtkmm/accelmap.h>
29
30 #include "pbd/convert.h"
31 #include "pbd/unwind.h"
32
33 #include <glibmm/threads.h>
34
35 #include <gtkmm2ext/gtk_ui.h>
36 #include <gtkmm2ext/utils.h>
37 #include <gtkmm2ext/tearoff.h>
38 #include <gtkmm2ext/window_title.h>
39
40 #include "ardour/debug.h"
41 #include "ardour/midi_track.h"
42 #include "ardour/plugin_manager.h"
43 #include "ardour/route_group.h"
44 #include "ardour/session.h"
45
46 #include "keyboard.h"
47 #include "mixer_ui.h"
48 #include "mixer_strip.h"
49 #include "monitor_section.h"
50 #include "plugin_selector.h"
51 #include "public_editor.h"
52 #include "ardour_ui.h"
53 #include "prompter.h"
54 #include "utils.h"
55 #include "route_sorter.h"
56 #include "actions.h"
57 #include "gui_thread.h"
58 #include "mixer_group_tabs.h"
59
60 #include "i18n.h"
61
62 using namespace ARDOUR;
63 using namespace PBD;
64 using namespace Gtk;
65 using namespace Glib;
66 using namespace Gtkmm2ext;
67 using namespace std;
68
69 using PBD::atoi;
70 using PBD::Unwinder;
71
72 Mixer_UI* Mixer_UI::_instance = 0;
73
74 Mixer_UI*
75 Mixer_UI::instance () 
76 {
77         if (!_instance) {
78                 _instance  = new Mixer_UI;
79         } 
80
81         return _instance;
82 }
83
84 Mixer_UI::Mixer_UI ()
85         : Window (Gtk::WINDOW_TOPLEVEL)
86         , _visible (false)
87         , no_track_list_redisplay (false)
88         , in_group_row_change (false)
89         , track_menu (0)
90         , _monitor_section (0)
91         , _strip_width (Config->get_default_narrow_ms() ? Narrow : Wide)
92         , ignore_reorder (false)
93         , _following_editor_selection (false)
94 {
95         /* allow this window to become the key focus window */
96         set_flags (CAN_FOCUS);
97
98         Route::SyncOrderKeys.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::sync_treeview_from_order_keys, this, _1), gui_context());
99
100         scroller_base.set_flags (Gtk::CAN_FOCUS);
101         scroller_base.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
102         scroller_base.set_name ("MixerWindow");
103         scroller_base.signal_button_release_event().connect (sigc::mem_fun(*this, &Mixer_UI::strip_scroller_button_release));
104         // add as last item of strip packer
105         strip_packer.pack_end (scroller_base, true, true);
106
107         _group_tabs = new MixerGroupTabs (this);
108         VBox* b = manage (new VBox);
109         b->pack_start (*_group_tabs, PACK_SHRINK);
110         b->pack_start (strip_packer);
111         b->show_all ();
112
113         scroller.add (*b);
114         scroller.set_policy (Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
115
116         setup_track_display ();
117
118         group_model = ListStore::create (group_columns);
119         group_display.set_model (group_model);
120         group_display.append_column (_("Group"), group_columns.text);
121         group_display.append_column (_("Show"), group_columns.visible);
122         group_display.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0));
123         group_display.get_column (1)->set_data (X_("colnum"), GUINT_TO_POINTER(1));
124         group_display.get_column (0)->set_expand(true);
125         group_display.get_column (1)->set_expand(false);
126         group_display.set_name ("EditGroupList");
127         group_display.get_selection()->set_mode (Gtk::SELECTION_SINGLE);
128         group_display.set_reorderable (true);
129         group_display.set_headers_visible (true);
130         group_display.set_rules_hint (true);
131
132         /* name is directly editable */
133
134         CellRendererText* name_cell = dynamic_cast<CellRendererText*>(group_display.get_column_cell_renderer (0));
135         name_cell->property_editable() = true;
136         name_cell->signal_edited().connect (sigc::mem_fun (*this, &Mixer_UI::route_group_name_edit));
137
138         /* use checkbox for the active column */
139
140         CellRendererToggle* active_cell = dynamic_cast<CellRendererToggle*>(group_display.get_column_cell_renderer (1));
141         active_cell->property_activatable() = true;
142         active_cell->property_radio() = false;
143
144         group_model->signal_row_changed().connect (sigc::mem_fun (*this, &Mixer_UI::route_group_row_change));
145         /* We use this to notice drag-and-drop reorders of the group list */
146         group_model->signal_row_deleted().connect (sigc::mem_fun (*this, &Mixer_UI::route_group_row_deleted));
147         group_display.signal_button_press_event().connect (sigc::mem_fun (*this, &Mixer_UI::group_display_button_press), false);
148
149         group_display_scroller.add (group_display);
150         group_display_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
151
152         HBox* route_group_display_button_box = manage (new HBox());
153
154         Button* route_group_add_button = manage (new Button ());
155         Button* route_group_remove_button = manage (new Button ());
156
157         Widget* w;
158
159         w = manage (new Image (Stock::ADD, ICON_SIZE_BUTTON));
160         w->show();
161         route_group_add_button->add (*w);
162
163         w = manage (new Image (Stock::REMOVE, ICON_SIZE_BUTTON));
164         w->show();
165         route_group_remove_button->add (*w);
166
167         route_group_display_button_box->set_homogeneous (true);
168
169         route_group_add_button->signal_clicked().connect (sigc::mem_fun (*this, &Mixer_UI::new_route_group));
170         route_group_remove_button->signal_clicked().connect (sigc::mem_fun (*this, &Mixer_UI::remove_selected_route_group));
171
172         route_group_display_button_box->add (*route_group_add_button);
173         route_group_display_button_box->add (*route_group_remove_button);
174
175         group_display_vbox.pack_start (group_display_scroller, true, true);
176         group_display_vbox.pack_start (*route_group_display_button_box, false, false);
177
178         group_display_frame.set_name ("BaseFrame");
179         group_display_frame.set_shadow_type (Gtk::SHADOW_IN);
180         group_display_frame.add (group_display_vbox);
181
182         rhs_pane1.pack1 (track_display_frame);
183         rhs_pane1.pack2 (group_display_frame);
184
185         list_vpacker.pack_start (rhs_pane1, true, true);
186
187         global_hpacker.pack_start (scroller, true, true);
188 #ifdef GTKOSX
189         /* current gtk-quartz has dirty updates on borders like this one */
190         global_hpacker.pack_start (out_packer, false, false, 0);
191 #else
192         global_hpacker.pack_start (out_packer, false, false, 12);
193 #endif
194         list_hpane.pack1(list_vpacker, true, true);
195         list_hpane.pack2(global_hpacker, true, false);
196
197         rhs_pane1.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Mixer_UI::pane_allocation_handler),
198                                                         static_cast<Gtk::Paned*> (&rhs_pane1)));
199         list_hpane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Mixer_UI::pane_allocation_handler),
200                                                          static_cast<Gtk::Paned*> (&list_hpane)));
201
202         global_vpacker.pack_start (list_hpane, true, true);
203
204         add (global_vpacker);
205         set_name ("MixerWindow");
206
207         update_title ();
208
209         set_wmclass (X_("ardour_mixer"), PROGRAM_NAME);
210
211         signal_delete_event().connect (sigc::mem_fun (*this, &Mixer_UI::hide_window));
212         add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
213
214         signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
215
216         route_group_display_button_box->show();
217         route_group_add_button->show();
218         route_group_remove_button->show();
219
220         global_hpacker.show();
221         global_vpacker.show();
222         scroller.show();
223         scroller_base.show();
224         scroller_hpacker.show();
225         mixer_scroller_vpacker.show();
226         list_vpacker.show();
227         group_display_button_label.show();
228         group_display_button.show();
229         group_display_scroller.show();
230         group_display_vbox.show();
231         group_display_frame.show();
232         rhs_pane1.show();
233         strip_packer.show();
234         out_packer.show();
235         list_hpane.show();
236         group_display.show();
237
238         _in_group_rebuild_or_clear = false;
239
240         MixerStrip::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::remove_strip, this, _1), gui_context());
241
242         MonitorSection::setup_knob_images ();
243
244 #ifndef DEFER_PLUGIN_SELECTOR_LOAD
245         _plugin_selector = new PluginSelector (PluginManager::instance ());
246 #endif
247 }
248
249 Mixer_UI::~Mixer_UI ()
250 {
251         if (_monitor_section) {
252                 delete _monitor_section;
253         }
254 }
255
256 void
257 Mixer_UI::track_editor_selection ()
258 {
259         PublicEditor::instance().get_selection().TracksChanged.connect (sigc::mem_fun (*this, &Mixer_UI::follow_editor_selection));
260 }
261
262
263 void
264 Mixer_UI::ensure_float (Window& win)
265 {
266         win.set_transient_for (*this);
267 }
268
269 void
270 Mixer_UI::show_window ()
271 {
272         present ();
273         if (!_visible) {
274                 set_window_pos_and_size ();
275
276                 /* show/hide group tabs as required */
277                 parameter_changed ("show-group-tabs");
278
279                 /* now reset each strips width so the right widgets are shown */
280                 MixerStrip* ms;
281
282                 TreeModel::Children rows = track_model->children();
283                 TreeModel::Children::iterator ri;
284
285                 for (ri = rows.begin(); ri != rows.end(); ++ri) {
286                         ms = (*ri)[track_columns.strip];
287                         ms->set_width_enum (ms->get_width_enum (), ms->width_owner());
288                         /* Fix visibility of mixer strip stuff */
289                         ms->parameter_changed (X_("mixer-strip-visibility"));
290                 }
291         }
292         
293         /* force focus into main area */
294         scroller_base.grab_focus ();
295
296         _visible = true;
297 }
298
299 bool
300 Mixer_UI::hide_window (GdkEventAny *ev)
301 {
302         get_window_pos_and_size ();
303
304         _visible = false;
305         return just_hide_it(ev, static_cast<Gtk::Window *>(this));
306 }
307
308
309 void
310 Mixer_UI::add_strips (RouteList& routes)
311 {
312         MixerStrip* strip;
313
314         try {
315                 no_track_list_redisplay = true;
316                 track_display.set_model (Glib::RefPtr<ListStore>());
317
318                 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
319                         boost::shared_ptr<Route> route = (*x);
320                         
321                         if (route->is_hidden()) {
322                                 continue;
323                         }
324                         
325                         if (route->is_monitor()) {
326                                 
327                                 if (!_monitor_section) {
328                                         _monitor_section = new MonitorSection (_session);
329                                         
330                                         XMLNode* mnode = ARDOUR_UI::instance()->tearoff_settings (X_("monitor-section"));
331                                         if (mnode) {
332                                                 _monitor_section->tearoff().set_state (*mnode);
333                                         }
334                                 } 
335                                 
336                                 out_packer.pack_end (_monitor_section->tearoff(), false, false);
337                                 _monitor_section->set_session (_session);
338                                 _monitor_section->tearoff().show_all ();
339                                 
340                                 route->DropReferences.connect (*this, invalidator(*this), boost::bind (&Mixer_UI::monitor_section_going_away, this), gui_context());
341                                 
342                                 /* no regular strip shown for control out */
343                                 
344                                 continue;
345                         }
346                         
347                         strip = new MixerStrip (*this, _session, route);
348                         strips.push_back (strip);
349
350                         Config->get_default_narrow_ms() ? _strip_width = Narrow : _strip_width = Wide;
351                         
352                         if (strip->width_owner() != strip) {
353                                 strip->set_width_enum (_strip_width, this);
354                         }
355                         
356                         show_strip (strip);
357                         
358                         TreeModel::Row row = *(track_model->append());
359                         row[track_columns.text] = route->name();
360                         row[track_columns.visible] = strip->route()->is_master() ? true : strip->marked_for_display();
361                         row[track_columns.route] = route;
362                         row[track_columns.strip] = strip;
363                         
364                         route->PropertyChanged.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::strip_property_changed, this, _1, strip), gui_context());
365                         
366                         strip->WidthChanged.connect (sigc::mem_fun(*this, &Mixer_UI::strip_width_changed));
367                         strip->signal_button_release_event().connect (sigc::bind (sigc::mem_fun(*this, &Mixer_UI::strip_button_release_event), strip));
368                 }
369
370         } catch (...) {
371         }
372
373         no_track_list_redisplay = false;
374         track_display.set_model (track_model);
375         
376         sync_order_keys_from_treeview ();
377         redisplay_track_list ();
378 }
379
380 void
381 Mixer_UI::remove_strip (MixerStrip* strip)
382 {
383         if (_session && _session->deletion_in_progress()) {
384                 /* its all being taken care of */
385                 return;
386         }
387
388         TreeModel::Children rows = track_model->children();
389         TreeModel::Children::iterator ri;
390         list<MixerStrip *>::iterator i;
391         
392         if ((i = find (strips.begin(), strips.end(), strip)) != strips.end()) {
393                 strips.erase (i);
394         }
395         
396         for (ri = rows.begin(); ri != rows.end(); ++ri) {
397                 if ((*ri)[track_columns.strip] == strip) {
398                         track_model->erase (ri);
399                         break;
400                 }
401         }
402 }
403
404 void
405 Mixer_UI::reset_remote_control_ids ()
406 {
407         if (Config->get_remote_model() != MixerOrdered || !_session || _session->deletion_in_progress()) {
408                 return;
409         }
410
411         TreeModel::Children rows = track_model->children();
412         
413         if (rows.empty()) {
414                 return;
415         }
416
417         DEBUG_TRACE (DEBUG::OrderKeys, "mixer resets remote control ids after remote model change\n");
418
419         TreeModel::Children::iterator ri;
420         bool rid_change = false;
421         uint32_t rid = 1;
422         uint32_t invisible_key = UINT32_MAX;
423
424         for (ri = rows.begin(); ri != rows.end(); ++ri) {
425                 boost::shared_ptr<Route> route = (*ri)[track_columns.route];
426                 bool visible = (*ri)[track_columns.visible];
427
428                 if (!route->is_master() && !route->is_monitor()) {
429                         
430                         uint32_t new_rid = (visible ? rid : invisible_key--);
431                         
432                         if (new_rid != route->remote_control_id()) {
433                                 route->set_remote_control_id_from_order_key (MixerSort, new_rid);       
434                                 rid_change = true;
435                         }
436                         
437                         if (visible) {
438                                 rid++;
439                         }
440                 }
441         }
442
443         if (rid_change) {
444                 /* tell the world that we changed the remote control IDs */
445                 _session->notify_remote_id_change ();
446         }
447 }
448
449 void
450 Mixer_UI::sync_order_keys_from_treeview ()
451 {
452         if (ignore_reorder || !_session || _session->deletion_in_progress()) {
453                 return;
454         }
455
456         TreeModel::Children rows = track_model->children();
457         
458         if (rows.empty()) {
459                 return;
460         }
461
462         DEBUG_TRACE (DEBUG::OrderKeys, "mixer sync order keys from model\n");
463
464         TreeModel::Children::iterator ri;
465         bool changed = false;
466         bool rid_change = false;
467         uint32_t order = 0;
468         uint32_t rid = 1;
469         uint32_t invisible_key = UINT32_MAX;
470
471         for (ri = rows.begin(); ri != rows.end(); ++ri) {
472                 boost::shared_ptr<Route> route = (*ri)[track_columns.route];
473                 bool visible = (*ri)[track_columns.visible];
474
475                 uint32_t old_key = route->order_key (MixerSort);
476
477                 if (order != old_key) {
478                         route->set_order_key (MixerSort, order);
479                         changed = true;
480                 }
481
482                 if ((Config->get_remote_model() == MixerOrdered) && !route->is_master() && !route->is_monitor()) {
483
484                         uint32_t new_rid = (visible ? rid : invisible_key--);
485
486                         if (new_rid != route->remote_control_id()) {
487                                 route->set_remote_control_id_from_order_key (MixerSort, new_rid);       
488                                 rid_change = true;
489                         }
490                         
491                         if (visible) {
492                                 rid++;
493                         }
494
495                 }
496
497                 ++order;
498         }
499
500         if (changed) {
501                 /* tell everyone that we changed the mixer sort keys */
502                 _session->sync_order_keys (MixerSort);
503         }
504
505         if (rid_change) {
506                 /* tell the world that we changed the remote control IDs */
507                 _session->notify_remote_id_change ();
508         }
509 }
510
511 void
512 Mixer_UI::sync_treeview_from_order_keys (RouteSortOrderKey src)
513 {
514         if (!_session || _session->deletion_in_progress()) {
515                 return;
516         }
517
518         DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("mixer sync model from order keys, src = %1\n", enum_2_string (src)));
519
520         if (src == EditorSort) {
521
522                 if (!Config->get_sync_all_route_ordering()) {
523                         /* editor sort keys changed - we don't care */
524                         return;
525                 }
526
527                 DEBUG_TRACE (DEBUG::OrderKeys, "reset mixer order key to match editor\n");
528
529                 /* editor sort keys were changed, update the mixer sort
530                  * keys since "sync mixer+editor order" is enabled.
531                  */
532
533                 boost::shared_ptr<RouteList> r = _session->get_routes ();
534                 
535                 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
536                         (*i)->sync_order_keys (src);
537                 }
538         }
539
540         /* we could get here after either a change in the Mixer or Editor sort
541          * order, but either way, the mixer order keys reflect the intended
542          * order for the GUI, so reorder the treeview model to match it.
543          */
544
545         vector<int> neworder;
546         TreeModel::Children rows = track_model->children();
547         uint32_t old_order = 0;
548         bool changed = false;
549
550         if (rows.empty()) {
551                 return;
552         }
553
554         OrderKeySortedRoutes sorted_routes;
555
556         for (TreeModel::Children::iterator ri = rows.begin(); ri != rows.end(); ++ri, ++old_order) {
557                 boost::shared_ptr<Route> route = (*ri)[track_columns.route];
558                 sorted_routes.push_back (RoutePlusOrderKey (route, old_order, route->order_key (MixerSort)));
559         }
560
561         SortByNewDisplayOrder cmp;
562
563         sort (sorted_routes.begin(), sorted_routes.end(), cmp);
564         neworder.assign (sorted_routes.size(), 0);
565
566         uint32_t n = 0;
567         
568         for (OrderKeySortedRoutes::iterator sr = sorted_routes.begin(); sr != sorted_routes.end(); ++sr, ++n) {
569
570                 neworder[n] = sr->old_display_order;
571
572                 if (sr->old_display_order != n) {
573                         changed = true;
574                 }
575
576                 DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("MIXER change order for %1 from %2 to %3\n",
577                                                                sr->route->name(), sr->old_display_order, n));
578         }
579
580         if (changed) {
581                 Unwinder<bool> uw (ignore_reorder, true);
582                 track_model->reorder (neworder);
583         }
584
585         redisplay_track_list ();
586 }
587
588 void
589 Mixer_UI::follow_editor_selection ()
590 {
591         if (!Config->get_link_editor_and_mixer_selection() || _following_editor_selection) {
592                 return;
593         }
594
595         _following_editor_selection = true;
596         _selection.block_routes_changed (true);
597         
598         TrackSelection& s (PublicEditor::instance().get_selection().tracks);
599
600         _selection.clear_routes ();
601
602         for (TrackViewList::iterator i = s.begin(); i != s.end(); ++i) {
603                 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*i);
604                 if (rtav) {
605                         MixerStrip* ms = strip_by_route (rtav->route());
606                         if (ms) {
607                                 _selection.add (ms);
608                         }
609                 }
610         }
611
612         _following_editor_selection = false;
613         _selection.block_routes_changed (false);
614 }
615
616
617 MixerStrip*
618 Mixer_UI::strip_by_route (boost::shared_ptr<Route> r)
619 {
620         for (list<MixerStrip *>::iterator i = strips.begin(); i != strips.end(); ++i) {
621                 if ((*i)->route() == r) {
622                         return (*i);
623                 }
624         }
625
626         return 0;
627 }
628
629 bool
630 Mixer_UI::strip_button_release_event (GdkEventButton *ev, MixerStrip *strip)
631 {
632         if (ev->button == 1) {
633                 if (_selection.selected (strip)) {
634                         /* primary-click: toggle selection state of strip */
635                         if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
636                                 _selection.remove (strip);
637                         } 
638                 } else {
639                         if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
640                                 _selection.add (strip);
641                         } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::RangeSelectModifier)) {
642
643                                 if (!_selection.selected(strip)) {
644                                 
645                                         /* extend selection */
646                                         
647                                         vector<MixerStrip*> tmp;
648                                         bool accumulate = false;
649                                         
650                                         tmp.push_back (strip);
651
652                                         for (list<MixerStrip*>::iterator i = strips.begin(); i != strips.end(); ++i) {
653                                                 if ((*i) == strip) {
654                                                         /* hit clicked strip, start accumulating till we hit the first 
655                                                            selected strip
656                                                         */
657                                                         if (accumulate) {
658                                                                 /* done */
659                                                                 break;
660                                                         } else {
661                                                                 accumulate = true;
662                                                         }
663                                                 } else if (_selection.selected (*i)) {
664                                                         /* hit selected strip. if currently accumulating others,
665                                                            we're done. if not accumulating others, start doing so.
666                                                         */
667                                                         if (accumulate) {
668                                                                 /* done */
669                                                                 break;
670                                                         } else {
671                                                                 accumulate = true;
672                                                         }
673                                                 } else {
674                                                         if (accumulate) {
675                                                                 tmp.push_back (*i);
676                                                         }
677                                                 }
678                                         }
679
680                                         for (vector<MixerStrip*>::iterator i = tmp.begin(); i != tmp.end(); ++i) {
681                                                 _selection.add (*i);
682                                         }
683                                 }
684
685                         } else {
686                                 _selection.set (strip);
687                         }
688                 }
689         }
690
691         return true;
692 }
693
694 void
695 Mixer_UI::set_session (Session* sess)
696 {
697         SessionHandlePtr::set_session (sess);
698
699         if (_plugin_selector) {
700                 _plugin_selector->set_session (_session);
701         }
702
703         _group_tabs->set_session (sess);
704
705         if (!_session) {
706                 return;
707         }
708
709         XMLNode* node = ARDOUR_UI::instance()->mixer_settings();
710         set_state (*node);
711
712         update_title ();
713
714         initial_track_display ();
715
716         _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Mixer_UI::add_strips, this, _1), gui_context());
717         _session->route_group_added.connect (_session_connections, invalidator (*this), boost::bind (&Mixer_UI::add_route_group, this, _1), gui_context());
718         _session->route_group_removed.connect (_session_connections, invalidator (*this), boost::bind (&Mixer_UI::route_groups_changed, this), gui_context());
719         _session->route_groups_reordered.connect (_session_connections, invalidator (*this), boost::bind (&Mixer_UI::route_groups_changed, this), gui_context());
720         _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Mixer_UI::parameter_changed, this, _1), gui_context());
721         _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Mixer_UI::update_title, this), gui_context());
722         _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Mixer_UI::update_title, this), gui_context());
723
724         Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::parameter_changed, this, _1), gui_context ());
725
726         route_groups_changed ();
727
728         if (_visible) {
729                 show_window();
730
731                 /* Bit of a hack; if we're here, we're opening the mixer because of our
732                    instant XML state having a show-mixer property.  Fix up the corresponding
733                    action state.
734                 */
735                 ActionManager::check_toggleaction ("<Actions>/Common/toggle-mixer");
736         }
737
738         start_updating ();
739 }
740
741 void
742 Mixer_UI::session_going_away ()
743 {
744         ENSURE_GUI_THREAD (*this, &Mixer_UI::session_going_away);
745
746         _in_group_rebuild_or_clear = true;
747         group_model->clear ();
748         _in_group_rebuild_or_clear = false;
749
750         _selection.clear ();
751         track_model->clear ();
752
753         for (list<MixerStrip *>::iterator i = strips.begin(); i != strips.end(); ++i) {
754                 delete (*i);
755         }
756
757         if (_monitor_section) {
758                 _monitor_section->tearoff().hide_visible ();
759         }
760
761         strips.clear ();
762
763         stop_updating ();
764
765         SessionHandlePtr::session_going_away ();
766
767         _session = 0;
768         update_title ();
769 }
770
771 void
772 Mixer_UI::track_visibility_changed (std::string const & path)
773 {
774         if (_session && _session->deletion_in_progress()) {
775                 return;
776         }
777
778         TreeIter iter;
779
780         if ((iter = track_model->get_iter (path))) {
781                 MixerStrip* strip = (*iter)[track_columns.strip];
782                 if (strip) {
783                         bool visible = (*iter)[track_columns.visible];
784
785                         if (strip->set_marked_for_display (!visible)) {
786                                 update_track_visibility ();
787                         }
788                 }
789         }
790 }
791
792 void
793 Mixer_UI::update_track_visibility ()
794 {
795         TreeModel::Children rows = track_model->children();
796         TreeModel::Children::iterator i;
797
798         {
799                 Unwinder<bool> uw (no_track_list_redisplay, true);
800                 
801                 for (i = rows.begin(); i != rows.end(); ++i) {
802                         MixerStrip *strip = (*i)[track_columns.strip];
803                         (*i)[track_columns.visible] = strip->marked_for_display ();
804                 }
805                 
806                 /* force route order keys catch up with visibility changes
807                  */
808                 
809                 sync_order_keys_from_treeview ();
810         }
811
812         redisplay_track_list ();
813 }
814
815 void
816 Mixer_UI::show_strip (MixerStrip* ms)
817 {
818         TreeModel::Children rows = track_model->children();
819         TreeModel::Children::iterator i;
820
821         for (i = rows.begin(); i != rows.end(); ++i) {
822
823                 MixerStrip* strip = (*i)[track_columns.strip];
824                 if (strip == ms) {
825                         (*i)[track_columns.visible] = true;
826                         redisplay_track_list ();
827                         break;
828                 }
829         }
830 }
831
832 void
833 Mixer_UI::hide_strip (MixerStrip* ms)
834 {
835         TreeModel::Children rows = track_model->children();
836         TreeModel::Children::iterator i;
837
838         for (i = rows.begin(); i != rows.end(); ++i) {
839
840                 MixerStrip* strip = (*i)[track_columns.strip];
841                 if (strip == ms) {
842                         (*i)[track_columns.visible] = false;
843                         redisplay_track_list ();
844                         break;
845                 }
846         }
847 }
848
849 gint
850 Mixer_UI::start_updating ()
851 {
852     fast_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (sigc::mem_fun(*this, &Mixer_UI::fast_update_strips));
853     return 0;
854 }
855
856 gint
857 Mixer_UI::stop_updating ()
858 {
859     fast_screen_update_connection.disconnect();
860     return 0;
861 }
862
863 void
864 Mixer_UI::fast_update_strips ()
865 {
866         if (is_mapped () && _session) {
867                 for (list<MixerStrip *>::iterator i = strips.begin(); i != strips.end(); ++i) {
868                         (*i)->fast_update ();
869                 }
870         }
871 }
872
873 void
874 Mixer_UI::set_all_strips_visibility (bool yn)
875 {
876         TreeModel::Children rows = track_model->children();
877         TreeModel::Children::iterator i;
878
879         {
880                 Unwinder<bool> uw (no_track_list_redisplay, true);
881                 
882                 for (i = rows.begin(); i != rows.end(); ++i) {
883                         
884                         TreeModel::Row row = (*i);
885                         MixerStrip* strip = row[track_columns.strip];
886                         
887                         if (strip == 0) {
888                                 continue;
889                         }
890                         
891                         if (strip->route()->is_master() || strip->route()->is_monitor()) {
892                                 continue;
893                         }
894                         
895                         (*i)[track_columns.visible] = yn;
896                 }
897         }
898
899         redisplay_track_list ();
900 }
901
902
903 void
904 Mixer_UI::set_all_audio_visibility (int tracks, bool yn)
905 {
906         TreeModel::Children rows = track_model->children();
907         TreeModel::Children::iterator i;
908
909         {
910                 Unwinder<bool> uw (no_track_list_redisplay, true);
911                 
912                 for (i = rows.begin(); i != rows.end(); ++i) {
913                         TreeModel::Row row = (*i);
914                         MixerStrip* strip = row[track_columns.strip];
915                         
916                         if (strip == 0) {
917                                 continue;
918                         }
919                         
920                         if (strip->route()->is_master() || strip->route()->is_monitor()) {
921                                 continue;
922                         }
923                         
924                         boost::shared_ptr<AudioTrack> at = strip->audio_track();
925                         
926                         switch (tracks) {
927                         case 0:
928                                 (*i)[track_columns.visible] = yn;
929                                 break;
930                                 
931                         case 1:
932                                 if (at) { /* track */
933                                         (*i)[track_columns.visible] = yn;
934                                 }
935                                 break;
936                                 
937                         case 2:
938                                 if (!at) { /* bus */
939                                         (*i)[track_columns.visible] = yn;
940                                 }
941                                 break;
942                         }
943                 }
944         }
945
946         redisplay_track_list ();
947 }
948
949 void
950 Mixer_UI::hide_all_routes ()
951 {
952         set_all_strips_visibility (false);
953 }
954
955 void
956 Mixer_UI::show_all_routes ()
957 {
958         set_all_strips_visibility (true);
959 }
960
961 void
962 Mixer_UI::show_all_audiobus ()
963 {
964         set_all_audio_visibility (2, true);
965 }
966 void
967 Mixer_UI::hide_all_audiobus ()
968 {
969         set_all_audio_visibility (2, false);
970 }
971
972 void
973 Mixer_UI::show_all_audiotracks()
974 {
975         set_all_audio_visibility (1, true);
976 }
977 void
978 Mixer_UI::hide_all_audiotracks ()
979 {
980         set_all_audio_visibility (1, false);
981 }
982
983 void
984 Mixer_UI::track_list_reorder (const TreeModel::Path&, const TreeModel::iterator&, int* /*new_order*/)
985 {
986         DEBUG_TRACE (DEBUG::OrderKeys, "mixer UI treeview reordered\n");
987         sync_order_keys_from_treeview ();
988 }
989
990 void
991 Mixer_UI::track_list_delete (const Gtk::TreeModel::Path&)
992 {
993         /* this happens as the second step of a DnD within the treeview as well
994            as when a row/route is actually deleted.
995         */
996         DEBUG_TRACE (DEBUG::OrderKeys, "mixer UI treeview row deleted\n");
997         sync_order_keys_from_treeview ();
998 }
999
1000 void
1001 Mixer_UI::redisplay_track_list ()
1002 {
1003         TreeModel::Children rows = track_model->children();
1004         TreeModel::Children::iterator i;
1005         
1006         if (no_track_list_redisplay) {
1007                 return;
1008         }
1009
1010         for (i = rows.begin(); i != rows.end(); ++i) {
1011
1012                 MixerStrip* strip = (*i)[track_columns.strip];
1013
1014                 if (strip == 0) {
1015                         /* we're in the middle of changing a row, don't worry */
1016                         continue;
1017                 }
1018
1019                 bool const visible = (*i)[track_columns.visible];
1020
1021                 if (visible) {
1022                         strip->set_gui_property ("visible", true);
1023
1024                         if (strip->packed()) {
1025
1026                                 if (strip->route()->is_master() || strip->route()->is_monitor()) {
1027                                         out_packer.reorder_child (*strip, -1);
1028
1029                                 } else {
1030                                         strip_packer.reorder_child (*strip, -1); /* put at end */
1031                                 }
1032
1033                         } else {
1034
1035                                 if (strip->route()->is_master() || strip->route()->is_monitor()) {
1036                                         out_packer.pack_start (*strip, false, false);
1037                                 } else {
1038                                         strip_packer.pack_start (*strip, false, false);
1039                                 }
1040                                 strip->set_packed (true);
1041                         }
1042
1043                 } else {
1044
1045                         strip->set_gui_property ("visible", false);
1046
1047                         if (strip->route()->is_master() || strip->route()->is_monitor()) {
1048                                 /* do nothing, these cannot be hidden */
1049                         } else {
1050                                 if (strip->packed()) {
1051                                         strip_packer.remove (*strip);
1052                                         strip->set_packed (false);
1053                                 }
1054                         }
1055                 }
1056         }
1057
1058         _group_tabs->set_dirty ();
1059 }
1060
1061 void
1062 Mixer_UI::strip_width_changed ()
1063 {
1064         _group_tabs->set_dirty ();
1065
1066 #ifdef GTKOSX
1067         TreeModel::Children rows = track_model->children();
1068         TreeModel::Children::iterator i;
1069         long order;
1070
1071         for (order = 0, i = rows.begin(); i != rows.end(); ++i, ++order) {
1072                 MixerStrip* strip = (*i)[track_columns.strip];
1073
1074                 if (strip == 0) {
1075                         continue;
1076                 }
1077
1078                 bool visible = (*i)[track_columns.visible];
1079
1080                 if (visible) {
1081                         strip->queue_draw();
1082                 }
1083         }
1084 #endif
1085
1086 }
1087
1088 struct SignalOrderRouteSorter {
1089     bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
1090             if (a->is_master() || a->is_monitor()) {
1091                     /* "a" is a special route (master, monitor, etc), and comes
1092                      * last in the mixer ordering
1093                      */
1094                     return false;
1095             } else if (b->is_master() || b->is_monitor()) {
1096                     /* everything comes before b */
1097                     return true;
1098             }
1099             return a->order_key (MixerSort) < b->order_key (MixerSort);
1100
1101     }
1102 };
1103
1104 void
1105 Mixer_UI::initial_track_display ()
1106 {
1107         boost::shared_ptr<RouteList> routes = _session->get_routes();
1108         RouteList copy (*routes);
1109         SignalOrderRouteSorter sorter;
1110
1111         copy.sort (sorter);
1112
1113         {
1114                 Unwinder<bool> uw1 (no_track_list_redisplay, true);
1115                 Unwinder<bool> uw2 (ignore_reorder, true);
1116
1117                 track_model->clear ();
1118                 add_strips (copy);
1119         }
1120         
1121         _session->sync_order_keys (MixerSort);
1122
1123         redisplay_track_list ();
1124 }
1125
1126 void
1127 Mixer_UI::show_track_list_menu ()
1128 {
1129         if (track_menu == 0) {
1130                 build_track_menu ();
1131         }
1132
1133         track_menu->popup (1, gtk_get_current_event_time());
1134 }
1135
1136 bool
1137 Mixer_UI::track_display_button_press (GdkEventButton* ev)
1138 {
1139         if (Keyboard::is_context_menu_event (ev)) {
1140                 show_track_list_menu ();
1141                 return true;
1142         }
1143
1144         return false;
1145 }
1146
1147 void
1148 Mixer_UI::build_track_menu ()
1149 {
1150         using namespace Menu_Helpers;
1151         using namespace Gtk;
1152
1153         track_menu = new Menu;
1154         track_menu->set_name ("ArdourContextMenu");
1155         MenuList& items = track_menu->items();
1156
1157         items.push_back (MenuElem (_("Show All"), sigc::mem_fun(*this, &Mixer_UI::show_all_routes)));
1158         items.push_back (MenuElem (_("Hide All"), sigc::mem_fun(*this, &Mixer_UI::hide_all_routes)));
1159         items.push_back (MenuElem (_("Show All Audio Tracks"), sigc::mem_fun(*this, &Mixer_UI::show_all_audiotracks)));
1160         items.push_back (MenuElem (_("Hide All Audio Tracks"), sigc::mem_fun(*this, &Mixer_UI::hide_all_audiotracks)));
1161         items.push_back (MenuElem (_("Show All Audio Busses"), sigc::mem_fun(*this, &Mixer_UI::show_all_audiobus)));
1162         items.push_back (MenuElem (_("Hide All Audio Busses"), sigc::mem_fun(*this, &Mixer_UI::hide_all_audiobus)));
1163
1164 }
1165
1166 void
1167 Mixer_UI::strip_property_changed (const PropertyChange& what_changed, MixerStrip* mx)
1168 {
1169         if (!what_changed.contains (ARDOUR::Properties::name)) {
1170                 return;
1171         }
1172
1173         ENSURE_GUI_THREAD (*this, &Mixer_UI::strip_name_changed, what_changed, mx)
1174
1175         TreeModel::Children rows = track_model->children();
1176         TreeModel::Children::iterator i;
1177
1178         for (i = rows.begin(); i != rows.end(); ++i) {
1179                 if ((*i)[track_columns.strip] == mx) {
1180                         (*i)[track_columns.text] = mx->route()->name();
1181                         return;
1182                 }
1183         }
1184
1185         error << _("track display list item for renamed strip not found!") << endmsg;
1186 }
1187
1188 bool
1189 Mixer_UI::group_display_button_press (GdkEventButton* ev)
1190 {
1191         TreeModel::Path path;
1192         TreeViewColumn* column;
1193         int cellx;
1194         int celly;
1195
1196         if (!group_display.get_path_at_pos ((int)ev->x, (int)ev->y, path, column, cellx, celly)) {
1197                 return false;
1198         }
1199
1200         TreeIter iter = group_model->get_iter (path);
1201         if (!iter) {
1202                 return false;
1203         }
1204
1205         RouteGroup* group = (*iter)[group_columns.group];
1206
1207         if (Keyboard::is_context_menu_event (ev)) {
1208                 _group_tabs->get_menu(group)->popup (1, ev->time);
1209                 return true;
1210         }
1211
1212         switch (GPOINTER_TO_UINT (column->get_data (X_("colnum")))) {
1213         case 0:
1214                 if (Keyboard::is_edit_event (ev)) {
1215                         if (group) {
1216                                 // edit_route_group (group);
1217 #ifdef GTKOSX
1218                                 group_display.queue_draw();
1219 #endif
1220                                 return true;
1221                         }
1222                 }
1223                 break;
1224
1225         case 1:
1226         {
1227                 bool visible = (*iter)[group_columns.visible];
1228                 (*iter)[group_columns.visible] = !visible;
1229 #ifdef GTKOSX
1230                 group_display.queue_draw();
1231 #endif
1232                 return true;
1233         }
1234
1235         default:
1236                 break;
1237         }
1238
1239         return false;
1240  }
1241
1242 void
1243 Mixer_UI::activate_all_route_groups ()
1244 {
1245         _session->foreach_route_group (sigc::bind (sigc::mem_fun (*this, &Mixer_UI::set_route_group_activation), true));
1246 }
1247
1248 void
1249 Mixer_UI::disable_all_route_groups ()
1250 {
1251         _session->foreach_route_group (sigc::bind (sigc::mem_fun (*this, &Mixer_UI::set_route_group_activation), false));
1252 }
1253
1254 void
1255 Mixer_UI::route_groups_changed ()
1256 {
1257         ENSURE_GUI_THREAD (*this, &Mixer_UI::route_groups_changed);
1258
1259         _in_group_rebuild_or_clear = true;
1260
1261         /* just rebuild the while thing */
1262
1263         group_model->clear ();
1264
1265         {
1266                 TreeModel::Row row;
1267                 row = *(group_model->append());
1268                 row[group_columns.visible] = true;
1269                 row[group_columns.text] = (_("-all-"));
1270                 row[group_columns.group] = 0;
1271         }
1272
1273         _session->foreach_route_group (sigc::mem_fun (*this, &Mixer_UI::add_route_group));
1274
1275         _group_tabs->set_dirty ();
1276         _in_group_rebuild_or_clear = false;
1277 }
1278
1279 void
1280 Mixer_UI::new_route_group ()
1281 {
1282         RouteList rl;
1283
1284         _group_tabs->run_new_group_dialog (rl);
1285 }
1286
1287 void
1288 Mixer_UI::remove_selected_route_group ()
1289 {
1290         Glib::RefPtr<TreeSelection> selection = group_display.get_selection();
1291         TreeView::Selection::ListHandle_Path rows = selection->get_selected_rows ();
1292
1293         if (rows.empty()) {
1294                 return;
1295         }
1296
1297         TreeView::Selection::ListHandle_Path::iterator i = rows.begin();
1298         TreeIter iter;
1299
1300         /* selection mode is single, so rows.begin() is it */
1301
1302         if ((iter = group_model->get_iter (*i))) {
1303
1304                 RouteGroup* rg = (*iter)[group_columns.group];
1305
1306                 if (rg) {
1307                         _session->remove_route_group (*rg);
1308                 }
1309         }
1310 }
1311
1312 void
1313 Mixer_UI::route_group_property_changed (RouteGroup* group, const PropertyChange& change)
1314 {
1315         if (in_group_row_change) {
1316                 return;
1317         }
1318
1319         /* force an update of any mixer strips that are using this group,
1320            otherwise mix group names don't change in mixer strips
1321         */
1322
1323         for (list<MixerStrip *>::iterator i = strips.begin(); i != strips.end(); ++i) {
1324                 if ((*i)->route_group() == group) {
1325                         (*i)->route_group_changed();
1326                 }
1327         }
1328
1329         TreeModel::iterator i;
1330         TreeModel::Children rows = group_model->children();
1331         Glib::RefPtr<TreeSelection> selection = group_display.get_selection();
1332
1333         in_group_row_change = true;
1334
1335         for (i = rows.begin(); i != rows.end(); ++i) {
1336                 if ((*i)[group_columns.group] == group) {
1337                         (*i)[group_columns.visible] = !group->is_hidden ();
1338                         (*i)[group_columns.text] = group->name ();
1339                         break;
1340                 }
1341         }
1342
1343         in_group_row_change = false;
1344
1345         if (change.contains (Properties::name)) {
1346                 _group_tabs->set_dirty ();
1347         }
1348
1349         for (list<MixerStrip*>::iterator j = strips.begin(); j != strips.end(); ++j) {
1350                 if ((*j)->route_group() == group) {
1351                         if (group->is_hidden ()) {
1352                                 hide_strip (*j);
1353                         } else {
1354                                 show_strip (*j);
1355                         }
1356                 }
1357         }
1358 }
1359
1360 void
1361 Mixer_UI::route_group_name_edit (const std::string& path, const std::string& new_text)
1362 {
1363         RouteGroup* group;
1364         TreeIter iter;
1365
1366         if ((iter = group_model->get_iter (path))) {
1367
1368                 if ((group = (*iter)[group_columns.group]) == 0) {
1369                         return;
1370                 }
1371
1372                 if (new_text != group->name()) {
1373                         group->set_name (new_text);
1374                 }
1375         }
1376 }
1377
1378 void
1379 Mixer_UI::route_group_row_change (const Gtk::TreeModel::Path&, const Gtk::TreeModel::iterator& iter)
1380 {
1381         RouteGroup* group;
1382
1383         if (in_group_row_change) {
1384                 return;
1385         }
1386
1387         if ((group = (*iter)[group_columns.group]) == 0) {
1388                 return;
1389         }
1390
1391         std::string name = (*iter)[group_columns.text];
1392
1393         if (name != group->name()) {
1394                 group->set_name (name);
1395         }
1396
1397         bool hidden = !(*iter)[group_columns.visible];
1398
1399         if (hidden != group->is_hidden ()) {
1400                 group->set_hidden (hidden, this);
1401         }
1402 }
1403
1404 /** Called when a group model row is deleted, but also when the model is
1405  *  reordered by a user drag-and-drop; the latter is what we are
1406  *  interested in here.
1407  */
1408 void
1409 Mixer_UI::route_group_row_deleted (Gtk::TreeModel::Path const &)
1410 {
1411         if (_in_group_rebuild_or_clear) {
1412                 return;
1413         }
1414
1415         /* Re-write the session's route group list so that the new order is preserved */
1416
1417         list<RouteGroup*> new_list;
1418
1419         Gtk::TreeModel::Children children = group_model->children();
1420         for (Gtk::TreeModel::Children::iterator i = children.begin(); i != children.end(); ++i) {
1421                 RouteGroup* g = (*i)[group_columns.group];
1422                 if (g) {
1423                         new_list.push_back (g);
1424                 }
1425         }
1426
1427         _session->reorder_route_groups (new_list);
1428 }
1429
1430
1431 void
1432 Mixer_UI::add_route_group (RouteGroup* group)
1433 {
1434         ENSURE_GUI_THREAD (*this, &Mixer_UI::add_route_group, group)
1435         bool focus = false;
1436
1437         in_group_row_change = true;
1438
1439         TreeModel::Row row = *(group_model->append());
1440         row[group_columns.visible] = !group->is_hidden ();
1441         row[group_columns.group] = group;
1442         if (!group->name().empty()) {
1443                 row[group_columns.text] = group->name();
1444         } else {
1445                 row[group_columns.text] = _("unnamed");
1446                 focus = true;
1447         }
1448
1449         group->PropertyChanged.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::route_group_property_changed, this, group, _1), gui_context());
1450
1451         if (focus) {
1452                 TreeViewColumn* col = group_display.get_column (0);
1453                 CellRendererText* name_cell = dynamic_cast<CellRendererText*>(group_display.get_column_cell_renderer (0));
1454                 group_display.set_cursor (group_model->get_path (row), *col, *name_cell, true);
1455         }
1456
1457         _group_tabs->set_dirty ();
1458
1459         in_group_row_change = false;
1460 }
1461
1462 bool
1463 Mixer_UI::strip_scroller_button_release (GdkEventButton* ev)
1464 {
1465         using namespace Menu_Helpers;
1466
1467         if (Keyboard::is_context_menu_event (ev)) {
1468                 ARDOUR_UI::instance()->add_route (this);
1469                 return true;
1470         }
1471
1472         return false;
1473 }
1474
1475 void
1476 Mixer_UI::set_strip_width (Width w)
1477 {
1478         _strip_width = w;
1479
1480         for (list<MixerStrip*>::iterator i = strips.begin(); i != strips.end(); ++i) {
1481                 (*i)->set_width_enum (w, this);
1482         }
1483 }
1484
1485 void
1486 Mixer_UI::set_window_pos_and_size ()
1487 {
1488         resize (m_width, m_height);
1489         move (m_root_x, m_root_y);
1490 }
1491
1492         void
1493 Mixer_UI::get_window_pos_and_size ()
1494 {
1495         get_position(m_root_x, m_root_y);
1496         get_size(m_width, m_height);
1497 }
1498
1499 int
1500 Mixer_UI::set_state (const XMLNode& node)
1501 {
1502         const XMLProperty* prop;
1503         XMLNode* geometry;
1504
1505         m_width = default_width;
1506         m_height = default_height;
1507         m_root_x = 1;
1508         m_root_y = 1;
1509
1510         if ((geometry = find_named_node (node, "geometry")) != 0) {
1511
1512                 XMLProperty* prop;
1513
1514                 if ((prop = geometry->property("x_size")) == 0) {
1515                         prop = geometry->property ("x-size");
1516                 }
1517                 if (prop) {
1518                         m_width = atoi(prop->value());
1519                 }
1520                 if ((prop = geometry->property("y_size")) == 0) {
1521                         prop = geometry->property ("y-size");
1522                 }
1523                 if (prop) {
1524                         m_height = atoi(prop->value());
1525                 }
1526
1527                 if ((prop = geometry->property ("x_pos")) == 0) {
1528                         prop = geometry->property ("x-pos");
1529                 }
1530                 if (prop) {
1531                         m_root_x = atoi (prop->value());
1532
1533                 }
1534                 if ((prop = geometry->property ("y_pos")) == 0) {
1535                         prop = geometry->property ("y-pos");
1536                 }
1537                 if (prop) {
1538                         m_root_y = atoi (prop->value());
1539                 }
1540         }
1541
1542         set_window_pos_and_size ();
1543
1544         if ((prop = node.property ("narrow-strips"))) {
1545                 if (string_is_affirmative (prop->value())) {
1546                         set_strip_width (Narrow);
1547                 } else {
1548                         set_strip_width (Wide);
1549                 }
1550         }
1551
1552         if ((prop = node.property ("show-mixer"))) {
1553                 if (string_is_affirmative (prop->value())) {
1554                        _visible = true;
1555                 }
1556         }
1557
1558         return 0;
1559 }
1560
1561 XMLNode&
1562 Mixer_UI::get_state (void)
1563 {
1564         XMLNode* node = new XMLNode ("Mixer");
1565
1566         if (is_realized()) {
1567                 Glib::RefPtr<Gdk::Window> win = get_window();
1568
1569                 get_window_pos_and_size ();
1570
1571                 XMLNode* geometry = new XMLNode ("geometry");
1572                 char buf[32];
1573                 snprintf(buf, sizeof(buf), "%d", m_width);
1574                 geometry->add_property(X_("x_size"), string(buf));
1575                 snprintf(buf, sizeof(buf), "%d", m_height);
1576                 geometry->add_property(X_("y_size"), string(buf));
1577                 snprintf(buf, sizeof(buf), "%d", m_root_x);
1578                 geometry->add_property(X_("x_pos"), string(buf));
1579                 snprintf(buf, sizeof(buf), "%d", m_root_y);
1580                 geometry->add_property(X_("y_pos"), string(buf));
1581
1582                 // written only for compatibility, they are not used.
1583                 snprintf(buf, sizeof(buf), "%d", 0);
1584                 geometry->add_property(X_("x_off"), string(buf));
1585                 snprintf(buf, sizeof(buf), "%d", 0);
1586                 geometry->add_property(X_("y_off"), string(buf));
1587
1588                 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&rhs_pane1)->gobj()));
1589                 geometry->add_property(X_("mixer_rhs_pane1_pos"), string(buf));
1590                 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&list_hpane)->gobj()));
1591                 geometry->add_property(X_("mixer_list_hpane_pos"), string(buf));
1592
1593                 node->add_child_nocopy (*geometry);
1594         }
1595
1596         node->add_property ("narrow-strips", _strip_width == Narrow ? "yes" : "no");
1597
1598         node->add_property ("show-mixer", _visible ? "yes" : "no");
1599
1600         return *node;
1601 }
1602
1603
1604 void
1605 Mixer_UI::pane_allocation_handler (Allocation&, Gtk::Paned* which)
1606 {
1607         int pos;
1608         XMLProperty* prop = 0;
1609         char buf[32];
1610         XMLNode* node = ARDOUR_UI::instance()->mixer_settings();
1611         XMLNode* geometry;
1612         int height;
1613         static int32_t done[3] = { 0, 0, 0 };
1614
1615         height = default_height;
1616
1617         if ((geometry = find_named_node (*node, "geometry")) != 0) {
1618
1619                 if ((prop = geometry->property ("y_size")) == 0) {
1620                         prop = geometry->property ("y-size");
1621                 }
1622                 if (prop) {
1623                         height = atoi (prop->value());
1624                 }
1625         }
1626
1627         if (which == static_cast<Gtk::Paned*> (&rhs_pane1)) {
1628
1629                 if (done[0]) {
1630                         return;
1631                 }
1632
1633                 if (!geometry || (prop = geometry->property("mixer-rhs-pane1-pos")) == 0) {
1634                         pos = height / 3;
1635                         snprintf (buf, sizeof(buf), "%d", pos);
1636                 } else {
1637                         pos = atoi (prop->value());
1638                 }
1639
1640                 if ((done[0] = GTK_WIDGET(rhs_pane1.gobj())->allocation.height > pos)) {
1641                         rhs_pane1.set_position (pos);
1642                 }
1643
1644         } else if (which == static_cast<Gtk::Paned*> (&list_hpane)) {
1645
1646                 if (done[2]) {
1647                         return;
1648                 }
1649
1650                 if (!geometry || (prop = geometry->property("mixer-list-hpane-pos")) == 0) {
1651                         pos = 75;
1652                         snprintf (buf, sizeof(buf), "%d", pos);
1653                 } else {
1654                         pos = atoi (prop->value());
1655                 }
1656
1657                 if ((done[2] = GTK_WIDGET(list_hpane.gobj())->allocation.width > pos)) {
1658                         list_hpane.set_position (pos);
1659                 }
1660         }
1661 }
1662 void
1663 Mixer_UI::scroll_left ()
1664 {
1665         Adjustment* adj = scroller.get_hscrollbar()->get_adjustment();
1666         /* stupid GTK: can't rely on clamping across versions */
1667         scroller.get_hscrollbar()->set_value (max (adj->get_lower(), adj->get_value() - adj->get_step_increment()));
1668 }
1669
1670 void
1671 Mixer_UI::scroll_right ()
1672 {
1673         Adjustment* adj = scroller.get_hscrollbar()->get_adjustment();
1674         /* stupid GTK: can't rely on clamping across versions */
1675         scroller.get_hscrollbar()->set_value (min (adj->get_upper(), adj->get_value() + adj->get_step_increment()));
1676 }
1677
1678 bool
1679 Mixer_UI::on_key_press_event (GdkEventKey* ev)
1680 {
1681         /* focus widget gets first shot, then bindings, otherwise
1682            forward to main window
1683         */
1684
1685         if (gtk_window_propagate_key_event (GTK_WINDOW(gobj()), ev)) {
1686                 return true;
1687         }
1688
1689         KeyboardKey k (ev->state, ev->keyval);
1690
1691         if (bindings.activate (k, Bindings::Press)) {
1692                 return true;
1693         }
1694
1695         return forward_key_press (ev);
1696 }
1697
1698 bool
1699 Mixer_UI::on_key_release_event (GdkEventKey* ev)
1700 {
1701         if (gtk_window_propagate_key_event (GTK_WINDOW(gobj()), ev)) {
1702                 return true;
1703         }
1704
1705         KeyboardKey k (ev->state, ev->keyval);
1706         
1707         if (bindings.activate (k, Bindings::Release)) {
1708                 return true;
1709         }
1710
1711         /* don't forward releases */
1712
1713         return true;
1714 }
1715
1716 bool
1717 Mixer_UI::on_scroll_event (GdkEventScroll* ev)
1718 {
1719         switch (ev->direction) {
1720         case GDK_SCROLL_LEFT:
1721                 scroll_left ();
1722                 return true;
1723         case GDK_SCROLL_UP:
1724                 if (ev->state & Keyboard::TertiaryModifier) {
1725                         scroll_left ();
1726                         return true;
1727                 }
1728                 return false;
1729
1730         case GDK_SCROLL_RIGHT:
1731                 scroll_right ();
1732                 return true;
1733
1734         case GDK_SCROLL_DOWN:
1735                 if (ev->state & Keyboard::TertiaryModifier) {
1736                         scroll_right ();
1737                         return true;
1738                 }
1739                 return false;
1740         }
1741
1742         return false;
1743 }
1744
1745
1746 void
1747 Mixer_UI::parameter_changed (string const & p)
1748 {
1749         if (p == "show-group-tabs") {
1750                 bool const s = _session->config.get_show_group_tabs ();
1751                 if (s) {
1752                         _group_tabs->show ();
1753                 } else {
1754                         _group_tabs->hide ();
1755                 }
1756         } else if (p == "default-narrow_ms") {
1757                 bool const s = Config->get_default_narrow_ms ();
1758                 for (list<MixerStrip*>::iterator i = strips.begin(); i != strips.end(); ++i) {
1759                         (*i)->set_width_enum (s ? Narrow : Wide, this);
1760                 }
1761         } else if (p == "remote-model") {
1762                 reset_remote_control_ids ();
1763         }
1764 }
1765
1766 void
1767 Mixer_UI::set_route_group_activation (RouteGroup* g, bool a)
1768 {
1769         g->set_active (a, this);
1770 }
1771
1772 PluginSelector*
1773 Mixer_UI::plugin_selector()
1774 {
1775 #ifdef DEFER_PLUGIN_SELECTOR_LOAD
1776         if (!_plugin_selector)
1777                 _plugin_selector = new PluginSelector (PluginManager::instance());
1778 #endif
1779
1780         return _plugin_selector;
1781 }
1782
1783 void
1784 Mixer_UI::setup_track_display ()
1785 {
1786         track_model = ListStore::create (track_columns);
1787         track_display.set_model (track_model);
1788         track_display.append_column (_("Strips"), track_columns.text);
1789         track_display.append_column (_("Show"), track_columns.visible);
1790         track_display.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0));
1791         track_display.get_column (1)->set_data (X_("colnum"), GUINT_TO_POINTER(1));
1792         track_display.get_column (0)->set_expand(true);
1793         track_display.get_column (1)->set_expand(false);
1794         track_display.set_name (X_("EditGroupList"));
1795         track_display.get_selection()->set_mode (Gtk::SELECTION_NONE);
1796         track_display.set_reorderable (true);
1797         track_display.set_headers_visible (true);
1798
1799         track_model->signal_row_deleted().connect (sigc::mem_fun (*this, &Mixer_UI::track_list_delete));
1800         track_model->signal_rows_reordered().connect (sigc::mem_fun (*this, &Mixer_UI::track_list_reorder));
1801
1802         CellRendererToggle* track_list_visible_cell = dynamic_cast<CellRendererToggle*>(track_display.get_column_cell_renderer (1));
1803         track_list_visible_cell->property_activatable() = true;
1804         track_list_visible_cell->property_radio() = false;
1805         track_list_visible_cell->signal_toggled().connect (sigc::mem_fun (*this, &Mixer_UI::track_visibility_changed));
1806
1807         track_display.signal_button_press_event().connect (sigc::mem_fun (*this, &Mixer_UI::track_display_button_press), false);
1808
1809         track_display_scroller.add (track_display);
1810         track_display_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
1811
1812         VBox* v = manage (new VBox);
1813         v->show ();
1814         v->pack_start (track_display_scroller, true, true);
1815
1816         Button* b = manage (new Button);
1817         b->show ();
1818         Widget* w = manage (new Image (Stock::ADD, ICON_SIZE_BUTTON));
1819         w->show ();
1820         b->add (*w);
1821
1822         b->signal_clicked().connect (sigc::mem_fun (*this, &Mixer_UI::new_track_or_bus));
1823
1824         v->pack_start (*b, false, false);
1825
1826         track_display_frame.set_name("BaseFrame");
1827         track_display_frame.set_shadow_type (Gtk::SHADOW_IN);
1828         track_display_frame.add (*v);
1829
1830         track_display_scroller.show();
1831         track_display_frame.show();
1832         track_display.show();
1833 }
1834
1835 void
1836 Mixer_UI::new_track_or_bus ()
1837 {
1838         ARDOUR_UI::instance()->add_route (this);
1839 }
1840
1841
1842 void
1843 Mixer_UI::update_title ()
1844 {
1845         if (_session) {
1846                 string n;
1847                 
1848                 if (_session->snap_name() != _session->name()) {
1849                         n = _session->snap_name ();
1850                 } else {
1851                         n = _session->name ();
1852                 }
1853
1854                 if (_session->dirty ()) {
1855                         n = "*" + n;
1856                 }
1857                 
1858                 WindowTitle title (n);
1859                 title += S_("Window|Mixer");
1860                 title += Glib::get_application_name ();
1861                 set_title (title.get_string());
1862
1863         } else {
1864                 
1865                 WindowTitle title (S_("Window|Mixer"));
1866                 title += Glib::get_application_name ();
1867                 set_title (title.get_string());
1868         }
1869 }
1870
1871 MixerStrip*
1872 Mixer_UI::strip_by_x (int x)
1873 {
1874         for (list<MixerStrip*>::iterator i = strips.begin(); i != strips.end(); ++i) {
1875                 int x1, x2, y;
1876
1877                 (*i)->translate_coordinates (*this, 0, 0, x1, y);
1878                 x2 = x1 + (*i)->get_width();
1879
1880                 if (x >= x1 && x <= x2) {
1881                         return (*i);
1882                 }
1883         }
1884
1885         return 0;
1886 }
1887
1888 void
1889 Mixer_UI::set_route_targets_for_operation ()
1890 {
1891         _route_targets.clear ();
1892
1893         if (!_selection.empty()) {
1894                 _route_targets = _selection.routes;
1895                 return;
1896         }
1897
1898         /* nothing selected ... try to get mixer strip at mouse */
1899
1900         int x, y;
1901         get_pointer (x, y);
1902         
1903         MixerStrip* ms = strip_by_x (x);
1904         
1905         if (ms) {
1906                 _route_targets.insert (ms);
1907         }
1908 }
1909
1910 void
1911 Mixer_UI::monitor_section_going_away ()
1912 {
1913         if (_monitor_section) {
1914                 out_packer.remove (_monitor_section->tearoff());
1915                 _monitor_section->set_session (0);
1916         }
1917 }
1918
1919 void
1920 Mixer_UI::toggle_midi_input_active (bool flip_others)
1921 {
1922         boost::shared_ptr<RouteList> rl (new RouteList);
1923         bool onoff;
1924
1925         set_route_targets_for_operation ();
1926
1927         for (RouteUISelection::iterator r = _route_targets.begin(); r != _route_targets.end(); ++r) {
1928                 boost::shared_ptr<MidiTrack> mt = (*r)->midi_track();
1929
1930                 if (mt) {
1931                         rl->push_back ((*r)->route());
1932                         onoff = !mt->input_active();
1933                 }
1934         }
1935         
1936         _session->set_exclusive_input_active (rl, onoff, flip_others);
1937 }