diff options
author | David Robillard <d@drobilla.net> | 2017-12-16 22:27:22 +0100 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2017-12-16 22:27:22 +0100 |
commit | f2d3c77c9a470f20506c90098ab5cf4d3e5c9eff (patch) | |
tree | 38b27fed96f39bd1a3b255206f3af93c8f4708af | |
parent | d078741456bacf08e2bc3e5d6cda58c2d16ef029 (diff) | |
download | ingen-f2d3c77c9a470f20506c90098ab5cf4d3e5c9eff.tar.gz ingen-f2d3c77c9a470f20506c90098ab5cf4d3e5c9eff.tar.bz2 ingen-f2d3c77c9a470f20506c90098ab5cf4d3e5c9eff.zip |
Adjust indices when ports are deleted
-rw-r--r-- | src/server/GraphImpl.cpp | 38 | ||||
-rw-r--r-- | src/server/GraphImpl.hpp | 1 | ||||
-rw-r--r-- | src/server/PortImpl.cpp | 4 | ||||
-rw-r--r-- | src/server/PortImpl.hpp | 1 | ||||
-rw-r--r-- | src/server/events/CreatePort.cpp | 29 | ||||
-rw-r--r-- | src/server/events/Delete.cpp | 38 | ||||
-rw-r--r-- | src/server/events/Delete.hpp | 7 | ||||
-rw-r--r-- | src/server/events/Delta.cpp | 8 | ||||
-rw-r--r-- | src/server/events/Delta.hpp | 1 |
9 files changed, 110 insertions, 17 deletions
diff --git a/src/server/GraphImpl.cpp b/src/server/GraphImpl.cpp index adfb433d..389fd182 100644 --- a/src/server/GraphImpl.cpp +++ b/src/server/GraphImpl.cpp @@ -312,6 +312,27 @@ GraphImpl::num_ports_non_rt() const return _inputs.size() + _outputs.size(); } +bool +GraphImpl::has_port_with_index(uint32_t index) const +{ + BufferFactory& bufs = *_engine.buffer_factory(); + const auto index_atom = bufs.forge().make(int32_t(index)); + + for (auto p = _inputs.begin(); p != _inputs.end(); ++p) { + if (p->has_property(bufs.uris().lv2_index, index_atom)) { + return true; + } + } + + for (auto p = _outputs.begin(); p != _outputs.end(); ++p) { + if (p->has_property(bufs.uris().lv2_index, index_atom)) { + return true; + } + } + + return false; +} + void GraphImpl::remove_port(DuplexPort& port) { @@ -337,13 +358,18 @@ GraphImpl::build_ports_array(Raul::Maid& maid) const size_t n = _inputs.size() + _outputs.size(); MPtr<Ports> result = maid.make_managed<Ports>(n); - size_t i = 0; - - for (PortList::iterator p = _inputs.begin(); p != _inputs.end(); ++p, ++i) - result->at(i) = &*p; + std::map<size_t, DuplexPort*> ports; + for (PortList::iterator p = _inputs.begin(); p != _inputs.end(); ++p) { + ports.emplace(p->index(), &*p); + } + for (PortList::iterator p = _outputs.begin(); p != _outputs.end(); ++p) { + ports.emplace(p->index(), &*p); + } - for (PortList::iterator p = _outputs.begin(); p != _outputs.end(); ++p, ++i) - result->at(i) = &*p; + size_t i = 0; + for (const auto& p : ports) { + result->at(i++) = p.second; + } assert(i == n); diff --git a/src/server/GraphImpl.hpp b/src/server/GraphImpl.hpp index 6064624a..352c0957 100644 --- a/src/server/GraphImpl.hpp +++ b/src/server/GraphImpl.hpp @@ -117,6 +117,7 @@ public: const Blocks& blocks() const { return _blocks; } uint32_t num_ports_non_rt() const; + bool has_port_with_index(uint32_t index) const; typedef boost::intrusive::slist< DuplexPort, boost::intrusive::constant_time_size<true> > PortList; diff --git a/src/server/PortImpl.cpp b/src/server/PortImpl.cpp index 9a701d39..3302ff95 100644 --- a/src/server/PortImpl.cpp +++ b/src/server/PortImpl.cpp @@ -84,7 +84,9 @@ PortImpl::PortImpl(BufferFactory& bufs, set_type(type, buffer_type); - set_property(uris.lv2_index, bufs.forge().make((int32_t)index), Resource::Graph::INTERNAL); + remove_property(uris.lv2_index, uris.patch_wildcard); + set_property(uris.lv2_index, bufs.forge().make((int32_t)index)); + if (has_value()) { set_property(uris.ingen_value, value); } diff --git a/src/server/PortImpl.hpp b/src/server/PortImpl.hpp index 33c4adac..6f04a552 100644 --- a/src/server/PortImpl.hpp +++ b/src/server/PortImpl.hpp @@ -194,6 +194,7 @@ public: virtual void recycle_buffers(); uint32_t index() const { return _index; } + void set_index(RunContext&, uint32_t index) { _index = index; } inline bool is_a(PortType type) const { return _type == type; } diff --git a/src/server/events/CreatePort.cpp b/src/server/events/CreatePort.cpp index 3adf2f8b..bc43ca41 100644 --- a/src/server/events/CreatePort.cpp +++ b/src/server/events/CreatePort.cpp @@ -115,14 +115,22 @@ CreatePort::pre_process(PreProcessContext& ctx) typedef Properties::const_iterator PropIter; PropIter index_i = _properties.find(uris.lv2_index); - if (index_i == _properties.end()) { + int32_t index = 0; + if (index_i != _properties.end()) { + // Ensure given index is sane and not taken + if (index_i->second.type() != uris.forge.Int) { + return Event::pre_process_done(Status::BAD_REQUEST); + } + + index = index_i->second.get<int32_t>(); + if (_graph->has_port_with_index(index)) { + return Event::pre_process_done(Status::BAD_INDEX); + } + } else { // No index given, append - index_i = _properties.insert( - std::make_pair(uris.lv2_index, - _engine.world()->forge().make(old_n_ports))); - } else if (index_i->second.type() != uris.forge.Int || - index_i->second.get<int32_t>() != old_n_ports) { - return Event::pre_process_done(Status::BAD_INDEX, _path); + index = old_n_ports; + index_i = _properties.emplace(uris.lv2_index, + _engine.world()->forge().make(index)); } const PropIter poly_i = _properties.find(uris.ingen_polyphonic); @@ -138,7 +146,7 @@ CreatePort::pre_process(PreProcessContext& ctx) // Create port _graph_port = new DuplexPort(bufs, _graph, Raul::Symbol(_path.symbol()), - _graph->num_ports_non_rt(), + index, polyphonic, _port_type, _buf_type, buf_size, value, _flow == Flow::OUTPUT); @@ -164,7 +172,6 @@ CreatePort::pre_process(PreProcessContext& ctx) assert(_graph_port->index() == (uint32_t)index_i->second.get<int32_t>()); assert(_graph->num_ports_non_rt() == (uint32_t)old_n_ports + 1); - assert(_graph_port->index() == (uint32_t)old_n_ports); assert(_ports_array->size() == _graph->num_ports_non_rt()); assert(_graph_port->index() < _ports_array->size()); return Event::pre_process_done(Status::SUCCESS); @@ -177,7 +184,9 @@ CreatePort::execute(RunContext& context) const MPtr<GraphImpl::Ports>& old_ports = _graph->external_ports(); if (old_ports) { for (uint32_t i = 0; i < old_ports->size(); ++i) { - (*_ports_array)[i] = (*old_ports)[i]; + const auto* const old_port = (*old_ports)[i]; + assert(old_port->index() < _ports_array->size()); + (*_ports_array)[old_port->index()] = (*old_ports)[i]; } } assert(!(*_ports_array)[_graph_port->index()]); diff --git a/src/server/events/Delete.cpp b/src/server/events/Delete.cpp index 6153540e..0a065a8a 100644 --- a/src/server/events/Delete.cpp +++ b/src/server/events/Delete.cpp @@ -61,6 +61,7 @@ Delete::~Delete() bool Delete::pre_process(PreProcessContext& ctx) { + const Ingen::URIs& uris = _engine.world()->uris(); if (_path.is_root() || _path == "/control" || _path == "/notify") { return Event::pre_process_done(Status::NOT_DELETABLE, _path); } @@ -104,6 +105,19 @@ Delete::pre_process(PreProcessContext& ctx) if (parent->enabled()) { _ports_array = parent->build_ports_array(*_engine.maid()); assert(_ports_array->size() == parent->num_ports_non_rt()); + + // Adjust port indices if necessary and record changes for later + for (size_t i = 0; i < _ports_array->size(); ++i) { + PortImpl* const port = _ports_array->at(i); + if (port->index() != i) { + _port_index_changes.emplace( + port->path(), std::make_pair(port->index(), i)); + port->remove_property(uris.lv2_index, uris.patch_wildcard); + port->set_property( + uris.lv2_index, + _engine.buffer_factory()->forge().make((int32_t)i)); + } + } } if (!parent->parent()) { @@ -131,6 +145,15 @@ Delete::execute(RunContext& context) GraphImpl* parent = _block ? _block->parent_graph() : NULL; if (_port) { + // Adjust port indices if necessary + for (size_t i = 0; i < _ports_array->size(); ++i) { + PortImpl* const port = _ports_array->at(i); + if (port->index() != i) { + port->set_index(context, i); + } + } + + // Replace ports array in graph parent = _port->parent_graph(); parent->set_external_ports(std::move(_ports_array)); @@ -165,12 +188,27 @@ Delete::post_process() void Delete::undo(Interface& target) { + const Ingen::URIs& uris = _engine.world()->uris(); + Ingen::Forge& forge = _engine.buffer_factory()->forge(); + auto i = _removed_objects.find(_path); if (i != _removed_objects.end()) { + // Undo disconnect if (_disconnect_event) { _disconnect_event->undo(target); } + + // Put deleted item back target.put(_uri, i->second->properties()); + + // Adjust port indices + for (const auto& c : _port_index_changes) { + if (c.first != _uri) { + target.set_property(path_to_uri(c.first), + uris.lv2_index, + forge.make(int32_t(c.second.first))); + } + } } } diff --git a/src/server/events/Delete.hpp b/src/server/events/Delete.hpp index 0003e821..03c994fe 100644 --- a/src/server/events/Delete.hpp +++ b/src/server/events/Delete.hpp @@ -17,6 +17,9 @@ #ifndef INGEN_EVENTS_DELETE_HPP #define INGEN_EVENTS_DELETE_HPP +#include <map> +#include <vector> + #include "ingen/Store.hpp" #include "CompiledGraph.hpp" @@ -60,6 +63,9 @@ public: void undo(Interface& target); private: + using IndexChange = std::pair<uint32_t, uint32_t>; + using IndexChanges = std::map<Raul::Path, IndexChange>; + Raul::URI _uri; Raul::Path _path; SPtr<BlockImpl> _block; ///< Non-NULL iff a block @@ -69,6 +75,7 @@ private: MPtr<CompiledGraph> _compiled_graph; ///< Graph's new process order DisconnectAll* _disconnect_event; Store::Objects _removed_objects; + IndexChanges _port_index_changes; std::vector<ControlBindings::Binding*> _removed_bindings; }; diff --git a/src/server/events/Delta.cpp b/src/server/events/Delta.cpp index 0c50aabc..fccb887c 100644 --- a/src/server/events/Delta.cpp +++ b/src/server/events/Delta.cpp @@ -312,6 +312,9 @@ Delta::pre_process(PreProcessContext& ctx) } else { _status = Status::BAD_OBJECT_TYPE; } + } else if (key == uris.lv2_index) { + op = SpecialType::PORT_INDEX; + port->set_property(key, value); } } else if ((block = dynamic_cast<BlockImpl*>(_object))) { if (key == uris.midi_binding && value == uris.patch_wildcard) { @@ -498,6 +501,11 @@ Delta::execute(RunContext& context) _status = Status::INTERNAL_ERROR; } break; + case SpecialType::PORT_INDEX: + if (port) { + port->set_index(context, value.get<int32_t>()); + } + break; case SpecialType::CONTROL_BINDING: if (port) { if (!_engine.control_bindings()->set_port_binding(context, port, _binding, value)) { diff --git a/src/server/events/Delta.hpp b/src/server/events/Delta.hpp index 40c65ef8..24d58b99 100644 --- a/src/server/events/Delta.hpp +++ b/src/server/events/Delta.hpp @@ -87,6 +87,7 @@ private: ENABLE_BROADCAST, POLYPHONY, POLYPHONIC, + PORT_INDEX, CONTROL_BINDING, PRESET, LOADED_BUNDLE |