summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2015-10-30 17:02:07 +0000
committerDavid Robillard <d@drobilla.net>2015-10-30 17:02:07 +0000
commit8510f80faad7a719a97cf14b1a82a1cc2141282b (patch)
tree11ab0ede29a4a2e29d1e689f6b2cb23ee0da47f1 /src
parent2fe35cd17f96a1d393fda203ccaa234b0aa69b16 (diff)
downloadingen-8510f80faad7a719a97cf14b1a82a1cc2141282b.tar.gz
ingen-8510f80faad7a719a97cf14b1a82a1cc2141282b.tar.bz2
ingen-8510f80faad7a719a97cf14b1a82a1cc2141282b.zip
Update clients when plugins are unloaded/reloaded
git-svn-id: http://svn.drobilla.net/lad/trunk/ingen@5808 a436a847-0d15-0410-975c-d299462d15a1
Diffstat (limited to 'src')
-rw-r--r--src/client/ClientStore.cpp6
-rw-r--r--src/gui/GraphCanvas.cpp18
-rw-r--r--src/gui/GraphCanvas.hpp2
-rw-r--r--src/gui/PluginMenu.cpp16
-rw-r--r--src/gui/PluginMenu.hpp1
-rw-r--r--src/server/BlockFactory.cpp41
-rw-r--r--src/server/BlockFactory.hpp7
-rw-r--r--src/server/ClientUpdate.cpp155
-rw-r--r--src/server/ClientUpdate.hpp81
-rw-r--r--src/server/LV2Plugin.cpp18
-rw-r--r--src/server/LV2Plugin.hpp7
-rw-r--r--src/server/PluginImpl.hpp8
-rw-r--r--src/server/events/CreateBlock.hpp4
-rw-r--r--src/server/events/CreateGraph.hpp2
-rw-r--r--src/server/events/Delta.cpp25
-rw-r--r--src/server/events/Delta.hpp1
-rw-r--r--src/server/events/Get.cpp112
-rw-r--r--src/server/events/Get.hpp45
-rw-r--r--src/server/internals/Controller.cpp12
-rw-r--r--src/server/internals/Controller.hpp12
-rw-r--r--src/server/wscript1
21 files changed, 388 insertions, 186 deletions
diff --git a/src/client/ClientStore.cpp b/src/client/ClientStore.cpp
index a0c789c4..1061fb6b 100644
--- a/src/client/ClientStore.cpp
+++ b/src/client/ClientStore.cpp
@@ -211,6 +211,12 @@ ClientStore::del(const Raul::URI& uri)
{
if (Node::uri_is_path(uri)) {
remove_object(Node::uri_to_path(uri));
+ } else {
+ Plugins::iterator p = _plugins->find(uri);
+ if (p != _plugins->end()) {
+ _plugins->erase(p);
+ _signal_plugin_deleted.emit(uri);
+ }
}
}
diff --git a/src/gui/GraphCanvas.cpp b/src/gui/GraphCanvas.cpp
index 16739a55..85ab4855 100644
--- a/src/gui/GraphCanvas.cpp
+++ b/src/gui/GraphCanvas.cpp
@@ -88,6 +88,7 @@ GraphCanvas::GraphCanvas(App& app,
, _plugin_menu(NULL)
, _human_names(true)
, _show_port_names(true)
+ , _menu_dirty(false)
{
Glib::RefPtr<Gtk::Builder> xml = WidgetFactory::create("canvas_menu");
xml->get_widget("canvas_menu", _menu);
@@ -157,6 +158,8 @@ GraphCanvas::GraphCanvas(App& app,
_app.store()->signal_new_plugin().connect(
sigc::mem_fun(this, &GraphCanvas::add_plugin));
+ _app.store()->signal_plugin_deleted().connect(
+ sigc::mem_fun(this, &GraphCanvas::remove_plugin));
// Connect widget signals to do things
_menu_load_plugin->signal_activate().connect(
@@ -178,7 +181,7 @@ GraphCanvas::show_menu(bool position, unsigned button, uint32_t time)
{
_app.request_plugins_if_necessary();
- if (!_internal_menu)
+ if (!_internal_menu || _menu_dirty)
build_menus();
if (position)
@@ -205,7 +208,9 @@ GraphCanvas::build_menus()
}
// Build skeleton LV2 plugin class heirarchy for 'Plugin' menu
- if (!_plugin_menu) {
+ if (_plugin_menu) {
+ _plugin_menu->clear();
+ } else {
_plugin_menu = Gtk::manage(new PluginMenu(*_app.world()));
_menu->items().push_back(
Gtk::Menu_Helpers::ImageMenuElem(
@@ -223,6 +228,8 @@ GraphCanvas::build_menus()
for (const auto& p : *plugins.get()) {
add_plugin(p.second);
}
+
+ _menu_dirty = false;
}
void
@@ -308,6 +315,13 @@ GraphCanvas::add_plugin(SPtr<PluginModel> p)
}
void
+GraphCanvas::remove_plugin(const Raul::URI& uri)
+{
+ // Flag menus as dirty so they will be rebuilt when needed next
+ _menu_dirty = true;
+}
+
+void
GraphCanvas::add_block(SPtr<const BlockModel> bm)
{
SPtr<const GraphModel> pm = dynamic_ptr_cast<const GraphModel>(bm);
diff --git a/src/gui/GraphCanvas.hpp b/src/gui/GraphCanvas.hpp
index 8970a88a..b055d530 100644
--- a/src/gui/GraphCanvas.hpp
+++ b/src/gui/GraphCanvas.hpp
@@ -63,6 +63,7 @@ public:
bool show_port_names() const { return _show_port_names; }
void add_plugin(SPtr<Client::PluginModel> pm);
+ void remove_plugin(const Raul::URI& uri);
void add_block(SPtr<const Client::BlockModel> bm);
void remove_block(SPtr<const Client::BlockModel> bm);
void add_port(SPtr<const Client::PortModel> pm);
@@ -149,6 +150,7 @@ private:
bool _human_names;
bool _show_port_names;
+ bool _menu_dirty;
};
} // namespace GUI
diff --git a/src/gui/PluginMenu.cpp b/src/gui/PluginMenu.cpp
index 9bc47bff..c997bf19 100644
--- a/src/gui/PluginMenu.cpp
+++ b/src/gui/PluginMenu.cpp
@@ -25,10 +25,22 @@ PluginMenu::PluginMenu(Ingen::World& world)
: _world(world)
, _classless_menu(NULL, NULL)
{
+ clear();
+}
+
+void
+PluginMenu::clear()
+{
const LilvWorld* lworld = _world.lilv_world();
const LilvPluginClass* lv2_plugin = lilv_world_get_plugin_class(lworld);
const LilvPluginClasses* classes = lilv_world_get_plugin_classes(lworld);
+ // Empty completely
+ _classless_menu = MenuRecord(NULL, NULL);
+ _class_menus.clear();
+ items().clear();
+
+ // Build skeleton
LV2Children children;
LILV_FOREACH(plugin_classes, i, classes) {
const LilvPluginClass* c = lilv_plugin_classes_get(classes, i);
@@ -44,7 +56,7 @@ PluginMenu::PluginMenu(Ingen::World& world)
items().push_back(Gtk::Menu_Helpers::MenuElem("_Uncategorized"));
_classless_menu.item = &(items().back());
- _classless_menu.menu = new Gtk::Menu();
+ _classless_menu.menu = Gtk::manage(new Gtk::Menu());
_classless_menu.item->set_submenu(*_classless_menu.menu);
_classless_menu.item->hide();
}
@@ -109,7 +121,7 @@ PluginMenu::build_plugin_class_menu(Gtk::Menu* menu,
menu->items().push_back(menu_elem);
Gtk::MenuItem* menu_item = &(menu->items().back());
- Gtk::Menu* submenu = new Gtk::Menu();
+ Gtk::Menu* submenu = Gtk::manage(new Gtk::Menu());
menu_item->set_submenu(*submenu);
size_t num_child_items = build_plugin_class_menu(
diff --git a/src/gui/PluginMenu.hpp b/src/gui/PluginMenu.hpp
index c8fda171..bc654db5 100644
--- a/src/gui/PluginMenu.hpp
+++ b/src/gui/PluginMenu.hpp
@@ -43,6 +43,7 @@ class PluginMenu : public Gtk::Menu
public:
PluginMenu(Ingen::World& world);
+ void clear();
void add_plugin(SPtr<Client::PluginModel> p);
sigc::signal< void, WPtr<Client::PluginModel> > signal_load_plugin;
diff --git a/src/server/BlockFactory.cpp b/src/server/BlockFactory.cpp
index 0a51e03e..b715ecb7 100644
--- a/src/server/BlockFactory.cpp
+++ b/src/server/BlockFactory.cpp
@@ -59,14 +59,46 @@ BlockFactory::plugins()
{
ThreadManager::assert_thread(THREAD_PRE_PROCESS);
if (!_has_loaded) {
- _has_loaded = true;
- // TODO: Plugin list refreshing
load_lv2_plugins();
_has_loaded = true;
}
return _plugins;
}
+std::set<PluginImpl*>
+BlockFactory::refresh()
+{
+ // Record current plugins, and those that are currently zombies
+ const Plugins old_plugins(_plugins);
+ std::set<PluginImpl*> zombies;
+ for (const auto& p : _plugins) {
+ if (p.second->is_zombie()) {
+ zombies.insert(p.second);
+ }
+ }
+
+ // Re-load plugins
+ load_lv2_plugins();
+
+ // Add any new plugins to response
+ std::set<PluginImpl*> new_plugins;
+ for (const auto& p : _plugins) {
+ Plugins::const_iterator o = old_plugins.find(p.first);
+ if (o == old_plugins.end()) {
+ new_plugins.insert(p.second);
+ }
+ }
+
+ // Add any resurrected plugins to response
+ for (const auto& z : zombies) {
+ if (!z->is_zombie()) {
+ new_plugins.insert(z);
+ }
+ }
+
+ return new_plugins;
+}
+
PluginImpl*
BlockFactory::plugin(const Raul::URI& uri)
{
@@ -182,9 +214,12 @@ BlockFactory::load_lv2_plugins()
continue;
}
- if (_plugins.find(uri) == _plugins.end()) {
+ Plugins::iterator p = _plugins.find(uri);
+ if (p == _plugins.end()) {
LV2Plugin* const plugin = new LV2Plugin(_world, lv2_plug);
_plugins.insert(make_pair(uri, plugin));
+ } else if (lilv_plugin_verify(lv2_plug)) {
+ p->second->set_is_zombie(false);
}
}
diff --git a/src/server/BlockFactory.hpp b/src/server/BlockFactory.hpp
index 776ef948..71e72bbc 100644
--- a/src/server/BlockFactory.hpp
+++ b/src/server/BlockFactory.hpp
@@ -18,6 +18,7 @@
#define INGEN_ENGINE_BLOCKFACTORY_HPP
#include <map>
+#include <set>
#include "ingen/World.hpp"
#include "ingen/types.hpp"
@@ -39,6 +40,12 @@ public:
explicit BlockFactory(Ingen::World* world);
~BlockFactory();
+ /** Reload plugin list.
+ *
+ * @return The set of newly loaded plugins.
+ */
+ std::set<PluginImpl*> refresh();
+
void load_plugin(const Raul::URI& uri);
typedef std::map<Raul::URI, PluginImpl*> Plugins;
diff --git a/src/server/ClientUpdate.cpp b/src/server/ClientUpdate.cpp
new file mode 100644
index 00000000..217d3a32
--- /dev/null
+++ b/src/server/ClientUpdate.cpp
@@ -0,0 +1,155 @@
+/*
+ This file is part of Ingen.
+ Copyright 2007-2015 David Robillard <http://drobilla.net/>
+
+ Ingen is free software: you can redistribute it and/or modify it under the
+ terms of the GNU Affero General Public License as published by the Free
+ Software Foundation, either version 3 of the License, or any later version.
+
+ Ingen is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with Ingen. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "ingen/Interface.hpp"
+#include "ingen/URIs.hpp"
+
+#include "BlockImpl.hpp"
+#include "BufferFactory.hpp"
+#include "ClientUpdate.hpp"
+#include "GraphImpl.hpp"
+#include "PortImpl.hpp"
+
+namespace Ingen {
+namespace Server {
+
+void
+ClientUpdate::put(const Raul::URI& uri,
+ const Resource::Properties& props,
+ Resource::Graph ctx)
+{
+ const ClientUpdate::Put put = { uri, props, ctx };
+ puts.push_back(put);
+}
+
+void
+ClientUpdate::put_port(const PortImpl* port)
+{
+ const URIs& uris = port->bufs().uris();
+ if (port->is_a(PortType::CONTROL) || port->is_a(PortType::CV)) {
+ Resource::Properties props = port->properties();
+ props.erase(uris.ingen_value);
+ props.insert(std::make_pair(uris.ingen_value, port->value()));
+ put(port->uri(), props);
+ } else {
+ put(port->uri(), port->properties());
+ }
+}
+
+void
+ClientUpdate::put_block(const BlockImpl* block)
+{
+ const PluginImpl* const plugin = block->plugin_impl();
+ const URIs& uris = plugin->uris();
+
+ if (uris.ingen_Graph == plugin->type()) {
+ put_graph((const GraphImpl*)block);
+ } else {
+ put(block->uri(), block->properties());
+ for (size_t j = 0; j < block->num_ports(); ++j) {
+ put_port(block->port_impl(j));
+ }
+ }
+}
+
+void
+ClientUpdate::put_graph(const GraphImpl* graph)
+{
+ put(graph->uri(),
+ graph->properties(Resource::Graph::INTERNAL),
+ Resource::Graph::INTERNAL);
+
+ put(graph->uri(),
+ graph->properties(Resource::Graph::EXTERNAL),
+ Resource::Graph::EXTERNAL);
+
+ // Enqueue blocks
+ for (const auto& b : graph->blocks()) {
+ put_block(&b);
+ }
+
+ // Enqueue ports
+ for (uint32_t i = 0; i < graph->num_ports_non_rt(); ++i) {
+ put_port(graph->port_impl(i));
+ }
+
+ // Enqueue arcs
+ for (const auto& a : graph->arcs()) {
+ const SPtr<const Arc> arc = a.second;
+ const Connect connect = { arc->tail_path(), arc->head_path() };
+ connects.push_back(connect);
+ }
+}
+
+void
+ClientUpdate::put_plugin(PluginImpl* plugin)
+{
+ put(plugin->uri(), plugin->properties());
+
+ for (const auto& p : plugin->presets()) {
+ put_preset(plugin->uris(), plugin->uri(), p.first, p.second);
+ }
+}
+
+void
+ClientUpdate::put_preset(const URIs& uris,
+ const Raul::URI& plugin,
+ const Raul::URI& preset,
+ const std::string& label)
+{
+ Resource::Properties props{
+ { uris.rdf_type, uris.pset_Preset.urid },
+ { uris.rdfs_label, uris.forge.alloc(label) },
+ { uris.lv2_appliesTo, uris.forge.make_urid(plugin) }};
+ put(preset, props);
+}
+
+void
+ClientUpdate::del(const Raul::URI& subject)
+{
+ dels.push_back(subject);
+}
+
+/** Returns true if a is closer to the root than b. */
+static inline bool
+put_higher_than(const ClientUpdate::Put& a, const ClientUpdate::Put& b)
+{
+ return (std::count(a.uri.begin(), a.uri.end(), '/') <
+ std::count(b.uri.begin(), b.uri.end(), '/'));
+}
+
+void
+ClientUpdate::send(Interface* dest)
+{
+ // Send deletions
+ for (const Raul::URI& subject : dels) {
+ dest->del(subject);
+ }
+
+ // Send puts in increasing depth order so parents are sent first
+ std::stable_sort(puts.begin(), puts.end(), put_higher_than);
+ for (const ClientUpdate::Put& put : puts) {
+ dest->put(put.uri, put.properties, put.ctx);
+ }
+
+ // Send connections
+ for (const ClientUpdate::Connect& connect : connects) {
+ dest->connect(connect.tail, connect.head);
+ }
+}
+
+} // namespace Server
+} // namespace Ingen
diff --git a/src/server/ClientUpdate.hpp b/src/server/ClientUpdate.hpp
new file mode 100644
index 00000000..dcdcc132
--- /dev/null
+++ b/src/server/ClientUpdate.hpp
@@ -0,0 +1,81 @@
+/*
+ This file is part of Ingen.
+ Copyright 2007-2015 David Robillard <http://drobilla.net/>
+
+ Ingen is free software: you can redistribute it and/or modify it under the
+ terms of the GNU Affero General Public License as published by the Free
+ Software Foundation, either version 3 of the License, or any later version.
+
+ Ingen is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Affero General Public License for details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with Ingen. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef INGEN_ENGINE_CLIENTUPDATE_HPP
+#define INGEN_ENGINE_CLIENTUPDATE_HPP
+
+#include <string>
+#include <vector>
+
+#include "ingen/Resource.hpp"
+#include "raul/Path.hpp"
+#include "raul/URI.hpp"
+
+namespace Ingen {
+
+class Interface;
+class URIs;
+
+namespace Server {
+
+class PortImpl;
+class BlockImpl;
+class GraphImpl;
+class PluginImpl;
+
+/** A sequence of puts/connects/deletes to update clients.
+ *
+ * Events like Get construct this in pre_process() and later send it in
+ * post_process() to avoid the need to lock.
+ */
+struct ClientUpdate {
+ void put(const Raul::URI& uri,
+ const Resource::Properties& props,
+ Resource::Graph ctx=Resource::Graph::DEFAULT);
+
+ void put_port(const PortImpl* port);
+ void put_block(const BlockImpl* block);
+ void put_graph(const GraphImpl* graph);
+ void put_plugin(PluginImpl* plugin);
+ void put_preset(const URIs& uris,
+ const Raul::URI& plugin,
+ const Raul::URI& preset,
+ const std::string& label);
+
+ void del(const Raul::URI& subject);
+
+ void send(Interface* dest);
+
+ struct Put {
+ Raul::URI uri;
+ Resource::Properties properties;
+ Resource::Graph ctx;
+ };
+
+ struct Connect {
+ Raul::Path tail;
+ Raul::Path head;
+ };
+
+ std::vector<Raul::URI> dels;
+ std::vector<Put> puts;
+ std::vector<Connect> connects;
+};
+
+} // namespace Server
+} // namespace Ingen
+
+#endif // INGEN_ENGINE_CLIENTUPDATE_HPP
diff --git a/src/server/LV2Plugin.cpp b/src/server/LV2Plugin.cpp
index 5e0dc609..ce920f4e 100644
--- a/src/server/LV2Plugin.cpp
+++ b/src/server/LV2Plugin.cpp
@@ -39,20 +39,26 @@ LV2Plugin::LV2Plugin(World* world, const LilvPlugin* lplugin)
{
set_property(_uris.rdf_type, _uris.lv2_Plugin);
- LilvNode* minor = lilv_world_get(world->lilv_world(),
- lilv_plugin_get_uri(lplugin),
+ update_properties();
+}
+
+void
+LV2Plugin::update_properties()
+{
+ LilvNode* minor = lilv_world_get(_world->lilv_world(),
+ lilv_plugin_get_uri(_lilv_plugin),
_uris.lv2_minorVersion,
NULL);
- LilvNode* micro = lilv_world_get(world->lilv_world(),
- lilv_plugin_get_uri(lplugin),
+ LilvNode* micro = lilv_world_get(_world->lilv_world(),
+ lilv_plugin_get_uri(_lilv_plugin),
_uris.lv2_minorVersion,
NULL);
if (lilv_node_is_int(minor) && lilv_node_is_int(micro)) {
set_property(_uris.lv2_minorVersion,
- world->forge().make(lilv_node_as_int(minor)));
+ _world->forge().make(lilv_node_as_int(minor)));
set_property(_uris.lv2_microVersion,
- world->forge().make(lilv_node_as_int(micro)));
+ _world->forge().make(lilv_node_as_int(micro)));
}
lilv_node_free(minor);
diff --git a/src/server/LV2Plugin.hpp b/src/server/LV2Plugin.hpp
index 0eee6731..aa10d90a 100644
--- a/src/server/LV2Plugin.hpp
+++ b/src/server/LV2Plugin.hpp
@@ -52,8 +52,15 @@ public:
World* world() const { return _world; }
const LilvPlugin* lilv_plugin() const { return _lilv_plugin; }
+ void update_properties();
+
void load_presets();
+ Raul::URI bundle_uri() const {
+ const LilvNode* bundle = lilv_plugin_get_bundle_uri(_lilv_plugin);
+ return Raul::URI(lilv_node_as_uri(bundle));
+ }
+
private:
World* _world;
const LilvPlugin* _lilv_plugin;
diff --git a/src/server/PluginImpl.hpp b/src/server/PluginImpl.hpp
index 414bd1f1..29daba7b 100644
--- a/src/server/PluginImpl.hpp
+++ b/src/server/PluginImpl.hpp
@@ -49,6 +49,7 @@ public:
const Raul::URI& uri)
: Resource(uris, uri)
, _type(type)
+ , _is_zombie(false)
{}
virtual ~PluginImpl() {}
@@ -63,6 +64,8 @@ public:
const Atom& type() const { return _type; }
void set_type(const Atom& t) { _type = t; }
+ bool is_zombie() const { return _is_zombie; }
+ void set_is_zombie(bool t) { _is_zombie = t; }
typedef std::pair<Raul::URI, std::string> Preset;
typedef std::map<Raul::URI, std::string> Presets;
@@ -75,12 +78,17 @@ public:
return _presets;
}
+ virtual void update_properties() {}
+
virtual void load_presets() { _presets_loaded = true; }
+ virtual Raul::URI bundle_uri() const { return Raul::URI("ingen:/"); }
+
protected:
Atom _type;
Presets _presets;
bool _presets_loaded;
+ bool _is_zombie;
};
} // namespace Server
diff --git a/src/server/events/CreateBlock.hpp b/src/server/events/CreateBlock.hpp
index 189a0896..40d72f52 100644
--- a/src/server/events/CreateBlock.hpp
+++ b/src/server/events/CreateBlock.hpp
@@ -19,8 +19,8 @@
#include "ingen/Resource.hpp"
+#include "ClientUpdate.hpp"
#include "Event.hpp"
-#include "events/Get.hpp"
namespace Ingen {
namespace Server {
@@ -54,7 +54,7 @@ public:
private:
Raul::Path _path;
Resource::Properties& _properties;
- Events::Get::Response _update;
+ ClientUpdate _update;
GraphImpl* _graph;
BlockImpl* _block;
CompiledGraph* _compiled_graph;
diff --git a/src/server/events/CreateGraph.hpp b/src/server/events/CreateGraph.hpp
index bcb857ae..cf40fb41 100644
--- a/src/server/events/CreateGraph.hpp
+++ b/src/server/events/CreateGraph.hpp
@@ -55,7 +55,7 @@ private:
const Raul::Path _path;
Resource::Properties _properties;
- Events::Get::Response _update;
+ ClientUpdate _update;
GraphImpl* _graph;
GraphImpl* _parent;
CompiledGraph* _compiled_graph;
diff --git a/src/server/events/Delta.cpp b/src/server/events/Delta.cpp
index 9b990c2d..66ebf803 100644
--- a/src/server/events/Delta.cpp
+++ b/src/server/events/Delta.cpp
@@ -160,7 +160,7 @@ get_file_node(LilvWorld* lworld, const URIs& uris, const Atom& value)
* a patch:Put ;
* patch:subject </> ;
* patch:body [
- * ingen:loadedBundle <file:///old.lv2>
+ * ingen:loadedBundle <file:///old.lv2/>
* ] .
*
* # Replace /old.lv2 with /new.lv2
@@ -168,10 +168,10 @@ get_file_node(LilvWorld* lworld, const URIs& uris, const Atom& value)
* a patch:Patch ;
* patch:subject </> ;
* patch:remove [
- * ingen:loadedBundle <file:///old.lv2>
+ * ingen:loadedBundle <file:///old.lv2/>
* ];
* patch:add [
- * ingen:loadedBundle <file:///new.lv2>
+ * ingen:loadedBundle <file:///new.lv2/>
* ] .
* @endcode
*/
@@ -277,7 +277,14 @@ Delta::pre_process()
LilvWorld* lworld = _engine.world()->lilv_world();
LilvNode* bundle = get_file_node(lworld, uris, value);
if (bundle) {
+ for (const auto& p : _engine.block_factory()->plugins()) {
+ if (p.second->bundle_uri() == lilv_node_as_string(bundle)) {
+ p.second->set_is_zombie(true);
+ _update.del(p.second->uri());
+ }
+ }
lilv_world_unload_bundle(lworld, bundle);
+ _engine.block_factory()->refresh();
lilv_node_free(bundle);
} else {
_status = Status::BAD_VALUE;
@@ -423,6 +430,14 @@ Delta::pre_process()
LilvNode* bundle = get_file_node(lworld, uris, value);
if (bundle) {
lilv_world_load_bundle(lworld, bundle);
+ const std::set<PluginImpl*> new_plugins =
+ _engine.block_factory()->refresh();
+
+ for (PluginImpl* p : new_plugins) {
+ if (p->bundle_uri() == lilv_node_as_string(bundle)) {
+ _update.put_plugin(p);
+ }
+ }
lilv_node_free(bundle);
} else {
_status = Status::BAD_VALUE;
@@ -568,6 +583,8 @@ Delta::post_process()
}
if (respond() == Status::SUCCESS) {
+ _update.send(_engine.broadcaster());
+
switch (_type) {
case Type::SET:
/* Kludge to avoid feedback for set events only. The GUI
@@ -583,7 +600,7 @@ Delta::post_process()
case Type::PUT:
if (_type == Type::PUT && _subject.substr(0, 5) == "file:") {
// Preset save
- Get::Response response;
+ ClientUpdate response;
response.put(_preset->uri(), _preset->properties());
response.send(_engine.broadcaster());
} else {
diff --git a/src/server/events/Delta.hpp b/src/server/events/Delta.hpp
index 0782238c..569b3e92 100644
--- a/src/server/events/Delta.hpp
+++ b/src/server/events/Delta.hpp
@@ -98,6 +98,7 @@ private:
Raul::URI _subject;
Resource::Properties _properties;
Resource::Properties _remove;
+ ClientUpdate _update;
Ingen::Resource* _object;
GraphImpl* _graph;
CompiledGraph* _compiled_graph;
diff --git a/src/server/events/Get.cpp b/src/server/events/Get.cpp
index 6d49657d..fa56f23a 100644
--- a/src/server/events/Get.cpp
+++ b/src/server/events/Get.cpp
@@ -34,118 +34,6 @@ namespace Ingen {
namespace Server {
namespace Events {
-void
-Get::Response::put(const Raul::URI& uri,
- const Resource::Properties& props,
- Resource::Graph ctx)
-{
- const Get::Response::Put put = { uri, props, ctx };
- puts.push_back(put);
-}
-
-void
-Get::Response::put_port(const PortImpl* port)
-{
- if (port->is_a(PortType::CONTROL) || port->is_a(PortType::CV)) {
- Resource::Properties props = port->properties();
- props.erase(port->bufs().uris().ingen_value);
- props.insert(std::make_pair(port->bufs().uris().ingen_value,
- port->value()));
- put(port->uri(), props);
- } else {
- put(port->uri(), port->properties());
- }
-}
-
-void
-Get::Response::put_block(const BlockImpl* block)
-{
- const PluginImpl* const plugin = block->plugin_impl();
- const URIs& uris = plugin->uris();
-
- if (uris.ingen_Graph == plugin->type()) {
- put_graph((const GraphImpl*)block);
- } else {
- put(block->uri(), block->properties());
- for (size_t j = 0; j < block->num_ports(); ++j) {
- put_port(block->port_impl(j));
- }
- }
-}
-
-void
-Get::Response::put_graph(const GraphImpl* graph)
-{
- put(graph->uri(),
- graph->properties(Resource::Graph::INTERNAL),
- Resource::Graph::INTERNAL);
-
- put(graph->uri(),
- graph->properties(Resource::Graph::EXTERNAL),
- Resource::Graph::EXTERNAL);
-
- // Enqueue blocks
- for (const auto& b : graph->blocks()) {
- put_block(&b);
- }
-
- // Enqueue ports
- for (uint32_t i = 0; i < graph->num_ports_non_rt(); ++i) {
- put_port(graph->port_impl(i));
- }
-
- // Enqueue arcs
- for (const auto& a : graph->arcs()) {
- const SPtr<const Arc> arc = a.second;
- const Connect connect = { arc->tail_path(), arc->head_path() };
- connects.push_back(connect);
- }
-}
-
-void
-Get::Response::put_plugin(PluginImpl* plugin)
-{
- put(plugin->uri(), plugin->properties());
-
- for (const auto& p : plugin->presets()) {
- put_preset(plugin->uris(), plugin->uri(), p.first, p.second);
- }
-}
-
-void
-Get::Response::put_preset(const URIs& uris,
- const Raul::URI& plugin,
- const Raul::URI& preset,
- const std::string& label)
-{
- Resource::Properties props{
- { uris.rdf_type, uris.pset_Preset.urid },
- { uris.rdfs_label, uris.forge.alloc(label) },
- { uris.lv2_appliesTo, uris.forge.make_urid(plugin) }};
- put(preset, props);
-}
-
-/** Returns true if a is closer to the root than b. */
-static inline bool
-put_higher_than(const Get::Response::Put& a, const Get::Response::Put& b)
-{
- return (std::count(a.uri.begin(), a.uri.end(), '/') <
- std::count(b.uri.begin(), b.uri.end(), '/'));
-}
-
-void
-Get::Response::send(Interface* dest)
-{
- // Sort puts by increasing depth so parents are sent first
- std::stable_sort(puts.begin(), puts.end(), put_higher_than);
- for (const Response::Put& put : puts) {
- dest->put(put.uri, put.properties, put.ctx);
- }
- for (const Response::Connect& connect : connects) {
- dest->connect(connect.tail, connect.head);
- }
-}
-
Get::Get(Engine& engine,
SPtr<Interface> client,
int32_t id,
diff --git a/src/server/events/Get.hpp b/src/server/events/Get.hpp
index f24e42e0..fc5fcb13 100644
--- a/src/server/events/Get.hpp
+++ b/src/server/events/Get.hpp
@@ -19,8 +19,9 @@
#include <vector>
-#include "Event.hpp"
#include "BlockFactory.hpp"
+#include "ClientUpdate.hpp"
+#include "Event.hpp"
#include "types.hpp"
namespace Ingen {
@@ -50,52 +51,12 @@ public:
void execute(ProcessContext& context) {}
void post_process();
- /** A sequence of puts and connects to respond to client with.
- * This is constructed in the pre_process() and later sent in
- * post_process() to avoid the need to lock.
- *
- * Ideally events (both server and client) would always be in a standard
- * message format so the Ingen protocol went the whole way through the
- * system, but for now things are controlled procedurally through
- * Interface, so this interim structure is necessary.
- */
- struct Response {
- void put(const Raul::URI& uri,
- const Resource::Properties& props,
- Resource::Graph ctx=Resource::Graph::DEFAULT);
-
- void put_port(const PortImpl* port);
- void put_block(const BlockImpl* block);
- void put_graph(const GraphImpl* graph);
- void put_plugin(PluginImpl* plugin);
- void put_preset(const URIs& uris,
- const Raul::URI& plugin,
- const Raul::URI& preset,
- const std::string& label);
-
- void send(Interface* dest);
-
- struct Put {
- Raul::URI uri;
- Resource::Properties properties;
- Resource::Graph ctx;
- };
-
- struct Connect {
- Raul::Path tail;
- Raul::Path head;
- };
-
- std::vector<Put> puts;
- std::vector<Connect> connects;
- };
-
private:
const Raul::URI _uri;
const Node* _object;
PluginImpl* _plugin;
BlockFactory::Plugins _plugins;
- Response _response;
+ ClientUpdate _response;
};
} // namespace Events
diff --git a/src/server/internals/Controller.cpp b/src/server/internals/Controller.cpp
index f6555a96..62400efa 100644
--- a/src/server/internals/Controller.cpp
+++ b/src/server/internals/Controller.cpp
@@ -41,12 +41,12 @@ InternalPlugin* ControllerNode::internal_plugin(URIs& uris) {
uris, Raul::URI(NS_INTERNALS "Controller"), Raul::Symbol("controller"));
}
-ControllerNode::ControllerNode(InternalPlugin* plugin,
- BufferFactory& bufs,
- const Raul::Symbol& symbol,
- bool polyphonic,
- GraphImpl* parent,
- SampleRate srate)
+ControllerNode::ControllerNode(InternalPlugin* plugin,
+ BufferFactory& bufs,
+ const Raul::Symbol& symbol,
+ bool polyphonic,
+ GraphImpl* parent,
+ SampleRate srate)
: InternalBlock(plugin, symbol, false, parent, srate)
, _learning(false)
{
diff --git a/src/server/internals/Controller.hpp b/src/server/internals/Controller.hpp
index 4eb1f508..1c3e05f0 100644
--- a/src/server/internals/Controller.hpp
+++ b/src/server/internals/Controller.hpp
@@ -38,12 +38,12 @@ namespace Internals {
class ControllerNode : public InternalBlock
{
public:
- ControllerNode(InternalPlugin* plugin,
- BufferFactory& bufs,
- const Raul::Symbol& symbol,
- bool polyphonic,
- GraphImpl* parent,
- SampleRate srate);
+ ControllerNode(InternalPlugin* plugin,
+ BufferFactory& bufs,
+ const Raul::Symbol& symbol,
+ bool polyphonic,
+ GraphImpl* parent,
+ SampleRate srate);
void run(ProcessContext& context);
diff --git a/src/server/wscript b/src/server/wscript
index 7dde5361..ddf47889 100644
--- a/src/server/wscript
+++ b/src/server/wscript
@@ -9,6 +9,7 @@ def build(bld):
Broadcaster.cpp
Buffer.cpp
BufferFactory.cpp
+ ClientUpdate.cpp
Context.cpp
ControlBindings.cpp
DuplexPort.cpp