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