#include "ardour/control_protocol_manager.h"
#include "ardour/search_paths.h"
-
+#include "ardour/selection.h"
+#include "ardour/session.h"
using namespace ARDOUR;
using namespace std;
ControlProtocolManager* ControlProtocolManager::_instance = 0;
const string ControlProtocolManager::state_node_name = X_("ControlProtocols");
-
+PBD::Signal1<void,StripableNotificationListPtr> ControlProtocolManager::StripableSelectionChanged;
ControlProtocolInfo::~ControlProtocolInfo ()
{
ControlProtocolManager::~ControlProtocolManager()
{
- Glib::Threads::Mutex::Lock lm (protocols_lock);
+ Glib::Threads::RWLock::WriterLock lm (protocols_lock);
for (list<ControlProtocol*>::iterator i = control_protocols.begin(); i != control_protocols.end(); ++i) {
delete (*i);
for (list<ControlProtocolInfo*>::iterator p = control_protocol_info.begin(); p != control_protocol_info.end(); ++p) {
+ (*p)->protocol = 0; // protocol was already destroyed above.
delete (*p);
}
{
SessionHandlePtr::set_session (s);
- if (_session) {
- Glib::Threads::Mutex::Lock lm (protocols_lock);
+ if (!_session) {
+ return;
+ }
+
+ {
+ Glib::Threads::RWLock::ReaderLock lm (protocols_lock);
for (list<ControlProtocolInfo*>::iterator i = control_protocol_info.begin(); i != control_protocol_info.end(); ++i) {
if ((*i)->requested || (*i)->mandatory) {
}
}
}
+
+ CoreSelection::StripableAutomationControls sac;
+ _session->selection().get_stripables (sac);
+
+ if (!sac.empty()) {
+ StripableNotificationListPtr v (new StripableNotificationList);
+ for (CoreSelection::StripableAutomationControls::iterator i = sac.begin(); i != sac.end(); ++i) {
+ if ((*i).stripable) {
+ v->push_back (boost::weak_ptr<Stripable> ((*i).stripable));
+ }
+ }
+ if (!v->empty()) {
+ StripableSelectionChanged (v); /* EMIT SIGNAL */
+ }
+ }
}
int
cp->set_state (XMLNode(""), Stateful::loading_state_version);
}
- cp->set_active (true);
+ if (cp->set_active (true)) {
+ error << string_compose (_("Control protocol support for %1 failed to activate"), cpi.name) << endmsg;
+ teardown (cpi, false);
+ }
return 0;
}
ControlProtocolManager::deactivate (ControlProtocolInfo& cpi)
{
cpi.requested = false;
- return teardown (cpi);
+ return teardown (cpi, true);
}
void
* before the process cycle stops and ports vanish.
*/
- Glib::Threads::Mutex::Lock lm (protocols_lock);
+ Glib::Threads::RWLock::WriterLock lm (protocols_lock);
for (list<ControlProtocol*>::iterator p = control_protocols.begin(); p != control_protocols.end(); ++p) {
delete *p;
if ((*p)->protocol) {
(*p)->requested = true;
(*p)->protocol = 0;
+ ProtocolStatusChange (*p); /* EMIT SIGNAL */
}
}
}
}
int
-ControlProtocolManager::teardown (ControlProtocolInfo& cpi)
+ControlProtocolManager::teardown (ControlProtocolInfo& cpi, bool lock_required)
{
if (!cpi.protocol) {
delete cpi.state;
cpi.state = new XMLNode (cpi.protocol->get_state());
- cpi.state->add_property (X_("active"), "no");
+ cpi.state->set_property (X_("active"), false);
cpi.descriptor->destroy (cpi.descriptor, cpi.protocol);
- {
- Glib::Threads::Mutex::Lock lm (protocols_lock);
+ if (lock_required) {
+ Glib::Threads::RWLock::WriterLock lm (protocols_lock);
+ list<ControlProtocol*>::iterator p = find (control_protocols.begin(), control_protocols.end(), cpi.protocol);
+ if (p != control_protocols.end()) {
+ control_protocols.erase (p);
+ } else {
+ cerr << "Programming error: ControlProtocolManager::teardown() called for " << cpi.name << ", but it was not found in control_protocols" << endl;
+ }
+ } else {
list<ControlProtocol*>::iterator p = find (control_protocols.begin(), control_protocols.end(), cpi.protocol);
if (p != control_protocols.end()) {
control_protocols.erase (p);
cpi.protocol = 0;
- delete cpi.state;
- cpi.state = 0;
+ if (lock_required) {
+ /* the lock is only required when the protocol is torn down from the GUI.
+ * If a user disables a protocol, we take this as indicator to forget the
+ * state.
+ */
+ delete cpi.state;
+ cpi.state = 0;
+ }
delete (Glib::Module*) cpi.descriptor->module;
/* cpi->descriptor is now inaccessible since dlclose() or equivalent
* has been performed, and the descriptor is (or could be) a static
return;
}
- Glib::Threads::Mutex::Lock lm (protocols_lock);
+ Glib::Threads::RWLock::ReaderLock lm (protocols_lock);
for (list<ControlProtocolInfo*>::iterator i = control_protocol_info.begin(); i != control_protocol_info.end(); ++i) {
if ((*i)->mandatory && ((*i)->protocol == 0)) {
if ((descriptor = get_descriptor (path)) != 0) {
if (!descriptor->probe (descriptor)) {
- DEBUG_TRACE (DEBUG::ControlProtocols,
- string_compose (_("Control protocol %1 not usable"), descriptor->name));
+ warning << string_compose (_("Control protocol %1 not usable"), descriptor->name) << endmsg;
} else {
ControlProtocolInfo* cpi = new ControlProtocolInfo ();
{
XMLNodeList clist;
XMLNodeConstIterator citer;
- XMLProperty const * prop;
- Glib::Threads::Mutex::Lock lm (protocols_lock);
+ Glib::Threads::RWLock::WriterLock lm (protocols_lock);
clist = node.children();
if (child->name() == X_("Protocol")) {
- if ((prop = child->property (X_("active"))) == 0) {
- continue;
- }
-
- bool active = string_is_affirmative (prop->value());
-
- if ((prop = child->property (X_("name"))) == 0) {
+ bool active;
+ std::string name;
+ if (!child->get_property (X_("active"), active) ||
+ !child->get_property (X_("name"), name)) {
continue;
}
- ControlProtocolInfo* cpi = cpi_by_name (prop->value());
+ ControlProtocolInfo* cpi = cpi_by_name (name);
if (cpi) {
- delete cpi->state;
- cpi->state = new XMLNode (**citer);
+#ifndef NDEBUG
+ std::cerr << "protocol " << name << " active ? " << active << std::endl;
+#endif
if (active) {
+ delete cpi->state;
+ cpi->state = new XMLNode (**citer);
if (_session) {
instantiate (*cpi);
} else {
cpi->requested = true;
}
} else {
+ if (!cpi->state) {
+ cpi->state = new XMLNode (**citer);
+ cpi->state->set_property (X_("active"), false);
+ }
+ cpi->requested = false;
if (_session) {
- teardown (*cpi);
- } else {
- cpi->requested = false;
+ teardown (*cpi, false);
}
}
+ } else {
+ std::cerr << "protocol " << name << " not found\n";
}
}
}
ControlProtocolManager::get_state ()
{
XMLNode* root = new XMLNode (state_node_name);
- Glib::Threads::Mutex::Lock lm (protocols_lock);
+ Glib::Threads::RWLock::ReaderLock lm (protocols_lock);
for (list<ControlProtocolInfo*>::iterator i = control_protocol_info.begin(); i != control_protocol_info.end(); ++i) {
if ((*i)->protocol) {
XMLNode& child_state ((*i)->protocol->get_state());
- child_state.add_property (X_("active"), "yes");
+ child_state.set_property (X_("active"), true);
root->add_child_nocopy (child_state);
} else if ((*i)->state) {
XMLNode* child_state = new XMLNode (*(*i)->state);
- child_state->add_property (X_("active"), "no");
+ child_state->set_property (X_("active"), false);
root->add_child_nocopy (*child_state);
} else {
XMLNode* child_state = new XMLNode (X_("Protocol"));
- child_state->add_property (X_("name"), (*i)->name);
- child_state->add_property (X_("active"), "no");
+ child_state->set_property (X_("name"), (*i)->name);
+ child_state->set_property (X_("active"), false);
root->add_child_nocopy (*child_state);
}
void
ControlProtocolManager::midi_connectivity_established ()
{
- Glib::Threads::Mutex::Lock lm (protocols_lock);
+ Glib::Threads::RWLock::ReaderLock lm (protocols_lock);
for (list<ControlProtocol*>::iterator p = control_protocols.begin(); p != control_protocols.end(); ++p) {
(*p)->midi_connectivity_established ();
void
ControlProtocolManager::register_request_buffer_factories ()
{
- Glib::Threads::Mutex::Lock lm (protocols_lock);
+ Glib::Threads::RWLock::ReaderLock lm (protocols_lock);
for (list<ControlProtocolInfo*>::iterator i = control_protocol_info.begin(); i != control_protocol_info.end(); ++i) {
}
}
}
+
+void
+ControlProtocolManager::stripable_selection_changed (StripableNotificationListPtr sp)
+{
+ /* this sets up the (static) data structures owned by ControlProtocol
+ that are "shared" across all control protocols.
+ */
+
+ DEBUG_TRACE (DEBUG::Selection, string_compose ("Surface manager: selection changed, now %1 stripables\n", sp ? sp->size() : -1));
+ StripableSelectionChanged (sp); /* EMIT SIGNAL */
+
+ /* now give each protocol the chance to respond to the selection change
+ */
+
+ {
+ Glib::Threads::RWLock::ReaderLock lm (protocols_lock);
+
+ for (list<ControlProtocol*>::iterator p = control_protocols.begin(); p != control_protocols.end(); ++p) {
+ DEBUG_TRACE (DEBUG::Selection, string_compose ("selection change notification for surface \"%1\"\n", (*p)->name()));
+ (*p)->stripable_selection_changed ();
+ }
+ }
+}