summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2014-01-31 23:58:48 +0000
committerDavid Robillard <d@drobilla.net>2014-01-31 23:58:48 +0000
commitcc3359a6bea22c3d4584a5d57403e7d568e16fe7 (patch)
treeb0e57cf8c8227da9ef4be982db062b32f3a0cbdc /src
parenta659a13c531e991851e013db3d4223bf16a343b8 (diff)
downloadingen-cc3359a6bea22c3d4584a5d57403e7d568e16fe7.tar.gz
ingen-cc3359a6bea22c3d4584a5d57403e7d568e16fe7.tar.bz2
ingen-cc3359a6bea22c3d4584a5d57403e7d568e16fe7.zip
Subscribe to ports before instantiating plugin UIs (fix #954).
Respond to put/set/patch with the same type of event (not set=>delta). Don't feed back changes to originating client. git-svn-id: http://svn.drobilla.net/lad/trunk/ingen@5326 a436a847-0d15-0410-975c-d299462d15a1
Diffstat (limited to 'src')
-rw-r--r--src/client/ClientStore.cpp9
-rw-r--r--src/client/PluginUI.cpp51
-rw-r--r--src/server/Broadcaster.hpp16
-rw-r--r--src/server/EventWriter.cpp8
-rw-r--r--src/server/events/Delta.cpp23
-rw-r--r--src/server/events/Delta.hpp10
6 files changed, 81 insertions, 36 deletions
diff --git a/src/client/ClientStore.cpp b/src/client/ClientStore.cpp
index d3438f46..a3fc60aa 100644
--- a/src/client/ClientStore.cpp
+++ b/src/client/ClientStore.cpp
@@ -215,7 +215,7 @@ ClientStore::put(const Raul::URI& uri,
{
typedef Resource::Properties::const_iterator Iterator;
#ifdef INGEN_CLIENT_STORE_DUMP
- std::cerr << "Put " << uri << " {" << endl;
+ std::cerr << "Client put " << uri << " {" << endl;
for (auto p : properties)
std::cerr << '\t' << p.first << " = " << _uris.forge.str(p.second)
<< " :: " << p.second.type() << endl;
@@ -312,7 +312,7 @@ ClientStore::delta(const Raul::URI& uri,
const Resource::Properties& add)
{
#ifdef INGEN_CLIENT_STORE_DUMP
- std::cerr << "Delta " << uri << " {" << endl;
+ std::cerr << "Client delta " << uri << " {" << endl;
for (auto r : remove)
std::cerr << " - " << r.first
<< " = " << _uris.forge.str(r.second)
@@ -352,6 +352,11 @@ ClientStore::set_property(const Raul::URI& subject_uri,
const Raul::URI& predicate,
const Atom& value)
{
+#ifdef INGEN_CLIENT_STORE_DUMP
+ std::cerr << "Client set " << subject_uri << " : "
+ << predicate << " = " << _uris.forge.str(value) << std::endl;
+#endif
+
if (subject_uri == Raul::URI("ingen:/engine")) {
_log.info(fmt("Engine property <%1%> = %2%\n")
% predicate.c_str() % _uris.forge.str(value));
diff --git a/src/client/PluginUI.cpp b/src/client/PluginUI.cpp
index 227f6000..0e308abd 100644
--- a/src/client/PluginUI.cpp
+++ b/src/client/PluginUI.cpp
@@ -80,7 +80,7 @@ lv2_ui_write(SuilController controller,
Atom val = ui->world()->forge().alloc(
atom->size, atom->type, LV2_ATOM_BODY_CONST(atom));
ui->world()->interface()->set_property(port->uri(),
- uris.ingen_value,
+ uris.ingen_activity,
val);
} else {
@@ -199,30 +199,14 @@ PluginUI::create(Ingen::World* world,
return SPtr<PluginUI>();
}
+ // Create the PluginUI, but don't instantiate yet
SPtr<PluginUI> ret(new PluginUI(world, block, lilv_ui_get_uri(ui)));
ret->_features = world->lv2_features().lv2_features(
world, const_cast<BlockModel*>(block.get()));
- SuilInstance* instance = suil_instance_new(
- PluginUI::ui_host,
- ret.get(),
- lilv_node_as_uri(gtk_ui),
- lilv_node_as_uri(lilv_plugin_get_uri(plugin)),
- lilv_node_as_uri(lilv_ui_get_uri(ui)),
- lilv_node_as_uri(ui_type),
- lilv_uri_to_path(lilv_node_as_uri(lilv_ui_get_bundle_uri(ui))),
- lilv_uri_to_path(lilv_node_as_uri(lilv_ui_get_binary_uri(ui))),
- ret->_features->array());
-
- lilv_node_free(gtk_ui);
-
- if (!instance) {
- world->log().error("Failed to instantiate LV2 UI\n");
- return SPtr<PluginUI>();
- }
-
- ret->_instance = instance;
-
+ /* Subscribe (enable broadcast) for any requested port notifications. This
+ must be done before instantiation so responses to any events sent by the
+ UI's init() will be sent back to this client. */
LilvWorld* lworld = world->lilv_world();
LilvNode* ui_portNotification = lilv_new_uri(lworld, LV2_UI__portNotification);
LilvNode* lv2_symbol = lilv_new_uri(lworld, LV2_CORE__symbol);
@@ -243,6 +227,31 @@ PluginUI::create(Ingen::World* world,
lilv_node_free(lv2_symbol);
lilv_node_free(ui_portNotification);
+ // Instantiate the actual plugin UI via Suil
+ SuilInstance* instance = suil_instance_new(
+ PluginUI::ui_host,
+ ret.get(),
+ lilv_node_as_uri(gtk_ui),
+ lilv_node_as_uri(lilv_plugin_get_uri(plugin)),
+ lilv_node_as_uri(lilv_ui_get_uri(ui)),
+ lilv_node_as_uri(ui_type),
+ lilv_uri_to_path(lilv_node_as_uri(lilv_ui_get_bundle_uri(ui))),
+ lilv_uri_to_path(lilv_node_as_uri(lilv_ui_get_binary_uri(ui))),
+ ret->_features->array());
+
+ lilv_node_free(gtk_ui);
+
+ if (!instance) {
+ world->log().error("Failed to instantiate LV2 UI\n");
+ // Cancel any subscriptions
+ for (uint32_t i : ret->_subscribed_ports) {
+ lv2_ui_unsubscribe(ret.get(), i, 0, NULL);
+ }
+ return SPtr<PluginUI>();
+ }
+
+ ret->_instance = instance;
+
return ret;
}
diff --git a/src/server/Broadcaster.hpp b/src/server/Broadcaster.hpp
index 069a0499..b9e37c44 100644
--- a/src/server/Broadcaster.hpp
+++ b/src/server/Broadcaster.hpp
@@ -50,6 +50,14 @@ public:
void set_broadcast(const Raul::URI& client, bool broadcast);
+ /** Ignore a client when broadcasting.
+ *
+ * This is used to prevent feeding back updates to the client that
+ * initiated a property set in the first place.
+ */
+ void set_ignore_client(SPtr<Interface> client) { _ignore_client = client; }
+ void clear_ignore_client() { _ignore_client.reset(); }
+
/** Return true iff there are any clients with broadcasting enabled.
*
* This is used in the audio thread to decide whether or not notifications
@@ -85,8 +93,11 @@ public:
#define BROADCAST(msg, ...) \
std::lock_guard<std::mutex> lock(_clients_mutex); \
- for (const auto& c : _clients) \
- c.second->msg(__VA_ARGS__)
+ for (const auto& c : _clients) { \
+ if (c.second != _ignore_client) { \
+ c.second->msg(__VA_ARGS__); \
+ } \
+ } \
void bundle_begin() { BROADCAST(bundle_begin); }
void bundle_end() { BROADCAST(bundle_end); }
@@ -151,6 +162,7 @@ private:
std::set<Raul::URI> _broadcastees;
std::atomic<bool> _must_broadcast;
unsigned _bundle_depth;
+ SPtr<Interface> _ignore_client;
};
} // namespace Server
diff --git a/src/server/EventWriter.cpp b/src/server/EventWriter.cpp
index 96814ed2..60096d85 100644
--- a/src/server/EventWriter.cpp
+++ b/src/server/EventWriter.cpp
@@ -54,7 +54,7 @@ EventWriter::put(const Raul::URI& uri,
{
_engine.enqueue_event(
new Events::Delta(_engine, _respondee, _request_id, now(),
- true, ctx, uri, properties));
+ Events::Delta::Type::PUT, ctx, uri, properties));
}
void
@@ -64,7 +64,8 @@ EventWriter::delta(const Raul::URI& uri,
{
_engine.enqueue_event(
new Events::Delta(_engine, _respondee, _request_id, now(),
- false, Resource::Graph::DEFAULT, uri, add, remove));
+ Events::Delta::Type::PATCH, Resource::Graph::DEFAULT,
+ uri, add, remove));
}
void
@@ -124,7 +125,8 @@ EventWriter::set_property(const Raul::URI& uri,
add.insert(make_pair(predicate, value));
_engine.enqueue_event(
new Events::Delta(_engine, _respondee, _request_id, now(),
- false, Resource::Graph::DEFAULT, uri, add, remove));
+ Events::Delta::Type::SET, Resource::Graph::DEFAULT,
+ uri, add, remove));
}
void
diff --git a/src/server/events/Delta.cpp b/src/server/events/Delta.cpp
index 90baaa52..6fd14fd5 100644
--- a/src/server/events/Delta.cpp
+++ b/src/server/events/Delta.cpp
@@ -48,7 +48,7 @@ Delta::Delta(Engine& engine,
SPtr<Interface> client,
int32_t id,
SampleCount timestamp,
- bool create,
+ Type type,
Resource::Graph context,
const Raul::URI& subject,
const Properties& properties,
@@ -62,7 +62,7 @@ Delta::Delta(Engine& engine,
, _graph(NULL)
, _compiled_graph(NULL)
, _context(context)
- , _create(create)
+ , _type(type)
, _poly_lock(engine.store()->lock(), Glib::NOT_LOCK)
{
if (context != Resource::Graph::DEFAULT) {
@@ -113,7 +113,7 @@ Delta::pre_process()
? static_cast<Ingen::Resource*>(_engine.store()->get(Node::uri_to_path(_subject)))
: static_cast<Ingen::Resource*>(_engine.block_factory()->plugin(_subject));
- if (!_object && !is_client && (!is_graph_object || !_create)) {
+ if (!_object && !is_client && (!is_graph_object || _type != Type::PUT)) {
return Event::pre_process_done(Status::NOT_FOUND, _subject);
}
@@ -163,7 +163,7 @@ Delta::pre_process()
}
// Remove all added properties if this is a put
- if (_create && _object) {
+ if (_type == Type::PUT && _object) {
for (const auto& p : _properties) {
_object->remove_property(p.first, p.second);
}
@@ -381,11 +381,22 @@ Delta::post_process()
_create_event->post_process();
} else {
respond();
- if (_create) {
+ _engine.broadcaster()->set_ignore_client(_request_client);
+ switch (_type) {
+ case Type::SET:
+ _engine.broadcaster()->set_property(
+ _subject,
+ (*_properties.begin()).first,
+ (*_properties.begin()).second);
+ break;
+ case Type::PUT:
_engine.broadcaster()->put(_subject, _properties, _context);
- } else {
+ break;
+ case Type::PATCH:
_engine.broadcaster()->delta(_subject, _remove, _properties);
+ break;
}
+ _engine.broadcaster()->clear_ignore_client();
}
} else {
respond();
diff --git a/src/server/events/Delta.hpp b/src/server/events/Delta.hpp
index 451b8e62..a8e8ed0b 100644
--- a/src/server/events/Delta.hpp
+++ b/src/server/events/Delta.hpp
@@ -69,11 +69,17 @@ class SetPortValue;
class Delta : public Event
{
public:
+ enum class Type {
+ SET,
+ PUT,
+ PATCH
+ };
+
Delta(Engine& engine,
SPtr<Interface> client,
int32_t id,
SampleCount timestamp,
- bool create,
+ Type type,
Resource::Graph context,
const Raul::URI& subject,
const Resource::Properties& properties,
@@ -109,7 +115,7 @@ private:
CompiledGraph* _compiled_graph;
Resource::Graph _context;
ControlBindings::Key _binding;
- bool _create;
+ Type _type;
SPtr<ControlBindings::Bindings> _old_bindings;