2 Copyright (C) 2002-2007 Paul Davis
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.
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.
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.
20 #include <gtkmm/messagedialog.h>
21 #include <glibmm/objectbase.h>
23 #include <gtkmm2ext/doi.h>
25 #include "ardour/port_insert.h"
26 #include "ardour/session.h"
27 #include "ardour/io.h"
28 #include "ardour/audioengine.h"
29 #include "ardour/track.h"
30 #include "ardour/audio_track.h"
31 #include "ardour/midi_track.h"
32 #include "ardour/mtdm.h"
33 #include "ardour/data_type.h"
34 #include "ardour/port.h"
35 #include "ardour/bundle.h"
37 #include "io_selector.h"
39 #include "gui_thread.h"
42 using namespace ARDOUR
;
45 IOSelector::IOSelector (Gtk::Window
* p
, ARDOUR::Session
* session
, boost::shared_ptr
<ARDOUR::IO
> io
)
46 : PortMatrix (p
, session
, DataType::NIL
)
51 /* signal flow from 0 to 1 */
53 _find_inputs_for_io_outputs
= (_io
->direction() == IO::Output
);
55 if (_find_inputs_for_io_outputs
) {
63 _port_group
.reset (new PortGroup (io
->name()));
64 _ports
[_ours
].add_group (_port_group
);
66 io
->changed
.connect (_io_connection
, invalidator (*this), boost::bind (&IOSelector::io_changed_proxy
, this), gui_context ());
73 IOSelector::setup_type ()
75 /* set type according to what's in the IO */
78 DataType type_with_ports
= DataType::NIL
;
79 for (DataType::iterator i
= DataType::begin(); i
!= DataType::end(); ++i
) {
80 if (_io
->ports().num_ports (*i
)) {
87 set_type (type_with_ports
);
89 set_type (DataType::NIL
);
94 IOSelector::io_changed_proxy ()
96 /* The IO's changed signal is emitted from code that holds its route's processor lock,
97 so we can't call setup_all_ports (which results in a call to Route::foreach_processor)
98 without a deadlock unless we break things up with this idle handler.
101 Glib::signal_idle().connect_once (sigc::mem_fun (*this, &IOSelector::io_changed
));
105 IOSelector::io_changed ()
112 IOSelector::setup_ports (int dim
)
118 _ports
[dim
].suspend_signals ();
122 _ports
[_other
].gather (_session
, type(), _find_inputs_for_io_outputs
, false);
126 _port_group
->clear ();
127 _port_group
->add_bundle (_io
->bundle (), _io
);
130 _ports
[dim
].resume_signals ();
134 IOSelector::set_state (ARDOUR::BundleChannel c
[2], bool s
)
136 ARDOUR::Bundle::PortList
const & our_ports
= c
[_ours
].bundle
->channel_ports (c
[_ours
].channel
);
137 ARDOUR::Bundle::PortList
const & other_ports
= c
[_other
].bundle
->channel_ports (c
[_other
].channel
);
139 for (ARDOUR::Bundle::PortList::const_iterator i
= our_ports
.begin(); i
!= our_ports
.end(); ++i
) {
140 for (ARDOUR::Bundle::PortList::const_iterator j
= other_ports
.begin(); j
!= other_ports
.end(); ++j
) {
142 Port
* f
= _session
->engine().get_port_by_name (*i
);
148 _io
->connect (f
, *j
, 0);
150 _io
->disconnect (f
, *j
, 0);
156 PortMatrixNode::State
157 IOSelector::get_state (ARDOUR::BundleChannel c
[2]) const
159 ARDOUR::Bundle::PortList
const & our_ports
= c
[_ours
].bundle
->channel_ports (c
[_ours
].channel
);
160 ARDOUR::Bundle::PortList
const & other_ports
= c
[_other
].bundle
->channel_ports (c
[_other
].channel
);
162 if (!_session
|| our_ports
.empty() || other_ports
.empty()) {
163 /* we're looking at a bundle with no parts associated with this channel,
164 so nothing to connect */
165 return PortMatrixNode::NOT_ASSOCIATED
;
168 for (ARDOUR::Bundle::PortList::const_iterator i
= our_ports
.begin(); i
!= our_ports
.end(); ++i
) {
169 for (ARDOUR::Bundle::PortList::const_iterator j
= other_ports
.begin(); j
!= other_ports
.end(); ++j
) {
171 Port
* f
= _session
->engine().get_port_by_name (*i
);
173 /* since we are talking about an IO, our ports should all have an associated Port *,
174 so the above call should never fail */
177 if (!f
->connected_to (*j
)) {
178 /* if any one thing is not connected, all bets are off */
179 return PortMatrixNode::NOT_ASSOCIATED
;
184 return PortMatrixNode::ASSOCIATED
;
188 IOSelector::n_io_ports () const
190 if (!_find_inputs_for_io_outputs
) {
191 return _io
->n_ports().get (_io
->default_type());
193 return _io
->n_ports().get (_io
->default_type());
198 IOSelector::list_is_global (int dim
) const
200 return (dim
== _other
);
204 IOSelector::disassociation_verb () const
206 return _("Disconnect");
210 IOSelector::channel_noun () const
215 IOSelectorWindow::IOSelectorWindow (ARDOUR::Session
* session
, boost::shared_ptr
<ARDOUR::IO
> io
, bool /*can_cancel*/)
216 : ArdourDialog (_("I/O selector"))
217 , _selector (this, session
, io
)
219 set_name ("IOSelectorWindow2");
221 get_vbox()->pack_start (_selector
);
223 set_position (Gtk::WIN_POS_MOUSE
);
225 io_name_changed (this);
229 signal_delete_event().connect (sigc::mem_fun (*this, &IOSelectorWindow::wm_delete
));
233 IOSelectorWindow::wm_delete (GdkEventAny
* /*event*/)
235 _selector
.Finished (IOSelector::Accepted
);
242 IOSelectorWindow::on_map ()
244 _selector
.setup_all_ports ();
249 IOSelectorWindow::on_show ()
251 Gtk::Window::on_show ();
252 pair
<uint32_t, uint32_t> const pm_max
= _selector
.max_size ();
253 resize_window_to_proportion_of_monitor (this, pm_max
.first
, pm_max
.second
);
257 IOSelectorWindow::io_name_changed (void*)
259 ENSURE_GUI_THREAD (*this, &IOSelectorWindow::io_name_changed
, src
)
263 if (!_selector
.find_inputs_for_io_outputs()) {
264 title
= string_compose(_("%1 input"), _selector
.io()->name());
266 title
= string_compose(_("%1 output"), _selector
.io()->name());