replaced slot() with mem_fun() and ptr_fun().
[ardour.git] / gtk2_ardour / io_selector.cc
1 /*
2     Copyright (C) 2002-2003 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     $Id$
19 */
20
21 #include <map>
22 #include <vector>
23
24 #include <pbd/lockmonitor.h>
25
26 #include <ardour/io.h>
27 #include <ardour/route.h>
28 #include <ardour/audioengine.h>
29 #include <ardour/port.h>
30 #include <ardour/insert.h>
31 #include <ardour/session.h>
32 #include <ardour/diskstream.h>
33
34 #include <gtkmm2ext/doi.h>
35 #include <gtkmm2ext/gtk_ui.h>
36
37 #include "utils.h"
38 #include "ardour_message.h"
39 #include "io_selector.h"
40 #include "extra_bind.h"
41 #include "keyboard.h"
42 #include "gui_thread.h"
43
44 #include "i18n.h"
45
46 using namespace std;
47 using namespace Gtk;
48 using namespace sigc;
49 using namespace ARDOUR;
50
51 IOSelectorWindow::IOSelectorWindow (Session& sess, IO& ior, bool input, bool can_cancel)
52         : ArdourDialog ("i/o selector"),
53           _selector (sess, ior, input),
54           ok_button (can_cancel ? _("OK"): _("Close")),
55           cancel_button (_("Cancel")),
56           rescan_button (_("Rescan"))
57
58 {
59         add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
60         set_name ("IOSelectorWindow");
61
62         string title;
63         if (input) {
64                 title = compose(_("%1 input"), ior.name());
65         } else {
66                 title = compose(_("%1 output"), ior.name());
67         }
68
69         ok_button.set_name ("IOSelectorButton");
70         cancel_button.set_name ("IOSelectorButton");
71         rescan_button.set_name ("IOSelectorButton");
72
73         button_box.set_spacing (5);
74         button_box.set_border_width (5);
75         button_box.set_homogeneous (true);
76         button_box.pack_start (rescan_button);
77
78         if (can_cancel) {
79                 button_box.pack_start (cancel_button);
80         }
81         else {
82                 cancel_button.hide();
83         }
84                 
85         button_box.pack_start (ok_button);
86
87         vbox.pack_start (_selector);
88         vbox.pack_start (button_box, false, false);
89
90         ok_button.signal_clicked().connect (mem_fun(*this, &IOSelectorWindow::accept));
91         cancel_button.signal_clicked().connect (mem_fun(*this, &IOSelectorWindow::cancel));
92         rescan_button.signal_clicked().connect (mem_fun(*this, &IOSelectorWindow::rescan));
93
94         set_title (title);
95         set_position (Gtk::WIN_POS_MOUSE);
96         add (vbox);
97
98         delete_event.connect (bind (ptr_fun (just_hide_it), reinterpret_cast<Window *> (this)));
99 }
100
101 IOSelectorWindow::~IOSelectorWindow()
102 {
103 }
104
105 void
106 IOSelectorWindow::rescan ()
107 {
108         _selector.redisplay ();
109 }
110
111 void
112 IOSelectorWindow::cancel ()
113 {
114         _selector.Finished(IOSelector::Cancelled);
115         hide ();
116 }
117
118 void
119 IOSelectorWindow::accept ()
120 {
121         _selector.Finished(IOSelector::Accepted);
122         hide ();
123 }
124
125
126 gint
127 IOSelectorWindow::map_event_impl (GdkEventAny *ev)
128 {
129         _selector.redisplay ();
130         return Window::map_event_impl (ev);
131 }
132
133 /*************************
134   The IO Selector "widget"
135  *************************/  
136
137 IOSelector::IOSelector (Session& sess, IO& ior, bool input)
138         : session (sess),
139           io (ior),
140           for_input (input),
141           port_frame (for_input? _("Inputs") : _("Outputs")),
142           add_port_button (for_input? _("Add Input") : _("Add Output")),
143           remove_port_button (for_input? _("Remove Input") : _("Remove Output")),
144           clear_connections_button (_("Disconnect All"))
145 {
146         selected_port = 0;
147
148         notebook.set_name ("IOSelectorNotebook");
149         notebook.set_size_request (-1, 125);
150
151         clear_connections_button.set_name ("IOSelectorButton");
152         add_port_button.set_name ("IOSelectorButton");
153         remove_port_button.set_name ("IOSelectorButton");
154
155         selector_frame.set_name ("IOSelectorFrame");
156         port_frame.set_name ("IOSelectorFrame");
157
158         selector_frame.set_label (_("Available connections"));
159         
160         selector_button_box.set_spacing (5);
161         selector_button_box.set_border_width (5);
162
163         selector_box.set_spacing (5);
164         selector_box.set_border_width (5);
165         selector_box.pack_start (notebook);
166         selector_box.pack_start (selector_button_box, false, false);
167
168         selector_frame.add (selector_box);
169
170         port_box.set_spacing (5);
171         port_box.set_border_width (5);
172
173         port_display_scroller.set_name ("IOSelectorNotebook");
174         port_display_scroller.set_border_width (0);
175         port_display_scroller.set_size_request (-1, 170);
176         port_display_scroller.add_with_viewport (port_box);
177         port_display_scroller.set_policy (Gtk::POLICY_NEVER,
178                                           Gtk::POLICY_AUTOMATIC);
179
180         port_button_box.set_spacing (5);
181         port_button_box.set_border_width (5);
182
183         port_button_box.pack_start (add_port_button, false, false);
184
185         if (for_input) {
186                 if (io.input_maximum() < 0 || io.input_maximum() > (int) io.n_inputs()) {
187                         add_port_button.set_sensitive (true);
188                 } else {
189                         add_port_button.set_sensitive (false);
190                 }
191
192         } else {
193                 if (io.output_maximum() < 0 || io.output_maximum() > (int) io.n_outputs()) {
194                         add_port_button.set_sensitive (true);
195                 } else {
196                         add_port_button.set_sensitive (false);
197                 }
198                         
199         }
200
201         port_button_box.pack_start (remove_port_button, false, false);
202
203         if (for_input) {
204                 if (io.input_minimum() < 0 || io.input_minimum() < (int) io.n_inputs()) {
205                         remove_port_button.set_sensitive (true);
206                 } else {
207                         remove_port_button.set_sensitive (false);
208                 }
209                         
210         } else {
211                 if (io.output_minimum() < 0 || io.output_minimum() < (int) io.n_outputs()) {
212                         remove_port_button.set_sensitive (true);
213                 } else {
214                         remove_port_button.set_sensitive (false);
215                 }
216         }
217
218         port_button_box.pack_start (clear_connections_button, false, false);
219
220         port_and_button_box.set_border_width (5);
221         port_and_button_box.pack_start (port_button_box, false, false);
222         port_and_button_box.pack_start (port_display_scroller);
223
224         port_frame.add (port_and_button_box);
225
226         port_and_selector_box.set_spacing (5);
227         port_and_selector_box.pack_start (port_frame);
228         port_and_selector_box.pack_start (selector_frame);
229
230         set_spacing (5);
231         set_border_width (5);
232         pack_start (port_and_selector_box);
233
234         rescan();
235         display_ports ();
236
237         clear_connections_button.signal_clicked().connect (mem_fun(*this, &IOSelector::clear_connections));
238
239         add_port_button.signal_clicked().connect (mem_fun(*this, &IOSelector::add_port));
240         remove_port_button.signal_clicked().connect (mem_fun(*this, &IOSelector::remove_port));
241
242         if (for_input) {
243                 io.input_changed.connect (mem_fun(*this, &IOSelector::ports_changed));
244         } else {
245                 io.output_changed.connect (mem_fun(*this, &IOSelector::ports_changed));
246         }
247
248         io.name_changed.connect (mem_fun(*this, &IOSelector::name_changed));
249 }
250
251 IOSelector::~IOSelector ()
252 {
253 }
254
255 void
256 IOSelector::name_changed (void* src)
257 {
258         ENSURE_GUI_THREAD(bind (mem_fun(*this, &IOSelector::name_changed), src));
259         
260         display_ports ();
261 }
262
263 void
264 IOSelector::clear_connections ()
265 {
266         if (for_input) {
267                 io.disconnect_inputs (this);
268         } else {
269                 io.disconnect_outputs (this);
270         }
271 }
272
273 void
274 IOSelector::rescan ()
275 {
276         using namespace Notebook_Helpers;
277         using namespace CList_Helpers;
278
279         typedef map<string,vector<pair<string,string> > > PortMap;
280         PortMap portmap;
281         const char **ports;
282         PageList& pages = notebook.pages();
283         gint current_page;
284         vector<string> rowdata;
285
286         current_page = notebook.get_current_page_num ();
287         pages.clear ();
288
289         /* get relevant current JACK ports */
290
291         ports = session.engine().get_ports ("", JACK_DEFAULT_AUDIO_TYPE, for_input?JackPortIsOutput:JackPortIsInput);
292
293         if (ports == 0) {
294                 return;
295         }
296
297         /* find all the client names and group their ports into a list-by-client */
298         
299         for (int n = 0; ports[n]; ++n) {
300
301                 pair<string,vector<pair<string,string> > > newpair;
302                 pair<string,string> strpair;
303                 pair<PortMap::iterator,bool> result;
304
305                 string str = ports[n];
306                 string::size_type pos;
307                 string portname;
308
309                 pos = str.find (':');
310
311                 newpair.first = str.substr (0, pos); 
312                 portname = str.substr (pos+1);
313
314                 /* this may or may not succeed at actually inserting. 
315                    we don't care, however: we just want an iterator
316                    that gives us either the inserted element or
317                    the existing one with the same name.
318                 */
319
320                 result = portmap.insert (newpair);
321
322                 strpair.first = portname;
323                 strpair.second = str;
324
325                 result.first->second.push_back (strpair);
326         }
327
328         PortMap::iterator i;
329
330         for (i = portmap.begin(); i != portmap.end(); ++i) {
331                 
332                 Box *client_box = manage (new VBox);
333                 Gtk::CList *client_port_display = manage (new Gtk::CList (1));
334                 ScrolledWindow *scroller = manage (new ScrolledWindow);
335
336                 scroller->add_with_viewport (*client_port_display);
337                 scroller->set_policy (Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
338
339                 client_box->pack_start (*scroller);
340
341                 client_port_display->set_selection_mode (GTK_SELECTION_BROWSE);
342                 client_port_display->set_name ("IOSelectorList");
343
344                 for (vector<pair<string,string> >::iterator s = i->second.begin(); s != i->second.end(); ++s) {
345                         
346                         rowdata.clear ();
347                         rowdata.push_back (s->first);
348                         client_port_display->rows().push_back (rowdata);
349                         client_port_display->rows().back().set_data (g_strdup (s->second.c_str()), free);
350                 }
351
352                 client_port_display->columns_autosize ();
353                 client_port_display->select_row.connect (bind (mem_fun(*this, &IOSelector::port_selection_handler), client_port_display));
354
355                 Label *tab_label = manage (new Label);
356
357                 tab_label->set_name ("IOSelectorNotebookTab");
358                 tab_label->set_text ((*i).first);
359
360                 pages.push_back (TabElem (*client_box, *tab_label));
361         }
362
363         notebook.set_page (current_page);
364         notebook.show.connect (bind (mem_fun (notebook, &Notebook::set_page), current_page));
365         selector_box.show_all ();
366 }       
367
368 void
369 IOSelector::display_ports ()
370 {
371         CList *clist = 0;
372         CList *firstclist = 0;
373         CList *selected_port_list = 0;
374
375         {
376                 LockMonitor lm (port_display_lock, __LINE__, __FILE__);
377                 Port *port;
378                 uint32_t limit;
379
380                 if (for_input) {
381                         limit = io.n_inputs();
382                 } else {
383                         limit = io.n_outputs();
384                 }
385
386                 for (slist<CList *>::iterator i = port_displays.begin(); i != port_displays.end(); ) {
387                 
388                         slist<CList *>::iterator tmp;
389
390                         tmp = i;
391                         ++tmp;
392
393                         port_box.remove (**i);
394                         delete *i;
395                         port_displays.erase (i);
396
397                         i = tmp;
398                 } 
399
400                 for (uint32_t n = 0; n < limit; ++n) {
401                         const gchar *title[1];
402                         string really_short_name;
403
404                         if (for_input) {
405                                 port = io.input (n);
406                         } else {
407                                 port = io.output (n);
408                         }
409
410                         /* we know there is '/' because we put it there */
411
412                         really_short_name = port->short_name();
413                         really_short_name = really_short_name.substr (really_short_name.find ('/') + 1);
414
415                         title[0] = really_short_name.c_str();
416                         clist = new CList (1, title);
417                         if (!firstclist) {
418                                 firstclist = clist;
419                         }
420                         
421                         port_displays.insert (port_displays.end(), clist);
422                         port_box.pack_start (*clist);
423
424                         clist->set_data (_("port"), port);
425
426                         /* XXX THIS IS A DIGUSTING AND DIRTY HACK, FORCED UPON US BECAUSE
427                            GtkCList DOESN'T PROVIDE ANY WAY TO CONNECT TO BUTTON_PRESS_EVENTS
428                            FOR THE COLUMN TITLE BUTTON.
429                          */
430
431                         clist->column(0).get_widget();  // force the column title button to be created
432                         GtkButton *b = GTK_BUTTON(clist->gobj()->column[0].button); // no API to access this
433                         Gtk::Button *B = wrap (b); // make C++ signal handling easier.
434
435                         clist->column_titles_show ();
436                         clist->column_titles_active ();
437
438                         if (for_input) {
439
440                                 if (io.input_maximum() == 1) {
441                                         selected_port = port;
442                                         selected_port_list = clist;
443                                 } else {
444                                         if (port == selected_port) {
445                                                 selected_port_list = clist;
446                                         }
447                                 }
448                                 
449                                 B->button_release_event.connect 
450                                         (bind (mem_fun(*this, &IOSelector::port_column_button_release), clist));
451                         
452                         } else {
453
454                                 if (io.output_maximum() == 1) {
455                                         selected_port = port;
456                                         selected_port_list = clist;
457                                 } else {
458                                         if (port == selected_port) {
459                                                 selected_port_list = clist;
460                                         }
461                                 }
462
463                                 B->button_release_event.connect 
464                                         (bind (mem_fun(*this, &IOSelector::port_column_button_release), clist));
465                         }
466
467                         clist->set_name ("IOSelectorPortList");
468                         clist->set_selection_mode (GTK_SELECTION_SINGLE);
469                         clist->set_shadow_type (Gtk::SHADOW_IN);
470                         clist->set_size_request (-1, 75);
471
472                         /* now fill the clist with the current connections */
473
474                         const char **connections = port->get_connections ();
475
476                         if (connections) {
477
478                                 for (uint32_t c = 0; connections[c]; ++c) {
479                                         
480                                         const gchar *txt[1];
481                                 
482                                         txt[0] = connections[c];
483
484                                         clist->rows().push_back (txt);
485                                 }
486
487                                 free (connections);
488                         }
489
490                         clist->columns_autosize ();
491                         clist->button_release_event.connect (bind (mem_fun(*this, &IOSelector::connection_click), clist));
492                 }
493
494                 port_box.show_all ();
495
496                 if (selected_port_list) {
497                         selected_port_list->click_column(0);
498                         selected_port_list->set_name ("IOSelectorPortListSelected");
499                         for (slist<CList *>::iterator i = port_displays.begin(); i != port_displays.end(); ++i) {
500                                 if (*i != selected_port_list) {
501                                         (*i)->set_name ("IOSelectorPortList");
502                                         (*i)->queue_draw ();
503                                 }
504                         }
505                 } else {
506                         selected_port = 0;
507                         selector_box.hide_all ();
508                 }
509         }
510         
511         if (selected_port_list) {
512                 select_clist (selected_port_list);
513         } else if (firstclist) {
514                 // select first
515                 select_clist (firstclist);
516         }
517 }
518
519 void
520 IOSelector::port_selection_handler (gint row, gint col, GdkEvent *ev, Gtk::CList *clist)
521 {
522         using namespace CList_Helpers;
523         int status;
524
525         if (selected_port == 0) {
526                 return;
527         }
528
529         string other_port_name = (char *) clist->rows()[row].get_data();
530
531         if (for_input) {
532                 if ((status = io.connect_input (selected_port, other_port_name, this)) == 0) {
533                         Port *p = session.engine().get_port_by_name (other_port_name);
534                         p->enable_metering();
535                 }
536         } else {
537                 status = io.connect_output (selected_port, other_port_name, this);
538         }
539
540         if (status == 0) {
541                 select_next_clist ();
542         }
543 }
544
545 void
546 IOSelector::ports_changed (IOChange change, void *src)
547 {
548         ENSURE_GUI_THREAD(bind (mem_fun(*this, &IOSelector::ports_changed), change, src));
549         
550         display_ports ();
551 }
552
553 void
554 IOSelector::add_port ()
555 {
556         /* add a new port, then hide the button if we're up to the maximum allowed */
557
558         if (for_input) {
559
560
561                 try {
562
563                         io.add_input_port ("", this);
564                 }
565
566                 catch (AudioEngine::PortRegistrationFailure& err) {
567                         ArdourMessage msg (0,  X_("noport dialog"),
568                                            _("There are no more JACK ports available."));
569                 }
570
571                 if (io.input_maximum() >= 0 && io.input_maximum() <= (int) io.n_inputs()) {
572                         add_port_button.set_sensitive (false);
573                 }
574                 
575                 if (io.input_minimum() < (int) io.n_inputs()) {
576                         remove_port_button.set_sensitive (true);
577                 }
578
579         } else {
580
581                 try {
582                         io.add_output_port ("", this);
583                 }
584
585                 catch (AudioEngine::PortRegistrationFailure& err) {
586                         ArdourMessage msg (0, X_("noport dialog"),
587                                            _("There are no more JACK ports available."));
588                 }
589
590                 if (io.output_maximum() >= 0 && io.output_maximum() <= (int) io.n_outputs()) {
591                         add_port_button.set_sensitive (false);
592                 }
593         }
594 }
595
596 void
597 IOSelector::remove_port ()
598 {
599         // always remove last port
600         uint32_t nports;
601         
602         if (for_input) {
603                 if ((nports = io.n_inputs()) > 0) {
604                         io.remove_input_port (io.input(nports-1), this);
605                 }
606                 if (io.input_minimum() == (int) io.n_inputs()) {
607                         remove_port_button.set_sensitive (false);
608                 }
609         } else {
610                 if ((nports = io.n_outputs()) > 0) {
611                         io.remove_output_port (io.output(nports-1), this);
612                 }
613         }
614 }
615
616 gint
617 IOSelector::remove_port_when_idle (Port *port)
618 {
619         if (for_input) {
620                 io.remove_input_port (port, this);
621         } else {
622                 io.remove_output_port (port, this);
623         }
624
625         return FALSE;
626 }
627
628 gint
629 IOSelector::port_column_button_release (GdkEventButton *event, CList *clist)
630 {
631         if (Keyboard::is_delete_event (event)) {
632                 Port* port;
633                 {
634                         LockMonitor lm (port_display_lock, __LINE__, __FILE__);
635                         
636                         port = reinterpret_cast<Port *> (clist->get_data (_("port")));
637                         
638                         if (port == selected_port) {
639                                 selected_port = 0;
640                                 clist->set_name ("IOSelectorPortList");
641                                 clist->queue_draw();
642                         }
643                 }
644
645                 /* remove the port when idle - if we do it here, we will destroy the widget
646                    for whom we are handling an event. not good.
647                 */
648
649                 Gtk::Main::idle.connect (bind (mem_fun(*this, &IOSelector::remove_port_when_idle), port));
650
651         } else {
652                 select_clist(clist);
653         }
654
655         return TRUE;
656 }
657
658 void
659 IOSelector::select_next_clist ()
660 {
661         slist<CList*>::iterator next;
662
663         for (slist<CList *>::iterator i = port_displays.begin(); i != port_displays.end(); ++i) {
664
665                 if ((*i)->get_name() == "IOSelectorPortListSelected") {
666
667                         ++i;
668
669                         if (i == port_displays.end()) {
670                                 select_clist (port_displays.front());
671                         } else {
672                                 select_clist (*i);
673                         }
674                         
675                         break;
676                 }
677         }
678 }
679
680 void
681 IOSelector::select_clist(Gtk::CList* clist)
682 {
683         /* Gack. CList's don't respond visually to a change
684            in their state, so rename them to force a style
685            switch.
686         */
687         LockMonitor lm (port_display_lock, __LINE__, __FILE__);
688         Port* port = reinterpret_cast<Port *> (clist->get_data (_("port")));
689         
690         if (port != selected_port) {
691                 selected_port = port;
692                 
693                 clist->set_name ("IOSelectorPortListSelected");
694                 
695                 for (slist<CList *>::iterator i = port_displays.begin(); i != port_displays.end(); ++i) {
696                         if (*i != clist) {
697                                 (*i)->set_name ("IOSelectorPortList");
698                                 (*i)->queue_draw ();
699                         }
700                 }
701                 selector_box.show_all ();
702         }
703 }
704
705 gint
706 IOSelector::connection_click (GdkEventButton *ev, CList *clist)
707 {
708         gint row, col;
709
710         /* only handle button1 events here */
711
712         if (ev->button != 1) {
713                 return FALSE;
714         }
715
716         if (clist->get_selection_info ((int)ev->x, (int)ev->y, &row, &col) == 0) {
717                 return FALSE;
718         }
719
720         if (row < 0 || col < 0) {
721                 return FALSE;
722         }
723
724         Port *port = reinterpret_cast<Port *> (clist->get_data (_("port")));
725         string connected_port_name = clist->cell(row,col).get_text ();
726
727         if (for_input) {
728                 Port *p = session.engine().get_port_by_name (connected_port_name);
729                 p->disable_metering();
730                 io.disconnect_input (port, connected_port_name, this);
731         } else {
732                 io.disconnect_output (port, connected_port_name, this);
733         }
734
735         return TRUE;
736 }
737
738 void
739 IOSelector::redisplay ()
740 {
741         display_ports ();
742
743         if (for_input) {
744                 if (io.input_maximum() != 0) {
745                         rescan ();
746                 }
747         } else {
748                 if (io.output_maximum() != 0) {
749                         rescan();
750                 }
751         }
752 }
753
754 PortInsertUI::PortInsertUI (Session& sess, PortInsert& pi)
755         : input_selector (sess, pi, true),
756           output_selector (sess, pi, false)
757 {
758         hbox.pack_start (output_selector, true, true);
759         hbox.pack_start (input_selector, true, true);
760
761
762         pack_start (hbox);
763 }
764
765 void
766 PortInsertUI::redisplay()
767 {
768
769         input_selector.redisplay();
770         output_selector.redisplay();
771 }
772
773 void
774 PortInsertUI::finished(IOSelector::Result r)
775 {
776         input_selector.Finished (r);
777         output_selector.Finished (r);
778 }
779
780
781 PortInsertWindow::PortInsertWindow (Session& sess, PortInsert& pi, bool can_cancel)
782         : ArdourDialog ("port insert dialog"),
783           _portinsertui(sess, pi),
784           ok_button (can_cancel ? _("OK"): _("Close")),
785           cancel_button (_("Cancel")),
786           rescan_button (_("Rescan"))
787 {
788
789         set_name ("IOSelectorWindow");
790         string title = _("ardour: ");
791         title += pi.name();
792         set_title (title);
793         
794         ok_button.set_name ("IOSelectorButton");
795         cancel_button.set_name ("IOSelectorButton");
796         rescan_button.set_name ("IOSelectorButton");
797
798         button_box.set_spacing (5);
799         button_box.set_border_width (5);
800         button_box.set_homogeneous (true);
801         button_box.pack_start (rescan_button);
802         if (can_cancel) {
803                 button_box.pack_start (cancel_button);
804         }
805         else {
806                 cancel_button.hide();
807         }
808         button_box.pack_start (ok_button);
809
810         vbox.pack_start (_portinsertui);
811         vbox.pack_start (button_box, false, false);
812
813         add (vbox);
814
815         ok_button.signal_clicked().connect (mem_fun(*this, &PortInsertWindow::accept));
816         cancel_button.signal_clicked().connect (mem_fun(*this, &PortInsertWindow::cancel));
817         rescan_button.signal_clicked().connect (mem_fun(*this, &PortInsertWindow::rescan));
818
819         delete_event.connect (bind (ptr_fun (just_hide_it), reinterpret_cast<Window *> (this)));        
820         pi.GoingAway.connect (mem_fun(*this, &PortInsertWindow::plugin_going_away));
821 }
822
823 void
824 PortInsertWindow::plugin_going_away (ARDOUR::Redirect* ignored)
825 {
826         ENSURE_GUI_THREAD(bind (mem_fun(*this, &PortInsertWindow::plugin_going_away), ignored));
827         
828         delete_when_idle (this);
829 }
830
831 gint
832 PortInsertWindow::map_event_impl (GdkEventAny *ev)
833 {
834         _portinsertui.redisplay ();
835         return Window::map_event_impl (ev);
836 }
837
838
839 void
840 PortInsertWindow::rescan ()
841 {
842         _portinsertui.redisplay();
843 }
844
845 void
846 PortInsertWindow::cancel ()
847 {
848         _portinsertui.finished(IOSelector::Cancelled);
849         hide ();
850 }
851
852 void
853 PortInsertWindow::accept ()
854 {
855         _portinsertui.finished(IOSelector::Accepted);
856         hide ();
857 }