diff options
author | David Robillard <d@drobilla.net> | 2014-01-31 23:58:48 +0000 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2014-01-31 23:58:48 +0000 |
commit | cc3359a6bea22c3d4584a5d57403e7d568e16fe7 (patch) | |
tree | b0e57cf8c8227da9ef4be982db062b32f3a0cbdc | |
parent | a659a13c531e991851e013db3d4223bf16a343b8 (diff) | |
download | ingen-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
-rw-r--r-- | src/client/ClientStore.cpp | 9 | ||||
-rw-r--r-- | src/client/PluginUI.cpp | 51 | ||||
-rw-r--r-- | src/server/Broadcaster.hpp | 16 | ||||
-rw-r--r-- | src/server/EventWriter.cpp | 8 | ||||
-rw-r--r-- | src/server/events/Delta.cpp | 23 | ||||
-rw-r--r-- | src/server/events/Delta.hpp | 10 |
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; |