+ add (*this);
+}
+
+void
+Controllable::add (Controllable& ctl)
+{
+ using namespace boost;
+
+ Glib::Threads::RWLock::WriterLock lm (registry_lock);
+ registry.insert (&ctl);
+
+ if (!registry_connections) {
+ registry_connections = new ScopedConnectionList;
+ }
+
+ /* Controllable::remove() is static - no need to manage this connection */
+
+ ctl.DropReferences.connect_same_thread (*registry_connections, boost::bind (&Controllable::remove, &ctl));
+}
+
+void
+Controllable::remove (Controllable* ctl)
+{
+ Glib::Threads::RWLock::WriterLock lm (registry_lock);
+
+ for (Controllables::iterator i = registry.begin(); i != registry.end(); ++i) {
+ if ((*i) == ctl) {
+ registry.erase (i);
+ break;
+ }
+ }
+}
+
+Controllable*
+Controllable::by_id (const ID& id)
+{
+ Glib::Threads::RWLock::ReaderLock lm (registry_lock);
+
+ for (Controllables::iterator i = registry.begin(); i != registry.end(); ++i) {
+ if ((*i)->id() == id) {
+ return (*i);
+ }
+ }
+ return 0;
+}
+
+Controllable*
+Controllable::by_name (const string& str)
+{
+ Glib::Threads::RWLock::ReaderLock lm (registry_lock);
+
+ for (Controllables::iterator i = registry.begin(); i != registry.end(); ++i) {
+ if ((*i)->_name == str) {
+ return (*i);
+ }
+ }
+ return 0;