add Port::PostDisconnect signal to allow objects other than the one being directly disconnected to act when disconnection happens. This turns out to be much easier than using the JACK port connect/disconnect callback

git-svn-id: svn://localhost/ardour2/branches/3.0@11355 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
Paul Davis 2012-01-26 19:00:27 +00:00
parent 9b3aefec1b
commit e3b2111109
5 changed files with 53 additions and 10 deletions

View File

@ -247,6 +247,7 @@ class IO : public SessionObject, public Latent
std::string bundle_channel_name (uint32_t, uint32_t, DataType) const;
BufferSet _buffers;
void disconnect_check (boost::shared_ptr<ARDOUR::Port>, boost::shared_ptr<ARDOUR::Port>);
};
} // namespace ARDOUR

View File

@ -125,7 +125,7 @@ public:
static void set_engine (AudioEngine *);
PBD::Signal1<void,bool> MonitorInputChanged;
static PBD::Signal2<void,boost::shared_ptr<Port>,boost::shared_ptr<Port> > PostDisconnect;
static void set_cycle_framecnt (pframes_t n) {
_cycle_nframes = n;

View File

@ -69,6 +69,7 @@ IO::IO (Session& s, const string& name, Direction dir, DataType default_type)
, _default_type (default_type)
{
_active = true;
Port::PostDisconnect.connect_same_thread (*this, boost::bind (&IO::disconnect_check, this, _1, _2));
pending_state_node = 0;
setup_bundle ();
}
@ -80,6 +81,7 @@ IO::IO (Session& s, const XMLNode& node, DataType dt)
{
_active = true;
pending_state_node = 0;
Port::PostDisconnect.connect_same_thread (*this, boost::bind (&IO::disconnect_check, this, _1, _2));
set_state (node, Stateful::loading_state_version);
setup_bundle ();
@ -96,6 +98,31 @@ IO::~IO ()
}
}
void
IO::disconnect_check (boost::shared_ptr<Port> a, boost::shared_ptr<Port> b)
{
/* this could be called from within our own ::disconnect() method(s)
or from somewhere that operates directly on a port. so, we don't
know for sure if we can take this lock or not. if we fail,
we assume that its safely locked by our own ::disconnect().
*/
Glib::Mutex::Lock tm (io_lock, Glib::TRY_LOCK);
if (tm.locked()) {
/* we took the lock, so we cannot be here from inside
* ::disconnect()
*/
if (_ports.contains (a) || _ports.contains (b)) {
changed (IOChange (IOChange::ConnectionsChanged), this); /* EMIT SIGNAL */
}
} else {
/* we didn't get the lock, so assume that we're inside
* ::disconnect(), and it will call changed() appropriately.
*/
}
}
void
IO::increment_port_buffer_offset (pframes_t offset)
{

View File

@ -39,6 +39,8 @@ using namespace std;
using namespace ARDOUR;
using namespace PBD;
PBD::Signal2<void,boost::shared_ptr<Port>, boost::shared_ptr<Port> > Port::PostDisconnect;
AudioEngine* Port::_engine = 0;
bool Port::_connecting_blocked = false;
pframes_t Port::_global_port_buffer_offset = 0;
@ -94,6 +96,11 @@ Port::disconnect_all ()
jack_port_disconnect (_engine->jack(), _jack_port);
_connections.clear ();
/* a cheaper, less hacky way to do boost::shared_from_this() ...
*/
boost::shared_ptr<Port> pself = _engine->get_port_by_name (name());
PostDisconnect (pself, boost::shared_ptr<Port>()); // emit signal
return 0;
}
@ -168,21 +175,34 @@ Port::connect (std::string const & other)
int
Port::disconnect (std::string const & other)
{
std::string const other_shrt = _engine->make_port_name_non_relative (other);
std::string const this_shrt = _engine->make_port_name_non_relative (_name);
std::string const other_fullname = _engine->make_port_name_non_relative (other);
std::string const this_fullname = _engine->make_port_name_non_relative (_name);
int r = 0;
if (sends_output ()) {
r = jack_disconnect (_engine->jack (), this_shrt.c_str (), other_shrt.c_str ());
r = jack_disconnect (_engine->jack (), this_fullname.c_str (), other_fullname.c_str ());
} else {
r = jack_disconnect (_engine->jack (), other_shrt.c_str (), this_shrt.c_str ());
r = jack_disconnect (_engine->jack (), other_fullname.c_str (), this_fullname.c_str ());
}
if (r == 0) {
_connections.erase (other);
}
/* a cheaper, less hacky way to do boost::shared_from_this() ...
*/
boost::shared_ptr<Port> pself = _engine->get_port_by_name (name());
boost::shared_ptr<Port> pother = _engine->get_port_by_name (other);
if (pself && pother) {
/* Disconnecting from another Ardour port: need to allow
a check on whether this may affect anything that we
need to know about.
*/
PostDisconnect (pself, pother); // emit signal
}
return r;
}

View File

@ -2837,8 +2837,6 @@ Route::input_change_handler (IOChange change, void * /*src*/)
io_changed (); /* EMIT SIGNAL */
}
cerr << _name << ": input change, connected ? " << _input->connected() << endl;
if (!_input->connected() && _soloed_by_others_upstream) {
if (need_to_queue_solo_change) {
_session.cancel_solo_after_disconnect (shared_from_this(), true);
@ -2860,8 +2858,6 @@ Route::output_change_handler (IOChange change, void * /*src*/)
need_to_queue_solo_change = false;
}
cerr << _name << ": output change, connected ? " << _output->connected() << endl;
if (!_output->connected() && _soloed_by_others_downstream) {
if (need_to_queue_solo_change) {
_session.cancel_solo_after_disconnect (shared_from_this(), false);
@ -2874,7 +2870,6 @@ Route::output_change_handler (IOChange change, void * /*src*/)
void
Route::cancel_solo_after_disconnect (bool upstream)
{
cerr << _name << " CSAD upstream ? " << upstream << endl;
if (upstream) {
_soloed_by_others_upstream = 0;
} else {