summaryrefslogtreecommitdiffstats
path: root/include/ingen/client
diff options
context:
space:
mode:
Diffstat (limited to 'include/ingen/client')
-rw-r--r--include/ingen/client/ArcModel.hpp67
-rw-r--r--include/ingen/client/BlockModel.hpp117
-rw-r--r--include/ingen/client/ClientStore.hpp132
-rw-r--r--include/ingen/client/GraphModel.hpp82
-rw-r--r--include/ingen/client/ObjectModel.hpp99
-rw-r--r--include/ingen/client/PluginModel.hpp127
-rw-r--r--include/ingen/client/PluginUI.hpp116
-rw-r--r--include/ingen/client/PortModel.hpp97
-rw-r--r--include/ingen/client/SigClientInterface.hpp63
-rw-r--r--include/ingen/client/SocketClient.hpp80
-rw-r--r--include/ingen/client/signal.hpp31
11 files changed, 1011 insertions, 0 deletions
diff --git a/include/ingen/client/ArcModel.hpp b/include/ingen/client/ArcModel.hpp
new file mode 100644
index 00000000..e42dd7bd
--- /dev/null
+++ b/include/ingen/client/ArcModel.hpp
@@ -0,0 +1,67 @@
+/*
+ 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_CLIENT_ARCMODEL_HPP
+#define INGEN_CLIENT_ARCMODEL_HPP
+
+#include "ingen/Arc.hpp"
+#include "ingen/client/PortModel.hpp"
+#include "ingen/ingen.h"
+#include "ingen/types.hpp"
+#include "raul/Path.hpp"
+
+#include <cassert>
+
+namespace ingen {
+namespace client {
+
+class ClientStore;
+
+/** Class to represent a port->port connections in the engine.
+ *
+ * @ingroup IngenClient
+ */
+class INGEN_API ArcModel : public Arc
+{
+public:
+ SPtr<PortModel> tail() const { return _tail; }
+ SPtr<PortModel> head() const { return _head; }
+
+ const Raul::Path& tail_path() const override { return _tail->path(); }
+ const Raul::Path& head_path() const override { return _head->path(); }
+
+private:
+ friend class ClientStore;
+
+ ArcModel(SPtr<PortModel> tail, SPtr<PortModel> head)
+ : _tail(std::move(tail))
+ , _head(std::move(head))
+ {
+ assert(_tail);
+ assert(_head);
+ assert(_tail->parent());
+ assert(_head->parent());
+ assert(_tail->path() != _head->path());
+ }
+
+ const SPtr<PortModel> _tail;
+ const SPtr<PortModel> _head;
+};
+
+} // namespace client
+} // namespace ingen
+
+#endif // INGEN_CLIENT_ARCMODEL_HPP
diff --git a/include/ingen/client/BlockModel.hpp b/include/ingen/client/BlockModel.hpp
new file mode 100644
index 00000000..d003b7d1
--- /dev/null
+++ b/include/ingen/client/BlockModel.hpp
@@ -0,0 +1,117 @@
+/*
+ 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_CLIENT_BLOCKMODEL_HPP
+#define INGEN_CLIENT_BLOCKMODEL_HPP
+
+#include "ingen/Node.hpp"
+#include "ingen/client/ObjectModel.hpp"
+#include "ingen/client/PluginModel.hpp"
+#include "ingen/ingen.h"
+#include "ingen/types.hpp"
+
+#include <algorithm>
+#include <cstdint>
+#include <string>
+#include <vector>
+
+namespace Raul { class Path; }
+
+namespace ingen {
+
+class URIs;
+
+namespace client {
+
+class PortModel;
+
+/** Block model class, used by the client to store engine's state.
+ *
+ * @ingroup IngenClient
+ */
+class INGEN_API BlockModel : public ObjectModel
+{
+public:
+ BlockModel(const BlockModel& copy);
+ virtual ~BlockModel();
+
+ GraphType graph_type() const override { return Node::GraphType::BLOCK; }
+
+ using Ports = std::vector<SPtr<const PortModel>>;
+
+ SPtr<const PortModel> get_port(const Raul::Symbol& symbol) const;
+ SPtr<const PortModel> get_port(uint32_t index) const;
+
+ Node* port(uint32_t index) const override;
+
+ const URI& plugin_uri() const { return _plugin_uri; }
+ const Resource* plugin() const override { return _plugin.get(); }
+ Resource* plugin() { return _plugin.get(); }
+ SPtr<PluginModel> plugin_model() const { return _plugin; }
+ uint32_t num_ports() const override { return _ports.size(); }
+ const Ports& ports() const { return _ports; }
+
+ void default_port_value_range(const SPtr<const PortModel>& port,
+ float& min,
+ float& max,
+ uint32_t srate = 1) const;
+
+ void port_value_range(const SPtr<const PortModel>& port,
+ float& min,
+ float& max,
+ uint32_t srate = 1) const;
+
+ std::string label() const;
+ std::string port_label(const SPtr<const PortModel>& port) const;
+
+ // Signals
+ INGEN_SIGNAL(new_port, void, SPtr<const PortModel>)
+ INGEN_SIGNAL(removed_port, void, SPtr<const PortModel>)
+
+protected:
+ friend class ClientStore;
+
+ BlockModel(URIs& uris, URI plugin_uri, const Raul::Path& path);
+
+ BlockModel(URIs& uris,
+ const SPtr<PluginModel>& plugin,
+ const Raul::Path& path);
+
+ explicit BlockModel(const Raul::Path& path);
+
+ void add_child(const SPtr<ObjectModel>& c) override;
+ bool remove_child(const SPtr<ObjectModel>& c) override;
+ void add_port(const SPtr<PortModel>& pm);
+ void remove_port(const SPtr<PortModel>& port);
+ void remove_port(const Raul::Path& port_path);
+ void set(const SPtr<ObjectModel>& model) override;
+
+ virtual void clear();
+
+ Ports _ports; ///< Vector of ports
+ URI _plugin_uri; ///< Plugin URI (if PluginModel is unknown)
+ SPtr<PluginModel> _plugin; ///< The plugin this block is an instance of
+
+private:
+ mutable uint32_t _num_values; ///< Size of _min_values and _max_values
+ mutable float* _min_values; ///< Port min values (cached for LV2)
+ mutable float* _max_values; ///< Port max values (cached for LV2)
+};
+
+} // namespace client
+} // namespace ingen
+
+#endif // INGEN_CLIENT_BLOCKMODEL_HPP
diff --git a/include/ingen/client/ClientStore.hpp b/include/ingen/client/ClientStore.hpp
new file mode 100644
index 00000000..54eaf373
--- /dev/null
+++ b/include/ingen/client/ClientStore.hpp
@@ -0,0 +1,132 @@
+/*
+ This file is part of Ingen.
+ Copyright 2007-2016 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_CLIENT_CLIENTSTORE_HPP
+#define INGEN_CLIENT_CLIENTSTORE_HPP
+
+#include "ingen/Interface.hpp"
+#include "ingen/Message.hpp"
+#include "ingen/Store.hpp"
+#include "ingen/URI.hpp"
+#include "ingen/client/signal.hpp"
+#include "ingen/ingen.h"
+#include "ingen/types.hpp"
+#include "raul/Path.hpp"
+
+#include <map>
+
+namespace Raul {
+class Path;
+} // namespace Raul
+
+namespace ingen {
+
+class Atom;
+class Log;
+class Node;
+class Resource;
+class URIs;
+
+namespace client {
+
+class BlockModel;
+class GraphModel;
+class ObjectModel;
+class PluginModel;
+class PortModel;
+class SigClientInterface;
+
+/** Automatically manages models of objects in the engine.
+ *
+ * @ingroup IngenClient
+ */
+class INGEN_API ClientStore : public Store
+ , public Interface
+ , public INGEN_TRACKABLE {
+public:
+ ClientStore(
+ URIs& uris,
+ Log& log,
+ const SPtr<SigClientInterface>& emitter = SPtr<SigClientInterface>());
+
+ URI uri() const override { return URI("ingen:/clients/store"); }
+
+ SPtr<const ObjectModel> object(const Raul::Path& path) const;
+ SPtr<const PluginModel> plugin(const URI& uri) const;
+ SPtr<const Resource> resource(const URI& uri) const;
+
+ void clear();
+
+ using Plugins = std::map<const URI, SPtr<PluginModel>>;
+
+ SPtr<const Plugins> plugins() const { return _plugins; }
+ SPtr<Plugins> plugins() { return _plugins; }
+ void set_plugins(SPtr<Plugins> p) { _plugins = std::move(p); }
+
+ URIs& uris() { return _uris; }
+
+ void message(const Message& msg) override;
+
+ void operator()(const BundleBegin&) {}
+ void operator()(const BundleEnd&) {}
+ void operator()(const Connect&);
+ void operator()(const Copy&);
+ void operator()(const Del&);
+ void operator()(const Delta&);
+ void operator()(const Disconnect&);
+ void operator()(const DisconnectAll&);
+ void operator()(const Error&) {}
+ void operator()(const Get&) {}
+ void operator()(const Move&);
+ void operator()(const Put&);
+ void operator()(const Redo&) {}
+ void operator()(const Response&) {}
+ void operator()(const SetProperty&);
+ void operator()(const Undo&) {}
+
+ INGEN_SIGNAL(new_object, void, SPtr<ObjectModel>)
+ INGEN_SIGNAL(new_plugin, void, SPtr<PluginModel>)
+ INGEN_SIGNAL(plugin_deleted, void, URI)
+
+private:
+ SPtr<ObjectModel> _object(const Raul::Path& path);
+ SPtr<PluginModel> _plugin(const URI& uri);
+ SPtr<PluginModel> _plugin(const Atom& uri);
+ SPtr<Resource> _resource(const URI& uri);
+
+ void add_object(const SPtr<ObjectModel>& object);
+ SPtr<ObjectModel> remove_object(const Raul::Path& path);
+
+ void add_plugin(const SPtr<PluginModel>& pm);
+
+ SPtr<GraphModel> connection_graph(const Raul::Path& tail_path,
+ const Raul::Path& head_path);
+
+ // Slots for SigClientInterface signals
+ bool attempt_connection(const Raul::Path& tail_path,
+ const Raul::Path& head_path);
+
+ URIs& _uris;
+ Log& _log;
+ SPtr<SigClientInterface> _emitter;
+
+ SPtr<Plugins> _plugins; ///< Map, keyed by plugin URI
+};
+
+} // namespace client
+} // namespace ingen
+
+#endif // INGEN_CLIENT_CLIENTSTORE_HPP
diff --git a/include/ingen/client/GraphModel.hpp b/include/ingen/client/GraphModel.hpp
new file mode 100644
index 00000000..2248e7e3
--- /dev/null
+++ b/include/ingen/client/GraphModel.hpp
@@ -0,0 +1,82 @@
+/*
+ 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_CLIENT_GRAPHMODEL_HPP
+#define INGEN_CLIENT_GRAPHMODEL_HPP
+
+#include "ingen/Node.hpp"
+#include "ingen/URIs.hpp"
+#include "ingen/client/BlockModel.hpp"
+#include "ingen/client/signal.hpp"
+#include "ingen/ingen.h"
+#include "ingen/types.hpp"
+
+#include <cstdint>
+
+namespace ingen {
+namespace client {
+
+class ArcModel;
+class ClientStore;
+
+/** Client's model of a graph.
+ *
+ * @ingroup IngenClient
+ */
+class INGEN_API GraphModel : public BlockModel
+{
+public:
+ /* WARNING: Copy constructor creates a shallow copy WRT connections */
+
+ GraphType graph_type() const override { return Node::GraphType::GRAPH; }
+
+ SPtr<ArcModel> get_arc(const ingen::Node* tail,
+ const ingen::Node* head);
+
+ bool enabled() const;
+ bool polyphonic() const;
+ uint32_t internal_poly() const;
+
+ // Signals
+ INGEN_SIGNAL(new_block, void, SPtr<BlockModel>)
+ INGEN_SIGNAL(removed_block, void, SPtr<BlockModel>)
+ INGEN_SIGNAL(new_arc, void, SPtr<ArcModel>)
+ INGEN_SIGNAL(removed_arc, void, SPtr<ArcModel>)
+
+private:
+ friend class ClientStore;
+
+ GraphModel(URIs& uris, const Raul::Path& graph_path)
+ : BlockModel(uris,
+ static_cast<const URI&>(uris.ingen_Graph),
+ graph_path)
+ {
+ }
+
+ void clear() override;
+ void add_child(const SPtr<ObjectModel>& c) override;
+ bool remove_child(const SPtr<ObjectModel>& o) override;
+ void remove_arcs_on(const SPtr<PortModel>& p);
+
+ void add_arc(const SPtr<ArcModel>& arc);
+ void remove_arc(const ingen::Node* tail,
+ const ingen::Node* head);
+};
+
+} // namespace client
+} // namespace ingen
+
+#endif // INGEN_CLIENT_GRAPHMODEL_HPP
diff --git a/include/ingen/client/ObjectModel.hpp b/include/ingen/client/ObjectModel.hpp
new file mode 100644
index 00000000..39729377
--- /dev/null
+++ b/include/ingen/client/ObjectModel.hpp
@@ -0,0 +1,99 @@
+/*
+ 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/>.
+*/
+
+/**
+ @defgroup IngenClient Client-Side Models and Utilities
+*/
+
+#ifndef INGEN_CLIENT_OBJECTMODEL_HPP
+#define INGEN_CLIENT_OBJECTMODEL_HPP
+
+#include "ingen/Node.hpp"
+#include "ingen/URI.hpp"
+#include "ingen/URIs.hpp"
+#include "ingen/client/signal.hpp"
+#include "ingen/ingen.h"
+#include "ingen/types.hpp"
+#include "raul/Path.hpp"
+#include "raul/Symbol.hpp"
+
+namespace ingen {
+
+class Atom;
+
+namespace client {
+
+/** Base class for all Node models (BlockModel, GraphModel, PortModel).
+ *
+ * There are no non-const public methods intentionally, models are not allowed
+ * to be manipulated directly by anything (but the Store) because of the
+ * asynchronous nature of engine control. To change something, use the
+ * controller (which the model probably shouldn't have a reference to but oh
+ * well, it reduces Collection Hell) and wait for the result (as a signal
+ * from this Model).
+ *
+ * @ingroup IngenClient
+ */
+class INGEN_API ObjectModel : public Node
+{
+public:
+ bool is_a(const URIs::Quark& type) const;
+
+ const Atom& get_property(const URI& key) const override;
+
+ void on_property(const URI& uri, const Atom& value) override;
+ void on_property_removed(const URI& uri, const Atom& value) override;
+
+ const Raul::Path& path() const override { return _path; }
+ const Raul::Symbol& symbol() const override { return _symbol; }
+
+ SPtr<ObjectModel> parent() const { return _parent; }
+ bool polyphonic() const;
+
+ Node* graph_parent() const override { return _parent.get(); }
+
+ // Signals
+ INGEN_SIGNAL(new_child, void, SPtr<ObjectModel>)
+ INGEN_SIGNAL(removed_child, void, SPtr<ObjectModel>)
+ INGEN_SIGNAL(property, void, const URI&, const Atom&)
+ INGEN_SIGNAL(property_removed, void, const URI&, const Atom&)
+ INGEN_SIGNAL(destroyed, void)
+ INGEN_SIGNAL(moved, void)
+
+protected:
+ friend class ClientStore;
+
+ ObjectModel(URIs& uris, const Raul::Path& path);
+ ObjectModel(const ObjectModel& copy);
+
+ void set_path(const Raul::Path& p) override;
+ virtual void set_parent(const SPtr<ObjectModel>& p);
+ virtual void add_child(const SPtr<ObjectModel>& c) {}
+ virtual bool remove_child(const SPtr<ObjectModel>& c) { return true; }
+
+ virtual void set(const SPtr<ObjectModel>& o);
+
+ SPtr<ObjectModel> _parent;
+
+private:
+ Raul::Path _path;
+ Raul::Symbol _symbol;
+};
+
+} // namespace client
+} // namespace ingen
+
+#endif // INGEN_CLIENT_OBJECTMODEL_HPP
diff --git a/include/ingen/client/PluginModel.hpp b/include/ingen/client/PluginModel.hpp
new file mode 100644
index 00000000..dbefaf95
--- /dev/null
+++ b/include/ingen/client/PluginModel.hpp
@@ -0,0 +1,127 @@
+/*
+ This file is part of Ingen.
+ Copyright 2007-2017 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_CLIENT_PLUGINMODEL_HPP
+#define INGEN_CLIENT_PLUGINMODEL_HPP
+
+#include "ingen/Forge.hpp"
+#include "ingen/Resource.hpp"
+#include "ingen/World.hpp"
+#include "ingen/client/signal.hpp"
+#include "ingen/ingen.h"
+#include "ingen/types.hpp"
+#include "lilv/lilv.h"
+#include "raul/Symbol.hpp"
+#include "sord/sordmm.hpp"
+
+#include <cstdint>
+#include <map>
+#include <string>
+
+namespace ingen {
+
+class URIs;
+
+namespace client {
+
+class GraphModel;
+class BlockModel;
+class PluginUI;
+
+/** Model for a plugin available for loading.
+ *
+ * @ingroup IngenClient
+ */
+class INGEN_API PluginModel : public ingen::Resource
+{
+public:
+ PluginModel(URIs& uris,
+ const URI& uri,
+ const Atom& type,
+ const ingen::Properties& properties);
+
+ const Atom& type() const { return _type; }
+
+ URI type_uri() const
+ {
+ return URI(_type.is_valid() ? _uris.forge.str(_type, false)
+ : "http://www.w3.org/2002/07/owl#Nothing");
+ }
+
+ const Atom& get_property(const URI& key) const override;
+
+ Raul::Symbol default_block_symbol() const;
+ std::string human_name() const;
+ std::string port_human_name(uint32_t i) const;
+
+ using ScalePoints = std::map<float, std::string>;
+ ScalePoints port_scale_points(uint32_t i) const;
+
+ using Presets = std::map<URI, std::string>;
+ const Presets& presets() const { return _presets; }
+
+ static LilvWorld* lilv_world() { return _lilv_world; }
+ const LilvPlugin* lilv_plugin() const { return _lilv_plugin; }
+
+ const LilvPort* lilv_port(uint32_t index) const;
+
+ static void set_lilv_world(LilvWorld* world);
+
+ bool has_ui() const;
+
+ SPtr<PluginUI>
+ ui(ingen::World& world, const SPtr<const BlockModel>& block) const;
+
+ std::string documentation(bool html) const;
+ std::string port_documentation(uint32_t index, bool html) const;
+
+ static void set_rdf_world(Sord::World& world) {
+ _rdf_world = &world;
+ }
+
+ static Sord::World* rdf_world() { return _rdf_world; }
+
+ // Signals
+ INGEN_SIGNAL(changed, void)
+ INGEN_SIGNAL(property, void, const URI&, const Atom&)
+ INGEN_SIGNAL(preset, void, const URI&, const std::string&)
+
+ bool fetched() const { return _fetched; }
+ void set_fetched(bool f) { _fetched = f; }
+
+protected:
+ friend class ClientStore;
+ void set(const SPtr<PluginModel>& p);
+
+ void add_preset(const URI& uri, const std::string& label);
+
+private:
+ static std::string get_documentation(const LilvNode* subject, bool html);
+
+ static Sord::World* _rdf_world;
+ static LilvWorld* _lilv_world;
+ static const LilvPlugins* _lilv_plugins;
+
+ Atom _type;
+ const LilvPlugin* _lilv_plugin;
+ Presets _presets;
+ bool _fetched;
+};
+
+} // namespace client
+} // namespace ingen
+
+#endif // INGEN_CLIENT_PLUGINMODEL_HPP
diff --git a/include/ingen/client/PluginUI.hpp b/include/ingen/client/PluginUI.hpp
new file mode 100644
index 00000000..70ff7274
--- /dev/null
+++ b/include/ingen/client/PluginUI.hpp
@@ -0,0 +1,116 @@
+/*
+ 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_CLIENT_PLUGINUI_HPP
+#define INGEN_CLIENT_PLUGINUI_HPP
+
+#include "signal.hpp"
+
+#include "ingen/LV2Features.hpp"
+#include "ingen/Resource.hpp"
+#include "ingen/ingen.h"
+#include "ingen/types.hpp"
+#include "lilv/lilv.h"
+#include "suil/suil.h"
+
+#include <cstdint>
+#include <set>
+
+namespace ingen {
+
+class Atom;
+class URI;
+class World;
+
+namespace client {
+
+class BlockModel;
+
+/** Custom user interface for a plugin.
+ *
+ * @ingroup IngenClient
+ */
+class INGEN_API PluginUI {
+public:
+ ~PluginUI();
+
+ /** Create a UI for the given block and plugin.
+ *
+ * This does not actually instantiate the UI itself, so signals can be
+ * connected first. The caller should connect to signal_property_changed,
+ * then call instantiate().
+ */
+ static SPtr<PluginUI> create(ingen::World& world,
+ const SPtr<const BlockModel>& block,
+ const LilvPlugin* plugin);
+
+ /** Instantiate the UI.
+ *
+ * If true is returned, instantiation was successfull and the widget can be
+ * obtained with get_widget(). Otherwise, instantiation failed, so there is
+ * no widget and the UI can not be used.
+ */
+ bool instantiate();
+ bool instantiated () { return _instance != nullptr; }
+
+ SuilWidget get_widget();
+
+ void port_event(uint32_t port_index,
+ uint32_t buffer_size,
+ uint32_t format,
+ const void* buffer);
+
+ bool is_resizable() const;
+
+ /** Signal emitted when the UI sets a property.
+ *
+ * The application must connect to this signal to communicate with the
+ * engine and/or update itself as necessary.
+ */
+ INGEN_SIGNAL(property_changed, void,
+ const URI&, // Subject
+ const URI&, // Predicate
+ const Atom&, // Object
+ Resource::Graph) // Context
+
+ ingen::World& world() const { return _world; }
+ SPtr<const BlockModel> block() const { return _block; }
+
+private:
+ PluginUI(ingen::World& world,
+ SPtr<const BlockModel> block,
+ LilvUIs* uis,
+ const LilvUI* ui,
+ const LilvNode* ui_type);
+
+ ingen::World& _world;
+ SPtr<const BlockModel> _block;
+ SuilInstance* _instance;
+ LilvUIs* _uis;
+ const LilvUI* _ui;
+ LilvNode* _ui_node;
+ LilvNode* _ui_type;
+ std::set<uint32_t> _subscribed_ports;
+
+ static SuilHost* ui_host;
+
+ SPtr<LV2Features::FeatureArray> _features;
+};
+
+} // namespace client
+} // namespace ingen
+
+#endif // INGEN_CLIENT_PLUGINUI_HPP
diff --git a/include/ingen/client/PortModel.hpp b/include/ingen/client/PortModel.hpp
new file mode 100644
index 00000000..c386dff0
--- /dev/null
+++ b/include/ingen/client/PortModel.hpp
@@ -0,0 +1,97 @@
+/*
+ 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_CLIENT_PORTMODEL_HPP
+#define INGEN_CLIENT_PORTMODEL_HPP
+
+#include "ingen/client/ObjectModel.hpp"
+#include "ingen/ingen.h"
+#include "ingen/types.hpp"
+#include "lv2/core/lv2.h"
+#include "lv2/port-props/port-props.h"
+
+#include <cstdlib>
+#include <string>
+
+namespace Raul { class Path; }
+
+namespace ingen {
+namespace client {
+
+/** Model of a port.
+ *
+ * @ingroup IngenClient
+ */
+class INGEN_API PortModel : public ObjectModel
+{
+public:
+ enum class Direction { INPUT, OUTPUT };
+
+ GraphType graph_type() const override { return Node::GraphType::PORT; }
+
+ bool supports(const URIs::Quark& value_type) const;
+
+ inline uint32_t index() const { return _index; }
+ inline const Atom& value() const { return get_property(_uris.ingen_value); }
+ inline bool is_input() const { return (_direction == Direction::INPUT); }
+ inline bool is_output() const { return (_direction == Direction::OUTPUT); }
+
+ bool port_property(const URIs::Quark& uri) const;
+
+ bool is_logarithmic() const { return port_property(_uris.pprops_logarithmic); }
+ bool is_enumeration() const { return port_property(_uris.lv2_enumeration); }
+ bool is_integer() const { return port_property(_uris.lv2_integer); }
+ bool is_toggle() const { return port_property(_uris.lv2_toggled); }
+ bool is_numeric() const {
+ return ObjectModel::is_a(_uris.lv2_ControlPort)
+ || ObjectModel::is_a(_uris.lv2_CVPort);
+ }
+ bool is_uri() const;
+
+ inline bool operator==(const PortModel& pm) const { return (path() == pm.path()); }
+
+ void on_property(const URI& uri, const Atom& value) override;
+
+ // Signals
+ INGEN_SIGNAL(value_changed, void, const Atom&)
+ INGEN_SIGNAL(voice_changed, void, uint32_t, const Atom&)
+ INGEN_SIGNAL(activity, void, const Atom&)
+
+private:
+ friend class ClientStore;
+
+ PortModel(URIs& uris,
+ const Raul::Path& path,
+ uint32_t index,
+ Direction dir)
+ : ObjectModel(uris, path)
+ , _index(index)
+ , _direction(dir)
+ {}
+
+ void add_child(const SPtr<ObjectModel>& c) override { throw; }
+ bool remove_child(const SPtr<ObjectModel>& c) override { throw; }
+
+ void set(const SPtr<ObjectModel>& model) override;
+
+ uint32_t _index;
+ Direction _direction;
+};
+
+} // namespace client
+} // namespace ingen
+
+#endif // INGEN_CLIENT_PORTMODEL_HPP
diff --git a/include/ingen/client/SigClientInterface.hpp b/include/ingen/client/SigClientInterface.hpp
new file mode 100644
index 00000000..674714a3
--- /dev/null
+++ b/include/ingen/client/SigClientInterface.hpp
@@ -0,0 +1,63 @@
+/*
+ This file is part of Ingen.
+ Copyright 2007-2016 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_CLIENT_SIGCLIENTINTERFACE_HPP
+#define INGEN_CLIENT_SIGCLIENTINTERFACE_HPP
+
+#include "ingen/Interface.hpp"
+#include "ingen/client/signal.hpp"
+#include "ingen/ingen.h"
+#include "raul/Path.hpp"
+
+#include <cstdint>
+#include <string>
+
+namespace ingen {
+namespace client {
+
+/** A LibSigC++ signal emitting interface for clients to use.
+ *
+ * This simply emits a signal for every event that comes from the engine.
+ * For a higher level model based view of the engine, use ClientStore.
+ *
+ * The signals here match the calls to ClientInterface exactly. See the
+ * documentation for ClientInterface for meanings of signal parameters.
+ *
+ * @ingroup IngenClient
+ */
+class INGEN_API SigClientInterface : public ingen::Interface,
+ public INGEN_TRACKABLE
+{
+public:
+ SigClientInterface() = default;
+
+ URI uri() const override { return URI("ingen:/clients/sig"); }
+
+ INGEN_SIGNAL(message, void, Message)
+
+ /** Fire pending signals. Only does anything on derived classes (that may queue) */
+ virtual bool emit_signals() { return false; }
+
+protected:
+ void message(const Message& msg) override {
+ _signal_message(msg);
+ }
+};
+
+} // namespace client
+} // namespace ingen
+
+#endif
diff --git a/include/ingen/client/SocketClient.hpp b/include/ingen/client/SocketClient.hpp
new file mode 100644
index 00000000..8e551821
--- /dev/null
+++ b/include/ingen/client/SocketClient.hpp
@@ -0,0 +1,80 @@
+/*
+ This file is part of Ingen.
+ Copyright 2012-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_CLIENT_SOCKET_CLIENT_HPP
+#define INGEN_CLIENT_SOCKET_CLIENT_HPP
+
+#include "ingen/SocketReader.hpp"
+#include "ingen/SocketWriter.hpp"
+#include "ingen/ingen.h"
+#include "raul/Socket.hpp"
+
+namespace ingen {
+namespace client {
+
+/** The client side of an Ingen socket connection. */
+class INGEN_API SocketClient : public SocketWriter
+{
+public:
+ SocketClient(World& world,
+ const URI& uri,
+ const SPtr<Raul::Socket>& sock,
+ const SPtr<Interface>& respondee)
+ : SocketWriter(world.uri_map(), world.uris(), uri, sock)
+ , _respondee(respondee)
+ , _reader(world, *respondee.get(), sock)
+ {}
+
+ SPtr<Interface> respondee() const override {
+ return _respondee;
+ }
+
+ void set_respondee(const SPtr<Interface>& respondee) override {
+ _respondee = respondee;
+ }
+
+ static SPtr<ingen::Interface>
+ new_socket_interface(ingen::World& world,
+ const URI& uri,
+ const SPtr<ingen::Interface>& respondee)
+ {
+ const Raul::Socket::Type type = (uri.scheme() == "unix"
+ ? Raul::Socket::Type::UNIX
+ : Raul::Socket::Type::TCP);
+
+ SPtr<Raul::Socket> sock(new Raul::Socket(type));
+ if (!sock->connect(uri)) {
+ world.log().error("Failed to connect <%1%> (%2%)\n",
+ sock->uri(), strerror(errno));
+ return SPtr<Interface>();
+ }
+ return SPtr<Interface>(new SocketClient(world, uri, sock, respondee));
+ }
+
+ static void register_factories(World& world) {
+ world.add_interface_factory("unix", &new_socket_interface);
+ world.add_interface_factory("tcp", &new_socket_interface);
+ }
+
+private:
+ SPtr<Interface> _respondee;
+ SocketReader _reader;
+};
+
+} // namespace client
+} // namespace ingen
+
+#endif // INGEN_CLIENT_SOCKET_CLIENT_HPP
diff --git a/include/ingen/client/signal.hpp b/include/ingen/client/signal.hpp
new file mode 100644
index 00000000..ba5b017b
--- /dev/null
+++ b/include/ingen/client/signal.hpp
@@ -0,0 +1,31 @@
+/*
+ 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_CLIENT_SIGNAL_HPP
+#define INGEN_CLIENT_SIGNAL_HPP
+
+#include <sigc++/sigc++.h>
+
+#define INGEN_SIGNAL(name, ...) \
+protected: \
+sigc::signal<__VA_ARGS__> _signal_##name; \
+public: \
+sigc::signal<__VA_ARGS__> signal_##name() const { return _signal_##name; } \
+sigc::signal<__VA_ARGS__>& signal_##name() { return _signal_##name; }
+
+#define INGEN_TRACKABLE sigc::trackable
+
+#endif // INGEN_CLIENT_SIGNAL_HPP