aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2018-11-24 13:44:03 +0100
committerDavid Robillard <d@drobilla.net>2018-11-24 13:44:03 +0100
commita7d83f19b08eb4c6f79a82fe60c2b86db13f4420 (patch)
treed9b620bfba1e7462df4ddb3f6225cc5216c0ca81 /src
parentd63edc742cebd685f8a05936682210aa5c1e69a9 (diff)
downloadingen-a7d83f19b08eb4c6f79a82fe60c2b86db13f4420.tar.gz
ingen-a7d83f19b08eb4c6f79a82fe60c2b86db13f4420.tar.bz2
ingen-a7d83f19b08eb4c6f79a82fe60c2b86db13f4420.zip
Squashed 'waflib/' changes from 6e726eb1..5ea8f99f
5ea8f99f Improve test output spacing 0e23b29f Raise exception when test suite fails to ensure non-zero exit status d6de073b Show run time of unit tests 5b655541 Add short configure option for ultra-strict flags 4687ba6d Use gtest-like test output 258903d9 Fix failure count in test group summaries da07e738 Fix verbose tests with Python 3 git-subtree-dir: waflib git-subtree-split: 5ea8f99f6e1246079c1fe6bb590c38a53aadd40d
Diffstat (limited to 'src')
-rw-r--r--src/AtomReader.cpp384
-rw-r--r--src/AtomWriter.cpp652
-rw-r--r--src/ClashAvoider.cpp136
-rw-r--r--src/ColorContext.cpp44
-rw-r--r--src/Configuration.cpp386
-rw-r--r--src/FilePath.cpp242
-rw-r--r--src/Forge.cpp69
-rw-r--r--src/LV2Features.cpp83
-rw-r--r--src/Library.cpp56
-rw-r--r--src/Log.cpp162
-rw-r--r--src/Parser.cpp713
-rw-r--r--src/Resource.cpp234
-rw-r--r--src/Serialiser.cpp583
-rw-r--r--src/SocketReader.cpp199
-rw-r--r--src/SocketWriter.cpp58
-rw-r--r--src/Store.cpp143
-rw-r--r--src/StreamWriter.cpp39
-rw-r--r--src/TurtleWriter.cpp101
-rw-r--r--src/URI.cpp113
-rw-r--r--src/URIMap.cpp123
-rw-r--r--src/URIs.cpp204
-rw-r--r--src/World.cpp355
-rw-r--r--src/client/BlockModel.cpp285
-rw-r--r--src/client/ClientStore.cpp487
-rw-r--r--src/client/GraphModel.cpp176
-rw-r--r--src/client/ObjectModel.cpp108
-rw-r--r--src/client/PluginModel.cpp360
-rw-r--r--src/client/PluginUI.cpp336
-rw-r--r--src/client/PortModel.cpp78
-rw-r--r--src/client/ingen_client.cpp34
-rw-r--r--src/client/wscript23
-rw-r--r--src/gui/App.cpp499
-rw-r--r--src/gui/App.hpp196
-rw-r--r--src/gui/Arc.cpp44
-rw-r--r--src/gui/Arc.hpp52
-rw-r--r--src/gui/BreadCrumbs.cpp229
-rw-r--r--src/gui/BreadCrumbs.hpp119
-rw-r--r--src/gui/ConnectWindow.cpp572
-rw-r--r--src/gui/ConnectWindow.hpp116
-rw-r--r--src/gui/GraphBox.cpp922
-rw-r--r--src/gui/GraphBox.hpp213
-rw-r--r--src/gui/GraphCanvas.cpp899
-rw-r--r--src/gui/GraphCanvas.hpp159
-rw-r--r--src/gui/GraphPortModule.cpp166
-rw-r--r--src/gui/GraphPortModule.hpp79
-rw-r--r--src/gui/GraphTreeWindow.cpp235
-rw-r--r--src/gui/GraphTreeWindow.hpp123
-rw-r--r--src/gui/GraphView.cpp154
-rw-r--r--src/gui/GraphView.hpp98
-rw-r--r--src/gui/GraphWindow.cpp85
-rw-r--r--src/gui/GraphWindow.hpp80
-rw-r--r--src/gui/LoadGraphWindow.cpp257
-rw-r--r--src/gui/LoadGraphWindow.hpp95
-rw-r--r--src/gui/LoadPluginWindow.cpp511
-rw-r--r--src/gui/LoadPluginWindow.hpp160
-rw-r--r--src/gui/MessagesWindow.cpp141
-rw-r--r--src/gui/MessagesWindow.hpp70
-rw-r--r--src/gui/NewSubgraphWindow.cpp119
-rw-r--r--src/gui/NewSubgraphWindow.hpp72
-rw-r--r--src/gui/NodeMenu.cpp253
-rw-r--r--src/gui/NodeMenu.hpp75
-rw-r--r--src/gui/NodeModule.cpp518
-rw-r--r--src/gui/NodeModule.hpp104
-rw-r--r--src/gui/ObjectMenu.cpp145
-rw-r--r--src/gui/ObjectMenu.hpp77
-rw-r--r--src/gui/PluginMenu.cpp176
-rw-r--r--src/gui/PluginMenu.hpp80
-rw-r--r--src/gui/Port.cpp534
-rw-r--r--src/gui/Port.hpp102
-rw-r--r--src/gui/PortMenu.cpp174
-rw-r--r--src/gui/PortMenu.hpp66
-rw-r--r--src/gui/PropertiesWindow.cpp591
-rw-r--r--src/gui/PropertiesWindow.hpp129
-rw-r--r--src/gui/RDFS.cpp259
-rw-r--r--src/gui/RDFS.hpp80
-rw-r--r--src/gui/RenameWindow.cpp137
-rw-r--r--src/gui/RenameWindow.hpp64
-rw-r--r--src/gui/Style.cpp106
-rw-r--r--src/gui/Style.hpp56
-rw-r--r--src/gui/SubgraphModule.cpp102
-rw-r--r--src/gui/SubgraphModule.hpp64
-rw-r--r--src/gui/ThreadedLoader.cpp148
-rw-r--r--src/gui/ThreadedLoader.hpp96
-rw-r--r--src/gui/URIEntry.cpp192
-rw-r--r--src/gui/URIEntry.hpp68
-rw-r--r--src/gui/WidgetFactory.cpp80
-rw-r--r--src/gui/WidgetFactory.hpp58
-rw-r--r--src/gui/Window.hpp78
-rw-r--r--src/gui/WindowFactory.cpp302
-rw-r--r--src/gui/WindowFactory.hpp99
-rw-r--r--src/gui/ingen_gui.cpp67
-rw-r--r--src/gui/ingen_gui.gladep9
-rw-r--r--src/gui/ingen_gui.ui3049
-rw-r--r--src/gui/ingen_gui_lv2.cpp209
-rw-r--r--src/gui/ingen_style.rc155
-rw-r--r--src/gui/rgba.hpp58
-rw-r--r--src/gui/wscript111
-rw-r--r--src/ingen/ingen.cpp263
-rw-r--r--src/ingen/ingen.desktop9
-rw-r--r--src/ingen/ingen.grind5
-rw-r--r--src/runtime_paths.cpp146
-rw-r--r--src/server/ArcImpl.cpp114
-rw-r--r--src/server/ArcImpl.hpp84
-rw-r--r--src/server/BlockFactory.cpp229
-rw-r--r--src/server/BlockFactory.hpp67
-rw-r--r--src/server/BlockImpl.cpp303
-rw-r--r--src/server/BlockImpl.hpp207
-rw-r--r--src/server/Broadcaster.cpp97
-rw-r--r--src/server/Broadcaster.hpp118
-rw-r--r--src/server/Buffer.cpp468
-rw-r--r--src/server/Buffer.hpp244
-rw-r--r--src/server/BufferFactory.cpp190
-rw-r--r--src/server/BufferFactory.hpp118
-rw-r--r--src/server/BufferRef.hpp38
-rw-r--r--src/server/ClientUpdate.cpp155
-rw-r--r--src/server/ClientUpdate.hpp80
-rw-r--r--src/server/CompiledGraph.cpp274
-rw-r--r--src/server/CompiledGraph.hpp84
-rw-r--r--src/server/ControlBindings.cpp425
-rw-r--r--src/server/ControlBindings.hpp148
-rw-r--r--src/server/DirectDriver.hpp108
-rw-r--r--src/server/Driver.hpp110
-rw-r--r--src/server/DuplexPort.cpp236
-rw-r--r--src/server/DuplexPort.hpp98
-rw-r--r--src/server/Engine.cpp526
-rw-r--r--src/server/Engine.hpp221
-rw-r--r--src/server/EnginePort.hpp66
-rw-r--r--src/server/Event.hpp163
-rw-r--r--src/server/EventWriter.cpp147
-rw-r--r--src/server/EventWriter.hpp86
-rw-r--r--src/server/FrameTimer.hpp110
-rw-r--r--src/server/GraphImpl.cpp379
-rw-r--r--src/server/GraphImpl.hpp200
-rw-r--r--src/server/GraphPlugin.hpp63
-rw-r--r--src/server/InputPort.cpp261
-rw-r--r--src/server/InputPort.hpp128
-rw-r--r--src/server/InternalBlock.cpp73
-rw-r--r--src/server/InternalBlock.hpp48
-rw-r--r--src/server/InternalPlugin.cpp67
-rw-r--r--src/server/InternalPlugin.hpp57
-rw-r--r--src/server/JackDriver.cpp584
-rw-r--r--src/server/JackDriver.hpp169
-rw-r--r--src/server/LV2Block.cpp742
-rw-r--r--src/server/LV2Block.hpp152
-rw-r--r--src/server/LV2Options.hpp71
-rw-r--r--src/server/LV2Plugin.cpp143
-rw-r--r--src/server/LV2Plugin.hpp72
-rw-r--r--src/server/LV2ResizeFeature.hpp65
-rw-r--r--src/server/Load.hpp57
-rw-r--r--src/server/NodeImpl.cpp50
-rw-r--r--src/server/NodeImpl.hpp109
-rw-r--r--src/server/OutputPort.hpp51
-rw-r--r--src/server/PluginImpl.hpp96
-rw-r--r--src/server/PortAudioDriver.cpp297
-rw-r--r--src/server/PortAudioDriver.hpp132
-rw-r--r--src/server/PortImpl.cpp569
-rw-r--r--src/server/PortImpl.hpp312
-rw-r--r--src/server/PortType.hpp91
-rw-r--r--src/server/PostProcessor.cpp114
-rw-r--r--src/server/PostProcessor.hpp74
-rw-r--r--src/server/PreProcessContext.hpp84
-rw-r--r--src/server/PreProcessor.cpp248
-rw-r--r--src/server/PreProcessor.hpp87
-rw-r--r--src/server/RunContext.cpp195
-rw-r--r--src/server/RunContext.hpp161
-rw-r--r--src/server/SocketListener.cpp190
-rw-r--r--src/server/SocketListener.hpp41
-rw-r--r--src/server/SocketServer.hpp80
-rw-r--r--src/server/Task.cpp158
-rw-r--r--src/server/Task.hpp120
-rw-r--r--src/server/ThreadManager.hpp68
-rw-r--r--src/server/UndoStack.cpp253
-rw-r--r--src/server/UndoStack.hpp107
-rw-r--r--src/server/Worker.cpp163
-rw-r--r--src/server/Worker.hpp76
-rw-r--r--src/server/events.hpp35
-rw-r--r--src/server/events/Connect.cpp188
-rw-r--r--src/server/events/Connect.hpp74
-rw-r--r--src/server/events/Copy.cpp216
-rw-r--r--src/server/events/Copy.hpp68
-rw-r--r--src/server/events/CreateBlock.cpp180
-rw-r--r--src/server/events/CreateBlock.hpp66
-rw-r--r--src/server/events/CreateGraph.cpp236
-rw-r--r--src/server/events/CreateGraph.hpp74
-rw-r--r--src/server/events/CreatePort.cpp219
-rw-r--r--src/server/events/CreatePort.hpp82
-rw-r--r--src/server/events/Delete.cpp216
-rw-r--r--src/server/events/Delete.hpp86
-rw-r--r--src/server/events/Delta.cpp670
-rw-r--r--src/server/events/Delta.hpp133
-rw-r--r--src/server/events/Disconnect.cpp224
-rw-r--r--src/server/events/Disconnect.hpp87
-rw-r--r--src/server/events/DisconnectAll.cpp176
-rw-r--r--src/server/events/DisconnectAll.hpp78
-rw-r--r--src/server/events/Get.cpp111
-rw-r--r--src/server/events/Get.hpp65
-rw-r--r--src/server/events/Mark.cpp112
-rw-r--r--src/server/events/Mark.hpp69
-rw-r--r--src/server/events/Move.cpp91
-rw-r--r--src/server/events/Move.hpp57
-rw-r--r--src/server/events/SetPortValue.cpp139
-rw-r--r--src/server/events/SetPortValue.hpp71
-rw-r--r--src/server/events/Undo.cpp85
-rw-r--r--src/server/events/Undo.hpp58
-rw-r--r--src/server/ingen_engine.cpp44
-rw-r--r--src/server/ingen_jack.cpp58
-rw-r--r--src/server/ingen_lv2.cpp850
-rw-r--r--src/server/ingen_portaudio.cpp54
-rw-r--r--src/server/internals/BlockDelay.cpp89
-rw-r--r--src/server/internals/BlockDelay.hpp62
-rw-r--r--src/server/internals/Controller.cpp174
-rw-r--r--src/server/internals/Controller.hpp71
-rw-r--r--src/server/internals/Note.cpp420
-rw-r--r--src/server/internals/Note.hpp109
-rw-r--r--src/server/internals/Time.cpp78
-rw-r--r--src/server/internals/Time.hpp59
-rw-r--r--src/server/internals/Trigger.cpp187
-rw-r--r--src/server/internals/Trigger.hpp75
-rw-r--r--src/server/jackey.h72
-rw-r--r--src/server/mix.cpp112
-rw-r--r--src/server/mix.hpp40
-rw-r--r--src/server/types.hpp27
-rw-r--r--src/server/util.hpp63
-rw-r--r--src/server/wscript104
-rw-r--r--src/wscript46
225 files changed, 0 insertions, 41856 deletions
diff --git a/src/AtomReader.cpp b/src/AtomReader.cpp
deleted file mode 100644
index 218110e4..00000000
--- a/src/AtomReader.cpp
+++ /dev/null
@@ -1,384 +0,0 @@
-/*
- 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/>.
-*/
-
-#include <cstdlib>
-#include <utility>
-
-#include "ingen/AtomReader.hpp"
-#include "ingen/Interface.hpp"
-#include "ingen/Log.hpp"
-#include "ingen/Message.hpp"
-#include "ingen/Node.hpp"
-#include "ingen/URIMap.hpp"
-#include "lv2/lv2plug.in/ns/ext/atom/util.h"
-#include "raul/Path.hpp"
-
-namespace Ingen {
-
-AtomReader::AtomReader(URIMap& map, URIs& uris, Log& log, Interface& iface)
- : _map(map)
- , _uris(uris)
- , _log(log)
- , _iface(iface)
-{}
-
-void
-AtomReader::get_atom(const LV2_Atom* in, Atom& out)
-{
- if (in) {
- if (in->type == _uris.atom_URID) {
- const LV2_Atom_URID* urid = (const LV2_Atom_URID*)in;
- const char* uri = _map.unmap_uri(urid->body);
- if (uri) {
- out = Atom(sizeof(int32_t), _uris.atom_URID, &urid->body);
- } else {
- _log.error(fmt("Unable to unmap URID %1%\n") % urid->body);
- }
- } else {
- out = Atom(in->size, in->type, LV2_ATOM_BODY_CONST(in));
- }
- }
-}
-
-void
-AtomReader::get_props(const LV2_Atom_Object* obj,
- Ingen::Properties& props)
-{
- if (obj->body.otype) {
- const Atom type(sizeof(int32_t), _uris.atom_URID, &obj->body.otype);
- props.emplace(_uris.rdf_type, type);
- }
- LV2_ATOM_OBJECT_FOREACH(obj, p) {
- Atom val;
- get_atom(&p->value, val);
- props.emplace(URI(_map.unmap_uri(p->key)), val);
- }
-}
-
-boost::optional<URI>
-AtomReader::atom_to_uri(const LV2_Atom* atom)
-{
- if (!atom) {
- return boost::optional<URI>();
- } else if (atom->type == _uris.atom_URI) {
- const char* str = (const char*)LV2_ATOM_BODY_CONST(atom);
- if (URI::is_valid(str)) {
- return URI(str);
- } else {
- _log.warn(fmt("Invalid URI <%1%>\n") % str);
- }
- } else if (atom->type == _uris.atom_Path) {
- const char* str = (const char*)LV2_ATOM_BODY_CONST(atom);
- if (!strncmp(str, "file://", 5)) {
- return URI(str);
- } else {
- return URI(std::string("file://") + str);
- }
- } else if (atom->type == _uris.atom_URID) {
- const char* str = _map.unmap_uri(((const LV2_Atom_URID*)atom)->body);
- if (str) {
- return URI(str);
- } else {
- _log.warn(fmt("Unknown URID %1%\n") % str);
- }
- }
- return boost::optional<URI>();
-}
-
-boost::optional<Raul::Path>
-AtomReader::atom_to_path(const LV2_Atom* atom)
-{
- boost::optional<URI> uri = atom_to_uri(atom);
- if (uri && uri_is_path(*uri)) {
- return uri_to_path(*uri);
- }
- return boost::optional<Raul::Path>();
-}
-
-Resource::Graph
-AtomReader::atom_to_context(const LV2_Atom* atom)
-{
- Resource::Graph ctx = Resource::Graph::DEFAULT;
- if (atom) {
- boost::optional<URI> maybe_uri = atom_to_uri(atom);
- if (maybe_uri) {
- ctx = Resource::uri_to_graph(*maybe_uri);
- } else {
- _log.warn("Message has invalid context\n");
- }
- }
- return ctx;
-}
-
-bool
-AtomReader::is_message(const URIs& uris, const LV2_Atom* msg)
-{
- if (msg->type != uris.atom_Object) {
- return false;
- }
-
- const LV2_Atom_Object* obj = (const LV2_Atom_Object*)msg;
- return (obj->body.otype == uris.patch_Get ||
- obj->body.otype == uris.patch_Delete ||
- obj->body.otype == uris.patch_Put ||
- obj->body.otype == uris.patch_Set ||
- obj->body.otype == uris.patch_Patch ||
- obj->body.otype == uris.patch_Move ||
- obj->body.otype == uris.patch_Response);
-}
-
-bool
-AtomReader::write(const LV2_Atom* msg, int32_t default_id)
-{
- if (msg->type != _uris.atom_Object) {
- _log.warn(fmt("Unknown message type <%1%>\n")
- % _map.unmap_uri(msg->type));
- return false;
- }
-
- const LV2_Atom_Object* obj = (const LV2_Atom_Object*)msg;
- const LV2_Atom* subject = nullptr;
- const LV2_Atom* number = nullptr;
-
- lv2_atom_object_get(obj,
- (LV2_URID)_uris.patch_subject, &subject,
- (LV2_URID)_uris.patch_sequenceNumber, &number,
- NULL);
-
- const boost::optional<URI> subject_uri = atom_to_uri(subject);
-
- const int32_t seq = ((number && number->type == _uris.atom_Int)
- ? ((const LV2_Atom_Int*)number)->body
- : default_id);
-
- if (obj->body.otype == _uris.patch_Get) {
- if (subject_uri) {
- _iface(Get{seq, *subject_uri});
- }
- } else if (obj->body.otype == _uris.ingen_BundleStart) {
- _iface(BundleBegin{seq});
- } else if (obj->body.otype == _uris.ingen_BundleEnd) {
- _iface(BundleEnd{seq});
- } else if (obj->body.otype == _uris.patch_Delete) {
- const LV2_Atom_Object* body = nullptr;
- lv2_atom_object_get(obj, (LV2_URID)_uris.patch_body, &body, 0);
-
- if (subject_uri && !body) {
- _iface(Del{seq, *subject_uri});
- return true;
- } else if (body && body->body.otype == _uris.ingen_Arc) {
- const LV2_Atom* tail = nullptr;
- const LV2_Atom* head = nullptr;
- const LV2_Atom* incidentTo = nullptr;
- lv2_atom_object_get(body,
- (LV2_URID)_uris.ingen_tail, &tail,
- (LV2_URID)_uris.ingen_head, &head,
- (LV2_URID)_uris.ingen_incidentTo, &incidentTo,
- NULL);
-
- boost::optional<Raul::Path> subject_path(atom_to_path(subject));
- boost::optional<Raul::Path> tail_path(atom_to_path(tail));
- boost::optional<Raul::Path> head_path(atom_to_path(head));
- boost::optional<Raul::Path> other_path(atom_to_path(incidentTo));
- if (tail_path && head_path) {
- _iface(Disconnect{seq, *tail_path, *head_path});
- } else if (subject_path && other_path) {
- _iface(DisconnectAll{seq, *subject_path, *other_path});
- } else {
- _log.warn("Delete of unknown object\n");
- return false;
- }
- }
- } else if (obj->body.otype == _uris.patch_Put) {
- const LV2_Atom_Object* body = nullptr;
- const LV2_Atom* context = nullptr;
- lv2_atom_object_get(obj,
- (LV2_URID)_uris.patch_body, &body,
- (LV2_URID)_uris.patch_context, &context,
- 0);
- if (!body) {
- _log.warn("Put message has no body\n");
- return false;
- } else if (!subject_uri) {
- _log.warn("Put message has no subject\n");
- return false;
- }
-
- if (body->body.otype == _uris.ingen_Arc) {
- LV2_Atom* tail = nullptr;
- LV2_Atom* head = nullptr;
- lv2_atom_object_get(body,
- (LV2_URID)_uris.ingen_tail, &tail,
- (LV2_URID)_uris.ingen_head, &head,
- NULL);
- if (!tail || !head) {
- _log.warn("Arc has no tail or head\n");
- return false;
- }
-
- boost::optional<Raul::Path> tail_path(atom_to_path(tail));
- boost::optional<Raul::Path> head_path(atom_to_path(head));
- if (tail_path && head_path) {
- _iface(Connect{seq, *tail_path, *head_path});
- } else {
- _log.warn("Arc has non-path tail or head\n");
- }
- } else {
- Ingen::Properties props;
- get_props(body, props);
- _iface(Put{seq, *subject_uri, props, atom_to_context(context)});
- }
- } else if (obj->body.otype == _uris.patch_Set) {
- if (!subject_uri) {
- _log.warn("Set message has no subject\n");
- return false;
- }
-
- const LV2_Atom_URID* prop = nullptr;
- const LV2_Atom* value = nullptr;
- const LV2_Atom* context = nullptr;
- lv2_atom_object_get(obj,
- (LV2_URID)_uris.patch_property, &prop,
- (LV2_URID)_uris.patch_value, &value,
- (LV2_URID)_uris.patch_context, &context,
- 0);
- if (!prop || ((const LV2_Atom*)prop)->type != _uris.atom_URID) {
- _log.warn("Set message missing property\n");
- return false;
- } else if (!value) {
- _log.warn("Set message missing value\n");
- return false;
- }
-
- Atom atom;
- get_atom(value, atom);
- _iface(SetProperty{seq,
- *subject_uri,
- URI(_map.unmap_uri(prop->body)),
- atom,
- atom_to_context(context)});
- } else if (obj->body.otype == _uris.patch_Patch) {
- if (!subject_uri) {
- _log.warn("Patch message has no subject\n");
- return false;
- }
-
- const LV2_Atom_Object* remove = nullptr;
- const LV2_Atom_Object* add = nullptr;
- const LV2_Atom* context = nullptr;
- lv2_atom_object_get(obj,
- (LV2_URID)_uris.patch_remove, &remove,
- (LV2_URID)_uris.patch_add, &add,
- (LV2_URID)_uris.patch_context, &context,
- 0);
- if (!remove) {
- _log.warn("Patch message has no remove\n");
- return false;
- } else if (!add) {
- _log.warn("Patch message has no add\n");
- return false;
- }
-
- Ingen::Properties add_props;
- get_props(add, add_props);
-
- Ingen::Properties remove_props;
- get_props(remove, remove_props);
-
- _iface(Delta{seq, *subject_uri, remove_props, add_props,
- atom_to_context(context)});
- } else if (obj->body.otype == _uris.patch_Copy) {
- if (!subject) {
- _log.warn("Copy message has no subject\n");
- return false;
- }
-
- const LV2_Atom* dest = nullptr;
- lv2_atom_object_get(obj, (LV2_URID)_uris.patch_destination, &dest, 0);
- if (!dest) {
- _log.warn("Copy message has no destination\n");
- return false;
- }
-
- boost::optional<URI> subject_uri(atom_to_uri(subject));
- if (!subject_uri) {
- _log.warn("Copy message has non-path subject\n");
- return false;
- }
-
- boost::optional<URI> dest_uri(atom_to_uri(dest));
- if (!dest_uri) {
- _log.warn("Copy message has non-URI destination\n");
- return false;
- }
-
- _iface(Copy{seq, *subject_uri, *dest_uri});
- } else if (obj->body.otype == _uris.patch_Move) {
- if (!subject) {
- _log.warn("Move message has no subject\n");
- return false;
- }
-
- const LV2_Atom* dest = nullptr;
- lv2_atom_object_get(obj, (LV2_URID)_uris.patch_destination, &dest, 0);
- if (!dest) {
- _log.warn("Move message has no destination\n");
- return false;
- }
-
- boost::optional<Raul::Path> subject_path(atom_to_path(subject));
- if (!subject_path) {
- _log.warn("Move message has non-path subject\n");
- return false;
- }
-
- boost::optional<Raul::Path> dest_path(atom_to_path(dest));
- if (!dest_path) {
- _log.warn("Move message has non-path destination\n");
- return false;
- }
-
- _iface(Move{seq, *subject_path, *dest_path});
- } else if (obj->body.otype == _uris.patch_Response) {
- const LV2_Atom* seq = nullptr;
- const LV2_Atom* body = nullptr;
- lv2_atom_object_get(obj,
- (LV2_URID)_uris.patch_sequenceNumber, &seq,
- (LV2_URID)_uris.patch_body, &body,
- 0);
- if (!seq || seq->type != _uris.atom_Int) {
- _log.warn("Response message has no sequence number\n");
- return false;
- } else if (!body || body->type != _uris.atom_Int) {
- _log.warn("Response message body is not integer\n");
- return false;
- }
- _iface(Response{((const LV2_Atom_Int*)seq)->body,
- (Ingen::Status)((const LV2_Atom_Int*)body)->body,
- subject_uri ? subject_uri->c_str() : ""});
- } else if (obj->body.otype == _uris.ingen_BundleStart) {
- _iface(BundleBegin{seq});
- } else if (obj->body.otype == _uris.ingen_BundleEnd) {
- _iface(BundleEnd{seq});
- } else {
- _log.warn(fmt("Unknown object type <%1%>\n")
- % _map.unmap_uri(obj->body.otype));
- }
-
- return true;
-}
-
-} // namespace Ingen
diff --git a/src/AtomWriter.cpp b/src/AtomWriter.cpp
deleted file mode 100644
index f235aafc..00000000
--- a/src/AtomWriter.cpp
+++ /dev/null
@@ -1,652 +0,0 @@
-/*
- 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/>.
-*/
-
-/** @page protocol Ingen Protocol
- * @tableofcontents
- *
- * @section introduction Controlling Ingen
- *
- * Ingen is controlled via a simple RDF-based protocol. This conceptual
- * protocol can be used in two concrete ways:
- *
- * 1. When Ingen is running as a process, a socket accepts messages in
- * (textual) Turtle syntax, and responds in the same syntax. Transfers are
- * delimited by NULL characters in the stream, so the client knows when to
- * finish parsing to interpret responses. By default, Ingen listens on
- * unix:///tmp/ingen.sock and tcp://localhost:16180
- *
- * 2. When Ingen is running as an LV2 plugin, the control and notify ports
- * accept and respond using (binary) LV2 atoms. Messages are read and written
- * as events with atom:Object bodies. The standard rules for LV2 event
- * transmission apply, but note that the graph manipulations described here are
- * executed asynchronously and not with sample accuracy, so the response may
- * come at a later frame or cycle.
- *
- * For documentation purposes, this page discusses messages in Turtle syntax,
- * but the same protocol is used in the LV2 case, just in a more compact binary
- * encoding.
- *
- * Conceptually, Ingen represents a tree of objects, each of which has a path
- * (like /main/in or /main/osc/out) and a set of properties. A property is a
- * URI key and some value. All changes to Ingen are represented as
- * manipulations of this tree of dictionaries. The core of the protocol is
- * based on the LV2 patch extension, which defines several messages for
- * manipulating data in this model which resemble HTTP methods.
- */
-
-#include <cassert>
-#include <cstdlib>
-#include <string>
-
-#include <boost/variant/apply_visitor.hpp>
-
-#include "ingen/AtomSink.hpp"
-#include "ingen/AtomWriter.hpp"
-#include "ingen/Node.hpp"
-#include "ingen/URIMap.hpp"
-#include "raul/Path.hpp"
-#include "serd/serd.h"
-
-namespace Ingen {
-
-AtomWriter::AtomWriter(URIMap& map, URIs& uris, AtomSink& sink)
- : _map(map)
- , _uris(uris)
- , _sink(sink)
-{
- lv2_atom_forge_init(&_forge, &map.urid_map_feature()->urid_map);
- _out.set_forge_sink(&_forge);
-}
-
-void
-AtomWriter::finish_msg()
-{
- assert(!_forge.stack);
- _sink.write(_out.atom());
- _out.clear();
-}
-
-void
-AtomWriter::message(const Message& message)
-{
- boost::apply_visitor(*this, message);
-}
-
-/** @page protocol
- * @subsection Bundles
- *
- * An [ingen:BundleStart](http://drobilla.net/ns/ingen#BundleStart) marks the
- * start of a bundle in the operation stream. A bundle groups a series of
- * messages for coarse-grained undo or atomic execution.
- *
- * @code{.ttl}
- * [] a ingen:BundleStart .
- * @endcode
-
- * An [ingen:BundleEnd](http://drobilla.net/ns/ingen#BundleEnd) marks the end
- * of a bundle in the operation stream.
- *
- * @code{.ttl}
- * [] a ingen:BundleEnd .
- * @endcode
- */
-void
-AtomWriter::operator()(const BundleBegin& message)
-{
- LV2_Atom_Forge_Frame msg;
- forge_request(&msg, _uris.ingen_BundleStart, message.seq);
- lv2_atom_forge_pop(&_forge, &msg);
- finish_msg();
-}
-
-void
-AtomWriter::operator()(const BundleEnd& message)
-{
- LV2_Atom_Forge_Frame msg;
- forge_request(&msg, _uris.ingen_BundleEnd, message.seq);
- lv2_atom_forge_pop(&_forge, &msg);
- finish_msg();
-}
-
-void
-AtomWriter::forge_uri(const URI& uri)
-{
- if (serd_uri_string_has_scheme((const uint8_t*)uri.c_str())) {
- lv2_atom_forge_urid(&_forge, _map.map_uri(uri.c_str()));
- } else {
- lv2_atom_forge_uri(&_forge, uri.c_str(), uri.length());
- }
-}
-
-void
-AtomWriter::forge_properties(const Properties& properties)
-{
- for (auto p : properties) {
- lv2_atom_forge_key(&_forge, _map.map_uri(p.first.c_str()));
- if (p.second.type() == _forge.URI) {
- forge_uri(URI(p.second.ptr<char>()));
- } else {
- lv2_atom_forge_atom(&_forge, p.second.size(), p.second.type());
- lv2_atom_forge_write(&_forge, p.second.get_body(), p.second.size());
- }
- }
-}
-
-void
-AtomWriter::forge_arc(const Raul::Path& tail, const Raul::Path& head)
-{
- LV2_Atom_Forge_Frame arc;
- lv2_atom_forge_object(&_forge, &arc, 0, _uris.ingen_Arc);
- lv2_atom_forge_key(&_forge, _uris.ingen_tail);
- forge_uri(path_to_uri(tail));
- lv2_atom_forge_key(&_forge, _uris.ingen_head);
- forge_uri(path_to_uri(head));
- lv2_atom_forge_pop(&_forge, &arc);
-}
-
-void
-AtomWriter::forge_request(LV2_Atom_Forge_Frame* frame, LV2_URID type, int32_t id)
-{
- lv2_atom_forge_object(&_forge, frame, 0, type);
-
- if (id) {
- lv2_atom_forge_key(&_forge, _uris.patch_sequenceNumber);
- lv2_atom_forge_int(&_forge, id);
- }
-}
-
-void
-AtomWriter::forge_context(Resource::Graph ctx)
-{
- switch (ctx) {
- case Resource::Graph::EXTERNAL:
- lv2_atom_forge_key(&_forge, _uris.patch_context);
- forge_uri(_uris.ingen_externalContext);
- break;
- case Resource::Graph::INTERNAL:
- lv2_atom_forge_key(&_forge, _uris.patch_context);
- forge_uri(_uris.ingen_internalContext);
- break;
- default: break;
- }
-}
-
-/** @page protocol
- * @section methods Methods
- * @subsection Put
- *
- * Send a [Put](http://lv2plug.in/ns/ext/patch#Put) to set properties on an
- * object, creating it if necessary.
- *
- * If the object already exists, all existing object properties with keys that
- * match any property in the message are first removed. Other properties are
- * left unchanged.
- *
- * If the object does not yet exist, the message must contain sufficient
- * information to create it, including at least one rdf:type property.
- *
- * @code{.ttl}
- * []
- * a patch:Put ;
- * patch:subject </main/osc> ;
- * patch:body [
- * a ingen:Block ;
- * lv2:prototype <http: //drobilla.net/plugins/mda/Shepard>
- * ] .
- * @endcode
- */
-void
-AtomWriter::operator()(const Put& message)
-{
- LV2_Atom_Forge_Frame msg;
- forge_request(&msg, _uris.patch_Put, message.seq);
- forge_context(message.ctx);
- lv2_atom_forge_key(&_forge, _uris.patch_subject);
- forge_uri(message.uri);
- lv2_atom_forge_key(&_forge, _uris.patch_body);
-
- LV2_Atom_Forge_Frame body;
- lv2_atom_forge_object(&_forge, &body, 0, 0);
- forge_properties(message.properties);
- lv2_atom_forge_pop(&_forge, &body);
-
- lv2_atom_forge_pop(&_forge, &msg);
- finish_msg();
-}
-
-/** @page protocol
- * @subsection Patch
- *
- * Send a [Patch](http://lv2plug.in/ns/ext/patch#Patch) to manipulate the
- * properties of an object. A set of properties are first removed, then
- * another is added. Analogous to WebDAV PROPPATCH.
- *
- * The special value [patch:wildcard](http://lv2plug.in/ns/ext/patch#wildcard)
- * may be used to specify that any value with the given key should be removed.
- *
- * @code{.ttl}
- * []
- * a patch:Patch ;
- * patch:subject </main/osc> ;
- * patch:add [
- * lv2:name "Osckillator" ;
- * ingen:canvasX 32.0 ;
- * ingen:canvasY 32.0 ;
- * ] ;
- * patch:remove [
- * eg:name "Old name" ; # Remove specific value
- * ingen:canvasX patch:wildcard ; # Remove all
- * ingen:canvasY patch:wildcard ; # Remove all
- * ] .
- * @endcode
- */
-void
-AtomWriter::operator()(const Delta& message)
-{
- LV2_Atom_Forge_Frame msg;
- forge_request(&msg, _uris.patch_Patch, message.seq);
- forge_context(message.ctx);
- lv2_atom_forge_key(&_forge, _uris.patch_subject);
- forge_uri(message.uri);
-
- lv2_atom_forge_key(&_forge, _uris.patch_remove);
- LV2_Atom_Forge_Frame remove_obj;
- lv2_atom_forge_object(&_forge, &remove_obj, 0, 0);
- forge_properties(message.remove);
- lv2_atom_forge_pop(&_forge, &remove_obj);
-
- lv2_atom_forge_key(&_forge, _uris.patch_add);
- LV2_Atom_Forge_Frame add_obj;
- lv2_atom_forge_object(&_forge, &add_obj, 0, 0);
- forge_properties(message.add);
- lv2_atom_forge_pop(&_forge, &add_obj);
-
- lv2_atom_forge_pop(&_forge, &msg);
- finish_msg();
-}
-
-/** @page protocol
- * @subsection Copy
- *
- * Send a [Copy](http://lv2plug.in/ns/ext/copy#Copy) to copy an object from
- * its current location (subject) to another (destination).
- *
- * If both the subject and destination are inside Ingen, like block paths, then the old object
- * is copied by, for example, creating a new plugin instance.
- *
- * If the subject is a filename (file URI or atom:Path) and the destination is
- * inside Ingen, then the subject must be an Ingen graph file or bundle, which
- * is loaded to the specified destination path.
- *
- * If the subject is inside Ingen and the destination is a filename, then the
- * subject is saved to an Ingen bundle at the given destination.
- *
- * @code{.ttl}
- * []
- * a patch:Copy ;
- * patch:subject </main/osc> ;
- * patch:destination </main/osc2> .
- * @endcode
- */
-void
-AtomWriter::operator()(const Copy& message)
-{
- LV2_Atom_Forge_Frame msg;
- forge_request(&msg, _uris.patch_Copy, message.seq);
- lv2_atom_forge_key(&_forge, _uris.patch_subject);
- forge_uri(message.old_uri);
- lv2_atom_forge_key(&_forge, _uris.patch_destination);
- forge_uri(message.new_uri);
- lv2_atom_forge_pop(&_forge, &msg);
- finish_msg();
-}
-
-/** @page protocol
- * @subsection Move
- *
- * Send a [Move](http://lv2plug.in/ns/ext/move#Move) to move an object from its
- * current location (subject) to another (destination).
- *
- * Both subject and destination must be paths in Ingen with the same parent,
- * moving between graphs is currently not supported.
- *
- * @code{.ttl}
- * []
- * a patch:Move ;
- * patch:subject </main/osc> ;
- * patch:destination </main/osc2> .
- * @endcode
- */
-void
-AtomWriter::operator()(const Move& message)
-{
- LV2_Atom_Forge_Frame msg;
- forge_request(&msg, _uris.patch_Move, message.seq);
- lv2_atom_forge_key(&_forge, _uris.patch_subject);
- forge_uri(path_to_uri(message.old_path));
- lv2_atom_forge_key(&_forge, _uris.patch_destination);
- forge_uri(path_to_uri(message.new_path));
- lv2_atom_forge_pop(&_forge, &msg);
- finish_msg();
-}
-
-/** @page protocol
- * @subsection Delete
- *
- * Send a [Delete](http://lv2plug.in/ns/ext/delete#Delete) to remove an
- * object from the engine and destroy it.
- *
- * All properties of the object are lost, as are all references to the object
- * (e.g. any connections to it).
- *
- * @code{.ttl}
- * []
- * a patch:Delete ;
- * patch:subject </main/osc> .
- * @endcode
- */
-void
-AtomWriter::operator()(const Del& message)
-{
- LV2_Atom_Forge_Frame msg;
- forge_request(&msg, _uris.patch_Delete, message.seq);
- lv2_atom_forge_key(&_forge, _uris.patch_subject);
- forge_uri(message.uri);
- lv2_atom_forge_pop(&_forge, &msg);
- finish_msg();
-}
-
-/** @page protocol
- * @subsection Set
- *
- * Send a [Set](http://lv2plug.in/ns/ext/patch#Set) to set a property on an
- * object. Any existing value for that property is removed.
- *
- * @code{.ttl}
- * []
- * a patch:Set ;
- * patch:subject </main/osc> ;
- * patch:property lv2:name ;
- * patch:value "Oscwellator" .
- * @endcode
- */
-void
-AtomWriter::operator()(const SetProperty& message)
-{
- LV2_Atom_Forge_Frame msg;
- forge_request(&msg, _uris.patch_Set, message.seq);
- forge_context(message.ctx);
- lv2_atom_forge_key(&_forge, _uris.patch_subject);
- forge_uri(message.subject);
- lv2_atom_forge_key(&_forge, _uris.patch_property);
- lv2_atom_forge_urid(&_forge, _map.map_uri(message.predicate.c_str()));
- lv2_atom_forge_key(&_forge, _uris.patch_value);
- lv2_atom_forge_atom(&_forge, message.value.size(), message.value.type());
- lv2_atom_forge_write(&_forge, message.value.get_body(), message.value.size());
-
- lv2_atom_forge_pop(&_forge, &msg);
- finish_msg();
-}
-
-/** @page protocol
- * @subsection Undo
- *
- * Use [ingen:Undo](http://drobilla.net/ns/ingen#Undo) to undo the last change
- * to the engine. Undo transactions can be delimited using bundle markers, if
- * the last operations(s) received were in a bundle, then an Undo will undo the
- * effects of that entire bundle.
- *
- * @code{.ttl}
- * [] a ingen:Undo .
- * @endcode
- */
-void
-AtomWriter::operator()(const Undo& message)
-{
- LV2_Atom_Forge_Frame msg;
- forge_request(&msg, _uris.ingen_Undo, message.seq);
- lv2_atom_forge_pop(&_forge, &msg);
- finish_msg();
-}
-
-/** @page protocol
- * @subsection Undo
- *
- * Use [ingen:Redo](http://drobilla.net/ns/ingen#Redo) to redo the last undone change.
- *
- * @code{.ttl}
- * [] a ingen:Redo .
- * @endcode
- */
-void
-AtomWriter::operator()(const Redo& message)
-{
- LV2_Atom_Forge_Frame msg;
- forge_request(&msg, _uris.ingen_Redo, message.seq);
- lv2_atom_forge_pop(&_forge, &msg);
- finish_msg();
-}
-
-/** @page protocol
- * @subsection Get
- *
- * Send a [Get](http://lv2plug.in/ns/ext/patch#Get) to get the description
- * of the subject.
- *
- * @code{.ttl}
- * []
- * a patch:Get ;
- * patch:subject </main/osc> .
- * @endcode
- */
-void
-AtomWriter::operator()(const Get& message)
-{
- LV2_Atom_Forge_Frame msg;
- forge_request(&msg, _uris.patch_Get, message.seq);
- lv2_atom_forge_key(&_forge, _uris.patch_subject);
- forge_uri(message.subject);
- lv2_atom_forge_pop(&_forge, &msg);
- finish_msg();
-}
-
-/** @page protocol
- *
- * @section arcs Arc Manipulation
- */
-
-/** @page protocol
- * @subsection Connect Connecting Ports
- *
- * Ports are connected by putting an arc with the desired tail (an output port)
- * and head (an input port). The tail and head must both be within the
- * subject, which must be a graph.
- *
- * @code{.ttl}
- * []
- * a patch:Put ;
- * patch:subject </main/> ;
- * patch:body [
- * a ingen:Arc ;
- * ingen:tail </main/osc/out> ;
- * ingen:head </main/filt/in> ;
- * ] .
- * @endcode
- */
-void
-AtomWriter::operator()(const Connect& message)
-{
- LV2_Atom_Forge_Frame msg;
- forge_request(&msg, _uris.patch_Put, message.seq);
- lv2_atom_forge_key(&_forge, _uris.patch_subject);
- forge_uri(path_to_uri(Raul::Path::lca(message.tail, message.head)));
- lv2_atom_forge_key(&_forge, _uris.patch_body);
- forge_arc(message.tail, message.head);
- lv2_atom_forge_pop(&_forge, &msg);
- finish_msg();
-}
-
-/** @page protocol
- * @subsection Disconnect Disconnecting Ports
- *
- * Ports are disconnected by deleting the arc between them. The description of
- * the arc is the same as in the put command used to create the connection.
- *
- * @code{.ttl}
- * []
- * a patch:Delete ;
- * patch:body [
- * a ingen:Arc ;
- * ingen:tail </main/osc/out> ;
- * ingen:head </main/filt/in> ;
- * ] .
- * @endcode
- */
-void
-AtomWriter::operator()(const Disconnect& message)
-{
- LV2_Atom_Forge_Frame msg;
- forge_request(&msg, _uris.patch_Delete, message.seq);
- lv2_atom_forge_key(&_forge, _uris.patch_body);
- forge_arc(message.tail, message.head);
- lv2_atom_forge_pop(&_forge, &msg);
- finish_msg();
-}
-
-/** @page protocol
- * @subsection DisconnectAll Fully Disconnecting Anything
- *
- * All arcs to or from anything can be removed by giving the special property
- * ingen:incidentTo rather than a specific head and tail. This works for both
- * ports and blocks (where the effect is to disconnect everything from ports on
- * that block).
- *
- * @code{.ttl}
- * []
- * a patch:Delete ;
- * patch:subject </main> ;
- * patch:body [
- * a ingen:Arc ;
- * ingen:incidentTo </main/osc/out>
- * ] .
- * @endcode
- */
-void
-AtomWriter::operator()(const DisconnectAll& message)
-{
- LV2_Atom_Forge_Frame msg;
- forge_request(&msg, _uris.patch_Delete, message.seq);
-
- lv2_atom_forge_key(&_forge, _uris.patch_subject);
- forge_uri(path_to_uri(message.graph));
-
- lv2_atom_forge_key(&_forge, _uris.patch_body);
- LV2_Atom_Forge_Frame arc;
- lv2_atom_forge_object(&_forge, &arc, 0, _uris.ingen_Arc);
- lv2_atom_forge_key(&_forge, _uris.ingen_incidentTo);
- forge_uri(path_to_uri(message.path));
- lv2_atom_forge_pop(&_forge, &arc);
-
- lv2_atom_forge_pop(&_forge, &msg);
- finish_msg();
-}
-
-/** @page protocol
- * @section Responses
- *
- * Ingen responds to requests if the patch:sequenceNumber property is set. For
- * example:
- * @code{.ttl}
- * []
- * a patch:Get ;
- * patch:sequenceNumber 42 ;
- * patch:subject </main/osc> .
- * @endcode
- *
- * Might receive a response like:
- * @code{.ttl}
- * []
- * a patch:Response ;
- * patch:sequenceNumber 42 ;
- * patch:subject </main/osc> ;
- * patch:body 0 .
- * @endcode
- *
- * Where 0 is a status code, 0 meaning success and any other value being an
- * error. Information about status codes, including error message strings,
- * are defined in ingen.lv2/errors.ttl.
- *
- * Note that a response is only a status response, operations that manipulate
- * the graph may generate new data on the stream, e.g. the above get request
- * would also receive a put that describes /main/osc in the stream immediately
- * following the response.
- */
-void
-AtomWriter::operator()(const Response& response)
-{
- const auto& subject = response.subject;
- if (!response.id) {
- return;
- }
-
- LV2_Atom_Forge_Frame msg;
- forge_request(&msg, _uris.patch_Response, 0);
- lv2_atom_forge_key(&_forge, _uris.patch_sequenceNumber);
- lv2_atom_forge_int(&_forge, response.id);
- if (!subject.empty()) {
- lv2_atom_forge_key(&_forge, _uris.patch_subject);
- lv2_atom_forge_uri(&_forge, subject.c_str(), subject.length());
- }
- lv2_atom_forge_key(&_forge, _uris.patch_body);
- lv2_atom_forge_int(&_forge, static_cast<int>(response.status));
- lv2_atom_forge_pop(&_forge, &msg);
- finish_msg();
-}
-
-void
-AtomWriter::operator()(const Error&)
-{
-}
-
-/** @page protocol
- * @section loading Loading and Unloading Bundles
- *
- * The property ingen:loadedBundle on the engine can be used to load
- * or unload bundles from Ingen's world. For example:
- *
- * @code{.ttl}
- * # Load /old.lv2
- * []
- * a patch:Put ;
- * patch:subject </> ;
- * patch:body [
- * ingen:loadedBundle <file:///old.lv2/>
- * ] .
- *
- * # Replace /old.lv2 with /new.lv2
- * []
- * a patch:Patch ;
- * patch:subject </> ;
- * patch:remove [
- * ingen:loadedBundle <file:///old.lv2/>
- * ];
- * patch:add [
- * ingen:loadedBundle <file:///new.lv2/>
- * ] .
- * @endcode
- */
-
-} // namespace Ingen
diff --git a/src/ClashAvoider.cpp b/src/ClashAvoider.cpp
deleted file mode 100644
index ae4438a4..00000000
--- a/src/ClashAvoider.cpp
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- 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 <cassert>
-#include <cstdio>
-#include <sstream>
-#include <string>
-#include <utility>
-
-#include "ingen/ClashAvoider.hpp"
-#include "ingen/Store.hpp"
-#include "ingen/paths.hpp"
-
-namespace Ingen {
-
-ClashAvoider::ClashAvoider(const Store& store)
- : _store(store)
-{}
-
-const URI
-ClashAvoider::map_uri(const URI& in)
-{
- if (uri_is_path(in)) {
- return path_to_uri(map_path(uri_to_path(in)));
- } else {
- return in;
- }
-}
-
-const Raul::Path
-ClashAvoider::map_path(const Raul::Path& in)
-{
- unsigned offset = 0;
- bool has_offset = false;
- const size_t pos = in.find_last_of('_');
- if (pos != std::string::npos && pos != (in.length()-1)) {
- const std::string trailing = in.substr(pos + 1);
- has_offset = (sscanf(trailing.c_str(), "%u", &offset) > 0);
- }
-
- // Path without _n suffix
- std::string base_path_str = in;
- if (has_offset) {
- base_path_str = base_path_str.substr(0, base_path_str.find_last_of('_'));
- }
-
- Raul::Path base_path(base_path_str);
-
- auto m = _symbol_map.find(in);
- if (m != _symbol_map.end()) {
- return m->second;
- } else {
- typedef std::pair<SymbolMap::iterator, bool> InsertRecord;
-
- // See if parent is mapped
- Raul::Path parent = in.parent();
- do {
- auto p = _symbol_map.find(parent);
- if (p != _symbol_map.end()) {
- const Raul::Path mapped = Raul::Path(
- p->second.base() + in.substr(parent.base().length()));
- InsertRecord i = _symbol_map.emplace(in, mapped);
- return i.first->second;
- }
- parent = parent.parent();
- } while (!parent.is_root());
-
- if (!exists(in) && _symbol_map.find(in) == _symbol_map.end()) {
- // No clash, use symbol unmodified
- InsertRecord i = _symbol_map.emplace(in, in);
- assert(i.second);
- return i.first->second;
-
- } else {
- // Append _2 _3 etc until an unused symbol is found
- while (true) {
- auto o = _offsets.find(base_path);
- if (o != _offsets.end()) {
- offset = ++o->second;
- } else {
- std::string parent_str = in.parent().base();
- parent_str = parent_str.substr(0, parent_str.find_last_of("/"));
- if (parent_str.empty()) {
- parent_str = "/";
- }
- }
-
- if (offset == 0) {
- offset = 2;
- }
-
- std::stringstream ss;
- ss << base_path << "_" << offset;
- if (!exists(Raul::Path(ss.str()))) {
- std::string name = base_path.symbol();
- if (name == "") {
- name = "_";
- }
- Raul::Symbol sym(name);
- std::string str = ss.str();
- InsertRecord i = _symbol_map.emplace(in, Raul::Path(str));
- offset = _store.child_name_offset(in.parent(), sym, false);
- _offsets.emplace(base_path, offset);
- return i.first->second;
- } else {
- if (o != _offsets.end()) {
- offset = ++o->second;
- } else {
- ++offset;
- }
- }
- }
- }
- }
-}
-
-bool
-ClashAvoider::exists(const Raul::Path& path) const
-{
- return _store.find(path) != _store.end();
-}
-
-} // namespace Ingen
diff --git a/src/ColorContext.cpp b/src/ColorContext.cpp
deleted file mode 100644
index 23b568f1..00000000
--- a/src/ColorContext.cpp
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- 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/>.
-*/
-
-#include "ingen/ColorContext.hpp"
-#include "ingen_config.h"
-
-#ifdef HAVE_ISATTY
-# include <unistd.h>
-#else
-inline int isatty(int fd) { return 0; }
-#endif
-
-namespace Ingen {
-
-ColorContext::ColorContext(FILE* stream, Color color)
- : _stream(stream)
-{
- if (isatty(fileno(_stream))) {
- fprintf(_stream, "\033[0;%dm", (int)color);
- }
-}
-
-ColorContext::~ColorContext()
-{
- if (isatty(fileno(_stream))) {
- fprintf(_stream, "\033[0m");
- fflush(_stream);
- }
-}
-
-} // namespace Ingen
diff --git a/src/Configuration.cpp b/src/Configuration.cpp
deleted file mode 100644
index c797cf93..00000000
--- a/src/Configuration.cpp
+++ /dev/null
@@ -1,386 +0,0 @@
-/*
- 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/>.
-*/
-
-#include <cassert>
-#include <cerrno>
-#include <cstring>
-#include <iostream>
-#include <thread>
-
-#include "ingen/Configuration.hpp"
-#include "ingen/Forge.hpp"
-#include "ingen/Log.hpp"
-#include "ingen/URIMap.hpp"
-#include "ingen/filesystem.hpp"
-#include "ingen/ingen.h"
-#include "ingen/runtime_paths.hpp"
-#include "sord/sordmm.hpp"
-#include "sratom/sratom.h"
-
-namespace Ingen {
-
-Configuration::Configuration(Forge& forge)
- : _forge(forge)
- , _shortdesc("A realtime modular audio processor.")
- , _desc(
- "Ingen is a flexible modular system that be used in various ways.\n"
- "The engine can run as a server controlled via a network protocol,\n"
- "as an LV2 plugin, or in a monolithic process with a GUI. The GUI\n"
- "may be run separately to control a remote engine, and many clients\n"
- "may connect to an engine at once.\n\n"
- "Examples:\n"
- " ingen -e # Run engine, listen for connections\n"
- " ingen -g # Run GUI, connect to running engine\n"
- " ingen -eg # Run engine and GUI in one process\n"
- " ingen -eg foo.ingen # Run engine and GUI and load a graph")
- , _max_name_length(0)
-{
- add("atomicBundles", "atomic-bundles", 'a', "Execute bundles atomically", GLOBAL, forge.Bool, forge.make(false));
- add("bufferSize", "buffer-size", 'b', "Buffer size in samples", GLOBAL, forge.Int, forge.make(1024));
- add("clientPort", "client-port", 'C', "Client port", GLOBAL, forge.Int, Atom());
- add("connect", "connect", 'c', "Connect to engine URI", SESSION, forge.String, forge.alloc("unix:///tmp/ingen.sock"));
- add("engine", "engine", 'e', "Run (JACK) engine", SESSION, forge.Bool, forge.make(false));
- add("enginePort", "engine-port", 'E', "Engine listen port", GLOBAL, forge.Int, forge.make(16180));
- add("socket", "socket", 'S', "Engine socket path", GLOBAL, forge.String, forge.alloc("/tmp/ingen.sock"));
- add("gui", "gui", 'g', "Launch the GTK graphical interface", SESSION, forge.Bool, forge.make(false));
- add("", "help", 'h', "Print this help message", SESSION, forge.Bool, forge.make(false));
- add("", "version", 'V', "Print version information", SESSION, forge.Bool, forge.make(false));
- add("jackName", "jack-name", 'n', "JACK name", GLOBAL, forge.String, forge.alloc("ingen"));
- add("jackServer", "jack-server", 's', "JACK server name", GLOBAL, forge.String, forge.alloc(""));
- add("uuid", "uuid", 'u', "JACK session UUID", GLOBAL, forge.String, Atom());
- add("load", "load", 'l', "Load graph", SESSION, forge.String, Atom());
- add("serverLoad", "server-load", 'i', "Load graph (server side)", SESSION, forge.String, Atom());
- add("save", "save", 'o', "Save graph", SESSION, forge.String, Atom());
- add("execute", "execute", 'x', "File of commands to execute", SESSION, forge.String, Atom());
- add("path", "path", 'L', "Target path for loaded graph", SESSION, forge.String, Atom());
- add("queueSize", "queue-size", 'q', "Event queue size", GLOBAL, forge.Int, forge.make(4096));
- add("flushLog", "flush-log", 'f', "Flush logs after every entry", GLOBAL, forge.Bool, forge.make(false));
- add("dump", "dump", 'd', "Print debug output", SESSION, forge.Bool, forge.make(false));
- add("trace", "trace", 't', "Show LV2 plugin trace messages", SESSION, forge.Bool, forge.make(false));
- add("threads", "threads", 'p', "Number of processing threads", GLOBAL, forge.Int, forge.make(int32_t(std::max(std::thread::hardware_concurrency(), 1U))));
- add("humanNames", "human-names", 0, "Show human names in GUI", GUI, forge.Bool, forge.make(true));
- add("portLabels", "port-labels", 0, "Show port labels in GUI", GUI, forge.Bool, forge.make(true));
- add("graphDirectory", "graph-directory", 0, "Default directory for opening graphs", GUI, forge.String, Atom());
-}
-
-Configuration&
-Configuration::add(const std::string& key,
- const std::string& name,
- char letter,
- const std::string& desc,
- Scope scope,
- const LV2_URID type,
- const Atom& value)
-{
- assert(value.type() == type || value.type() == 0);
- _max_name_length = std::max(_max_name_length, name.length());
- _options.emplace(name, Option{key, name, letter, desc, scope, type, value});
- if (!key.empty()) {
- _keys.emplace(key, name);
- }
- if (letter != '\0') {
- _short_names.emplace(letter, name);
- }
- return *this;
-}
-
-std::string
-Configuration::variable_string(LV2_URID type) const
-{
- if (type == _forge.String) {
- return "=STRING";
- } else if (type == _forge.Int) {
- return "=INT";
- }
- return "";
-}
-
-void
-Configuration::print_usage(const std::string& program, std::ostream& os)
-{
- os << "Usage: " << program << " [OPTION]... [GRAPH]" << std::endl;
- os << _shortdesc << std::endl << std::endl;
- os << _desc << std::endl << std::endl;
- os << "Options:" << std::endl;
- for (const auto& o : _options) {
- const Option& option = o.second;
- os << " ";
- if (option.letter != '\0') {
- os << "-" << option.letter << ", ";
- } else {
- os << " ";
- }
- os.width(_max_name_length + 11);
- os << std::left;
- os << (std::string("--") + o.first + variable_string(option.type));
- os << option.desc << std::endl;
- }
-}
-
-int
-Configuration::set_value_from_string(Configuration::Option& option,
- const std::string& value)
-{
- if (option.type == _forge.Int) {
- char* endptr = nullptr;
- int intval = static_cast<int>(strtol(value.c_str(), &endptr, 10));
- if (endptr && *endptr == '\0') {
- option.value = _forge.make(intval);
- } else {
- throw OptionError(
- (fmt("Option `%1%' has non-integer value `%2%'")
- % option.name % value).str());
- }
- } else if (option.type == _forge.String) {
- option.value = _forge.alloc(value.c_str());
- assert(option.value.type() == _forge.String);
- } else if (option.type == _forge.Bool) {
- option.value = _forge.make(bool(!strcmp(value.c_str(), "true")));
- assert(option.value.type() == _forge.Bool);
- } else {
- throw OptionError(
- (fmt("Bad option type `%1%'") % option.name).str());
- }
- return EXIT_SUCCESS;
-}
-
-/** Parse command line arguments. */
-void
-Configuration::parse(int argc, char** argv)
-{
- for (int i = 1; i < argc; ++i) {
- if (argv[i][0] != '-' || !strcmp(argv[i], "-")) {
- // File argument
- const Options::iterator o = _options.find("load");
- if (!o->second.value.is_valid()) {
- _options.find("load")->second.value = _forge.alloc(argv[i]);
- } else {
- throw OptionError("Multiple graphs specified");
- }
- } else if (argv[i][1] == '-') {
- // Long option
- std::string name = std::string(argv[i]).substr(2);
- const char* equals = strchr(argv[i], '=');
- if (equals) {
- name = name.substr(0, name.find('='));
- }
-
- const Options::iterator o = _options.find(name);
- if (o == _options.end()) {
- throw OptionError(
- (fmt("Unrecognized option `%1%'") % name).str());
- } else if (o->second.type == _forge.Bool) { // --flag
- o->second.value = _forge.make(true);
- } else if (equals) { // --opt=val
- set_value_from_string(o->second, equals + 1);
- } else if (++i < argc) { // --opt val
- set_value_from_string(o->second, argv[i]);
- } else {
- throw OptionError(
- (fmt("Missing value for `%1%'") % name).str());
- }
- } else {
- // Short option
- const size_t len = strlen(argv[i]);
- for (size_t j = 1; j < len; ++j) {
- const char letter = argv[i][j];
- const ShortNames::iterator n = _short_names.find(letter);
- if (n == _short_names.end()) {
- throw OptionError(
- (fmt("Unrecognized option `%1%'") % letter).str());
- }
-
- const Options::iterator o = _options.find(n->second);
- if (j < len - 1) { // Non-final POSIX style flag
- if (o->second.type != _forge.Bool) {
- throw OptionError(
- (fmt("Missing value for `%1%'") % letter).str());
- }
- o->second.value = _forge.make(true);
- } else if (o->second.type == _forge.Bool) { // -f
- o->second.value = _forge.make(true);
- } else if (++i < argc) { // -v val
- set_value_from_string(o->second, argv[i]);
- } else {
- throw OptionError(
- (fmt("Missing value for `%1%'") % letter).str());
- }
- }
- }
- }
-}
-
-bool
-Configuration::load(const FilePath& path)
-{
- if (!filesystem::exists(path)) {
- return false;
- }
-
- SerdNode node = serd_node_new_file_uri(
- (const uint8_t*)path.c_str(), nullptr, nullptr, true);
- const std::string uri((const char*)node.buf);
-
- Sord::World world;
- Sord::Model model(world, uri, SORD_SPO, false);
- SerdEnv* env = serd_env_new(&node);
- model.load_file(env, SERD_TURTLE, uri, uri);
-
- Sord::Node nodemm(world, Sord::Node::URI, (const char*)node.buf);
- Sord::Node nil;
- for (Sord::Iter i = model.find(nodemm, nil, nil); !i.end(); ++i) {
- const Sord::Node& pred = i.get_predicate();
- const Sord::Node& obj = i.get_object();
- if (pred.to_string().substr(0, sizeof(INGEN_NS) - 1) == INGEN_NS) {
- const std::string key = pred.to_string().substr(sizeof(INGEN_NS) - 1);
- const Keys::iterator k = _keys.find(key);
- if (k != _keys.end() && obj.type() == Sord::Node::LITERAL) {
- set_value_from_string(_options.find(k->second)->second,
- obj.to_string());
- }
- }
- }
-
- serd_node_free(&node);
- serd_env_free(env);
- return true;
-}
-
-FilePath
-Configuration::save(URIMap& uri_map,
- const std::string& app,
- const FilePath& filename,
- unsigned scopes)
-{
- // Save to file if it is absolute, otherwise save to user config dir
- FilePath path = filename;
- if (!path.is_absolute()) {
- path = FilePath(user_config_dir()) / app / filename;
- }
-
- // Create parent directories if necessary
- const FilePath dir = path.parent_path();
- if (!filesystem::create_directories(dir)) {
- throw FileError((fmt("Error creating directory %1% (%2%)")
- % dir % strerror(errno)).str());
- }
-
- // Attempt to open file for writing
- FILE* file = fopen(path.c_str(), "w");
- if (!file) {
- throw FileError((fmt("Failed to open file %1% (%2%)")
- % path % strerror(errno)).str());
- }
-
- // Use the file's URI as the base URI
- SerdURI base_uri;
- SerdNode base = serd_node_new_file_uri(
- (const uint8_t*)path.c_str(), nullptr, &base_uri, true);
-
- // Create environment with ingen prefix
- SerdEnv* env = serd_env_new(&base);
- serd_env_set_prefix_from_strings(
- env, (const uint8_t*)"ingen", (const uint8_t*)INGEN_NS);
-
- // Create Turtle writer
- SerdWriter* writer = serd_writer_new(
- SERD_TURTLE,
- (SerdStyle)(SERD_STYLE_RESOLVED|SERD_STYLE_ABBREVIATED),
- env,
- &base_uri,
- serd_file_sink,
- file);
-
- // Write a prefix directive for each prefix in the environment
- serd_env_foreach(env, (SerdPrefixSink)serd_writer_set_prefix, writer);
-
- // Create an atom serialiser and connect it to the Turtle writer
- Sratom* sratom = sratom_new(&uri_map.urid_map_feature()->urid_map);
- sratom_set_pretty_numbers(sratom, true);
- sratom_set_sink(sratom, (const char*)base.buf,
- (SerdStatementSink)serd_writer_write_statement, nullptr,
- writer);
-
- // Write a statement for each valid option
- for (auto o : _options) {
- const Atom& value = o.second.value;
- if (!(o.second.scope & scopes) ||
- o.second.key.empty() ||
- !value.is_valid()) {
- continue;
- }
-
- const std::string key(std::string("ingen:") + o.second.key);
- SerdNode pred = serd_node_from_string(
- SERD_CURIE, (const uint8_t*)key.c_str());
- sratom_write(sratom, &uri_map.urid_unmap_feature()->urid_unmap, 0,
- &base, &pred, value.type(), value.size(), value.get_body());
- }
-
- sratom_free(sratom);
- serd_writer_free(writer);
- serd_env_free(env);
- serd_node_free(&base);
- fclose(file);
-
- return path;
-}
-
-std::list<FilePath>
-Configuration::load_default(const std::string& app, const FilePath& filename)
-{
- std::list<FilePath> loaded;
-
- const std::vector<FilePath> dirs = system_config_dirs();
- for (const auto& d : dirs) {
- const FilePath path = d / app / filename;
- if (load(path)) {
- loaded.push_back(path);
- }
- }
-
- const FilePath path = user_config_dir() / app / filename;
- if (load(path)) {
- loaded.push_back(path);
- }
-
- return loaded;
-}
-
-const Atom&
-Configuration::option(const std::string& long_name) const
-{
- static const Atom nil;
- auto o = _options.find(long_name);
- if (o == _options.end()) {
- return nil;
- } else {
- return o->second.value;
- }
-}
-
-bool
-Configuration::set(const std::string& long_name, const Atom& value)
-{
- auto o = _options.find(long_name);
- if (o != _options.end()) {
- o->second.value = value;
- return true;
- }
- return false;
-}
-
-} // namespace Ingen
diff --git a/src/FilePath.cpp b/src/FilePath.cpp
deleted file mode 100644
index 557fabc9..00000000
--- a/src/FilePath.cpp
+++ /dev/null
@@ -1,242 +0,0 @@
-/*
- This file is part of Ingen.
- Copyright 2018 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/FilePath.hpp"
-
-namespace Ingen {
-
-template <typename Char>
-static bool
-is_sep(const Char chr)
-{
-#ifdef USE_WINDOWS_FILE_PATHS
- return chr == L'/' || chr == preferred_separator;
-#else
- return chr == '/';
-#endif
-}
-
-FilePath&
-FilePath::operator=(FilePath&& path) noexcept
-{
- _str = std::move(path._str);
- path.clear();
- return *this;
-}
-
-FilePath&
-FilePath::operator=(string_type&& str)
-{
- return *this = FilePath(std::move(str));
-}
-
-FilePath&
-FilePath::operator/=(const FilePath& path)
-{
- const FilePath::string_type str = path.string();
- if (!_str.empty() && !is_sep(_str.back()) && !str.empty() &&
- !is_sep(str.front())) {
- _str += preferred_separator;
- }
-
- _str += str;
- return *this;
-}
-
-FilePath&
-FilePath::operator+=(const FilePath& path)
-{
- return operator+=(path.native());
-}
-
-FilePath&
-FilePath::operator+=(const string_type& str)
-{
- _str += str;
- return *this;
-}
-
-FilePath&
-FilePath::operator+=(const value_type* str)
-{
- _str += str;
- return *this;
-}
-
-FilePath&
-FilePath::operator+=(value_type chr)
-{
- _str += chr;
- return *this;
-}
-
-FilePath&
-FilePath::operator+=(boost::basic_string_view<value_type> sv)
-{
- _str.append(sv.data(), sv.size());
- return *this;
-}
-
-FilePath
-FilePath::root_name() const
-{
-#ifdef USE_WINDOWS_FILE_PATHS
- if (_str.length() >= 2 && _str[0] >= 'A' && _str[0] <= 'Z' &&
- _str[1] == ':') {
- return FilePath(_str.substr(0, 2));
- }
-#endif
-
- return FilePath();
-}
-
-FilePath
-FilePath::root_directory() const
-{
-#ifdef USE_WINDOWS_FILE_PATHS
- const auto name = root_name().string();
- return name.empty() ? Path() : Path(name + preferred_separator);
-#endif
-
- return _str[0] == '/' ? FilePath("/") : FilePath();
-}
-
-FilePath
-FilePath::root_path() const
-{
-#ifdef USE_WINDOWS_FILE_PATHS
- const auto name = root_name();
- return name.empty() ? FilePath() : name / root_directory();
-#endif
- return root_directory();
-}
-
-FilePath
-FilePath::relative_path() const
-{
- const auto root = root_path();
- return root.empty() ? FilePath()
- : FilePath(_str.substr(root.string().length()));
-}
-
-FilePath
-FilePath::parent_path() const
-{
- if (empty() || *this == root_path()) {
- return *this;
- }
-
- const auto first_sep = find_first_sep();
- const auto last_sep = find_last_sep();
- return ((last_sep == std::string::npos || last_sep == first_sep)
- ? root_path()
- : FilePath(_str.substr(0, last_sep)));
-}
-
-FilePath
-FilePath::filename() const
-{
- return ((empty() || *this == root_path())
- ? FilePath()
- : FilePath(_str.substr(find_last_sep() + 1)));
-}
-
-FilePath
-FilePath::stem() const
-{
- const auto name = filename();
- const auto dot = name.string().find('.');
- return ((dot == std::string::npos) ? name
- : FilePath(name.string().substr(0, dot)));
-}
-
-FilePath
-FilePath::extension() const
-{
- const auto name = filename().string();
- const auto dot = name.find('.');
- return ((dot == std::string::npos) ? FilePath()
- : FilePath(name.substr(dot, dot)));
-}
-
-bool
-FilePath::is_absolute() const
-{
-#ifdef USE_WINDOWS_FILE_PATHS
- return !root_name().empty();
-#else
- return !root_directory().empty();
-#endif
-}
-
-std::size_t
-FilePath::find_first_sep() const
-{
- const auto i = std::find_if(_str.begin(), _str.end(), is_sep<value_type>);
- return i == _str.end() ? std::string::npos : (i - _str.begin());
-}
-
-std::size_t
-FilePath::find_last_sep() const
-{
- const auto i = std::find_if(_str.rbegin(), _str.rend(), is_sep<value_type>);
- return (i == _str.rend() ? std::string::npos
- : (_str.length() - 1 - (i - _str.rbegin())));
-}
-
-bool
-operator==(const FilePath& lhs, const FilePath& rhs) noexcept
-{
- return lhs.string() == rhs.string();
-}
-
-bool
-operator!=(const FilePath& lhs, const FilePath& rhs) noexcept
-{
- return !(lhs == rhs);
-}
-
-bool
-operator<(const FilePath& lhs, const FilePath& rhs) noexcept
-{
- return lhs.string().compare(rhs.string()) < 0;
-}
-
-bool
-operator<=(const FilePath& lhs, const FilePath& rhs) noexcept
-{
- return !(rhs < lhs);
-}
-
-bool
-operator>(const FilePath& lhs, const FilePath& rhs) noexcept
-{
- return rhs < lhs;
-}
-
-bool
-operator>=(const FilePath& lhs, const FilePath& rhs) noexcept
-{
- return !(lhs < rhs);
-}
-
-FilePath
-operator/(const FilePath& lhs, const FilePath& rhs)
-{
- return FilePath(lhs) /= rhs;
-}
-
-} // namespace Ingen
diff --git a/src/Forge.cpp b/src/Forge.cpp
deleted file mode 100644
index 688d994d..00000000
--- a/src/Forge.cpp
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- 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 <sstream>
-
-#include "ingen/Forge.hpp"
-#include "ingen/URI.hpp"
-#include "ingen/URIMap.hpp"
-#include "lv2/lv2plug.in/ns/ext/atom/atom.h"
-
-namespace Ingen {
-
-Forge::Forge(URIMap& map)
- : _map(map)
-{
- lv2_atom_forge_init(this, &map.urid_map_feature()->urid_map);
-}
-
-Atom
-Forge::make_urid(const Ingen::URI& u)
-{
- const LV2_URID urid = _map.map_uri(u.string());
- return Atom(sizeof(int32_t), URID, &urid);
-}
-
-std::string
-Forge::str(const Atom& atom, bool quoted)
-{
- std::ostringstream ss;
- if (atom.type() == Int) {
- ss << atom.get<int32_t>();
- } else if (atom.type() == Float) {
- ss << atom.get<float>();
- } else if (atom.type() == Bool) {
- ss << (atom.get<int32_t>() ? "true" : "false");
- } else if (atom.type() == URI) {
- ss << (quoted ? "<" : "")
- << atom.ptr<const char>()
- << (quoted ? ">" : "");
- } else if (atom.type() == URID) {
- ss << (quoted ? "<" : "")
- << _map.unmap_uri(atom.get<int32_t>())
- << (quoted ? ">" : "");
- } else if (atom.type() == Path) {
- ss << (quoted ? "<" : "")
- << atom.ptr<const char>()
- << (quoted ? ">" : "");
- } else if (atom.type() == String) {
- ss << (quoted ? "\"" : "")
- << atom.ptr<const char>()
- << (quoted ? "\"" : "");
- }
- return ss.str();
-}
-
-} // namespace Ingen
diff --git a/src/LV2Features.cpp b/src/LV2Features.cpp
deleted file mode 100644
index 356df42c..00000000
--- a/src/LV2Features.cpp
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- 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 <cstdlib>
-
-#include "ingen/LV2Features.hpp"
-
-namespace Ingen {
-
-void
-LV2Features::Feature::free_feature(LV2_Feature* feature)
-{
- free(feature->data);
- free(feature);
-}
-
-LV2Features::LV2Features()
-{
-}
-
-void
-LV2Features::add_feature(SPtr<Feature> feature)
-{
- _features.push_back(feature);
-}
-
-LV2Features::FeatureArray::FeatureArray(FeatureVector& features)
- : _features(features)
-{
- _array = (LV2_Feature**)malloc(sizeof(LV2_Feature*) * (features.size() + 1));
- _array[features.size()] = nullptr;
- for (size_t i = 0; i < features.size(); ++i) {
- _array[i] = features[i].get();
- }
-}
-
-LV2Features::FeatureArray::~FeatureArray()
-{
- free(_array);
-}
-
-bool
-LV2Features::is_supported(const std::string& uri) const
-{
- if (uri == "http://lv2plug.in/ns/lv2core#isLive") {
- return true;
- }
-
- for (const auto& f : _features) {
- if (f->uri() == uri) {
- return true;
- }
- }
- return false;
-}
-
-SPtr<LV2Features::FeatureArray>
-LV2Features::lv2_features(World* world, Node* node) const
-{
- FeatureArray::FeatureVector vec;
- for (const auto& f : _features) {
- SPtr<LV2_Feature> fptr = f->feature(world, node);
- if (fptr) {
- vec.push_back(fptr);
- }
- }
- return SPtr<FeatureArray>(new FeatureArray(vec));
-}
-
-} // namespace Ingen
diff --git a/src/Library.cpp b/src/Library.cpp
deleted file mode 100644
index 148b27d0..00000000
--- a/src/Library.cpp
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- This file is part of Ingen.
- Copyright 2018 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/Library.hpp"
-
-#ifdef _WIN32
-# include <windows.h>
-# define dlopen(path, flags) LoadLibrary(path)
-# define dlclose(lib) FreeLibrary((HMODULE)lib)
-# define dlerror() "unknown error"
-#else
-# include <dlfcn.h>
-#endif
-
-namespace Ingen {
-
-Library::Library(const FilePath& path) : _lib(dlopen(path.c_str(), RTLD_NOW))
-{}
-
-Library::~Library()
-{
- dlclose(_lib);
-}
-
-Library::VoidFuncPtr
-Library::get_function(const char* name)
-{
-#ifdef _WIN32
- return (VoidFuncPtr)GetProcAddress((HMODULE)_lib, name);
-#else
- typedef VoidFuncPtr (*VoidFuncGetter)(void*, const char*);
- VoidFuncGetter dlfunc = (VoidFuncGetter)dlsym;
- return dlfunc(_lib, name);
-#endif
-}
-
-const char*
-Library::get_last_error()
-{
- return dlerror();
-}
-
-} // namespace Ingen
diff --git a/src/Log.cpp b/src/Log.cpp
deleted file mode 100644
index 6145bcd1..00000000
--- a/src/Log.cpp
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- 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/>.
-*/
-
-#include <cstdio>
-
-#include "ingen/Log.hpp"
-#include "ingen/Node.hpp"
-#include "ingen/URIs.hpp"
-#include "ingen/World.hpp"
-#include "ingen/ColorContext.hpp"
-
-namespace Ingen {
-
-Log::Log(LV2_Log_Log* log, URIs& uris)
- : _log(log)
- , _uris(uris)
- , _flush(false)
- , _trace(false)
-{}
-
-void
-Log::rt_error(const char* msg)
-{
-#ifndef NDEBUG
- va_list args;
- vtprintf(_uris.log_Error, msg, args);
-#endif
-}
-
-void
-Log::error(const std::string& msg)
-{
- va_list args;
- vtprintf(_uris.log_Error, msg.c_str(), args);
-}
-
-void
-Log::warn(const std::string& msg)
-{
- va_list args;
- vtprintf(_uris.log_Warning, msg.c_str(), args);
-}
-
-void
-Log::info(const std::string& msg)
-{
- va_list args;
- vtprintf(_uris.log_Note, msg.c_str(), args);
-}
-
-void
-Log::trace(const std::string& msg)
-{
- va_list args;
- vtprintf(_uris.log_Trace, msg.c_str(), args);
-}
-
-void
-Log::print(FILE* stream, const std::string& msg)
-{
- fprintf(stream, "%s", msg.c_str());
- if (_flush) {
- fflush(stdout);
- }
-}
-
-int
-Log::vtprintf(LV2_URID type, const char* fmt, va_list args)
-{
- int ret = 0;
- if (type == _uris.log_Trace && !_trace) {
- return 0;
- } else if (_sink) {
- _sink(type, fmt, args);
- }
-
- if (_log) {
- ret = _log->vprintf(_log->handle, type, fmt, args);
- } else if (type == _uris.log_Error) {
- ColorContext ctx(stderr, ColorContext::Color::RED);
- ret = vfprintf(stderr, fmt, args);
- } else if (type == _uris.log_Warning) {
- ColorContext ctx(stderr, ColorContext::Color::YELLOW);
- ret = vfprintf(stderr, fmt, args);
- } else if (type == _uris.log_Note) {
- ColorContext ctx(stderr, ColorContext::Color::GREEN);
- ret = vfprintf(stdout, fmt, args);
- } else if (_trace && type == _uris.log_Trace) {
- ColorContext ctx(stderr, ColorContext::Color::GREEN);
- ret = vfprintf(stderr, fmt, args);
- } else {
- fprintf(stderr, "Unknown log type %d\n", type);
- return 0;
- }
- if (_flush) {
- fflush(stdout);
- }
- return ret;
-}
-
-static int
-log_vprintf(LV2_Log_Handle handle, LV2_URID type, const char* fmt, va_list args)
-{
- Log::Feature::Handle* f = (Log::Feature::Handle*)handle;
- va_list noargs;
-
- int ret = f->log->vtprintf(type, f->node->path().c_str(), noargs);
- ret += f->log->vtprintf(type, ": ", noargs);
- ret += f->log->vtprintf(type, fmt, args);
-
- return ret;
-}
-
-static int
-log_printf(LV2_Log_Handle handle, LV2_URID type, const char* fmt, ...)
-{
- va_list args;
- va_start(args, fmt);
- const int ret = log_vprintf(handle, type, fmt, args);
- va_end(args);
-
- return ret;
-}
-
-static void
-free_log_feature(LV2_Feature* feature) {
- LV2_Log_Log* lv2_log = (LV2_Log_Log*)feature->data;
- free(lv2_log->handle);
- free(feature);
-}
-
-SPtr<LV2_Feature>
-Log::Feature::feature(World* world, Node* block)
-{
- Handle* handle = (Handle*)calloc(1, sizeof(Handle));
- handle->lv2_log.handle = handle;
- handle->lv2_log.printf = log_printf;
- handle->lv2_log.vprintf = log_vprintf;
- handle->log = &world->log();
- handle->node = block;
-
- LV2_Feature* f = (LV2_Feature*)malloc(sizeof(LV2_Feature));
- f->URI = LV2_LOG__log;
- f->data = &handle->lv2_log;
-
- return SPtr<LV2_Feature>(f, &free_log_feature);
-}
-
-} // namespace Ingen
diff --git a/src/Parser.cpp b/src/Parser.cpp
deleted file mode 100644
index dace07ed..00000000
--- a/src/Parser.cpp
+++ /dev/null
@@ -1,713 +0,0 @@
-/*
- 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/>.
-*/
-
-#include <map>
-#include <set>
-#include <string>
-#include <utility>
-
-#include "ingen/Atom.hpp"
-#include "ingen/AtomForgeSink.hpp"
-#include "ingen/Forge.hpp"
-#include "ingen/Interface.hpp"
-#include "ingen/Log.hpp"
-#include "ingen/Parser.hpp"
-#include "ingen/URI.hpp"
-#include "ingen/URIMap.hpp"
-#include "ingen/URIs.hpp"
-#include "ingen/World.hpp"
-#include "ingen/filesystem.hpp"
-#include "ingen/paths.hpp"
-#include "lv2/lv2plug.in/ns/ext/atom/atom.h"
-#include "serd/serd.h"
-#include "sord/sordmm.hpp"
-#include "sratom/sratom.h"
-
-#define NS_RDF "http://www.w3.org/1999/02/22-rdf-syntax-ns#"
-#define NS_RDFS "http://www.w3.org/2000/01/rdf-schema#"
-
-namespace Ingen {
-
-std::set<Parser::ResourceRecord>
-Parser::find_resources(Sord::World& world,
- const URI& manifest_uri,
- const URI& type_uri)
-{
- const Sord::URI base (world, manifest_uri.string());
- const Sord::URI type (world, type_uri.string());
- const Sord::URI rdf_type (world, NS_RDF "type");
- const Sord::URI rdfs_seeAlso(world, NS_RDFS "seeAlso");
- const Sord::Node nil;
-
- SerdEnv* env = serd_env_new(sord_node_to_serd_node(base.c_obj()));
- Sord::Model model(world, manifest_uri.string());
- model.load_file(env, SERD_TURTLE, manifest_uri.string());
-
- std::set<ResourceRecord> resources;
- for (Sord::Iter i = model.find(nil, rdf_type, type); !i.end(); ++i) {
- const Sord::Node resource = i.get_subject();
- const std::string resource_uri = resource.to_c_string();
- std::string file_path = "";
- Sord::Iter f = model.find(resource, rdfs_seeAlso, nil);
- if (!f.end()) {
- uint8_t* p = serd_file_uri_parse(f.get_object().to_u_string(), nullptr);
- file_path = (const char*)p;
- serd_free(p);
- }
- resources.insert(ResourceRecord(resource, file_path));
- }
-
- serd_env_free(env);
- return resources;
-}
-
-static boost::optional<Raul::Path>
-get_path(const URI base, const URI uri)
-{
- const URI relative = uri.make_relative(base);
- const std::string uri_str = "/" + relative.string();
- return Raul::Path::is_valid(uri_str) ? Raul::Path(uri_str)
- : boost::optional<Raul::Path>();
-}
-
-static bool
-skip_property(Ingen::URIs& uris, const Sord::Node& predicate)
-{
- return (predicate == INGEN__file ||
- predicate == uris.ingen_arc ||
- predicate == uris.ingen_block ||
- predicate == uris.lv2_port);
-}
-
-static Properties
-get_properties(Ingen::World* world,
- Sord::Model& model,
- const Sord::Node& subject,
- Resource::Graph ctx)
-{
- LV2_URID_Map* map = &world->uri_map().urid_map_feature()->urid_map;
- Sratom* sratom = sratom_new(map);
-
- LV2_Atom_Forge forge;
- lv2_atom_forge_init(&forge, map);
-
- AtomForgeSink out(&forge);
-
- const Sord::Node nil;
- Properties props;
- for (Sord::Iter i = model.find(subject, nil, nil); !i.end(); ++i) {
- if (!skip_property(world->uris(), i.get_predicate())) {
- out.clear();
- sratom_read(sratom, &forge, world->rdf_world()->c_obj(),
- model.c_obj(), i.get_object().c_obj());
- const LV2_Atom* atom = out.atom();
- Atom atomm;
- atomm = world->forge().alloc(
- atom->size, atom->type, LV2_ATOM_BODY_CONST(atom));
- props.emplace(i.get_predicate(), Property(atomm, ctx));
- }
- }
-
- sratom_free(sratom);
- return props;
-}
-
-typedef std::pair<Raul::Path, Properties> PortRecord;
-
-static boost::optional<PortRecord>
-get_port(Ingen::World* world,
- Sord::Model& model,
- const Sord::Node& subject,
- Resource::Graph ctx,
- const Raul::Path& parent,
- uint32_t* index)
-{
- const URIs& uris = world->uris();
-
- // Get all properties
- Properties props = get_properties(world, model, subject, ctx);
-
- // Get index if requested (for Graphs)
- if (index) {
- Properties::const_iterator i = props.find(uris.lv2_index);
- if (i == props.end()
- || i->second.type() != world->forge().Int
- || i->second.get<int32_t>() < 0) {
- world->log().error(fmt("Port %1% has no valid index\n") % subject);
- return boost::optional<PortRecord>();
- }
- *index = i->second.get<int32_t>();
- }
-
- // Get symbol
- Properties::const_iterator s = props.find(uris.lv2_symbol);
- std::string sym;
- if (s != props.end() && s->second.type() == world->forge().String) {
- sym = s->second.ptr<char>();
- } else {
- const std::string subject_str = subject.to_string();
- const size_t last_slash = subject_str.find_last_of("/");
-
- sym = ((last_slash == std::string::npos)
- ? subject_str
- : subject_str.substr(last_slash + 1));
- }
-
- if (!Raul::Symbol::is_valid(sym)) {
- world->log().error(fmt("Port %1% has invalid symbol `%2%'\n")
- % subject % sym);
- return boost::optional<PortRecord>();
- }
-
- const Raul::Symbol port_sym(sym);
- const Raul::Path port_path(parent.child(port_sym));
-
- props.erase(uris.lv2_symbol); // Don't set symbol property in engine
- return make_pair(port_path, props);
-}
-
-static boost::optional<Raul::Path>
-parse(
- World* world,
- Interface* target,
- Sord::Model& model,
- const URI& base_uri,
- Sord::Node& subject,
- boost::optional<Raul::Path> parent = boost::optional<Raul::Path>(),
- boost::optional<Raul::Symbol> symbol = boost::optional<Raul::Symbol>(),
- boost::optional<Properties> data = boost::optional<Properties>());
-
-static boost::optional<Raul::Path>
-parse_graph(
- World* world,
- Interface* target,
- Sord::Model& model,
- const URI& base_uri,
- const Sord::Node& subject,
- Resource::Graph ctx,
- boost::optional<Raul::Path> parent = boost::optional<Raul::Path>(),
- boost::optional<Raul::Symbol> symbol = boost::optional<Raul::Symbol>(),
- boost::optional<Properties> data = boost::optional<Properties>());
-
-static boost::optional<Raul::Path>
-parse_block(
- World* world,
- Interface* target,
- Sord::Model& model,
- const URI& base_uri,
- const Sord::Node& subject,
- const Raul::Path& path,
- boost::optional<Properties> data = boost::optional<Properties>());
-
-static bool
-parse_properties(
- World* world,
- Interface* target,
- Sord::Model& model,
- const Sord::Node& subject,
- Resource::Graph ctx,
- const URI& uri,
- boost::optional<Properties> data = boost::optional<Properties>());
-
-static bool
-parse_arcs(
- World* world,
- Interface* target,
- Sord::Model& model,
- const URI& base_uri,
- const Sord::Node& subject,
- const Raul::Path& graph);
-
-static boost::optional<Raul::Path>
-parse_block(Ingen::World* world,
- Ingen::Interface* target,
- Sord::Model& model,
- const URI& base_uri,
- const Sord::Node& subject,
- const Raul::Path& path,
- boost::optional<Properties> data)
-{
- const URIs& uris = world->uris();
-
- // Try lv2:prototype and old ingen:prototype for backwards compatibility
- const Sord::URI prototype_predicates[] = {
- Sord::URI(*world->rdf_world(), uris.lv2_prototype),
- Sord::URI(*world->rdf_world(), uris.ingen_prototype)
- };
-
- // Get prototype
- Sord::Node prototype;
- for (const Sord::URI& pred : prototype_predicates) {
- prototype = model.get(subject, pred, Sord::Node());
- if (prototype.is_valid()) {
- break;
- }
- }
-
- if (!prototype.is_valid()) {
- world->log().error(
- fmt("Block %1% (%2%) missing mandatory lv2:prototype\n") %
- subject % path);
- return boost::optional<Raul::Path>();
- }
-
- const uint8_t* type_uri = (const uint8_t*)prototype.to_c_string();
- if (!serd_uri_string_has_scheme(type_uri) ||
- !strncmp((const char*)type_uri, "file:", 5)) {
- // Prototype is a file, subgraph
- SerdURI base_uri_parts;
- serd_uri_parse((const uint8_t*)base_uri.c_str(), &base_uri_parts);
-
- SerdURI ignored;
- SerdNode sub_uri = serd_node_new_uri_from_string(
- type_uri,
- &base_uri_parts,
- &ignored);
-
- const std::string sub_uri_str = (const char*)sub_uri.buf;
- const std::string sub_file = sub_uri_str + "/main.ttl";
-
- const SerdNode sub_base = serd_node_from_string(
- SERD_URI, (const uint8_t*)sub_file.c_str());
-
- Sord::Model sub_model(*world->rdf_world(), sub_file);
- SerdEnv* env = serd_env_new(&sub_base);
- sub_model.load_file(env, SERD_TURTLE, sub_file);
- serd_env_free(env);
-
- Sord::URI sub_node(*world->rdf_world(), sub_file);
- parse_graph(world, target, sub_model, sub_base,
- sub_node, Resource::Graph::INTERNAL,
- path.parent(), Raul::Symbol(path.symbol()));
-
- parse_graph(world, target, model, base_uri,
- subject, Resource::Graph::EXTERNAL,
- path.parent(), Raul::Symbol(path.symbol()));
- } else {
- // Prototype is non-file URI, plugin
- Properties props = get_properties(
- world, model, subject, Resource::Graph::DEFAULT);
- props.emplace(uris.rdf_type, uris.forge.make_urid(uris.ingen_Block));
- target->put(path_to_uri(path), props);
- }
- return path;
-}
-
-static boost::optional<Raul::Path>
-parse_graph(Ingen::World* world,
- Ingen::Interface* target,
- Sord::Model& model,
- const URI& base_uri,
- const Sord::Node& subject,
- Resource::Graph ctx,
- boost::optional<Raul::Path> parent,
- boost::optional<Raul::Symbol> symbol,
- boost::optional<Properties> data)
-{
- const URIs& uris = world->uris();
-
- const Sord::URI ingen_block(*world->rdf_world(), uris.ingen_block);
- const Sord::URI lv2_port(*world->rdf_world(), LV2_CORE__port);
-
- const Sord::Node& graph = subject;
- const Sord::Node nil;
-
- // Build graph path and symbol
- Raul::Path graph_path;
- if (parent && symbol) {
- graph_path = parent->child(*symbol);
- } else if (parent) {
- graph_path = *parent;
- } else {
- graph_path = Raul::Path("/");
- }
-
- if (!symbol) {
- symbol = Raul::Symbol("_");
- }
-
- // Create graph
- Properties props = get_properties(world, model, subject, ctx);
- target->put(path_to_uri(graph_path), props, ctx);
-
- // For each port on this graph
- typedef std::map<uint32_t, PortRecord> PortRecords;
- PortRecords ports;
- for (Sord::Iter p = model.find(graph, lv2_port, nil); !p.end(); ++p) {
- Sord::Node port = p.get_object();
-
- // Get all properties
- uint32_t index = 0;
- boost::optional<PortRecord> port_record = get_port(
- world, model, port, ctx, graph_path, &index);
- if (!port_record) {
- world->log().error(fmt("Invalid port %1%\n") % port);
- return boost::optional<Raul::Path>();
- }
-
- // Store port information in ports map
- if (ports.find(index) == ports.end()) {
- ports[index] = *port_record;
- } else {
- world->log().error(fmt("Ignored port %1% with duplicate index %2%\n")
- % port % index);
- }
- }
-
- // Create ports in order by index
- for (const auto& p : ports) {
- target->put(path_to_uri(p.second.first),
- p.second.second,
- ctx);
- }
-
- if (ctx != Resource::Graph::INTERNAL) {
- return graph_path; // Not parsing graph internals, finished now
- }
-
- // For each block in this graph
- for (Sord::Iter n = model.find(subject, ingen_block, nil); !n.end(); ++n) {
- Sord::Node node = n.get_object();
- URI node_uri = node;
- assert(!node_uri.path().empty() && node_uri.path() != "/");
- const Raul::Path block_path = graph_path.child(
- Raul::Symbol(FilePath(node_uri.path()).stem().string()));
-
- // Parse and create block
- parse_block(world, target, model, base_uri, node, block_path,
- boost::optional<Properties>());
-
- // For each port on this block
- for (Sord::Iter p = model.find(node, lv2_port, nil); !p.end(); ++p) {
- Sord::Node port = p.get_object();
-
- Resource::Graph subctx = Resource::Graph::DEFAULT;
- if (!model.find(node,
- Sord::URI(*world->rdf_world(), uris.rdf_type),
- Sord::URI(*world->rdf_world(), uris.ingen_Graph)).end()) {
- subctx = Resource::Graph::EXTERNAL;
- }
-
- // Get all properties
- boost::optional<PortRecord> port_record = get_port(
- world, model, port, subctx, block_path, nullptr);
- if (!port_record) {
- world->log().error(fmt("Invalid port %1%\n") % port);
- return boost::optional<Raul::Path>();
- }
-
- // Create port and/or set all port properties
- target->put(path_to_uri(port_record->first),
- port_record->second,
- subctx);
- }
- }
-
- // Now that all ports and blocks exist, create arcs inside graph
- parse_arcs(world, target, model, base_uri, subject, graph_path);
-
- return graph_path;
-}
-
-static bool
-parse_arc(Ingen::World* world,
- Ingen::Interface* target,
- Sord::Model& model,
- const URI& base_uri,
- const Sord::Node& subject,
- const Raul::Path& graph)
-{
- const URIs& uris = world->uris();
-
- const Sord::URI ingen_tail(*world->rdf_world(), uris.ingen_tail);
- const Sord::URI ingen_head(*world->rdf_world(), uris.ingen_head);
- const Sord::Node nil;
-
- Sord::Iter t = model.find(subject, ingen_tail, nil);
- Sord::Iter h = model.find(subject, ingen_head, nil);
-
- if (t.end()) {
- world->log().error("Arc has no tail\n");
- return false;
- } else if (h.end()) {
- world->log().error("Arc has no head\n");
- return false;
- }
-
- const boost::optional<Raul::Path> tail_path = get_path(
- base_uri, t.get_object());
- if (!tail_path) {
- world->log().error("Arc tail has invalid URI\n");
- return false;
- }
-
- const boost::optional<Raul::Path> head_path = get_path(
- base_uri, h.get_object());
- if (!head_path) {
- world->log().error("Arc head has invalid URI\n");
- return false;
- }
-
- if (!(++t).end()) {
- world->log().error("Arc has multiple tails\n");
- return false;
- } else if (!(++h).end()) {
- world->log().error("Arc has multiple heads\n");
- return false;
- }
-
- target->connect(graph.child(*tail_path), graph.child(*head_path));
-
- return true;
-}
-
-static bool
-parse_arcs(Ingen::World* world,
- Ingen::Interface* target,
- Sord::Model& model,
- const URI& base_uri,
- const Sord::Node& subject,
- const Raul::Path& graph)
-{
- const Sord::URI ingen_arc(*world->rdf_world(), world->uris().ingen_arc);
- const Sord::Node nil;
-
- for (Sord::Iter i = model.find(subject, ingen_arc, nil); !i.end(); ++i) {
- parse_arc(world, target, model, base_uri, i.get_object(), graph);
- }
-
- return true;
-}
-
-static bool
-parse_properties(Ingen::World* world,
- Ingen::Interface* target,
- Sord::Model& model,
- const Sord::Node& subject,
- Resource::Graph ctx,
- const URI& uri,
- boost::optional<Properties> data)
-{
- Properties properties = get_properties(world, model, subject, ctx);
-
- target->put(uri, properties, ctx);
-
- // Set passed properties last to override any loaded values
- if (data) {
- target->put(uri, data.get(), ctx);
- }
-
- return true;
-}
-
-static boost::optional<Raul::Path>
-parse(Ingen::World* world,
- Ingen::Interface* target,
- Sord::Model& model,
- const URI& base_uri,
- Sord::Node& subject,
- boost::optional<Raul::Path> parent,
- boost::optional<Raul::Symbol> symbol,
- boost::optional<Properties> data)
-{
- const URIs& uris = world->uris();
-
- const Sord::URI graph_class (*world->rdf_world(), uris.ingen_Graph);
- const Sord::URI block_class (*world->rdf_world(), uris.ingen_Block);
- const Sord::URI arc_class (*world->rdf_world(), uris.ingen_Arc);
- const Sord::URI internal_class(*world->rdf_world(), uris.ingen_Internal);
- const Sord::URI in_port_class (*world->rdf_world(), LV2_CORE__InputPort);
- const Sord::URI out_port_class(*world->rdf_world(), LV2_CORE__OutputPort);
- const Sord::URI lv2_class (*world->rdf_world(), LV2_CORE__Plugin);
- const Sord::URI rdf_type (*world->rdf_world(), uris.rdf_type);
- const Sord::Node nil;
-
- // Parse explicit subject graph
- if (subject.is_valid()) {
- return parse_graph(world, target, model, base_uri,
- subject, Resource::Graph::INTERNAL,
- parent, symbol, data);
- }
-
- // Get all subjects and their types (?subject a ?type)
- typedef std::map< Sord::Node, std::set<Sord::Node> > Subjects;
- Subjects subjects;
- for (Sord::Iter i = model.find(subject, rdf_type, nil); !i.end(); ++i) {
- const Sord::Node& subject = i.get_subject();
- const Sord::Node& rdf_class = i.get_object();
-
- assert(rdf_class.is_uri());
- auto s = subjects.find(subject);
- if (s == subjects.end()) {
- std::set<Sord::Node> types;
- types.insert(rdf_class);
- subjects.emplace(subject, types);
- } else {
- s->second.insert(rdf_class);
- }
- }
-
- // Parse and create each subject
- for (const auto& i : subjects) {
- const Sord::Node& s = i.first;
- const std::set<Sord::Node>& types = i.second;
- boost::optional<Raul::Path> ret;
- if (types.find(graph_class) != types.end()) {
- ret = parse_graph(world, target, model, base_uri,
- s, Resource::Graph::INTERNAL,
- parent, symbol, data);
- } else if (types.find(block_class) != types.end()) {
- const Raul::Path rel_path(*get_path(base_uri, s));
- const Raul::Path path = parent ? parent->child(rel_path) : rel_path;
- ret = parse_block(world, target, model, base_uri, s, path, data);
- } else if (types.find(in_port_class) != types.end() ||
- types.find(out_port_class) != types.end()) {
- const Raul::Path rel_path(*get_path(base_uri, s));
- const Raul::Path path = parent ? parent->child(rel_path) : rel_path;
- parse_properties(world, target, model,
- s, Resource::Graph::DEFAULT,
- path_to_uri(path), data);
- ret = path;
- } else if (types.find(arc_class) != types.end()) {
- Raul::Path parent_path(parent ? parent.get() : Raul::Path("/"));
- parse_arc(world, target, model, base_uri, s, parent_path);
- } else {
- world->log().error("Subject has no known types\n");
- }
- }
-
- return boost::optional<Raul::Path>();
-}
-
-bool
-Parser::parse_file(Ingen::World* world,
- Ingen::Interface* target,
- const FilePath& path,
- boost::optional<Raul::Path> parent,
- boost::optional<Raul::Symbol> symbol,
- boost::optional<Properties> data)
-{
- // Get absolute file path
- FilePath file_path = path;
- if (!file_path.is_absolute()) {
- file_path = filesystem::current_path() / file_path;
- }
-
- // Find file to use as manifest
- const bool is_bundle = filesystem::is_directory(file_path);
- const FilePath manifest_path =
- (is_bundle ? file_path / "manifest.ttl" : file_path);
-
- URI manifest_uri(manifest_path);
-
- // Find graphs in manifest
- const std::set<ResourceRecord> resources = find_resources(
- *world->rdf_world(), manifest_uri, URI(INGEN__Graph));
-
- if (resources.empty()) {
- world->log().error(fmt("No graphs found in %1%\n") % path);
- return false;
- }
-
- /* Choose the graph to load. If this is a manifest, then there should only be
- one, but if this is a graph file, subgraphs will be returned as well.
- In this case, choose the one with the file URI. */
- URI uri;
- for (const ResourceRecord& r : resources) {
- if (r.uri == URI(manifest_path)) {
- uri = r.uri;
- file_path = r.filename;
- break;
- }
- }
-
- if (uri.empty()) {
- // Didn't find a graph with the same URI as the file, use the first
- uri = (*resources.begin()).uri;
- file_path = (*resources.begin()).filename;
- }
-
- if (file_path.empty()) {
- // No seeAlso file, use manifest (probably the graph file itself)
- file_path = manifest_path;
- }
-
- // Initialise parsing environment
- const URI file_uri = URI(file_path);
- const uint8_t* uri_c_str = (const uint8_t*)uri.c_str();
- SerdNode base_node = serd_node_from_string(SERD_URI, uri_c_str);
- SerdEnv* env = serd_env_new(&base_node);
-
- // Load graph into model
- Sord::Model model(*world->rdf_world(), uri.string(), SORD_SPO|SORD_PSO, false);
- model.load_file(env, SERD_TURTLE, file_uri);
- serd_env_free(env);
-
- world->log().info(fmt("Loading %1% from %2%\n") % uri % file_path);
- if (parent) {
- world->log().info(fmt("Parent: %1%\n") % parent->c_str());
- }
- if (symbol) {
- world->log().info(fmt("Symbol: %1%\n") % symbol->c_str());
- }
-
- Sord::Node subject(*world->rdf_world(), Sord::Node::URI, uri.string());
- boost::optional<Raul::Path> parsed_path
- = parse(world, target, model, model.base_uri(),
- subject, parent, symbol, data);
-
- if (parsed_path) {
- target->set_property(path_to_uri(*parsed_path),
- URI(INGEN__file),
- world->forge().alloc_uri(uri.string()));
- return true;
- } else {
- world->log().warn("Document URI lost\n");
- return false;
- }
-}
-
-boost::optional<URI>
-Parser::parse_string(Ingen::World* world,
- Ingen::Interface* target,
- const std::string& str,
- const URI& base_uri,
- boost::optional<Raul::Path> parent,
- boost::optional<Raul::Symbol> symbol,
- boost::optional<Properties> data)
-{
- // Load string into model
- Sord::Model model(*world->rdf_world(), base_uri, SORD_SPO|SORD_PSO, false);
-
- SerdEnv* env = serd_env_new(nullptr);
- if (!base_uri.empty()) {
- const SerdNode base = serd_node_from_string(
- SERD_URI, (const uint8_t*)base_uri.c_str());
- serd_env_set_base_uri(env, &base);
- }
- model.load_string(env, SERD_TURTLE, str.c_str(), str.length(), base_uri);
-
- URI actual_base((const char*)serd_env_get_base_uri(env, nullptr)->buf);
- serd_env_free(env);
-
- world->log().info(fmt("Parsing string (base %1%)\n") % base_uri);
-
- Sord::Node subject;
- parse(world, target, model, actual_base, subject, parent, symbol, data);
- return actual_base;
-}
-
-} // namespace Ingen
diff --git a/src/Resource.cpp b/src/Resource.cpp
deleted file mode 100644
index d0261eee..00000000
--- a/src/Resource.cpp
+++ /dev/null
@@ -1,234 +0,0 @@
-/*
- 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/>.
-*/
-
-#include <cstdlib>
-#include <utility>
-
-#include "ingen/Atom.hpp"
-#include "ingen/Forge.hpp"
-#include "ingen/Resource.hpp"
-#include "ingen/URIs.hpp"
-
-namespace Ingen {
-
-bool
-Resource::add_property(const URI& uri, const Atom& value, Graph ctx)
-{
- // Ignore duplicate statements
- typedef Properties::const_iterator iterator;
- const std::pair<iterator, iterator> range = _properties.equal_range(uri);
- for (iterator i = range.first; i != range.second && i != _properties.end(); ++i) {
- if (i->second == value && i->second.context() == ctx) {
- return false;
- }
- }
-
- if (uri != _uris.ingen_activity) {
- // Insert new property
- const Atom& v = _properties.emplace(uri, Property(value, ctx))->second;
- on_property(uri, v);
- } else {
- // Announce ephemeral activity, but do not store
- on_property(uri, value);
- }
-
- return true;
-}
-
-const Atom&
-Resource::set_property(const URI& uri, const Atom& value, Resource::Graph ctx)
-{
- // Erase existing property in this context
- for (auto i = _properties.find(uri);
- (i != _properties.end()) && (i->first == uri);) {
- auto next = i;
- ++next;
- if (i->second.context() == ctx) {
- const Atom value(i->second);
- _properties.erase(i);
- on_property_removed(uri, value);
- }
- i = next;
- }
-
- if (uri != _uris.ingen_activity) {
- // Insert new property
- const Atom& v = _properties.emplace(uri, Property(value, ctx))->second;
- on_property(uri, v);
- return v;
- } else {
- // Announce ephemeral activity, but do not store
- on_property(uri, value);
- return value;
- }
-}
-
-const Atom&
-Resource::set_property(const URI& uri,
- const URIs::Quark& value,
- Resource::Graph ctx)
-{
- return set_property(uri, value.urid, ctx);
-}
-
-void
-Resource::remove_property(const URI& uri, const Atom& value)
-{
- if (_uris.patch_wildcard == value) {
- _properties.erase(uri);
- } else {
- for (auto i = _properties.find(uri);
- i != _properties.end() && (i->first == uri);
- ++i) {
- if (i->second == value) {
- _properties.erase(i);
- break;
- }
- }
- }
- on_property_removed(uri, value);
-}
-
-void
-Resource::remove_property(const URI& uri, const URIs::Quark& value)
-{
- remove_property(uri, value.urid);
- remove_property(uri, value.uri);
-}
-
-bool
-Resource::has_property(const URI& uri, const Atom& value) const
-{
- return _properties.contains(uri, value);
-}
-
-bool
-Resource::has_property(const URI& uri, const URIs::Quark& value) const
-{
- Properties::const_iterator i = _properties.find(uri);
- for (; (i != _properties.end()) && (i->first == uri); ++i) {
- if (value == i->second) {
- return true;
- }
- }
- return false;
-}
-
-const Atom&
-Resource::set_property(const URI& uri, const Atom& value) const
-{
- return const_cast<Resource*>(this)->set_property(uri, value);
-}
-
-const Atom&
-Resource::get_property(const URI& uri) const
-{
- static const Atom nil;
- Properties::const_iterator i = _properties.find(uri);
- return (i != _properties.end()) ? i->second : nil;
-}
-
-bool
-Resource::type(const URIs& uris,
- const Properties& properties,
- bool& graph,
- bool& block,
- bool& port,
- bool& is_output)
-{
- typedef Properties::const_iterator iterator;
- const std::pair<iterator, iterator> types_range = properties.equal_range(uris.rdf_type);
-
- graph = block = port = is_output = false;
- for (iterator i = types_range.first; i != types_range.second; ++i) {
- const Atom& atom = i->second;
- if (atom.type() != uris.forge.URI && atom.type() != uris.forge.URID) {
- continue; // Non-URI type, ignore garbage data
- }
-
- if (uris.ingen_Graph == atom) {
- graph = true;
- } else if (uris.ingen_Block == atom) {
- block = true;
- } else if (uris.lv2_InputPort == atom) {
- port = true;
- is_output = false;
- } else if (uris.lv2_OutputPort == atom) {
- port = true;
- is_output = true;
- }
- }
-
- if (graph && block && !port) { // => graph
- block = false;
- return true;
- } else if (port && (graph || block)) { // nonsense
- port = false;
- return false;
- } else if (graph || block || port) { // recognized type
- return true;
- } else { // unknown
- return false;
- }
-}
-
-void
-Resource::set_properties(const Properties& props)
-{
- /* Note a simple loop that calls set_property is inappropriate here since
- it will not correctly set multiple properties in p (notably rdf:type)
- */
-
- // Erase existing properties with matching keys
- for (const auto& p : props) {
- _properties.erase(p.first);
- on_property_removed(p.first, _uris.patch_wildcard.urid);
- }
-
- // Set new properties
- add_properties(props);
-}
-
-void
-Resource::add_properties(const Properties& props)
-{
- for (const auto& p : props) {
- add_property(p.first, p.second, p.second.context());
- }
-}
-
-void
-Resource::remove_properties(const Properties& props)
-{
- for (const auto& p : props) {
- remove_property(p.first, p.second);
- }
-}
-
-Properties
-Resource::properties(Resource::Graph ctx) const
-{
- Properties props;
- for (const auto& p : _properties) {
- if (p.second.context() == ctx) {
- props.emplace(p.first, p.second);
- }
- }
-
- return props;
-}
-
-} // namespace Ingen
diff --git a/src/Serialiser.cpp b/src/Serialiser.cpp
deleted file mode 100644
index 034ff96b..00000000
--- a/src/Serialiser.cpp
+++ /dev/null
@@ -1,583 +0,0 @@
-/*
- 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/>.
-*/
-
-#include <cassert>
-#include <cerrno>
-#include <cstdlib>
-#include <cstring>
-#include <set>
-#include <string>
-#include <utility>
-
-#include "ingen/Arc.hpp"
-#include "ingen/FilePath.hpp"
-#include "ingen/Forge.hpp"
-#include "ingen/Interface.hpp"
-#include "ingen/Log.hpp"
-#include "ingen/Node.hpp"
-#include "ingen/Resource.hpp"
-#include "ingen/Serialiser.hpp"
-#include "ingen/Store.hpp"
-#include "ingen/URI.hpp"
-#include "ingen/URIMap.hpp"
-#include "ingen/URIs.hpp"
-#include "ingen/World.hpp"
-#include "ingen/filesystem.hpp"
-#include "ingen/runtime_paths.hpp"
-#include "lv2/lv2plug.in/ns/ext/state/state.h"
-#include "lv2/lv2plug.in/ns/extensions/ui/ui.h"
-#include "raul/Path.hpp"
-#include "sord/sordmm.hpp"
-#include "sratom/sratom.h"
-
-namespace Ingen {
-
-struct Serialiser::Impl {
- explicit Impl(World& world)
- : _root_path("/")
- , _world(world)
- , _model(nullptr)
- , _sratom(sratom_new(&_world.uri_map().urid_map_feature()->urid_map))
- {}
-
- ~Impl() {
- sratom_free(_sratom);
- }
-
- enum class Mode { TO_FILE, TO_STRING };
-
- void start_to_file(const Raul::Path& root,
- const FilePath& filename);
-
- std::set<const Resource*> serialise_graph(SPtr<const Node> graph,
- const Sord::Node& graph_id);
-
- void serialise_block(SPtr<const Node> block,
- const Sord::Node& class_id,
- const Sord::Node& block_id);
-
- void serialise_port(const Node* port,
- Resource::Graph context,
- const Sord::Node& port_id);
-
- void serialise_properties(Sord::Node id,
- const Properties& props);
-
- void write_bundle(SPtr<const Node> graph, const URI& uri);
-
- Sord::Node path_rdf_node(const Raul::Path& path);
-
- void write_manifest(const FilePath& bundle_path,
- SPtr<const Node> graph);
-
- void write_plugins(const FilePath& bundle_path,
- const std::set<const Resource*> plugins);
-
- void serialise_arc(const Sord::Node& parent,
- SPtr<const Arc> arc);
-
- std::string finish();
-
- Raul::Path _root_path;
- Mode _mode;
- URI _base_uri;
- FilePath _basename;
- World& _world;
- Sord::Model* _model;
- Sratom* _sratom;
-};
-
-Serialiser::Serialiser(World& world)
- : me(new Impl(world))
-{}
-
-Serialiser::~Serialiser()
-{
- delete me;
-}
-
-void
-Serialiser::Impl::write_manifest(const FilePath& bundle_path,
- SPtr<const Node> graph)
-{
- const FilePath manifest_path(bundle_path / "manifest.ttl");
- const FilePath binary_path(ingen_module_path("lv2"));
-
- start_to_file(Raul::Path("/"), manifest_path);
-
- Sord::World& world = _model->world();
- const URIs& uris = _world.uris();
-
- const std::string filename("main.ttl");
- const Sord::URI subject(world, filename, _base_uri);
-
- _model->add_statement(subject,
- Sord::URI(world, uris.rdf_type),
- Sord::URI(world, uris.ingen_Graph));
- _model->add_statement(subject,
- Sord::URI(world, uris.rdf_type),
- Sord::URI(world, uris.lv2_Plugin));
- _model->add_statement(subject,
- Sord::URI(world, uris.rdfs_seeAlso),
- Sord::URI(world, filename, _base_uri));
- _model->add_statement(subject,
- Sord::URI(world, uris.lv2_prototype),
- Sord::URI(world, uris.ingen_GraphPrototype));
-
- finish();
-}
-
-void
-Serialiser::Impl::write_plugins(const FilePath& bundle_path,
- const std::set<const Resource*> plugins)
-{
- const FilePath plugins_path(bundle_path / "plugins.ttl");
-
- start_to_file(Raul::Path("/"), plugins_path);
-
- Sord::World& world = _model->world();
- const URIs& uris = _world.uris();
-
- for (const auto& p : plugins) {
- const Atom& minor = p->get_property(uris.lv2_minorVersion);
- const Atom& micro = p->get_property(uris.lv2_microVersion);
-
- _model->add_statement(Sord::URI(world, p->uri()),
- Sord::URI(world, uris.rdf_type),
- Sord::URI(world, uris.lv2_Plugin));
-
- if (minor.is_valid() && micro.is_valid()) {
- _model->add_statement(Sord::URI(world, p->uri()),
- Sord::URI(world, uris.lv2_minorVersion),
- Sord::Literal::integer(world, minor.get<int32_t>()));
- _model->add_statement(Sord::URI(world, p->uri()),
- Sord::URI(world, uris.lv2_microVersion),
- Sord::Literal::integer(world, micro.get<int32_t>()));
- }
- }
-
- finish();
-}
-
-void
-Serialiser::write_bundle(SPtr<const Node> graph, const URI& uri)
-{
- me->write_bundle(graph, uri);
-}
-
-void
-Serialiser::Impl::write_bundle(SPtr<const Node> graph, const URI& uri)
-{
- FilePath path(uri.path());
- if (filesystem::exists(path) && !filesystem::is_directory(path)) {
- path = path.parent_path();
- }
-
- _world.log().info(fmt("Writing bundle %1%\n") % path);
- filesystem::create_directories(path);
-
- const FilePath main_file = path / "main.ttl";
- const Raul::Path old_root_path = _root_path;
-
- start_to_file(graph->path(), main_file);
-
- std::set<const Resource*> plugins = serialise_graph(
- graph,
- Sord::URI(_model->world(), main_file, _base_uri));
-
- finish();
- write_manifest(path, graph);
- write_plugins(path, plugins);
-
- _root_path = old_root_path;
-}
-
-/** Begin a serialization to a file.
- *
- * This must be called before any serializing methods.
- */
-void
-Serialiser::Impl::start_to_file(const Raul::Path& root,
- const FilePath& filename)
-{
- _base_uri = URI(filename);
- _basename = filename.stem();
- if (_basename == "main") {
- _basename = filename.parent_path().stem();
- }
-
- _model = new Sord::Model(*_world.rdf_world(), _base_uri);
- _mode = Mode::TO_FILE;
- _root_path = root;
-}
-
-void
-Serialiser::start_to_string(const Raul::Path& root, const URI& base_uri)
-{
- me->_root_path = root;
- me->_base_uri = base_uri;
- me->_model = new Sord::Model(*me->_world.rdf_world(), base_uri);
- me->_mode = Impl::Mode::TO_STRING;
-}
-
-void
-Serialiser::start_to_file(const Raul::Path& root, const std::string& filename)
-{
- me->start_to_file(root, filename);
-}
-
-std::string
-Serialiser::finish()
-{
- return me->finish();
-}
-
-std::string
-Serialiser::Impl::finish()
-{
- std::string ret = "";
- if (_mode == Mode::TO_FILE) {
- SerdStatus st = _model->write_to_file(_base_uri, SERD_TURTLE);
- if (st) {
- _world.log().error(fmt("Error writing file %1% (%2%)\n")
- % _base_uri % serd_strerror(st));
- }
- } else {
- ret = _model->write_to_string(_base_uri, SERD_TURTLE);
- }
-
- delete _model;
- _model = nullptr;
- _base_uri = URI();
-
- return ret;
-}
-
-Sord::Node
-Serialiser::Impl::path_rdf_node(const Raul::Path& path)
-{
- assert(_model);
- assert(path == _root_path || path.is_child_of(_root_path));
- return Sord::URI(_model->world(),
- path.substr(_root_path.base().length()),
- _base_uri);
-}
-
-void
-Serialiser::serialise(SPtr<const Node> object)
-{
- if (!me->_model) {
- throw std::logic_error("serialise called without serialisation in progress");
- }
-
- if (object->graph_type() == Node::GraphType::GRAPH) {
- me->serialise_graph(object, me->path_rdf_node(object->path()));
- } else if (object->graph_type() == Node::GraphType::BLOCK) {
- const Sord::URI plugin_id(me->_model->world(), object->plugin()->uri());
- me->serialise_block(object, plugin_id, me->path_rdf_node(object->path()));
- } else if (object->graph_type() == Node::GraphType::PORT) {
- me->serialise_port(object.get(),
- Resource::Graph::DEFAULT,
- me->path_rdf_node(object->path()));
- } else {
- me->serialise_properties(me->path_rdf_node(object->path()),
- object->properties());
- }
-}
-
-std::set<const Resource*>
-Serialiser::Impl::serialise_graph(SPtr<const Node> graph,
- const Sord::Node& graph_id)
-{
- Sord::World& world = _model->world();
- const URIs& uris = _world.uris();
-
- _model->add_statement(graph_id,
- Sord::URI(world, uris.rdf_type),
- Sord::URI(world, uris.ingen_Graph));
-
- _model->add_statement(graph_id,
- Sord::URI(world, uris.rdf_type),
- Sord::URI(world, uris.lv2_Plugin));
-
- _model->add_statement(graph_id,
- Sord::URI(world, uris.lv2_extensionData),
- Sord::URI(world, LV2_STATE__interface));
-
- _model->add_statement(graph_id,
- Sord::URI(world, LV2_UI__ui),
- Sord::URI(world, "http://drobilla.net/ns/ingen#GraphUIGtk2"));
-
- // If the graph has no doap:name (required by LV2), use the basename
- if (graph->properties().find(uris.doap_name) == graph->properties().end()) {
- _model->add_statement(graph_id,
- Sord::URI(world, uris.doap_name),
- Sord::Literal(world, _basename));
- }
-
- const Properties props = graph->properties(Resource::Graph::INTERNAL);
- serialise_properties(graph_id, props);
-
- std::set<const Resource*> plugins;
-
- const Store::const_range kids = _world.store()->children_range(graph);
- for (Store::const_iterator n = kids.first; n != kids.second; ++n) {
- if (n->first.parent() != graph->path()) {
- continue;
- }
-
- if (n->second->graph_type() == Node::GraphType::GRAPH) {
- SPtr<Node> subgraph = n->second;
-
- SerdURI base_uri;
- serd_uri_parse((const uint8_t*)_base_uri.c_str(), &base_uri);
-
- const std::string sub_bundle_path = subgraph->path().substr(1) + ".ingen";
-
- SerdURI subgraph_uri;
- SerdNode subgraph_node = serd_node_new_uri_from_string(
- (const uint8_t*)sub_bundle_path.c_str(),
- &base_uri,
- &subgraph_uri);
-
- const Sord::URI subgraph_id(world, (const char*)subgraph_node.buf);
-
- // Save our state
- URI my_base_uri = _base_uri;
- Sord::Model* my_model = _model;
-
- // Write child bundle within this bundle
- write_bundle(subgraph, subgraph_id);
-
- // Restore our state
- _base_uri = my_base_uri;
- _model = my_model;
-
- // Serialise reference to graph block
- const Sord::Node block_id(path_rdf_node(subgraph->path()));
- _model->add_statement(graph_id,
- Sord::URI(world, uris.ingen_block),
- block_id);
- serialise_block(subgraph, subgraph_id, block_id);
- } else if (n->second->graph_type() == Node::GraphType::BLOCK) {
- SPtr<const Node> block = n->second;
-
- const Sord::URI class_id(world, block->plugin()->uri());
- const Sord::Node block_id(path_rdf_node(n->second->path()));
- _model->add_statement(graph_id,
- Sord::URI(world, uris.ingen_block),
- block_id);
- serialise_block(block, class_id, block_id);
-
- plugins.insert(block->plugin());
- }
- }
-
- for (uint32_t i = 0; i < graph->num_ports(); ++i) {
- Node* p = graph->port(i);
- const Sord::Node port_id = path_rdf_node(p->path());
-
- // Ensure lv2:name always exists so Graph is a valid LV2 plugin
- if (p->properties().find(uris.lv2_name) == p->properties().end()) {
- p->set_property(uris.lv2_name,
- _world.forge().alloc(p->symbol().c_str()));
- }
-
- _model->add_statement(graph_id,
- Sord::URI(world, LV2_CORE__port),
- port_id);
- serialise_port(p, Resource::Graph::DEFAULT, port_id);
- serialise_port(p, Resource::Graph::INTERNAL, port_id);
- }
-
- for (const auto& a : graph->arcs()) {
- serialise_arc(graph_id, a.second);
- }
-
- return plugins;
-}
-
-void
-Serialiser::Impl::serialise_block(SPtr<const Node> block,
- const Sord::Node& class_id,
- const Sord::Node& block_id)
-{
- const URIs& uris = _world.uris();
-
- _model->add_statement(block_id,
- Sord::URI(_model->world(), uris.rdf_type),
- Sord::URI(_model->world(), uris.ingen_Block));
- _model->add_statement(block_id,
- Sord::URI(_model->world(), uris.lv2_prototype),
- class_id);
-
- // Serialise properties, but remove possibly stale state:state (set again below)
- Properties props = block->properties();
- props.erase(uris.state_state);
- serialise_properties(block_id, props);
-
- if (_base_uri.scheme() == "file") {
- const FilePath base_path = _base_uri.file_path();
- const FilePath graph_dir = base_path.parent_path();
- const FilePath state_dir = graph_dir / block->symbol();
- const FilePath state_file = state_dir / "state.ttl";
- if (block->save_state(state_dir)) {
- _model->add_statement(block_id,
- Sord::URI(_model->world(), uris.state_state),
- Sord::URI(_model->world(), URI(state_file)));
- }
- }
-
- for (uint32_t i = 0; i < block->num_ports(); ++i) {
- Node* const p = block->port(i);
- const Sord::Node port_id = path_rdf_node(p->path());
- serialise_port(p, Resource::Graph::DEFAULT, port_id);
- _model->add_statement(block_id,
- Sord::URI(_model->world(), uris.lv2_port),
- port_id);
- }
-}
-
-void
-Serialiser::Impl::serialise_port(const Node* port,
- Resource::Graph context,
- const Sord::Node& port_id)
-{
- URIs& uris = _world.uris();
- Sord::World& world = _model->world();
- Properties props = port->properties(context);
-
- if (context == Resource::Graph::INTERNAL) {
- // Always write lv2:symbol for Graph ports (required for lv2:Plugin)
- _model->add_statement(port_id,
- Sord::URI(world, uris.lv2_symbol),
- Sord::Literal(world, port->path().symbol()));
- } else if (context == Resource::Graph::EXTERNAL) {
- // Never write lv2:index for plugin instances (not persistent/stable)
- props.erase(uris.lv2_index);
- }
-
- if (context == Resource::Graph::INTERNAL &&
- port->has_property(uris.rdf_type, uris.lv2_ControlPort) &&
- port->has_property(uris.rdf_type, uris.lv2_InputPort))
- {
- const Atom& val = port->get_property(uris.ingen_value);
- if (val.is_valid()) {
- props.erase(uris.lv2_default);
- props.emplace(uris.lv2_default, val);
- } else {
- _world.log().warn("Control input has no value, lv2:default omitted.\n");
- }
- } else if (context != Resource::Graph::INTERNAL &&
- !port->has_property(uris.rdf_type, uris.lv2_InputPort)) {
- props.erase(uris.ingen_value);
- }
-
- serialise_properties(port_id, props);
-}
-
-void
-Serialiser::serialise_arc(const Sord::Node& parent,
- SPtr<const Arc> arc)
-{
- return me->serialise_arc(parent, arc);
-}
-
-void
-Serialiser::Impl::serialise_arc(const Sord::Node& parent,
- SPtr<const Arc> arc)
-{
- if (!_model) {
- throw std::logic_error(
- "serialise_arc called without serialisation in progress");
- }
-
- Sord::World& world = _model->world();
- const URIs& uris = _world.uris();
-
- const Sord::Node src = path_rdf_node(arc->tail_path());
- const Sord::Node dst = path_rdf_node(arc->head_path());
- const Sord::Node arc_id = Sord::Node::blank_id(*_world.rdf_world());
- _model->add_statement(arc_id,
- Sord::URI(world, uris.ingen_tail),
- src);
- _model->add_statement(arc_id,
- Sord::URI(world, uris.ingen_head),
- dst);
-
- if (parent.is_valid()) {
- _model->add_statement(parent,
- Sord::URI(world, uris.ingen_arc),
- arc_id);
- } else {
- _model->add_statement(arc_id,
- Sord::URI(world, uris.rdf_type),
- Sord::URI(world, uris.ingen_Arc));
- }
-}
-
-static bool
-skip_property(Ingen::URIs& uris, const Sord::Node& predicate)
-{
- return (predicate == INGEN__file ||
- predicate == uris.ingen_arc ||
- predicate == uris.ingen_block ||
- predicate == uris.lv2_port);
-}
-
-void
-Serialiser::Impl::serialise_properties(Sord::Node id,
- const Properties& props)
-{
- LV2_URID_Unmap* unmap = &_world.uri_map().urid_unmap_feature()->urid_unmap;
- SerdNode base = serd_node_from_string(SERD_URI,
- (const uint8_t*)_base_uri.c_str());
- SerdEnv* env = serd_env_new(&base);
- SordInserter* inserter = sord_inserter_new(_model->c_obj(), env);
-
- sratom_set_sink(_sratom, _base_uri.c_str(),
- (SerdStatementSink)sord_inserter_write_statement, nullptr,
- inserter);
-
- sratom_set_pretty_numbers(_sratom, true);
-
- for (const auto& p : props) {
- const Sord::URI key(_model->world(), p.first);
- if (!skip_property(_world.uris(), key)) {
- if (p.second.type() == _world.uris().atom_URI &&
- !strncmp((const char*)p.second.get_body(), "ingen:/main/", 13)) {
- /* Value is a graph URI relative to the running engine.
- Chop the prefix and save the path relative to the graph file.
- This allows saving references to bundle resources. */
- sratom_write(_sratom, unmap, 0,
- sord_node_to_serd_node(id.c_obj()),
- sord_node_to_serd_node(key.c_obj()),
- p.second.type(), p.second.size(),
- (const char*)p.second.get_body() + 13);
- } else {
- sratom_write(_sratom, unmap, 0,
- sord_node_to_serd_node(id.c_obj()),
- sord_node_to_serd_node(key.c_obj()),
- p.second.type(), p.second.size(), p.second.get_body());
- }
- }
- }
-
- sord_inserter_free(inserter);
- serd_env_free(env);
-}
-
-} // namespace Ingen
diff --git a/src/SocketReader.cpp b/src/SocketReader.cpp
deleted file mode 100644
index 13e95430..00000000
--- a/src/SocketReader.cpp
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- 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/>.
-*/
-
-#include <cerrno>
-
-#include <poll.h>
-
-#include "ingen/AtomForgeSink.hpp"
-#include "ingen/AtomReader.hpp"
-#include "ingen/Interface.hpp"
-#include "ingen/Log.hpp"
-#include "ingen/SocketReader.hpp"
-#include "ingen/URIMap.hpp"
-#include "ingen/World.hpp"
-#include "raul/Socket.hpp"
-#include "sord/sordmm.hpp"
-#include "sratom/sratom.h"
-
-namespace Ingen {
-
-SocketReader::SocketReader(Ingen::World& world,
- Interface& iface,
- SPtr<Raul::Socket> sock)
- : _world(world)
- , _iface(iface)
- , _inserter(nullptr)
- , _msg_node(nullptr)
- , _socket(std::move(sock))
- , _exit_flag(false)
- , _thread(&SocketReader::run, this)
-{}
-
-SocketReader::~SocketReader()
-{
- _exit_flag = true;
- _socket->shutdown();
- _thread.join();
-}
-
-SerdStatus
-SocketReader::set_base_uri(SocketReader* iface,
- const SerdNode* uri_node)
-{
- return sord_inserter_set_base_uri(iface->_inserter, uri_node);
-}
-
-SerdStatus
-SocketReader::set_prefix(SocketReader* iface,
- const SerdNode* name,
- const SerdNode* uri_node)
-{
- return sord_inserter_set_prefix(iface->_inserter, name, uri_node);
-}
-
-SerdStatus
-SocketReader::write_statement(SocketReader* iface,
- SerdStatementFlags flags,
- const SerdNode* graph,
- const SerdNode* subject,
- const SerdNode* predicate,
- const SerdNode* object,
- const SerdNode* object_datatype,
- const SerdNode* object_lang)
-{
- if (!iface->_msg_node) {
- iface->_msg_node = sord_node_from_serd_node(
- iface->_world.rdf_world()->c_obj(), iface->_env, subject, nullptr, nullptr);
- }
-
- return sord_inserter_write_statement(
- iface->_inserter, flags, graph,
- subject, predicate, object,
- object_datatype, object_lang);
-}
-
-void
-SocketReader::run()
-{
- Sord::World* world = _world.rdf_world();
- LV2_URID_Map* map = &_world.uri_map().urid_map_feature()->urid_map;
-
- // Open socket as a FILE for reading directly with serd
- FILE* f = fdopen(_socket->fd(), "r");
- if (!f) {
- _world.log().error(fmt("Failed to open connection (%1%)\n")
- % strerror(errno));
- // Connection gone, exit
- _socket.reset();
- return;
- }
-
- // Set up sratom and a forge to build LV2 atoms from model
- Sratom* sratom = sratom_new(map);
- LV2_Atom_Forge forge;
- lv2_atom_forge_init(&forge, map);
-
- AtomForgeSink buffer(&forge);
-
- SordNode* base_uri = nullptr;
- SordModel* model = nullptr;
- {
- // Lock RDF world
- std::lock_guard<std::mutex> lock(_world.rdf_mutex());
-
- // Use <ingen:/> as base URI, so relative URIs are like bundle paths
- base_uri = sord_new_uri(world->c_obj(), (const uint8_t*)"ingen:/");
-
- // Make a model and reader to parse the next Turtle message
- _env = world->prefixes().c_obj();
- model = sord_new(world->c_obj(), SORD_SPO, false);
-
- // Create an inserter for writing incoming triples to model
- _inserter = sord_inserter_new(model, _env);
- }
-
- SerdReader* reader = serd_reader_new(
- SERD_TURTLE, this, nullptr,
- (SerdBaseSink)set_base_uri,
- (SerdPrefixSink)set_prefix,
- (SerdStatementSink)write_statement,
- nullptr);
-
- serd_env_set_base_uri(_env, sord_node_to_serd_node(base_uri));
- serd_reader_start_stream(reader, f, (const uint8_t*)"(socket)", false);
-
- // Make an AtomReader to call Ingen Interface methods based on Atom
- AtomReader ar(_world.uri_map(), _world.uris(), _world.log(), _iface);
-
- struct pollfd pfd;
- pfd.fd = _socket->fd();
- pfd.events = POLLIN;
- pfd.revents = 0;
-
- while (!_exit_flag) {
- if (feof(f)) {
- break; // Lost connection
- }
-
- // Wait for input to arrive at socket
- int ret = poll(&pfd, 1, -1);
- if (ret == -1 || (pfd.revents & (POLLERR|POLLHUP|POLLNVAL))) {
- on_hangup();
- break; // Hangup
- } else if (!ret) {
- continue; // No data, shouldn't happen
- }
-
- // Lock RDF world
- std::lock_guard<std::mutex> lock(_world.rdf_mutex());
-
- // Read until the next '.'
- SerdStatus st = serd_reader_read_chunk(reader);
- if (st == SERD_FAILURE || !_msg_node) {
- continue; // Read nothing, e.g. just whitespace
- } else if (st) {
- _world.log().error(fmt("Read error: %1%\n")
- % serd_strerror(st));
- continue;
- }
-
- // Build an LV2_Atom at chunk.buf from the message
- sratom_read(sratom, &forge, world->c_obj(), model, _msg_node);
-
- // Call _iface methods based on atom content
- ar.write(buffer.atom());
-
- // Reset everything for the next iteration
- buffer.clear();
- sord_node_free(world->c_obj(), _msg_node);
- _msg_node = nullptr;
- }
-
- // Lock RDF world
- std::lock_guard<std::mutex> lock(_world.rdf_mutex());
-
- // Destroy everything
- fclose(f);
- sord_inserter_free(_inserter);
- serd_reader_end_stream(reader);
- sratom_free(sratom);
- serd_reader_free(reader);
- sord_free(model);
- _socket.reset();
-}
-
-} // namespace Ingen
diff --git a/src/SocketWriter.cpp b/src/SocketWriter.cpp
deleted file mode 100644
index 68091bcc..00000000
--- a/src/SocketWriter.cpp
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- This file is part of Ingen.
- Copyright 2012-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/>.
-*/
-
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-
-#include "ingen/SocketWriter.hpp"
-#include "raul/Socket.hpp"
-
-#ifndef MSG_NOSIGNAL
-# define MSG_NOSIGNAL 0
-#endif
-
-namespace Ingen {
-
-SocketWriter::SocketWriter(URIMap& map,
- URIs& uris,
- const URI& uri,
- SPtr<Raul::Socket> sock)
- : TurtleWriter(map, uris, uri)
- , _socket(std::move(sock))
-{}
-
-size_t
-SocketWriter::text_sink(const void* buf, size_t len)
-{
- ssize_t ret = send(_socket->fd(), buf, len, MSG_NOSIGNAL);
- if (ret < 0) {
- return 0;
- }
- return ret;
-}
-
-void
-SocketWriter::bundle_end()
-{
- TurtleWriter::bundle_end();
-
- // Send a NULL byte to indicate end of bundle
- const char end[] = { 0 };
- send(_socket->fd(), end, 1, MSG_NOSIGNAL);
-}
-
-} // namespace Ingen
diff --git a/src/Store.cpp b/src/Store.cpp
deleted file mode 100644
index 327ce416..00000000
--- a/src/Store.cpp
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- 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 <sstream>
-
-#include "ingen/Node.hpp"
-#include "ingen/Store.hpp"
-
-namespace Ingen {
-
-void
-Store::add(Node* o)
-{
- if (find(o->path()) != end()) {
- return;
- }
-
- emplace(o->path(), SPtr<Node>(o));
-
- for (uint32_t i = 0; i < o->num_ports(); ++i) {
- add(o->port(i));
- }
-}
-
-/*
- TODO: These methods are currently O(n_children) but should logarithmic. The
- std::map methods do not allow passing a comparator, but std::upper_bound
- does. This should be achievable by making a rooted comparator that is a
- normal ordering except compares a special sentinel value as the greatest
- element that is a child of the parent. Searching for this sentinel should
- then find the end of the descendants in logarithmic time.
-*/
-
-Store::iterator
-Store::find_descendants_end(const iterator parent)
-{
- iterator descendants_end = parent;
- ++descendants_end;
- while (descendants_end != end() &&
- descendants_end->first.is_child_of(parent->first)) {
- ++descendants_end;
- }
-
- return descendants_end;
-}
-
-Store::const_iterator
-Store::find_descendants_end(const const_iterator parent) const
-{
- const_iterator descendants_end = parent;
- ++descendants_end;
- while (descendants_end != end() &&
- descendants_end->first.is_child_of(parent->first)) {
- ++descendants_end;
- }
-
- return descendants_end;
-}
-
-Store::const_range
-Store::children_range(SPtr<const Node> o) const
-{
- const const_iterator parent = find(o->path());
- if (parent != end()) {
- const_iterator first_child = parent;
- ++first_child;
- return std::make_pair(first_child, find_descendants_end(parent));
- }
- return make_pair(end(), end());
-}
-
-void
-Store::remove(const iterator top, Objects& removed)
-{
- if (top != end()) {
- const iterator descendants_end = find_descendants_end(top);
- removed.insert(top, descendants_end);
- erase(top, descendants_end);
- }
-}
-
-void
-Store::rename(const iterator top, const Raul::Path& new_path)
-{
- const Raul::Path old_path = top->first;
-
- // Remove the object and all its descendants
- Objects removed;
- remove(top, removed);
-
- // Rename all the removed objects
- for (Objects::const_iterator i = removed.begin(); i != removed.end(); ++i) {
- const Raul::Path path = (i->first == old_path)
- ? new_path
- : new_path.child(
- Raul::Path(i->first.substr(old_path.base().length() - 1)));
-
- i->second->set_path(path);
- assert(find(path) == end()); // Shouldn't be dropping objects!
- emplace(path, i->second);
- }
-}
-
-unsigned
-Store::child_name_offset(const Raul::Path& parent,
- const Raul::Symbol& symbol,
- bool allow_zero) const
-{
- unsigned offset = 0;
-
- while (true) {
- std::stringstream ss;
- ss << symbol;
- if (offset > 0) {
- ss << "_" << offset;
- }
- if (find(parent.child(Raul::Symbol(ss.str()))) == end() &&
- (allow_zero || offset > 0)) {
- break;
- } else if (offset == 0) {
- offset = 2;
- } else {
- ++offset;
- }
- }
-
- return offset;
-}
-
-} // namespace Ingen
diff --git a/src/StreamWriter.cpp b/src/StreamWriter.cpp
deleted file mode 100644
index 45853055..00000000
--- a/src/StreamWriter.cpp
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- This file is part of Ingen.
- Copyright 2012-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/>.
-*/
-
-#include "ingen/ColorContext.hpp"
-#include "ingen/StreamWriter.hpp"
-
-namespace Ingen {
-
-StreamWriter::StreamWriter(URIMap& map,
- URIs& uris,
- const URI& uri,
- FILE* stream,
- ColorContext::Color color)
- : TurtleWriter(map, uris, uri)
- , _stream(stream)
- , _color(color)
-{}
-
-size_t
-StreamWriter::text_sink(const void* buf, size_t len)
-{
- ColorContext ctx(_stream, _color);
- return fwrite(buf, 1, len, _stream);
-}
-
-} // namespace Ingen
diff --git a/src/TurtleWriter.cpp b/src/TurtleWriter.cpp
deleted file mode 100644
index 368184d4..00000000
--- a/src/TurtleWriter.cpp
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- This file is part of Ingen.
- Copyright 2012-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/>.
-*/
-
-#include "ingen/TurtleWriter.hpp"
-#include "ingen/URIMap.hpp"
-
-#define USTR(s) ((const uint8_t*)(s))
-
-namespace Ingen {
-
-static size_t
-c_text_sink(const void* buf, size_t len, void* stream)
-{
- TurtleWriter* writer = (TurtleWriter*)stream;
- return writer->text_sink(buf, len);
-}
-
-static SerdStatus
-write_prefix(void* handle, const SerdNode* name, const SerdNode* uri)
-{
- serd_writer_set_prefix((SerdWriter*)handle, name, uri);
- return SERD_SUCCESS;
-}
-
-TurtleWriter::TurtleWriter(URIMap& map, URIs& uris, const URI& uri)
- : AtomWriter(map, uris, *this)
- , _map(map)
- , _sratom(sratom_new(&map.urid_map_feature()->urid_map))
- , _uri(uri)
- , _wrote_prefixes(false)
-{
- // Use <ingen:/> as base URI, so relative URIs are like bundle paths
- _base = serd_node_from_string(SERD_URI, (const uint8_t*)"ingen:/");
- serd_uri_parse(_base.buf, &_base_uri);
-
- // Set up serialisation environment
- _env = serd_env_new(&_base);
- serd_env_set_prefix_from_strings(_env, USTR("atom"), USTR("http://lv2plug.in/ns/ext/atom#"));
- serd_env_set_prefix_from_strings(_env, USTR("doap"), USTR("http://usefulinc.com/ns/doap#"));
- serd_env_set_prefix_from_strings(_env, USTR("ingen"), USTR(INGEN_NS));
- serd_env_set_prefix_from_strings(_env, USTR("lv2"), USTR("http://lv2plug.in/ns/lv2core#"));
- serd_env_set_prefix_from_strings(_env, USTR("midi"), USTR("http://lv2plug.in/ns/ext/midi#"));
- serd_env_set_prefix_from_strings(_env, USTR("owl"), USTR("http://www.w3.org/2002/07/owl#"));
- serd_env_set_prefix_from_strings(_env, USTR("patch"), USTR("http://lv2plug.in/ns/ext/patch#"));
- serd_env_set_prefix_from_strings(_env, USTR("rdf"), USTR("http://www.w3.org/1999/02/22-rdf-syntax-ns#"));
- serd_env_set_prefix_from_strings(_env, USTR("rdfs"), USTR("http://www.w3.org/2000/01/rdf-schema#"));
- serd_env_set_prefix_from_strings(_env, USTR("xsd"), USTR("http://www.w3.org/2001/XMLSchema#"));
-
- // Make a Turtle writer that writes to text_sink
- _writer = serd_writer_new(
- SERD_TURTLE,
- (SerdStyle)(SERD_STYLE_RESOLVED|SERD_STYLE_ABBREVIATED|SERD_STYLE_CURIED),
- _env,
- &_base_uri,
- c_text_sink,
- this);
-
- // Configure sratom to write directly to the writer (and thus text_sink)
- sratom_set_sink(_sratom,
- (const char*)_base.buf,
- (SerdStatementSink)serd_writer_write_statement,
- (SerdEndSink)serd_writer_end_anon,
- _writer);
-}
-
-TurtleWriter::~TurtleWriter()
-{
- sratom_free(_sratom);
- serd_writer_free(_writer);
- serd_env_free(_env);
-}
-
-bool
-TurtleWriter::write(const LV2_Atom* msg, int32_t default_id)
-{
- if (!_wrote_prefixes) {
- // Write namespace prefixes once to reduce traffic
- serd_env_foreach(_env, write_prefix, _writer);
- _wrote_prefixes = true;
- }
-
- sratom_write(_sratom, &_map.urid_unmap_feature()->urid_unmap, 0,
- nullptr, nullptr, msg->type, msg->size, LV2_ATOM_BODY_CONST(msg));
- serd_writer_finish(_writer);
- return true;
-}
-
-} // namespace Ingen
diff --git a/src/URI.cpp b/src/URI.cpp
deleted file mode 100644
index 3e2d2a29..00000000
--- a/src/URI.cpp
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- This file is part of Ingen.
- Copyright 2018 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 <cassert>
-
-#include "ingen/FilePath.hpp"
-#include "ingen/URI.hpp"
-
-namespace Ingen {
-
-URI::URI()
- : _node(SERD_NODE_NULL)
- , _uri(SERD_URI_NULL)
-{}
-
-URI::URI(const std::string& str)
- : _node(serd_node_new_uri_from_string((const uint8_t*)str.c_str(),
- NULL,
- &_uri))
-{}
-
-URI::URI(const char* str)
- : _node(serd_node_new_uri_from_string((const uint8_t*)str, NULL, &_uri))
-{}
-
-URI::URI(const std::string& str, const URI& base)
- : _node(serd_node_new_uri_from_string((const uint8_t*)str.c_str(),
- &base._uri,
- &_uri))
-{}
-
-URI::URI(SerdNode node)
- : _node(serd_node_new_uri_from_node(&node, NULL, &_uri))
-{
- assert(node.type == SERD_URI);
-}
-
-URI::URI(SerdNode node, SerdURI uri)
- : _node(node)
- , _uri(uri)
-{
- assert(node.type == SERD_URI);
-}
-
-URI::URI(const Sord::Node& node)
- : URI(*node.to_serd_node())
-{
-}
-
-URI::URI(const FilePath& path)
- : _node(serd_node_new_file_uri((const uint8_t*)path.c_str(),
- NULL,
- &_uri,
- true))
-{}
-
-URI::URI(const URI& uri)
- : _node(serd_node_new_uri(&uri._uri, NULL, &_uri))
-{}
-
-URI&
-URI::operator=(const URI& uri)
-{
- serd_node_free(&_node);
- _node = serd_node_new_uri(&uri._uri, NULL, &_uri);
- return *this;
-}
-
-URI::URI(URI&& uri)
- : _node(uri._node)
- , _uri(uri._uri)
-{
- uri._node = SERD_NODE_NULL;
- uri._uri = SERD_URI_NULL;
-}
-
-URI&
-URI::operator=(URI&& uri)
-{
- _node = uri._node;
- _uri = uri._uri;
- uri._node = SERD_NODE_NULL;
- uri._uri = SERD_URI_NULL;
- return *this;
-}
-
-URI::~URI()
-{
- serd_node_free(&_node);
-}
-
-URI
-URI::make_relative(const URI& base) const
-{
- SerdURI uri;
- SerdNode node = serd_node_new_relative_uri(&_uri, &base._uri, NULL, &uri);
- return URI(node, uri);
-}
-
-} // namespace Ingen
diff --git a/src/URIMap.cpp b/src/URIMap.cpp
deleted file mode 100644
index 9ce1f178..00000000
--- a/src/URIMap.cpp
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- 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 <cstdint>
-
-#include "ingen/Log.hpp"
-#include "ingen/URI.hpp"
-#include "ingen/URIMap.hpp"
-
-namespace Ingen {
-
-URIMap::URIMap(Log& log, LV2_URID_Map* map, LV2_URID_Unmap* unmap)
- : _urid_map_feature(new URIDMapFeature(this, map, log))
- , _urid_unmap_feature(new URIDUnmapFeature(this, unmap))
-{
-}
-
-URIMap::URIDMapFeature::URIDMapFeature(URIMap* map,
- LV2_URID_Map* impl,
- Log& log)
- : Feature(LV2_URID__map, &urid_map)
- , log(log)
-{
- if (impl) {
- urid_map = *impl;
- } else {
- urid_map.map = default_map;
- urid_map.handle = map;
- }
-}
-
-LV2_URID
-URIMap::URIDMapFeature::default_map(LV2_URID_Map_Handle h,
- const char* c_uri)
-{
- URIMap* const map((URIMap*)h);
- std::string uri(c_uri);
- std::lock_guard<std::mutex> lock(map->_mutex);
-
- auto record = map->_map.emplace(uri, map->_map.size() + 1);
- const auto id = record.first->second;
- if (record.second) {
- assert(id == map->_map.size());
- assert(id == map->_unmap.size() + 1);
- map->_unmap.emplace_back(std::move(uri));
- }
- return id;
-}
-
-LV2_URID
-URIMap::URIDMapFeature::map(const char* uri)
-{
- if (!URI::is_valid(uri)) {
- log.error(fmt("Attempt to map invalid URI <%1%>\n") % uri);
- return 0;
- }
- return urid_map.map(urid_map.handle, uri);
-}
-
-URIMap::URIDUnmapFeature::URIDUnmapFeature(URIMap* map,
- LV2_URID_Unmap* impl)
- : Feature(LV2_URID__unmap, &urid_unmap)
-{
- if (impl) {
- urid_unmap = *impl;
- } else {
- urid_unmap.unmap = default_unmap;
- urid_unmap.handle = map;
- }
-}
-
-const char*
-URIMap::URIDUnmapFeature::default_unmap(LV2_URID_Unmap_Handle h,
- LV2_URID urid)
-{
- URIMap* const map((URIMap*)h);
- std::lock_guard<std::mutex> lock(map->_mutex);
-
- return (urid > 0 && urid <= map->_unmap.size()
- ? map->_unmap[urid - 1].c_str()
- : NULL);
-}
-
-const char*
-URIMap::URIDUnmapFeature::unmap(LV2_URID urid)
-{
- return urid_unmap.unmap(urid_unmap.handle, urid);
-}
-
-uint32_t
-URIMap::map_uri(const char* uri)
-{
- const uint32_t urid = _urid_map_feature->map(uri);
-#ifdef INGEN_DEBUG_URIDS
- fprintf(stderr, "Map URI %3u <= %s\n", urid, uri);
-#endif
- return urid;
-}
-
-const char*
-URIMap::unmap_uri(uint32_t urid) const
-{
- const char* uri = _urid_unmap_feature->unmap(urid);
-#ifdef INGEN_DEBUG_URIDS
- fprintf(stderr, "Unmap URI %3u => %s\n", urid, uri);
-#endif
- return uri;
-}
-
-} // namespace Ingen
diff --git a/src/URIs.cpp b/src/URIs.cpp
deleted file mode 100644
index af03b7b5..00000000
--- a/src/URIs.cpp
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- 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/>.
-*/
-
-#include "ingen/Forge.hpp"
-#include "ingen/URIMap.hpp"
-#include "ingen/URIs.hpp"
-#include "ingen/ingen.h"
-#include "lv2/lv2plug.in/ns/ext/atom/atom.h"
-#include "lv2/lv2plug.in/ns/ext/buf-size/buf-size.h"
-#include "lv2/lv2plug.in/ns/ext/log/log.h"
-#include "lv2/lv2plug.in/ns/ext/midi/midi.h"
-#include "lv2/lv2plug.in/ns/ext/morph/morph.h"
-#include "lv2/lv2plug.in/ns/ext/options/options.h"
-#include "lv2/lv2plug.in/ns/ext/parameters/parameters.h"
-#include "lv2/lv2plug.in/ns/ext/patch/patch.h"
-#include "lv2/lv2plug.in/ns/ext/port-props/port-props.h"
-#include "lv2/lv2plug.in/ns/ext/presets/presets.h"
-#include "lv2/lv2plug.in/ns/ext/resize-port/resize-port.h"
-#include "lv2/lv2plug.in/ns/ext/state/state.h"
-#include "lv2/lv2plug.in/ns/ext/time/time.h"
-#include "lv2/lv2plug.in/ns/ext/worker/worker.h"
-#include "lv2/lv2plug.in/ns/lv2core/lv2.h"
-
-namespace Ingen {
-
-URIs::Quark::Quark(Forge& forge,
- URIMap* map,
- LilvWorld* lworld,
- const char* str)
- : URI(str)
- , urid(forge.make_urid(URI(str)))
- , uri(forge.alloc_uri(str))
- , lnode(lilv_new_uri(lworld, str))
-{}
-
-URIs::Quark::Quark(const Quark& copy)
- : URI(copy)
- , urid(copy.urid)
- , uri(copy.uri)
- , lnode(lilv_node_duplicate(copy.lnode))
-{}
-
-URIs::Quark::~Quark()
-{
- lilv_node_free(lnode);
-}
-
-#define NS_RDF "http://www.w3.org/1999/02/22-rdf-syntax-ns#"
-#define NS_RDFS "http://www.w3.org/2000/01/rdf-schema#"
-
-URIs::URIs(Forge& forge, URIMap* map, LilvWorld* lworld)
- : forge(forge)
- , atom_AtomPort (forge, map, lworld, LV2_ATOM__AtomPort)
- , atom_Bool (forge, map, lworld, LV2_ATOM__Bool)
- , atom_Chunk (forge, map, lworld, LV2_ATOM__Chunk)
- , atom_Float (forge, map, lworld, LV2_ATOM__Float)
- , atom_Int (forge, map, lworld, LV2_ATOM__Int)
- , atom_Object (forge, map, lworld, LV2_ATOM__Object)
- , atom_Path (forge, map, lworld, LV2_ATOM__Path)
- , atom_Sequence (forge, map, lworld, LV2_ATOM__Sequence)
- , atom_Sound (forge, map, lworld, LV2_ATOM__Sound)
- , atom_String (forge, map, lworld, LV2_ATOM__String)
- , atom_URI (forge, map, lworld, LV2_ATOM__URI)
- , atom_URID (forge, map, lworld, LV2_ATOM__URID)
- , atom_bufferType (forge, map, lworld, LV2_ATOM__bufferType)
- , atom_eventTransfer (forge, map, lworld, LV2_ATOM__eventTransfer)
- , atom_supports (forge, map, lworld, LV2_ATOM__supports)
- , bufsz_maxBlockLength (forge, map, lworld, LV2_BUF_SIZE__maxBlockLength)
- , bufsz_minBlockLength (forge, map, lworld, LV2_BUF_SIZE__minBlockLength)
- , bufsz_sequenceSize (forge, map, lworld, LV2_BUF_SIZE__sequenceSize)
- , doap_name (forge, map, lworld, "http://usefulinc.com/ns/doap#name")
- , ingen_Arc (forge, map, lworld, INGEN__Arc)
- , ingen_Block (forge, map, lworld, INGEN__Block)
- , ingen_BundleEnd (forge, map, lworld, INGEN__BundleEnd)
- , ingen_BundleStart (forge, map, lworld, INGEN__BundleStart)
- , ingen_Graph (forge, map, lworld, INGEN__Graph)
- , ingen_GraphPrototype (forge, map, lworld, INGEN__GraphPrototype)
- , ingen_Internal (forge, map, lworld, INGEN__Internal)
- , ingen_Redo (forge, map, lworld, INGEN__Redo)
- , ingen_Undo (forge, map, lworld, INGEN__Undo)
- , ingen_activity (forge, map, lworld, INGEN__activity)
- , ingen_arc (forge, map, lworld, INGEN__arc)
- , ingen_block (forge, map, lworld, INGEN__block)
- , ingen_broadcast (forge, map, lworld, INGEN__broadcast)
- , ingen_canvasX (forge, map, lworld, INGEN__canvasX)
- , ingen_canvasY (forge, map, lworld, INGEN__canvasY)
- , ingen_enabled (forge, map, lworld, INGEN__enabled)
- , ingen_externalContext (forge, map, lworld, INGEN__externalContext)
- , ingen_file (forge, map, lworld, INGEN__file)
- , ingen_head (forge, map, lworld, INGEN__head)
- , ingen_incidentTo (forge, map, lworld, INGEN__incidentTo)
- , ingen_internalContext (forge, map, lworld, INGEN__internalContext)
- , ingen_loadedBundle (forge, map, lworld, INGEN__loadedBundle)
- , ingen_maxRunLoad (forge, map, lworld, INGEN__maxRunLoad)
- , ingen_meanRunLoad (forge, map, lworld, INGEN__meanRunLoad)
- , ingen_minRunLoad (forge, map, lworld, INGEN__minRunLoad)
- , ingen_numThreads (forge, map, lworld, INGEN__numThreads)
- , ingen_polyphonic (forge, map, lworld, INGEN__polyphonic)
- , ingen_polyphony (forge, map, lworld, INGEN__polyphony)
- , ingen_prototype (forge, map, lworld, INGEN__prototype)
- , ingen_sprungLayout (forge, map, lworld, INGEN__sprungLayout)
- , ingen_tail (forge, map, lworld, INGEN__tail)
- , ingen_uiEmbedded (forge, map, lworld, INGEN__uiEmbedded)
- , ingen_value (forge, map, lworld, INGEN__value)
- , log_Error (forge, map, lworld, LV2_LOG__Error)
- , log_Note (forge, map, lworld, LV2_LOG__Note)
- , log_Trace (forge, map, lworld, LV2_LOG__Trace)
- , log_Warning (forge, map, lworld, LV2_LOG__Warning)
- , lv2_AudioPort (forge, map, lworld, LV2_CORE__AudioPort)
- , lv2_CVPort (forge, map, lworld, LV2_CORE__CVPort)
- , lv2_ControlPort (forge, map, lworld, LV2_CORE__ControlPort)
- , lv2_InputPort (forge, map, lworld, LV2_CORE__InputPort)
- , lv2_OutputPort (forge, map, lworld, LV2_CORE__OutputPort)
- , lv2_Plugin (forge, map, lworld, LV2_CORE__Plugin)
- , lv2_appliesTo (forge, map, lworld, LV2_CORE__appliesTo)
- , lv2_binary (forge, map, lworld, LV2_CORE__binary)
- , lv2_connectionOptional(forge, map, lworld, LV2_CORE__connectionOptional)
- , lv2_control (forge, map, lworld, LV2_CORE__control)
- , lv2_default (forge, map, lworld, LV2_CORE__default)
- , lv2_designation (forge, map, lworld, LV2_CORE__designation)
- , lv2_enumeration (forge, map, lworld, LV2_CORE__enumeration)
- , lv2_extensionData (forge, map, lworld, LV2_CORE__extensionData)
- , lv2_index (forge, map, lworld, LV2_CORE__index)
- , lv2_integer (forge, map, lworld, LV2_CORE__integer)
- , lv2_maximum (forge, map, lworld, LV2_CORE__maximum)
- , lv2_microVersion (forge, map, lworld, LV2_CORE__microVersion)
- , lv2_minimum (forge, map, lworld, LV2_CORE__minimum)
- , lv2_minorVersion (forge, map, lworld, LV2_CORE__minorVersion)
- , lv2_name (forge, map, lworld, LV2_CORE__name)
- , lv2_port (forge, map, lworld, LV2_CORE__port)
- , lv2_portProperty (forge, map, lworld, LV2_CORE__portProperty)
- , lv2_prototype (forge, map, lworld, LV2_CORE__prototype)
- , lv2_sampleRate (forge, map, lworld, LV2_CORE__sampleRate)
- , lv2_scalePoint (forge, map, lworld, LV2_CORE__scalePoint)
- , lv2_symbol (forge, map, lworld, LV2_CORE__symbol)
- , lv2_toggled (forge, map, lworld, LV2_CORE__toggled)
- , midi_Bender (forge, map, lworld, LV2_MIDI__Bender)
- , midi_ChannelPressure (forge, map, lworld, LV2_MIDI__ChannelPressure)
- , midi_Controller (forge, map, lworld, LV2_MIDI__Controller)
- , midi_MidiEvent (forge, map, lworld, LV2_MIDI__MidiEvent)
- , midi_NoteOn (forge, map, lworld, LV2_MIDI__NoteOn)
- , midi_binding (forge, map, lworld, LV2_MIDI__binding)
- , midi_controllerNumber (forge, map, lworld, LV2_MIDI__controllerNumber)
- , midi_noteNumber (forge, map, lworld, LV2_MIDI__noteNumber)
- , morph_AutoMorphPort (forge, map, lworld, LV2_MORPH__AutoMorphPort)
- , morph_MorphPort (forge, map, lworld, LV2_MORPH__MorphPort)
- , morph_currentType (forge, map, lworld, LV2_MORPH__currentType)
- , morph_supportsType (forge, map, lworld, LV2_MORPH__supportsType)
- , opt_interface (forge, map, lworld, LV2_OPTIONS__interface)
- , param_sampleRate (forge, map, lworld, LV2_PARAMETERS__sampleRate)
- , patch_Copy (forge, map, lworld, LV2_PATCH__Copy)
- , patch_Delete (forge, map, lworld, LV2_PATCH__Delete)
- , patch_Get (forge, map, lworld, LV2_PATCH__Get)
- , patch_Message (forge, map, lworld, LV2_PATCH__Message)
- , patch_Move (forge, map, lworld, LV2_PATCH__Move)
- , patch_Patch (forge, map, lworld, LV2_PATCH__Patch)
- , patch_Put (forge, map, lworld, LV2_PATCH__Put)
- , patch_Response (forge, map, lworld, LV2_PATCH__Response)
- , patch_Set (forge, map, lworld, LV2_PATCH__Set)
- , patch_add (forge, map, lworld, LV2_PATCH__add)
- , patch_body (forge, map, lworld, LV2_PATCH__body)
- , patch_context (forge, map, lworld, LV2_PATCH__context)
- , patch_destination (forge, map, lworld, LV2_PATCH__destination)
- , patch_property (forge, map, lworld, LV2_PATCH__property)
- , patch_remove (forge, map, lworld, LV2_PATCH__remove)
- , patch_sequenceNumber (forge, map, lworld, LV2_PATCH__sequenceNumber)
- , patch_subject (forge, map, lworld, LV2_PATCH__subject)
- , patch_value (forge, map, lworld, LV2_PATCH__value)
- , patch_wildcard (forge, map, lworld, LV2_PATCH__wildcard)
- , pprops_logarithmic (forge, map, lworld, LV2_PORT_PROPS__logarithmic)
- , pset_Preset (forge, map, lworld, LV2_PRESETS__Preset)
- , pset_preset (forge, map, lworld, LV2_PRESETS__preset)
- , rdf_type (forge, map, lworld, NS_RDF "type")
- , rdfs_Class (forge, map, lworld, NS_RDFS "Class")
- , rdfs_label (forge, map, lworld, NS_RDFS "label")
- , rdfs_seeAlso (forge, map, lworld, NS_RDFS "seeAlso")
- , rsz_minimumSize (forge, map, lworld, LV2_RESIZE_PORT__minimumSize)
- , state_loadDefaultState(forge, map, lworld, LV2_STATE__loadDefaultState)
- , state_state (forge, map, lworld, LV2_STATE__state)
- , time_Position (forge, map, lworld, LV2_TIME__Position)
- , time_bar (forge, map, lworld, LV2_TIME__bar)
- , time_barBeat (forge, map, lworld, LV2_TIME__barBeat)
- , time_beatUnit (forge, map, lworld, LV2_TIME__beatUnit)
- , time_beatsPerBar (forge, map, lworld, LV2_TIME__beatsPerBar)
- , time_beatsPerMinute (forge, map, lworld, LV2_TIME__beatsPerMinute)
- , time_frame (forge, map, lworld, LV2_TIME__frame)
- , time_speed (forge, map, lworld, LV2_TIME__speed)
- , work_schedule (forge, map, lworld, LV2_WORKER__schedule)
-{}
-
-} // namespace Ingen
diff --git a/src/World.cpp b/src/World.cpp
deleted file mode 100644
index 568ab405..00000000
--- a/src/World.cpp
+++ /dev/null
@@ -1,355 +0,0 @@
-/*
- 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/>.
-*/
-
-#include <cstdlib>
-#include <map>
-#include <memory>
-#include <string>
-#include <utility>
-
-#include "ingen/Configuration.hpp"
-#include "ingen/DataAccess.hpp"
-#include "ingen/EngineBase.hpp"
-#include "ingen/Forge.hpp"
-#include "ingen/InstanceAccess.hpp"
-#include "ingen/LV2Features.hpp"
-#include "ingen/Log.hpp"
-#include "ingen/Module.hpp"
-#include "ingen/Parser.hpp"
-#include "ingen/Serialiser.hpp"
-#include "ingen/URIMap.hpp"
-#include "ingen/URIs.hpp"
-#include "ingen/World.hpp"
-#include "ingen/filesystem.hpp"
-#include "ingen/ingen.h"
-#include "ingen/runtime_paths.hpp"
-#include "lilv/lilv.h"
-#include "sord/sordmm.hpp"
-
-using std::string;
-
-namespace Ingen {
-
-class EngineBase;
-class Interface;
-class Parser;
-class Serialiser;
-class Store;
-
-/** Load a dynamic module from the default path.
- *
- * This will check in the directories specified in the environment variable
- * INGEN_MODULE_PATH (typical colon delimited format), then the default module
- * installation directory (ie /usr/local/lib/ingen), in that order.
- *
- * \param name The base name of the module, e.g. "ingen_jack"
- */
-static std::unique_ptr<Library>
-ingen_load_library(Log& log, const string& name)
-{
- std::unique_ptr<Library> library;
-
- // Search INGEN_MODULE_PATH first
- const char* const module_path = getenv("INGEN_MODULE_PATH");
- if (module_path) {
- string dir;
- std::istringstream iss(module_path);
- while (getline(iss, dir, search_path_separator)) {
- FilePath filename = Ingen::ingen_module_path(name, FilePath(dir));
- if (filesystem::exists(filename)) {
- library = std::unique_ptr<Library>(new Library(filename));
- if (*library) {
- return library;
- } else {
- log.error(Library::get_last_error());
- }
- }
- }
- }
-
- // Try default directory if not found
- library = std::unique_ptr<Library>(new Library(Ingen::ingen_module_path(name)));
-
- if (*library) {
- return library;
- } else if (!module_path) {
- log.error(fmt("Unable to find %1% (%2%)\n")
- % name % Library::get_last_error());
- return nullptr;
- } else {
- log.error(fmt("Unable to load %1% from %2% (%3%)\n")
- % name % module_path % Library::get_last_error());
- return nullptr;
- }
-}
-
-class World::Impl {
-public:
- Impl(LV2_URID_Map* map,
- LV2_URID_Unmap* unmap,
- LV2_Log_Log* lv2_log)
- : argc(nullptr)
- , argv(nullptr)
- , lv2_features(nullptr)
- , rdf_world(new Sord::World())
- , lilv_world(lilv_world_new())
- , uri_map(new URIMap(log, map, unmap))
- , forge(new Forge(*uri_map))
- , uris(new URIs(*forge, uri_map, lilv_world))
- , conf(*forge)
- , log(lv2_log, *uris)
- {
- lv2_features = new LV2Features();
- lv2_features->add_feature(uri_map->urid_map_feature());
- lv2_features->add_feature(uri_map->urid_unmap_feature());
- lv2_features->add_feature(SPtr<InstanceAccess>(new InstanceAccess()));
- lv2_features->add_feature(SPtr<DataAccess>(new DataAccess()));
- lv2_features->add_feature(SPtr<Log::Feature>(new Log::Feature()));
- lilv_world_load_all(lilv_world);
-
- // Set up RDF namespaces
- rdf_world->add_prefix("atom", "http://lv2plug.in/ns/ext/atom#");
- rdf_world->add_prefix("doap", "http://usefulinc.com/ns/doap#");
- rdf_world->add_prefix("ingen", INGEN_NS);
- rdf_world->add_prefix("lv2", "http://lv2plug.in/ns/lv2core#");
- rdf_world->add_prefix("midi", "http://lv2plug.in/ns/ext/midi#");
- rdf_world->add_prefix("owl", "http://www.w3.org/2002/07/owl#");
- rdf_world->add_prefix("patch", "http://lv2plug.in/ns/ext/patch#");
- rdf_world->add_prefix("rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#");
- rdf_world->add_prefix("rdfs", "http://www.w3.org/2000/01/rdf-schema#");
- rdf_world->add_prefix("xsd", "http://www.w3.org/2001/XMLSchema#");
-
- // Load internal 'plugin' information into lilv world
- LilvNode* rdf_type = lilv_new_uri(
- lilv_world, "http://www.w3.org/1999/02/22-rdf-syntax-ns#type");
- LilvNode* ingen_Plugin = lilv_new_uri(
- lilv_world, INGEN__Plugin);
- LilvNodes* internals = lilv_world_find_nodes(
- lilv_world, nullptr, rdf_type, ingen_Plugin);
- LILV_FOREACH(nodes, i, internals) {
- const LilvNode* internal = lilv_nodes_get(internals, i);
- lilv_world_load_resource(lilv_world, internal);
- }
- lilv_nodes_free(internals);
- lilv_node_free(rdf_type);
- lilv_node_free(ingen_Plugin);
- }
-
- ~Impl()
- {
- if (engine) {
- engine->quit();
- }
-
- // Delete module objects but save pointers to libraries
- typedef std::list<std::unique_ptr<Library>> Libs;
- Libs libs;
- for (auto& m : modules) {
- libs.emplace_back(std::move(m.second->library));
- delete m.second;
- }
-
- serialiser.reset();
- parser.reset();
- interface.reset();
- engine.reset();
- store.reset();
-
- interface_factories.clear();
- script_runners.clear();
-
- delete rdf_world;
- delete lv2_features;
- delete uris;
- delete forge;
- delete uri_map;
-
- lilv_world_free(lilv_world);
-
- // Module libraries go out of scope and close here
- }
-
- typedef std::map<const std::string, Module*> Modules;
- Modules modules;
-
- typedef std::map<const std::string, World::InterfaceFactory> InterfaceFactories;
- InterfaceFactories interface_factories;
-
- typedef bool (*ScriptRunner)(World* world, const char* filename);
- typedef std::map<const std::string, ScriptRunner> ScriptRunners;
- ScriptRunners script_runners;
-
- int* argc;
- char*** argv;
- LV2Features* lv2_features;
- Sord::World* rdf_world;
- LilvWorld* lilv_world;
- URIMap* uri_map;
- Forge* forge;
- URIs* uris;
- LV2_Log_Log* lv2_log;
- Configuration conf;
- Log log;
- SPtr<Interface> interface;
- SPtr<EngineBase> engine;
- SPtr<Serialiser> serialiser;
- SPtr<Parser> parser;
- SPtr<Store> store;
- std::mutex rdf_mutex;
- std::string jack_uuid;
-};
-
-World::World(LV2_URID_Map* map, LV2_URID_Unmap* unmap, LV2_Log_Log* log)
- : _impl(new Impl(map, unmap, log))
-{
- _impl->serialiser = SPtr<Serialiser>(new Serialiser(*this));
- _impl->parser = SPtr<Parser>(new Parser());
-}
-
-World::~World()
-{
- delete _impl;
-}
-
-void
-World::load_configuration(int& argc, char**& argv)
-{
- _impl->argc = &argc;
- _impl->argv = &argv;
-
- // Parse default configuration files
- const auto files = _impl->conf.load_default("ingen", "options.ttl");
- for (const auto& f : files) {
- _impl->log.info(fmt("Loaded configuration %1%\n") % f);
- }
-
- // Parse command line options, overriding configuration file values
- _impl->conf.parse(argc, argv);
- _impl->log.set_flush(_impl->conf.option("flush-log").get<int32_t>());
- _impl->log.set_trace(_impl->conf.option("trace").get<int32_t>());
-}
-
-void World::set_engine(SPtr<EngineBase> e) { _impl->engine = e; }
-void World::set_interface(SPtr<Interface> i) { _impl->interface = i; }
-void World::set_store(SPtr<Store> s) { _impl->store = s; }
-
-SPtr<EngineBase> World::engine() { return _impl->engine; }
-SPtr<Interface> World::interface() { return _impl->interface; }
-SPtr<Parser> World::parser() { return _impl->parser; }
-SPtr<Serialiser> World::serialiser() { return _impl->serialiser; }
-SPtr<Store> World::store() { return _impl->store; }
-
-int& World::argc() { return *_impl->argc; }
-char**& World::argv() { return *_impl->argv; }
-Configuration& World::conf() { return _impl->conf; }
-Log& World::log() { return _impl->log; }
-
-std::mutex& World::rdf_mutex() { return _impl->rdf_mutex; }
-
-Sord::World* World::rdf_world() { return _impl->rdf_world; }
-LilvWorld* World::lilv_world() { return _impl->lilv_world; }
-
-LV2Features& World::lv2_features() { return *_impl->lv2_features; }
-Forge& World::forge() { return *_impl->forge; }
-URIs& World::uris() { return *_impl->uris; }
-URIMap& World::uri_map() { return *_impl->uri_map; }
-
-bool
-World::load_module(const char* name)
-{
- auto i = _impl->modules.find(name);
- if (i != _impl->modules.end()) {
- return true;
- }
- log().info(fmt("Loading %1% module\n") % name);
- std::unique_ptr<Ingen::Library> lib = ingen_load_library(log(), name);
- Ingen::Module* (*module_load)() =
- lib ? (Ingen::Module* (*)())lib->get_function("ingen_module_load")
- : nullptr;
- if (module_load) {
- Module* module = module_load();
- if (module) {
- module->library = std::move(lib);
- module->load(this);
- _impl->modules.emplace(string(name), module);
- return true;
- }
- }
-
- log().error(fmt("Failed to load module `%1%' (%2%)\n") % name % lib->get_last_error());
- return false;
-}
-
-bool
-World::run_module(const char* name)
-{
- auto i = _impl->modules.find(name);
- if (i == _impl->modules.end()) {
- log().error(fmt("Attempt to run unloaded module `%1%'\n") % name);
- return false;
- }
-
- i->second->run(this);
- return true;
-}
-
-/** Get an interface for a remote engine at `engine_uri`
- */
-SPtr<Interface>
-World::new_interface(const URI& engine_uri, SPtr<Interface> respondee)
-{
- const Impl::InterfaceFactories::const_iterator i =
- _impl->interface_factories.find(std::string(engine_uri.scheme()));
- if (i == _impl->interface_factories.end()) {
- log().warn(fmt("Unknown URI scheme `%1%'\n") % engine_uri.scheme());
- return SPtr<Interface>();
- }
-
- return i->second(this, engine_uri, respondee);
-}
-
-/** Run a script of type `mime_type` at filename `filename` */
-bool
-World::run(const std::string& mime_type, const std::string& filename)
-{
- const Impl::ScriptRunners::const_iterator i = _impl->script_runners.find(mime_type);
- if (i == _impl->script_runners.end()) {
- log().warn(fmt("Unknown script MIME type `%1%'\n") % mime_type);
- return false;
- }
-
- return i->second(this, filename.c_str());
-}
-
-void
-World::add_interface_factory(const std::string& scheme, InterfaceFactory factory)
-{
- _impl->interface_factories.emplace(scheme, factory);
-}
-
-void
-World::set_jack_uuid(const std::string& uuid)
-{
- _impl->jack_uuid = uuid;
-}
-
-std::string
-World::jack_uuid()
-{
- return _impl->jack_uuid;
-}
-
-} // namespace Ingen
diff --git a/src/client/BlockModel.cpp b/src/client/BlockModel.cpp
deleted file mode 100644
index 910f7037..00000000
--- a/src/client/BlockModel.cpp
+++ /dev/null
@@ -1,285 +0,0 @@
-/*
- 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 <cassert>
-#include <cmath>
-#include <string>
-
-#include "ingen/client/BlockModel.hpp"
-#include "ingen/URIs.hpp"
-#include "ingen/World.hpp"
-
-namespace Ingen {
-namespace Client {
-
-BlockModel::BlockModel(URIs& uris,
- SPtr<PluginModel> plugin,
- const Raul::Path& path)
- : ObjectModel(uris, path)
- , _plugin_uri(plugin->uri())
- , _plugin(plugin)
- , _num_values(0)
- , _min_values(nullptr)
- , _max_values(nullptr)
-{
-}
-
-BlockModel::BlockModel(URIs& uris,
- const URI& plugin_uri,
- const Raul::Path& path)
- : ObjectModel(uris, path)
- , _plugin_uri(plugin_uri)
- , _num_values(0)
- , _min_values(nullptr)
- , _max_values(nullptr)
-{
-}
-
-BlockModel::BlockModel(const BlockModel& copy)
- : ObjectModel(copy)
- , _plugin_uri(copy._plugin_uri)
- , _num_values(copy._num_values)
- , _min_values((float*)malloc(sizeof(float) * _num_values))
- , _max_values((float*)malloc(sizeof(float) * _num_values))
-{
- memcpy(_min_values, copy._min_values, sizeof(float) * _num_values);
- memcpy(_max_values, copy._max_values, sizeof(float) * _num_values);
-}
-
-BlockModel::~BlockModel()
-{
- clear();
-}
-
-void
-BlockModel::remove_port(SPtr<PortModel> port)
-{
- for (auto i = _ports.begin(); i != _ports.end(); ++i) {
- if ((*i) == port) {
- _ports.erase(i);
- break;
- }
- }
- _signal_removed_port.emit(port);
-}
-
-void
-BlockModel::remove_port(const Raul::Path& port_path)
-{
- for (auto i = _ports.begin(); i != _ports.end(); ++i) {
- if ((*i)->path() == port_path) {
- _ports.erase(i);
- break;
- }
- }
-}
-
-void
-BlockModel::clear()
-{
- _ports.clear();
- assert(_ports.empty());
- delete[] _min_values;
- delete[] _max_values;
- _min_values = nullptr;
- _max_values = nullptr;
-}
-
-void
-BlockModel::add_child(SPtr<ObjectModel> c)
-{
- assert(c->parent().get() == this);
-
- //ObjectModel::add_child(c);
-
- SPtr<PortModel> pm = dynamic_ptr_cast<PortModel>(c);
- assert(pm);
- add_port(pm);
-}
-
-bool
-BlockModel::remove_child(SPtr<ObjectModel> c)
-{
- assert(c->path().is_child_of(path()));
- assert(c->parent().get() == this);
-
- //bool ret = ObjectModel::remove_child(c);
-
- SPtr<PortModel> pm = dynamic_ptr_cast<PortModel>(c);
- assert(pm);
- remove_port(pm);
-
- //return ret;
- return true;
-}
-
-void
-BlockModel::add_port(SPtr<PortModel> pm)
-{
- assert(pm);
- assert(pm->path().is_child_of(path()));
- assert(pm->parent().get() == this);
-
- // Store should have handled this by merging the two
- assert(find(_ports.begin(), _ports.end(), pm) == _ports.end());
-
- _ports.push_back(pm);
- _signal_new_port.emit(pm);
-}
-
-SPtr<const PortModel>
-BlockModel::get_port(const Raul::Symbol& symbol) const
-{
- for (auto p : _ports) {
- if (p->symbol() == symbol) {
- return p;
- }
- }
- return SPtr<PortModel>();
-}
-
-SPtr<const PortModel>
-BlockModel::get_port(uint32_t index) const
-{
- return _ports[index];
-}
-
-Ingen::Node*
-BlockModel::port(uint32_t index) const
-{
- assert(index < num_ports());
- return const_cast<Ingen::Node*>(
- dynamic_cast<const Ingen::Node*>(_ports[index].get()));
-}
-
-void
-BlockModel::default_port_value_range(SPtr<const PortModel> port,
- float& min,
- float& max,
- uint32_t srate) const
-{
- // Default control values
- min = 0.0;
- max = 1.0;
-
- // Get range from client-side LV2 data
- if (_plugin && _plugin->lilv_plugin()) {
- if (!_min_values) {
- _num_values = lilv_plugin_get_num_ports(_plugin->lilv_plugin());
- _min_values = new float[_num_values];
- _max_values = new float[_num_values];
- lilv_plugin_get_port_ranges_float(_plugin->lilv_plugin(),
- _min_values, _max_values, nullptr);
- }
-
- if (!std::isnan(_min_values[port->index()])) {
- min = _min_values[port->index()];
- }
- if (!std::isnan(_max_values[port->index()])) {
- max = _max_values[port->index()];
- }
- }
-
- if (port->port_property(_uris.lv2_sampleRate)) {
- min *= srate;
- max *= srate;
- }
-}
-
-void
-BlockModel::port_value_range(SPtr<const PortModel> port,
- float& min,
- float& max,
- uint32_t srate) const
-{
- assert(port->parent().get() == this);
-
- default_port_value_range(port, min, max);
-
- // Possibly overriden
- const Atom& min_atom = port->get_property(_uris.lv2_minimum);
- const Atom& max_atom = port->get_property(_uris.lv2_maximum);
- if (min_atom.type() == _uris.forge.Float) {
- min = min_atom.get<float>();
- }
- if (max_atom.type() == _uris.forge.Float) {
- max = max_atom.get<float>();
- }
-
- if (max <= min) {
- max = min + 1.0;
- }
-
- if (port->port_property(_uris.lv2_sampleRate)) {
- min *= srate;
- max *= srate;
- }
-}
-
-std::string
-BlockModel::label() const
-{
- const Atom& name_property = get_property(_uris.lv2_name);
- if (name_property.type() == _uris.forge.String) {
- return name_property.ptr<char>();
- } else if (plugin_model()) {
- return plugin_model()->human_name();
- } else {
- return symbol().c_str();
- }
-}
-
-std::string
-BlockModel::port_label(SPtr<const PortModel> port) const
-{
- const Atom& name = port->get_property(URI(LV2_CORE__name));
- if (name.is_valid() && name.type() == _uris.forge.String) {
- return name.ptr<char>();
- }
-
- if (_plugin && _plugin->lilv_plugin()) {
- LilvWorld* w = _plugin->lilv_world();
- const LilvPlugin* plug = _plugin->lilv_plugin();
- LilvNode* sym = lilv_new_string(w, port->symbol().c_str());
- const LilvPort* lport = lilv_plugin_get_port_by_symbol(plug, sym);
- if (lport) {
- LilvNode* lname = lilv_port_get_name(plug, lport);
- if (lname && lilv_node_is_string(lname)) {
- std::string ret(lilv_node_as_string(lname));
- lilv_node_free(lname);
- return ret;
- }
- lilv_node_free(lname);
- }
- }
-
- return port->symbol().c_str();
-}
-
-void
-BlockModel::set(SPtr<ObjectModel> model)
-{
- SPtr<BlockModel> block = dynamic_ptr_cast<BlockModel>(model);
- if (block) {
- _plugin_uri = block->_plugin_uri;
- _plugin = block->_plugin;
- }
-
- ObjectModel::set(model);
-}
-
-} // namespace Client
-} // namespace Ingen
diff --git a/src/client/ClientStore.cpp b/src/client/ClientStore.cpp
deleted file mode 100644
index 792f8949..00000000
--- a/src/client/ClientStore.cpp
+++ /dev/null
@@ -1,487 +0,0 @@
-/*
- 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/>.
-*/
-
-#include <boost/variant/apply_visitor.hpp>
-
-#include "ingen/Log.hpp"
-#include "ingen/client/ArcModel.hpp"
-#include "ingen/client/BlockModel.hpp"
-#include "ingen/client/ClientStore.hpp"
-#include "ingen/client/GraphModel.hpp"
-#include "ingen/client/ObjectModel.hpp"
-#include "ingen/client/PluginModel.hpp"
-#include "ingen/client/PortModel.hpp"
-#include "ingen/client/SigClientInterface.hpp"
-
-namespace Ingen {
-namespace Client {
-
-ClientStore::ClientStore(URIs& uris,
- Log& log,
- SPtr<SigClientInterface> emitter)
- : _uris(uris)
- , _log(log)
- , _emitter(emitter)
- , _plugins(new Plugins())
-{
- if (emitter) {
- emitter->signal_message().connect(
- sigc::mem_fun(this, &ClientStore::message));
- }
-}
-
-void
-ClientStore::clear()
-{
- Store::clear();
- _plugins->clear();
-}
-
-void
-ClientStore::add_object(SPtr<ObjectModel> object)
-{
- // If we already have "this" object, merge the existing one into the new
- // one (with precedence to the new values).
- auto existing = find(object->path());
- if (existing != end()) {
- dynamic_ptr_cast<ObjectModel>(existing->second)->set(object);
- } else {
- if (!object->path().is_root()) {
- SPtr<ObjectModel> parent = _object(object->path().parent());
- if (parent) {
- assert(object->path().is_child_of(parent->path()));
- object->set_parent(parent);
- parent->add_child(object);
- assert(parent && (object->parent() == parent));
-
- (*this)[object->path()] = object;
- _signal_new_object.emit(object);
- } else {
- _log.error(fmt("Object %1% with no parent\n") % object->path());
- }
- } else {
- (*this)[object->path()] = object;
- _signal_new_object.emit(object);
- }
- }
-
- for (auto p : object->properties()) {
- object->signal_property().emit(p.first, p.second);
- }
-}
-
-SPtr<ObjectModel>
-ClientStore::remove_object(const Raul::Path& path)
-{
- // Find the object, the "top" of the tree to remove
- const iterator top = find(path);
- if (top == end()) {
- return SPtr<ObjectModel>();
- }
-
- SPtr<ObjectModel> object = dynamic_ptr_cast<ObjectModel>(top->second);
-
- // Remove object and any adjacent arcs from parent if applicable
- if (object && object->parent()) {
- SPtr<PortModel> port = dynamic_ptr_cast<PortModel>(object);
- if (port && dynamic_ptr_cast<GraphModel>(port->parent())) {
- disconnect_all(port->parent()->path(), path);
- if (port->parent()->parent()) {
- disconnect_all(port->parent()->parent()->path(), path);
- }
- } else if (port && port->parent()->parent()) {
- disconnect_all(port->parent()->parent()->path(), path);
- } else {
- disconnect_all(object->parent()->path(), path);
- }
-
- object->parent()->remove_child(object);
- }
-
- // Remove the object and all its descendants
- Objects removed;
- remove(top, removed);
-
- // Notify everything that needs to know this object has been removed
- if (object) {
- object->signal_destroyed().emit();
- }
-
- return object;
-}
-
-SPtr<PluginModel>
-ClientStore::_plugin(const URI& uri)
-{
- const Plugins::iterator i = _plugins->find(uri);
- return (i == _plugins->end()) ? SPtr<PluginModel>() : (*i).second;
-}
-
-SPtr<PluginModel>
-ClientStore::_plugin(const Atom& uri)
-{
- /* FIXME: Should probably be stored with URIs rather than strings, to make
- this a fast case. */
-
- const Plugins::iterator i = _plugins->find(URI(_uris.forge.str(uri, false)));
- return (i == _plugins->end()) ? SPtr<PluginModel>() : (*i).second;
-}
-
-SPtr<const PluginModel>
-ClientStore::plugin(const URI& uri) const
-{
- return const_cast<ClientStore*>(this)->_plugin(uri);
-}
-
-SPtr<ObjectModel>
-ClientStore::_object(const Raul::Path& path)
-{
- const iterator i = find(path);
- if (i == end()) {
- return SPtr<ObjectModel>();
- } else {
- SPtr<ObjectModel> model = dynamic_ptr_cast<ObjectModel>(i->second);
- assert(model);
- assert(model->path().is_root() || model->parent());
- return model;
- }
-}
-
-SPtr<const ObjectModel>
-ClientStore::object(const Raul::Path& path) const
-{
- return const_cast<ClientStore*>(this)->_object(path);
-}
-
-SPtr<Resource>
-ClientStore::_resource(const URI& uri)
-{
- if (uri_is_path(uri)) {
- return _object(uri_to_path(uri));
- } else {
- return _plugin(uri);
- }
-}
-
-SPtr<const Resource>
-ClientStore::resource(const URI& uri) const
-{
- return const_cast<ClientStore*>(this)->_resource(uri);
-}
-
-void
-ClientStore::add_plugin(SPtr<PluginModel> pm)
-{
- SPtr<PluginModel> existing = _plugin(pm->uri());
- if (existing) {
- existing->set(pm);
- } else {
- _plugins->emplace(pm->uri(), pm);
- _signal_new_plugin.emit(pm);
- }
-}
-
-/* ****** Signal Handlers ******** */
-
-void
-ClientStore::operator()(const Del& del)
-{
- if (uri_is_path(del.uri)) {
- remove_object(uri_to_path(del.uri));
- } else {
- auto p = _plugins->find(del.uri);
- if (p != _plugins->end()) {
- _plugins->erase(p);
- _signal_plugin_deleted.emit(del.uri);
- }
- }
-}
-
-void
-ClientStore::operator()(const Copy&)
-{
- _log.error("Client store copy unsupported\n");
-}
-
-void
-ClientStore::operator()(const Move& msg)
-{
- const iterator top = find(msg.old_path);
- if (top != end()) {
- rename(top, msg.new_path);
- }
-}
-
-void
-ClientStore::message(const Message& msg)
-{
- boost::apply_visitor(*this, msg);
-}
-
-void
-ClientStore::operator()(const Put& msg)
-{
- typedef Properties::const_iterator Iterator;
-
- const auto& uri = msg.uri;
- const auto& properties = msg.properties;
-
- bool is_graph, is_block, is_port, is_output;
- Resource::type(uris(), properties,
- is_graph, is_block, is_port, is_output);
-
- // Check for specially handled types
- const Iterator t = properties.find(_uris.rdf_type);
- if (t != properties.end()) {
- const Atom& type(t->second);
- if (_uris.pset_Preset == type) {
- const Iterator p = properties.find(_uris.lv2_appliesTo);
- const Iterator l = properties.find(_uris.rdfs_label);
- SPtr<PluginModel> plug;
- if (p == properties.end()) {
- _log.error(fmt("Preset <%1%> with no plugin\n") % uri.c_str());
- } else if (l == properties.end()) {
- _log.error(fmt("Preset <%1%> with no label\n") % uri.c_str());
- } else if (l->second.type() != _uris.forge.String) {
- _log.error(fmt("Preset <%1%> label is not a string\n") % uri.c_str());
- } else if (!(plug = _plugin(p->second))) {
- _log.error(fmt("Preset <%1%> for unknown plugin %2%\n")
- % uri.c_str() % _uris.forge.str(p->second, true));
- } else {
- plug->add_preset(uri, l->second.ptr<char>());
- }
- return;
- } else if (_uris.ingen_Graph == type) {
- is_graph = true;
- } else if (_uris.ingen_Internal == type || _uris.lv2_Plugin == type) {
- SPtr<PluginModel> p(new PluginModel(uris(), uri, type, properties));
- add_plugin(p);
- return;
- }
- }
-
- if (!uri_is_path(uri)) {
- _log.error(fmt("Put for unknown subject <%1%>\n")
- % uri.c_str());
- return;
- }
-
- const Raul::Path path(uri_to_path(uri));
-
- SPtr<ObjectModel> obj = dynamic_ptr_cast<ObjectModel>(_object(path));
- if (obj) {
- obj->set_properties(properties);
- return;
- }
-
- if (path.is_root()) {
- is_graph = true;
- }
-
- if (is_graph) {
- SPtr<GraphModel> model(new GraphModel(uris(), path));
- model->set_properties(properties);
- add_object(model);
- } else if (is_block) {
- auto p = properties.find(_uris.lv2_prototype);
- if (p == properties.end()) {
- p = properties.find(_uris.ingen_prototype);
- }
-
- SPtr<PluginModel> plug;
- if (p->second.is_valid() && (p->second.type() == _uris.forge.URI ||
- p->second.type() == _uris.forge.URID)) {
- const URI uri(_uris.forge.str(p->second, false));
- if (!(plug = _plugin(uri))) {
- plug = SPtr<PluginModel>(
- new PluginModel(uris(), uri, Atom(), Properties()));
- add_plugin(plug);
- }
-
- SPtr<BlockModel> bm(new BlockModel(uris(), plug, path));
- bm->set_properties(properties);
- add_object(bm);
- } else {
- _log.warn(fmt("Block %1% has no prototype\n") % path.c_str());
- }
- } else if (is_port) {
- PortModel::Direction pdir = (is_output)
- ? PortModel::Direction::OUTPUT
- : PortModel::Direction::INPUT;
- uint32_t index = 0;
- const Iterator i = properties.find(_uris.lv2_index);
- if (i != properties.end() && i->second.type() == _uris.forge.Int) {
- index = i->second.get<int32_t>();
- }
-
- SPtr<PortModel> p(new PortModel(uris(), path, index, pdir));
- p->set_properties(properties);
- add_object(p);
- } else {
- _log.warn(fmt("Ignoring %1% of unknown type\n") % path.c_str());
- }
-}
-
-void
-ClientStore::operator()(const Delta& msg)
-{
- const auto& uri = msg.uri;
- if (uri == URI("ingen:/clients/this")) {
- // Client property, which we don't store (yet?)
- return;
- }
-
- if (!uri_is_path(uri)) {
- _log.error(fmt("Delta for unknown subject <%1%>\n")
- % uri.c_str());
- return;
- }
-
- const Raul::Path path(uri_to_path(uri));
-
- SPtr<ObjectModel> obj = _object(path);
- if (obj) {
- obj->remove_properties(msg.remove);
- obj->add_properties(msg.add);
- } else {
- _log.warn(fmt("Failed to find object `%1%'\n") % path.c_str());
- }
-}
-
-void
-ClientStore::operator()(const SetProperty& msg)
-{
- const auto& subject_uri = msg.subject;
- const auto& predicate = msg.predicate;
- const auto& value = msg.value;
-
- if (subject_uri == URI("ingen:/engine")) {
- _log.info(fmt("Engine property <%1%> = %2%\n")
- % predicate.c_str() % _uris.forge.str(value, false));
- return;
- }
- SPtr<Resource> subject = _resource(subject_uri);
- if (subject) {
- if (predicate == _uris.ingen_activity) {
- /* Activity is transient, trigger any live actions (like GUI
- blinkenlights) but do not store the property. */
- subject->on_property(predicate, value);
- } else {
- subject->set_property(predicate, value, msg.ctx);
- }
- } else {
- SPtr<PluginModel> plugin = _plugin(subject_uri);
- if (plugin) {
- plugin->set_property(predicate, value);
- } else if (predicate != _uris.ingen_activity) {
- _log.warn(fmt("Property <%1%> for unknown object %2%\n")
- % predicate.c_str() % subject_uri.c_str());
- }
- }
-}
-
-SPtr<GraphModel>
-ClientStore::connection_graph(const Raul::Path& tail_path,
- const Raul::Path& head_path)
-{
- SPtr<GraphModel> graph;
-
- if (tail_path.parent() == head_path.parent()) {
- graph = dynamic_ptr_cast<GraphModel>(_object(tail_path.parent()));
- }
-
- if (!graph && tail_path.parent() == head_path.parent().parent()) {
- graph = dynamic_ptr_cast<GraphModel>(_object(tail_path.parent()));
- }
-
- if (!graph && tail_path.parent().parent() == head_path.parent()) {
- graph = dynamic_ptr_cast<GraphModel>(_object(head_path.parent()));
- }
-
- if (!graph) {
- graph = dynamic_ptr_cast<GraphModel>(_object(tail_path.parent().parent()));
- }
-
- if (!graph) {
- _log.error(fmt("Unable to find graph for arc %1% => %2%\n")
- % tail_path % head_path);
- }
-
- return graph;
-}
-
-bool
-ClientStore::attempt_connection(const Raul::Path& tail_path,
- const Raul::Path& head_path)
-{
- SPtr<PortModel> tail = dynamic_ptr_cast<PortModel>(_object(tail_path));
- SPtr<PortModel> head = dynamic_ptr_cast<PortModel>(_object(head_path));
-
- if (tail && head) {
- SPtr<GraphModel> graph = connection_graph(tail_path, head_path);
- SPtr<ArcModel> arc(new ArcModel(tail, head));
- graph->add_arc(arc);
- return true;
- } else {
- _log.warn(fmt("Failed to connect %1% => %2%\n")
- % tail_path % head_path);
- return false;
- }
-}
-
-void
-ClientStore::operator()(const Connect& msg)
-{
- attempt_connection(msg.tail, msg.head);
-}
-
-void
-ClientStore::operator()(const Disconnect& msg)
-{
- SPtr<PortModel> tail = dynamic_ptr_cast<PortModel>(_object(msg.tail));
- SPtr<PortModel> head = dynamic_ptr_cast<PortModel>(_object(msg.head));
- SPtr<GraphModel> graph = connection_graph(msg.tail, msg.head);
- if (graph) {
- graph->remove_arc(tail.get(), head.get());
- }
-}
-
-void
-ClientStore::operator()(const DisconnectAll& msg)
-{
- SPtr<GraphModel> graph = dynamic_ptr_cast<GraphModel>(_object(msg.graph));
- SPtr<ObjectModel> object = _object(msg.path);
-
- if (!graph || !object) {
- _log.error(fmt("Bad disconnect all notification %1% in %2%\n")
- % msg.path % msg.graph);
- return;
- }
-
- const GraphModel::Arcs arcs = graph->arcs();
- for (auto a : arcs) {
- SPtr<ArcModel> arc = dynamic_ptr_cast<ArcModel>(a.second);
- if (arc->tail()->parent() == object
- || arc->head()->parent() == object
- || arc->tail()->path() == msg.path
- || arc->head()->path() == msg.path) {
- graph->remove_arc(arc->tail().get(), arc->head().get());
- }
- }
-}
-
-} // namespace Client
-} // namespace Ingen
diff --git a/src/client/GraphModel.cpp b/src/client/GraphModel.cpp
deleted file mode 100644
index 0723e59b..00000000
--- a/src/client/GraphModel.cpp
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- 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 <cassert>
-
-#include "ingen/URIs.hpp"
-#include "ingen/client/ArcModel.hpp"
-#include "ingen/client/BlockModel.hpp"
-#include "ingen/client/ClientStore.hpp"
-#include "ingen/client/GraphModel.hpp"
-
-namespace Ingen {
-namespace Client {
-
-void
-GraphModel::add_child(SPtr<ObjectModel> c)
-{
- assert(c->parent().get() == this);
-
- SPtr<PortModel> pm = dynamic_ptr_cast<PortModel>(c);
- if (pm) {
- add_port(pm);
- return;
- }
-
- SPtr<BlockModel> bm = dynamic_ptr_cast<BlockModel>(c);
- if (bm) {
- _signal_new_block.emit(bm);
- }
-}
-
-bool
-GraphModel::remove_child(SPtr<ObjectModel> o)
-{
- assert(o->path().is_child_of(path()));
- assert(o->parent().get() == this);
-
- SPtr<PortModel> pm = dynamic_ptr_cast<PortModel>(o);
- if (pm) {
- remove_arcs_on(pm);
- remove_port(pm);
- }
-
- SPtr<BlockModel> bm = dynamic_ptr_cast<BlockModel>(o);
- if (bm) {
- _signal_removed_block.emit(bm);
- }
-
- return true;
-}
-
-void
-GraphModel::remove_arcs_on(SPtr<PortModel> p)
-{
- // Remove any connections which referred to this object,
- // since they can't possibly exist anymore
- for (auto j = _arcs.begin(); j != _arcs.end();) {
- auto next = j;
- ++next;
-
- SPtr<ArcModel> arc = dynamic_ptr_cast<ArcModel>(j->second);
- if (arc->tail_path().parent() == p->path()
- || arc->tail_path() == p->path()
- || arc->head_path().parent() == p->path()
- || arc->head_path() == p->path()) {
- _signal_removed_arc.emit(arc);
- _arcs.erase(j); // Cuts our reference
- }
- j = next;
- }
-}
-
-void
-GraphModel::clear()
-{
- _arcs.clear();
-
- BlockModel::clear();
-
- assert(_arcs.empty());
- assert(_ports.empty());
-}
-
-SPtr<ArcModel>
-GraphModel::get_arc(const Node* tail, const Node* head)
-{
- auto i = _arcs.find(std::make_pair(tail, head));
- if (i != _arcs.end()) {
- return dynamic_ptr_cast<ArcModel>(i->second);
- } else {
- return SPtr<ArcModel>();
- }
-}
-
-/** Add a connection to this graph.
- *
- * A reference to `arc` is taken, released on deletion or removal.
- * If `arc` only contains paths (not pointers to the actual ports), the ports
- * will be found and set. The ports referred to not existing as children of
- * this graph is a fatal error.
- */
-void
-GraphModel::add_arc(SPtr<ArcModel> arc)
-{
- // Store should have 'resolved' the connection already
- assert(arc);
- assert(arc->tail());
- assert(arc->head());
- assert(arc->tail()->parent());
- assert(arc->head()->parent());
- assert(arc->tail_path() != arc->head_path());
- assert(arc->tail()->parent().get() == this
- || arc->tail()->parent()->parent().get() == this);
- assert(arc->head()->parent().get() == this
- || arc->head()->parent()->parent().get() == this);
-
- SPtr<ArcModel> existing = get_arc(
- arc->tail().get(), arc->head().get());
-
- if (existing) {
- assert(arc->tail() == existing->tail());
- assert(arc->head() == existing->head());
- } else {
- _arcs.emplace(std::make_pair(arc->tail().get(), arc->head().get()),
- arc);
- _signal_new_arc.emit(arc);
- }
-}
-
-void
-GraphModel::remove_arc(const Node* tail, const Node* head)
-{
- auto i = _arcs.find(std::make_pair(tail, head));
- if (i != _arcs.end()) {
- SPtr<ArcModel> arc = dynamic_ptr_cast<ArcModel>(i->second);
- _signal_removed_arc.emit(arc);
- _arcs.erase(i);
- }
-}
-
-bool
-GraphModel::enabled() const
-{
- const Atom& enabled = get_property(_uris.ingen_enabled);
- return (enabled.is_valid() && enabled.get<int32_t>());
-}
-
-uint32_t
-GraphModel::internal_poly() const
-{
- const Atom& poly = get_property(_uris.ingen_polyphony);
- return poly.is_valid() ? poly.get<int32_t>() : 1;
-}
-
-bool
-GraphModel::polyphonic() const
-{
- const Atom& poly = get_property(_uris.ingen_polyphonic);
- return poly.is_valid() && poly.get<int32_t>();
-}
-
-} // namespace Client
-} // namespace Ingen
diff --git a/src/client/ObjectModel.cpp b/src/client/ObjectModel.cpp
deleted file mode 100644
index 8d40b120..00000000
--- a/src/client/ObjectModel.cpp
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- 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/Node.hpp"
-#include "ingen/URIs.hpp"
-#include "ingen/client/ObjectModel.hpp"
-
-namespace Ingen {
-namespace Client {
-
-ObjectModel::ObjectModel(URIs& uris, const Raul::Path& path)
- : Node(uris, path)
- , _path(path)
- , _symbol((path == "/") ? "root" : path.symbol())
-{
-}
-
-ObjectModel::ObjectModel(const ObjectModel& copy)
- : Node(copy)
- , _parent(copy._parent)
- , _path(copy._path)
- , _symbol(copy._symbol)
-{
-}
-
-bool
-ObjectModel::is_a(const URIs::Quark& type) const
-{
- return has_property(_uris.rdf_type, type);
-}
-
-void
-ObjectModel::on_property(const URI& uri, const Atom& value)
-{
- _signal_property.emit(uri, value);
-}
-
-void
-ObjectModel::on_property_removed(const URI& uri, const Atom& value)
-{
- _signal_property_removed.emit(uri, value);
-}
-
-const Atom&
-ObjectModel::get_property(const URI& key) const
-{
- static const Atom null_atom;
- auto i = properties().find(key);
- return (i != properties().end()) ? i->second : null_atom;
-}
-
-bool
-ObjectModel::polyphonic() const
-{
- const Atom& polyphonic = get_property(_uris.ingen_polyphonic);
- return (polyphonic.is_valid() && polyphonic.get<int32_t>());
-}
-
-/** Merge the data of `o` with self, as much as possible.
- *
- * This will merge the two models, but with any conflict take the value in
- * `o` as correct. The paths of the two models MUST be equal.
- */
-void
-ObjectModel::set(SPtr<ObjectModel> o)
-{
- assert(_path == o->path());
- if (o->_parent) {
- _parent = o->_parent;
- }
-
- for (auto v : o->properties()) {
- Resource::set_property(v.first, v.second);
- _signal_property.emit(v.first, v.second);
- }
-}
-
-void
-ObjectModel::set_path(const Raul::Path& p)
-{
- _path = p;
- _symbol = Raul::Symbol(p.is_root() ? "root" : p.symbol());
- set_uri(path_to_uri(p));
- _signal_moved.emit();
-}
-
-void
-ObjectModel::set_parent(SPtr<ObjectModel> p)
-{
- assert(_path.is_child_of(p->path()));
- _parent = p;
-}
-
-} // namespace Client
-} // namespace Ingen
diff --git a/src/client/PluginModel.cpp b/src/client/PluginModel.cpp
deleted file mode 100644
index 5427b75e..00000000
--- a/src/client/PluginModel.cpp
+++ /dev/null
@@ -1,360 +0,0 @@
-/*
- 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 <string>
-#include <algorithm>
-
-#include <boost/optional.hpp>
-
-#include "raul/Path.hpp"
-
-#include "ingen/Atom.hpp"
-#include "ingen/client/GraphModel.hpp"
-#include "ingen/client/PluginModel.hpp"
-#include "ingen/client/PluginUI.hpp"
-
-#include "ingen_config.h"
-
-using std::string;
-
-namespace Ingen {
-namespace Client {
-
-LilvWorld* PluginModel::_lilv_world = nullptr;
-const LilvPlugins* PluginModel::_lilv_plugins = nullptr;
-
-Sord::World* PluginModel::_rdf_world = nullptr;
-
-PluginModel::PluginModel(URIs& uris,
- const URI& uri,
- const Atom& type,
- const Properties& properties)
- : Resource(uris, uri)
- , _type(type)
- , _fetched(false)
-{
- if (!_type.is_valid()) {
- if (uri.string().find("ingen-internals") != string::npos) {
- _type = uris.ingen_Internal.urid;
- } else {
- _type = uris.lv2_Plugin.urid; // Assume LV2 and hope for the best...
- }
- }
-
- add_property(uris.rdf_type, type);
- add_properties(properties);
-
- LilvNode* plugin_uri = lilv_new_uri(_lilv_world, uri.c_str());
- _lilv_plugin = lilv_plugins_get_by_uri(_lilv_plugins, plugin_uri);
- lilv_node_free(plugin_uri);
-
- if (uris.ingen_Internal == _type) {
- set_property(uris.doap_name,
- uris.forge.alloc(std::string(uri.fragment().substr(1))));
- }
-}
-
-static size_t
-last_uri_delim(const std::string& str)
-{
- for (size_t i = str.length() - 1; i > 0; --i) {
- switch (str[i]) {
- case ':': case '/': case '?': case '#':
- return i;
- }
- }
- return string::npos;
-}
-
-static bool
-contains_alpha_after(const std::string& str, size_t begin)
-{
- for (size_t i = begin; i < str.length(); ++i) {
- if (isalpha(str[i])) {
- return true;
- }
- }
- return false;
-}
-
-const Atom&
-PluginModel::get_property(const URI& key) const
-{
- static const Atom nil;
- const Atom& val = Resource::get_property(key);
- if (val.is_valid()) {
- return val;
- }
-
- // No lv2:symbol from data or engine, invent one
- if (key == _uris.lv2_symbol) {
- string str = this->uri();
- size_t last_delim = last_uri_delim(str);
- while (last_delim != string::npos &&
- !contains_alpha_after(str, last_delim)) {
- str = str.substr(0, last_delim);
- last_delim = last_uri_delim(str);
- }
- str = str.substr(last_delim + 1);
-
- std::string symbol = Raul::Symbol::symbolify(str);
- set_property(_uris.lv2_symbol, _uris.forge.alloc(symbol));
- return get_property(key);
- }
-
- if (_lilv_plugin) {
- boost::optional<const Atom&> ret;
- LilvNode* lv2_pred = lilv_new_uri(_lilv_world, key.c_str());
- LilvNodes* values = lilv_plugin_get_value(_lilv_plugin, lv2_pred);
- lilv_node_free(lv2_pred);
- LILV_FOREACH(nodes, i, values) {
- const LilvNode* val = lilv_nodes_get(values, i);
- if (lilv_node_is_uri(val)) {
- ret = set_property(
- key, _uris.forge.make_urid(URI(lilv_node_as_uri(val))));
- break;
- } else if (lilv_node_is_string(val)) {
- ret = set_property(
- key, _uris.forge.alloc(lilv_node_as_string(val)));
- break;
- } else if (lilv_node_is_float(val)) {
- ret = set_property(
- key, _uris.forge.make(lilv_node_as_float(val)));
- break;
- } else if (lilv_node_is_int(val)) {
- ret = set_property(
- key, _uris.forge.make(lilv_node_as_int(val)));
- break;
- }
- }
- lilv_nodes_free(values);
-
- if (ret) {
- return *ret;
- }
- }
-
- return nil;
-}
-
-void
-PluginModel::set(SPtr<PluginModel> p)
-{
- _type = p->_type;
-
- if (p->_lilv_plugin) {
- _lilv_plugin = p->_lilv_plugin;
- }
-
- for (auto v : p->properties()) {
- Resource::set_property(v.first, v.second);
- _signal_property.emit(v.first, v.second);
- }
-
- _signal_changed.emit();
-}
-
-void
-PluginModel::add_preset(const URI& uri, const std::string& label)
-{
- _presets.emplace(uri, label);
- _signal_preset.emit(uri, label);
-}
-
-Raul::Symbol
-PluginModel::default_block_symbol() const
-{
- const Atom& name_atom = get_property(_uris.lv2_symbol);
- if (name_atom.is_valid() && name_atom.type() == _uris.forge.String) {
- return Raul::Symbol::symbolify(name_atom.ptr<char>());
- } else {
- return Raul::Symbol("_");
- }
-}
-
-string
-PluginModel::human_name() const
-{
- const Atom& name_atom = get_property(_uris.doap_name);
- if (name_atom.type() == _uris.forge.String) {
- return name_atom.ptr<char>();
- } else {
- return default_block_symbol().c_str();
- }
-}
-
-string
-PluginModel::port_human_name(uint32_t i) const
-{
- if (_lilv_plugin) {
- const LilvPort* port = lilv_plugin_get_port_by_index(_lilv_plugin, i);
- LilvNode* name = lilv_port_get_name(_lilv_plugin, port);
- const string ret(lilv_node_as_string(name));
- lilv_node_free(name);
- return ret;
- }
- return "";
-}
-
-PluginModel::ScalePoints
-PluginModel::port_scale_points(uint32_t i) const
-{
- // TODO: Non-float scale points
- ScalePoints points;
- if (_lilv_plugin) {
- const LilvPort* port = lilv_plugin_get_port_by_index(_lilv_plugin, i);
- LilvScalePoints* sp = lilv_port_get_scale_points(_lilv_plugin, port);
- LILV_FOREACH(scale_points, i, sp) {
- const LilvScalePoint* p = lilv_scale_points_get(sp, i);
- points.emplace(
- lilv_node_as_float(lilv_scale_point_get_value(p)),
- lilv_node_as_string(lilv_scale_point_get_label(p)));
- }
- }
- return points;
-}
-
-bool
-PluginModel::has_ui() const
-{
- if (_lilv_plugin) {
- LilvUIs* uis = lilv_plugin_get_uis(_lilv_plugin);
- const bool ret = (lilv_nodes_size(uis) > 0);
- lilv_uis_free(uis);
- return ret;
- }
- return false;
-}
-
-SPtr<PluginUI>
-PluginModel::ui(Ingen::World* world,
- SPtr<const BlockModel> block) const
-{
- if (!_lilv_plugin) {
- return SPtr<PluginUI>();
- }
-
- return PluginUI::create(world, block, _lilv_plugin);
-}
-
-static std::string
-heading(const std::string& text, bool html, unsigned level)
-{
- if (html) {
- const std::string tag = std::string("h") + std::to_string(level);
- return std::string("<") + tag + ">" + text + "</" + tag + ">\n";
- } else {
- return text + ":\n\n";
- }
-}
-
-static std::string
-link(const std::string& addr, bool html)
-{
- if (html) {
- return std::string("<a href=\"") + addr + "\">" + addr + "</a>";
- } else {
- return addr;
- }
-}
-
-std::string
-PluginModel::get_documentation(const LilvNode* subject, bool html) const
-{
- std::string doc;
-
- LilvNode* lv2_documentation = lilv_new_uri(_lilv_world,
- LV2_CORE__documentation);
- LilvNode* rdfs_comment = lilv_new_uri(_lilv_world,
- LILV_NS_RDFS "comment");
-
- LilvNodes* vals = lilv_world_find_nodes(
- _lilv_world, subject, lv2_documentation, nullptr);
- const bool doc_is_html = vals;
- if (!vals) {
- vals = lilv_world_find_nodes(
- _lilv_world, subject, rdfs_comment, nullptr);
- }
-
- if (vals) {
- const LilvNode* val = lilv_nodes_get_first(vals);
- if (lilv_node_is_string(val)) {
- doc += lilv_node_as_string(val);
- }
- }
-
- if (html && !doc_is_html) {
- for (std::size_t i = 0; i < doc.size(); ++i) {
- if (doc.substr(i, 2) == "\n\n") {
- doc.replace(i, 2, "<br/><br/>");
- i += strlen("<br/><br/>");
- }
- }
- }
-
- lilv_node_free(rdfs_comment);
- lilv_node_free(lv2_documentation);
-
- return doc;
-}
-
-std::string
-PluginModel::documentation(const bool html) const
-{
- LilvNode* subject = (_lilv_plugin)
- ? lilv_node_duplicate(lilv_plugin_get_uri(_lilv_plugin))
- : lilv_new_uri(_lilv_world, uri().c_str());
-
- const std::string doc(get_documentation(subject, html));
-
- lilv_node_free(subject);
-
- return (heading(human_name(), html, 2) +
- link(uri(), html) + (html ? "<br/><br/>" : "\n\n") +
- doc);
-}
-
-std::string
-PluginModel::port_documentation(uint32_t index, bool html) const
-{
- if (!_lilv_plugin) {
- return "";
- }
-
- const LilvPort* port = lilv_plugin_get_port_by_index(_lilv_plugin, index);
- if (!port) {
- return "";
- }
-
- return (heading(port_human_name(index), html, 2) +
- get_documentation(lilv_port_get_node(_lilv_plugin, port), html));
-}
-
-const LilvPort*
-PluginModel::lilv_port(uint32_t index) const
-{
- return lilv_plugin_get_port_by_index(_lilv_plugin, index);
-}
-
-void
-PluginModel::set_lilv_world(LilvWorld* world)
-{
- _lilv_world = world;
- _lilv_plugins = lilv_world_get_all_plugins(_lilv_world);
-}
-
-} // namespace Client
-} // namespace Ingen
diff --git a/src/client/PluginUI.cpp b/src/client/PluginUI.cpp
deleted file mode 100644
index df983f7f..00000000
--- a/src/client/PluginUI.cpp
+++ /dev/null
@@ -1,336 +0,0 @@
-/*
- 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/Log.hpp"
-#include "ingen/URIs.hpp"
-#include "ingen/client/BlockModel.hpp"
-#include "ingen/client/PluginUI.hpp"
-#include "ingen/client/PortModel.hpp"
-#include "lv2/lv2plug.in/ns/ext/atom/atom.h"
-#include "lv2/lv2plug.in/ns/extensions/ui/ui.h"
-
-namespace Ingen {
-namespace Client {
-
-SuilHost* PluginUI::ui_host = nullptr;
-
-static SPtr<const PortModel>
-get_port(PluginUI* ui, uint32_t port_index)
-{
- if (port_index >= ui->block()->ports().size()) {
- ui->world()->log().error(
- fmt("%1% UI tried to access invalid port %2%\n")
- % ui->block()->plugin()->uri().c_str() % port_index);
- return SPtr<const PortModel>();
- }
- return ui->block()->ports()[port_index];
-}
-
-static void
-lv2_ui_write(SuilController controller,
- uint32_t port_index,
- uint32_t buffer_size,
- uint32_t format,
- const void* buffer)
-{
- PluginUI* const ui = (PluginUI*)controller;
- const URIs& uris = ui->world()->uris();
- SPtr<const PortModel> port = get_port(ui, port_index);
- if (!port) {
- return;
- }
-
- // float (special case, always 0)
- if (format == 0) {
- if (buffer_size != 4) {
- ui->world()->log().error(
- fmt("%1% UI wrote corrupt float with bad size\n")
- % ui->block()->plugin()->uri().c_str());
- return;
- }
- const float value = *(const float*)buffer;
- if (port->value().type() == uris.atom_Float &&
- value == port->value().get<float>()) {
- return; // Ignore feedback
- }
-
- ui->signal_property_changed()(
- port->uri(),
- uris.ingen_value,
- ui->world()->forge().make(value),
- Resource::Graph::DEFAULT);
-
- } else if (format == uris.atom_eventTransfer.urid.get<LV2_URID>()) {
- const LV2_Atom* atom = (const LV2_Atom*)buffer;
- Atom val = ui->world()->forge().alloc(
- atom->size, atom->type, LV2_ATOM_BODY_CONST(atom));
- ui->signal_property_changed()(port->uri(),
- uris.ingen_activity,
- val,
- Resource::Graph::DEFAULT);
- } else {
- ui->world()->log().warn(
- fmt("Unknown value format %1% from LV2 UI\n")
- % format % ui->block()->plugin()->uri().c_str());
- }
-}
-
-static uint32_t
-lv2_ui_port_index(SuilController controller, const char* port_symbol)
-{
- PluginUI* const ui = (PluginUI*)controller;
-
- const BlockModel::Ports& ports = ui->block()->ports();
- for (uint32_t i = 0; i < ports.size(); ++i) {
- if (ports[i]->symbol() == port_symbol) {
- return i;
- }
- }
- return LV2UI_INVALID_PORT_INDEX;
-}
-
-static uint32_t
-lv2_ui_subscribe(SuilController controller,
- uint32_t port_index,
- uint32_t protocol,
- const LV2_Feature* const* features)
-{
- PluginUI* const ui = (PluginUI*)controller;
- SPtr<const PortModel> port = get_port(ui, port_index);
- if (!port) {
- return 1;
- }
-
- ui->signal_property_changed()(
- ui->block()->ports()[port_index]->uri(),
- ui->world()->uris().ingen_broadcast,
- ui->world()->forge().make(true),
- Resource::Graph::DEFAULT);
-
- return 0;
-}
-
-static uint32_t
-lv2_ui_unsubscribe(SuilController controller,
- uint32_t port_index,
- uint32_t protocol,
- const LV2_Feature* const* features)
-{
- PluginUI* const ui = (PluginUI*)controller;
- SPtr<const PortModel> port = get_port(ui, port_index);
- if (!port) {
- return 1;
- }
-
- ui->signal_property_changed()(
- ui->block()->ports()[port_index]->uri(),
- ui->world()->uris().ingen_broadcast,
- ui->world()->forge().make(false),
- Resource::Graph::DEFAULT);
-
- return 0;
-}
-
-PluginUI::PluginUI(Ingen::World* world,
- SPtr<const BlockModel> block,
- LilvUIs* uis,
- const LilvUI* ui,
- const LilvNode* ui_type)
- : _world(world)
- , _block(std::move(block))
- , _instance(nullptr)
- , _uis(uis)
- , _ui(ui)
- , _ui_node(lilv_node_duplicate(lilv_ui_get_uri(ui)))
- , _ui_type(lilv_node_duplicate(ui_type))
-{
-}
-
-PluginUI::~PluginUI()
-{
- for (uint32_t i : _subscribed_ports) {
- lv2_ui_unsubscribe(this, i, 0, nullptr);
- }
- suil_instance_free(_instance);
- lilv_node_free(_ui_node);
- lilv_node_free(_ui_type);
- lilv_uis_free(_uis);
- lilv_world_unload_resource(_world->lilv_world(), lilv_ui_get_uri(_ui));
-}
-
-SPtr<PluginUI>
-PluginUI::create(Ingen::World* world,
- SPtr<const BlockModel> block,
- const LilvPlugin* plugin)
-{
- if (!PluginUI::ui_host) {
- PluginUI::ui_host = suil_host_new(lv2_ui_write,
- lv2_ui_port_index,
- lv2_ui_subscribe,
- lv2_ui_unsubscribe);
- }
-
- static const char* gtk_ui_uri = LV2_UI__GtkUI;
-
- LilvNode* gtk_ui = lilv_new_uri(world->lilv_world(), gtk_ui_uri);
-
- LilvUIs* uis = lilv_plugin_get_uis(plugin);
- const LilvUI* ui = nullptr;
- const LilvNode* ui_type = nullptr;
- LILV_FOREACH(uis, u, uis) {
- const LilvUI* this_ui = lilv_uis_get(uis, u);
- if (lilv_ui_is_supported(this_ui,
- suil_ui_supported,
- gtk_ui,
- &ui_type)) {
- // TODO: Multiple UI support
- ui = this_ui;
- break;
- }
- }
-
- if (!ui) {
- lilv_node_free(gtk_ui);
- return SPtr<PluginUI>();
- }
-
- // Create the PluginUI, but don't instantiate yet
- SPtr<PluginUI> ret(new PluginUI(world, block, uis, ui, ui_type));
- ret->_features = world->lv2_features().lv2_features(
- world, const_cast<BlockModel*>(block.get()));
-
- return ret;
-}
-
-bool
-PluginUI::instantiate()
-{
- const URIs& uris = _world->uris();
- const std::string plugin_uri = _block->plugin()->uri();
- LilvWorld* lworld = _world->lilv_world();
-
- // Load seeAlso files to access data like portNotification descriptions
- lilv_world_load_resource(lworld, lilv_ui_get_uri(_ui));
-
- /* 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. */
- LilvNode* ui_portNotification = lilv_new_uri(lworld, LV2_UI__portNotification);
- LilvNode* ui_plugin = lilv_new_uri(lworld, LV2_UI__plugin);
- LilvNodes* notes = lilv_world_find_nodes(
- lworld, lilv_ui_get_uri(_ui), ui_portNotification, nullptr);
- LILV_FOREACH(nodes, n, notes) {
- const LilvNode* note = lilv_nodes_get(notes, n);
- const LilvNode* sym = lilv_world_get(lworld, note, uris.lv2_symbol, nullptr);
- const LilvNode* plug = lilv_world_get(lworld, note, ui_plugin, nullptr);
- if (!plug) {
- _world->log().error(fmt("%1% UI %2% notification missing plugin\n")
- % plugin_uri % lilv_node_as_string(_ui_node));
- } else if (!sym) {
- _world->log().error(fmt("%1% UI %2% notification missing symbol\n")
- % plugin_uri % lilv_node_as_string(_ui_node));
- } else if (!lilv_node_is_uri(plug)) {
- _world->log().error(fmt("%1% UI %2% notification has non-URI plugin\n")
- % plugin_uri % lilv_node_as_string(_ui_node));
- } else if (!strcmp(lilv_node_as_uri(plug), plugin_uri.c_str())) {
- // Notification is valid and for this plugin
- uint32_t index = lv2_ui_port_index(this, lilv_node_as_string(sym));
- if (index != LV2UI_INVALID_PORT_INDEX) {
- lv2_ui_subscribe(this, index, 0, nullptr);
- _subscribed_ports.insert(index);
- }
- }
- }
- lilv_nodes_free(notes);
- lilv_node_free(ui_plugin);
- lilv_node_free(ui_portNotification);
-
- const char* bundle_uri = lilv_node_as_uri(lilv_ui_get_bundle_uri(_ui));
- const char* binary_uri = lilv_node_as_uri(lilv_ui_get_binary_uri(_ui));
- char* bundle_path = lilv_file_uri_parse(bundle_uri, nullptr);
- char* binary_path = lilv_file_uri_parse(binary_uri, nullptr);
-
- // Instantiate the actual plugin UI via Suil
- _instance = suil_instance_new(
- PluginUI::ui_host,
- this,
- LV2_UI__GtkUI,
- plugin_uri.c_str(),
- lilv_node_as_uri(lilv_ui_get_uri(_ui)),
- lilv_node_as_uri(_ui_type),
- bundle_path,
- binary_path,
- _features->array());
-
- lilv_free(binary_path);
- lilv_free(bundle_path);
-
- if (!_instance) {
- _world->log().error("Failed to instantiate LV2 UI\n");
- // Cancel any subscriptions
- for (uint32_t i : _subscribed_ports) {
- lv2_ui_unsubscribe(this, i, 0, nullptr);
- }
- return false;
- }
-
- return true;
-}
-
-SuilWidget
-PluginUI::get_widget()
-{
- return (SuilWidget*)suil_instance_get_widget(_instance);
-}
-
-void
-PluginUI::port_event(uint32_t port_index,
- uint32_t buffer_size,
- uint32_t format,
- const void* buffer)
-{
- if (_instance) {
- suil_instance_port_event(
- _instance, port_index, buffer_size, format, buffer);
- } else {
- _world->log().warn("LV2 UI port event with no instance\n");
- }
-}
-
-bool
-PluginUI::is_resizable() const
-{
- LilvWorld* w = _world->lilv_world();
- const LilvNode* s = _ui_node;
- LilvNode* p = lilv_new_uri(w, LV2_CORE__optionalFeature);
- LilvNode* fs = lilv_new_uri(w, LV2_UI__fixedSize);
- LilvNode* nrs = lilv_new_uri(w, LV2_UI__noUserResize);
-
- LilvNodes* fs_matches = lilv_world_find_nodes(w, s, p, fs);
- LilvNodes* nrs_matches = lilv_world_find_nodes(w, s, p, nrs);
-
- lilv_nodes_free(nrs_matches);
- lilv_nodes_free(fs_matches);
- lilv_node_free(nrs);
- lilv_node_free(fs);
- lilv_node_free(p);
-
- return !fs_matches && !nrs_matches;
-}
-
-} // namespace Client
-} // namespace Ingen
diff --git a/src/client/PortModel.cpp b/src/client/PortModel.cpp
deleted file mode 100644
index 5c9a8c77..00000000
--- a/src/client/PortModel.cpp
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- 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/client/BlockModel.hpp"
-#include "ingen/client/PortModel.hpp"
-
-namespace Ingen {
-namespace Client {
-
-void
-PortModel::on_property(const URI& uri, const Atom& value)
-{
- if (uri == _uris.ingen_activity) {
- // Don't store activity, it is transient
- signal_activity().emit(value);
- return;
- }
-
- ObjectModel::on_property(uri, value);
-
- if (uri == _uris.ingen_value) {
- signal_value_changed().emit(value);
- }
-}
-
-bool
-PortModel::supports(const URIs::Quark& value_type) const
-{
- return has_property(_uris.atom_supports, value_type);
-}
-
-bool
-PortModel::port_property(const URIs::Quark& uri) const
-{
- return has_property(_uris.lv2_portProperty, uri);
-}
-
-bool
-PortModel::is_uri() const
-{
- // FIXME: Resource::has_property doesn't work, URI != URID
- for (auto p : properties()) {
- if (p.second.type() == _uris.atom_URID &&
- static_cast<LV2_URID>(p.second.get<int32_t>()) == _uris.atom_URID) {
- return true;
- }
- }
- return false;
-}
-
-void
-PortModel::set(SPtr<ObjectModel> model)
-{
- ObjectModel::set(model);
-
- SPtr<PortModel> port = dynamic_ptr_cast<PortModel>(model);
- if (port) {
- _index = port->_index;
- _direction = port->_direction;
- _signal_value_changed.emit(get_property(_uris.ingen_value));
- }
-}
-
-} // namespace Client
-} // namespace Ingen
diff --git a/src/client/ingen_client.cpp b/src/client/ingen_client.cpp
deleted file mode 100644
index fe9d6605..00000000
--- a/src/client/ingen_client.cpp
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- 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/Module.hpp"
-#include "ingen/World.hpp"
-
-#include "ingen_config.h"
-
-struct IngenClientModule : public Ingen::Module {
- void load(Ingen::World* world) {}
-};
-
-extern "C" {
-
-Ingen::Module*
-ingen_module_load()
-{
- return new IngenClientModule();
-}
-
-} // extern "C"
diff --git a/src/client/wscript b/src/client/wscript
deleted file mode 100644
index df575c0d..00000000
--- a/src/client/wscript
+++ /dev/null
@@ -1,23 +0,0 @@
-#!/usr/bin/env python
-from waflib.extras import autowaf as autowaf
-
-def build(bld):
- obj = bld(features = 'cxx cxxshlib',
- includes = ['../..'],
- export_includes = ['../..'],
- name = 'libingen_client',
- target = 'ingen_client',
- install_path = '${LIBDIR}',
- use = 'libingen')
- autowaf.use_lib(bld, obj, 'GLIBMM LV2 LILV SUIL RAUL SERD SORD SIGCPP')
-
- obj.source = '''
- BlockModel.cpp
- ClientStore.cpp
- GraphModel.cpp
- ObjectModel.cpp
- PluginModel.cpp
- PluginUI.cpp
- PortModel.cpp
- ingen_client.cpp
- '''
diff --git a/src/gui/App.cpp b/src/gui/App.cpp
deleted file mode 100644
index 9f1a29ca..00000000
--- a/src/gui/App.cpp
+++ /dev/null
@@ -1,499 +0,0 @@
-/*
- 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/>.
-*/
-
-#include <cassert>
-#include <fstream>
-#include <string>
-#include <utility>
-
-#include <boost/variant/get.hpp>
-#include <gtk/gtkwindow.h>
-#include <gtkmm/stock.h>
-
-#include "ganv/Edge.hpp"
-#include "ingen/Configuration.hpp"
-#include "ingen/EngineBase.hpp"
-#include "ingen/Interface.hpp"
-#include "ingen/Log.hpp"
-#include "ingen/QueuedInterface.hpp"
-#include "ingen/StreamWriter.hpp"
-#include "ingen/World.hpp"
-#include "ingen/client/ClientStore.hpp"
-#include "ingen/client/GraphModel.hpp"
-#include "ingen/client/ObjectModel.hpp"
-#include "ingen/client/SigClientInterface.hpp"
-#include "ingen/runtime_paths.hpp"
-#include "lilv/lilv.h"
-#include "raul/Path.hpp"
-#include "suil/suil.h"
-
-#include "App.hpp"
-#include "ConnectWindow.hpp"
-#include "GraphTreeWindow.hpp"
-#include "GraphWindow.hpp"
-#include "LoadPluginWindow.hpp"
-#include "MessagesWindow.hpp"
-#include "NodeModule.hpp"
-#include "Port.hpp"
-#include "RDFS.hpp"
-#include "Style.hpp"
-#include "SubgraphModule.hpp"
-#include "ThreadedLoader.hpp"
-#include "WidgetFactory.hpp"
-#include "WindowFactory.hpp"
-#include "rgba.hpp"
-
-namespace Raul { class Deletable; }
-
-namespace Ingen {
-
-namespace Client { class PluginModel; }
-
-using namespace Client;
-
-namespace GUI {
-
-class Port;
-
-Gtk::Main* App::_main = nullptr;
-
-App::App(Ingen::World* world)
- : _style(new Style(*this))
- , _about_dialog(nullptr)
- , _window_factory(new WindowFactory(*this))
- , _world(world)
- , _sample_rate(48000)
- , _block_length(1024)
- , _n_threads(1)
- , _mean_run_load(0.0f)
- , _min_run_load(0.0f)
- , _max_run_load(0.0f)
- , _enable_signal(true)
- , _requested_plugins(false)
- , _is_plugin(false)
-{
- _world->conf().load_default("ingen", "gui.ttl");
-
- WidgetFactory::get_widget_derived("connect_win", _connect_window);
- WidgetFactory::get_widget_derived("messages_win", _messages_window);
- WidgetFactory::get_widget_derived("graph_tree_win", _graph_tree_window);
- WidgetFactory::get_widget("about_win", _about_dialog);
- _connect_window->init_dialog(*this);
- _messages_window->init_window(*this);
- _graph_tree_window->init_window(*this);
- _about_dialog->property_program_name() = "Ingen";
- _about_dialog->property_logo_icon_name() = "ingen";
-
- PluginModel::set_rdf_world(*world->rdf_world());
- PluginModel::set_lilv_world(world->lilv_world());
-
- using namespace std::placeholders;
- world->log().set_sink(std::bind(&MessagesWindow::log, _messages_window, _1, _2, _3));
-}
-
-App::~App()
-{
- delete _style;
- delete _window_factory;
-}
-
-SPtr<App>
-App::create(Ingen::World* world)
-{
- suil_init(&world->argc(), &world->argv(), SUIL_ARG_NONE);
-
- // Add RC file for embedded GUI Gtk style
- const std::string rc_path = Ingen::data_file_path("ingen_style.rc");
- Gtk::RC::add_default_file(rc_path);
-
- _main = Gtk::Main::instance();
- if (!_main) {
- Glib::set_application_name("Ingen");
- gtk_window_set_default_icon_name("ingen");
- _main = new Gtk::Main(&world->argc(), &world->argv());
- }
-
- App* app = new App(world);
-
- // Load configuration settings
- app->style()->load_settings();
- app->style()->apply_settings();
-
- // Set default window icon
- app->_about_dialog->property_program_name() = "Ingen";
- app->_about_dialog->property_logo_icon_name() = "ingen";
- gtk_window_set_default_icon_name("ingen");
-
- return SPtr<App>(app);
-}
-
-void
-App::run()
-{
- _connect_window->start(*this, world());
-
- // Run main iterations here until we're attached to the engine. Otherwise
- // with 'ingen -egl' we'd get a bunch of notifications about load
- // immediately before even knowing about the root graph or plugins)
- while (!_connect_window->attached()) {
- if (_main->iteration()) {
- break;
- }
- }
-
- _main->run();
-}
-
-void
-App::attach(SPtr<Ingen::Interface> client)
-{
- assert(!_client);
- assert(!_store);
- assert(!_loader);
-
- if (_world->engine()) {
- _world->engine()->register_client(client);
- }
-
- _client = client;
- _store = SPtr<ClientStore>(new ClientStore(_world->uris(), _world->log(), sig_client()));
- _loader = SPtr<ThreadedLoader>(new ThreadedLoader(*this, _world->interface()));
- if (!_world->store()) {
- _world->set_store(_store);
- }
-
- if (_world->conf().option("dump").get<int32_t>()) {
- _dumper = SPtr<StreamWriter>(new StreamWriter(_world->uri_map(),
- _world->uris(),
- URI("ingen:/client"),
- stderr,
- ColorContext::Color::CYAN));
-
- sig_client()->signal_message().connect(
- sigc::mem_fun(*_dumper.get(), &StreamWriter::message));
- }
-
- _graph_tree_window->init(*this, *_store);
- sig_client()->signal_message().connect(sigc::mem_fun(this, &App::message));
-}
-
-void
-App::detach()
-{
- if (_world->interface()) {
- _window_factory->clear();
- _store->clear();
-
- _loader.reset();
- _store.reset();
- _client.reset();
- _world->set_interface(SPtr<Interface>());
- }
-}
-
-void
-App::request_plugins_if_necessary()
-{
- if (!_requested_plugins) {
- _world->interface()->get(URI("ingen:/plugins"));
- _requested_plugins = true;
- }
-}
-
-SPtr<SigClientInterface>
-App::sig_client()
-{
- SPtr<QueuedInterface> qi = dynamic_ptr_cast<QueuedInterface>(_client);
- if (qi) {
- return dynamic_ptr_cast<SigClientInterface>(qi->sink());
- }
- return dynamic_ptr_cast<SigClientInterface>(_client);
-}
-
-SPtr<Serialiser>
-App::serialiser()
-{
- return _world->serialiser();
-}
-
-void
-App::message(const Message& msg)
-{
- if (const Response* const r = boost::get<Response>(&msg)) {
- response(r->id, r->status, r->subject);
- } else if (const Error* const e = boost::get<Error>(&msg)) {
- error_message(e->message);
- } else if (const Put* const p = boost::get<Put>(&msg)) {
- put(p->uri, p->properties, p->ctx);
- } else if (const SetProperty* const s = boost::get<SetProperty>(&msg)) {
- property_change(s->subject, s->predicate, s->value, s->ctx);
- }
-}
-
-void
-App::response(int32_t id, Status status, const std::string& subject)
-{
- if (status != Status::SUCCESS) {
- std::string msg = ingen_status_string(status);
- if (!subject.empty()) {
- msg += ": " + subject;
- }
- error_message(msg);
- }
-}
-
-void
-App::error_message(const std::string& str)
-{
- _messages_window->post_error(str);
-}
-
-void
-App::set_property(const URI& subject,
- const URI& key,
- const Atom& value,
- Resource::Graph ctx)
-{
- // Send message to server
- interface()->set_property(subject, key, value, ctx);
-
- /* The server does not feed back set messages (kludge to prevent control
- feedback and bandwidth wastage, see Delta.cpp). So, assume everything
- went as planned here and fire the signal ourselves as if the server
- feedback came back immediately. */
- if (key != uris().ingen_activity) {
- sig_client()->signal_message().emit(SetProperty{0, subject, key, value, ctx});
- }
-}
-
-void
-App::set_tooltip(Gtk::Widget* widget, const LilvNode* node)
-{
- const std::string comment = RDFS::comment(_world, node);
- if (!comment.empty()) {
- widget->set_tooltip_text(comment);
- }
-}
-
-void
-App::put(const URI& uri,
- const Properties& properties,
- Resource::Graph ctx)
-{
- _enable_signal = false;
- for (const auto& p : properties) {
- property_change(uri, p.first, p.second);
- }
- _enable_signal = true;
- _status_text = status_text();
- signal_status_text_changed.emit(_status_text);
-}
-
-void
-App::property_change(const URI& subject,
- const URI& key,
- const Atom& value,
- Resource::Graph ctx)
-{
- if (subject != URI("ingen:/engine")) {
- return;
- } else if (key == uris().param_sampleRate && value.type() == forge().Int) {
- _sample_rate = value.get<int32_t>();
- } else if (key == uris().bufsz_maxBlockLength && value.type() == forge().Int) {
- _block_length = value.get<int32_t>();
- } else if (key == uris().ingen_numThreads && value.type() == forge().Int) {
- _n_threads = value.get<int>();
- } else if (key == uris().ingen_minRunLoad && value.type() == forge().Float) {
- _min_run_load = value.get<float>();
- } else if (key == uris().ingen_meanRunLoad && value.type() == forge().Float) {
- _mean_run_load = value.get<float>();
- } else if (key == uris().ingen_maxRunLoad && value.type() == forge().Float) {
- _max_run_load = value.get<float>();
- } else {
- _world->log().warn(fmt("Unknown engine property %1%\n") % key);
- return;
- }
-
- if (_enable_signal) {
- _status_text = status_text();
- signal_status_text_changed.emit(_status_text);
- }
-}
-
-static std::string
-fraction_label(float f)
-{
- static const uint32_t GREEN = 0x4A8A0EFF;
- static const uint32_t RED = 0x960909FF;
-
- const uint32_t col = rgba_interpolate(GREEN, RED, std::min(f, 1.0f));
- char col_str[8];
- snprintf(col_str, sizeof(col_str), "%02X%02X%02X",
- RGBA_R(col), RGBA_G(col), RGBA_B(col));
- return (fmt("<span color='#%s'>%d%%</span>") % col_str % (f * 100)).str();
-}
-
-std::string
-App::status_text() const
-{
- return (fmt("%2.1f kHz / %.1f ms, %s, %s DSP")
- % (_sample_rate / 1e3f)
- % (_block_length * 1e3f / (float)_sample_rate)
- % ((_n_threads == 1)
- ? "1 thread"
- : (fmt("%1% threads") % _n_threads).str())
- % fraction_label(_max_run_load)).str();
-}
-
-void
-App::port_activity(Port* port)
-{
- std::pair<ActivityPorts::iterator, bool> inserted = _activity_ports.emplace(port, false);
- if (inserted.second) {
- inserted.first->second = false;
- }
-
- port->set_highlighted(true);
-}
-
-void
-App::activity_port_destroyed(Port* port)
-{
- auto i = _activity_ports.find(port);
- if (i != _activity_ports.end()) {
- _activity_ports.erase(i);
- }
-}
-
-bool
-App::animate()
-{
- for (auto i = _activity_ports.begin(); i != _activity_ports.end(); ) {
- auto next = i;
- ++next;
-
- if ((*i).second) { // saw it last time, unhighlight and pop
- (*i).first->set_highlighted(false);
- _activity_ports.erase(i);
- } else {
- (*i).second = true;
- }
-
- i = next;
- }
-
- return true;
-}
-
-/******** Event Handlers ************/
-
-void
-App::register_callbacks()
-{
- Glib::signal_timeout().connect(
- sigc::mem_fun(*this, &App::gtk_main_iteration), 33, G_PRIORITY_DEFAULT);
-}
-
-bool
-App::gtk_main_iteration()
-{
- if (!_client) {
- return false;
- }
-
- animate();
-
- if (_messages_window) {
- _messages_window->flush();
- }
-
- _enable_signal = false;
- if (_world->engine()) {
- if (!_world->engine()->main_iteration()) {
- Gtk::Main::quit();
- return false;
- }
- } else {
- dynamic_ptr_cast<QueuedInterface>(_client)->emit();
- }
- _enable_signal = true;
-
- return true;
-}
-
-void
-App::show_about()
-{
- _about_dialog->run();
- _about_dialog->hide();
-}
-
-/** Prompt (if necessary) and quit application (if confirmed).
- * @return true iff the application quit.
- */
-bool
-App::quit(Gtk::Window* dialog_parent)
-{
- bool quit = true;
- if (_world->engine() && _connect_window->attached()) {
- Gtk::MessageDialog d(
- "The engine is running in this process. Quitting will terminate Ingen."
- "\n\n" "Are you sure you want to quit?",
- true, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_NONE, true);
- if (dialog_parent) {
- d.set_transient_for(*dialog_parent);
- }
- d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
- d.add_button(Gtk::Stock::QUIT, Gtk::RESPONSE_CLOSE);
- quit = (d.run() == Gtk::RESPONSE_CLOSE);
- }
-
- if (!quit) {
- return false;
- }
-
- Gtk::Main::quit();
-
- try {
- const std::string path = _world->conf().save(
- _world->uri_map(), "ingen", "gui.ttl", Configuration::GUI);
- std::cout << (fmt("Saved GUI settings to %1%\n") % path);
- } catch (const std::exception& e) {
- std::cerr << (fmt("Error saving GUI settings (%1%)\n")
- % e.what());
- }
-
- return true;
-}
-
-bool
-App::can_control(const Client::PortModel* port) const
-{
- return port->is_a(uris().lv2_ControlPort)
- || port->is_a(uris().lv2_CVPort)
- || (port->is_a(uris().atom_AtomPort)
- && (port->supports(uris().atom_Float)
- || port->supports(uris().atom_String)));
-}
-
-uint32_t
-App::sample_rate() const
-{
- return _sample_rate;
-}
-
-} // namespace GUI
-} // namespace Ingen
diff --git a/src/gui/App.hpp b/src/gui/App.hpp
deleted file mode 100644
index 75661449..00000000
--- a/src/gui/App.hpp
+++ /dev/null
@@ -1,196 +0,0 @@
-/*
- 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_GUI_APP_HPP
-#define INGEN_GUI_APP_HPP
-
-#include <unordered_map>
-#include <string>
-
-#include <gtkmm/aboutdialog.h>
-#include <gtkmm/main.h>
-#include <gtkmm/window.h>
-
-#include "ingen/Atom.hpp"
-#include "ingen/Message.hpp"
-#include "ingen/Resource.hpp"
-#include "ingen/Status.hpp"
-#include "ingen/World.hpp"
-#include "ingen/ingen.h"
-#include "ingen/types.hpp"
-#include "lilv/lilv.h"
-#include "raul/Deletable.hpp"
-
-namespace Ingen {
-
-class Interface;
-class Log;
-class Port;
-class Serialiser;
-class StreamWriter;
-class World;
-
-namespace Client {
-
-class ClientStore;
-class GraphModel;
-class PluginModel;
-class PortModel;
-class SigClientInterface;
-
-}
-
-namespace GUI {
-
-class ConnectWindow;
-class GraphCanvas;
-class GraphTreeView;
-class GraphTreeWindow;
-class MessagesWindow;
-class Port;
-class Style;
-class ThreadedLoader;
-class WindowFactory;
-
-/** Ingen Gtk Application.
- * \ingroup GUI
- */
-class INGEN_API App
-{
-public:
- ~App();
-
- void error_message(const std::string& str);
-
- void attach(SPtr<Ingen::Interface> client);
-
- void detach();
-
- void request_plugins_if_necessary();
-
- void register_callbacks();
- bool gtk_main_iteration();
-
- void show_about();
- bool quit(Gtk::Window* dialog_parent);
-
- void port_activity(Port* port);
- void activity_port_destroyed(Port* port);
- bool can_control(const Client::PortModel* port) const;
-
- bool signal() const { return _enable_signal; }
- void enable_signals(bool b) { _enable_signal = b; }
- bool disable_signals() {
- bool old = _enable_signal;
- _enable_signal = false;
- return old;
- }
-
- void set_property(const URI& subject,
- const URI& key,
- const Atom& value,
- Resource::Graph ctx = Resource::Graph::DEFAULT);
-
- /** Set the tooltip for a widget from its RDF documentation. */
- void set_tooltip(Gtk::Widget* widget, const LilvNode* node);
-
- uint32_t sample_rate() const;
-
- bool is_plugin() const { return _is_plugin; }
- void set_is_plugin(bool b) { _is_plugin = b; }
-
- ConnectWindow* connect_window() const { return _connect_window; }
- MessagesWindow* messages_dialog() const { return _messages_window; }
- GraphTreeWindow* graph_tree() const { return _graph_tree_window; }
- Style* style() const { return _style; }
- WindowFactory* window_factory() const { return _window_factory; }
-
- Ingen::Forge& forge() const { return _world->forge(); }
- SPtr<Ingen::Interface> interface() const { return _world->interface(); }
- SPtr<Ingen::Interface> client() const { return _client; }
- SPtr<Client::ClientStore> store() const { return _store; }
- SPtr<ThreadedLoader> loader() const { return _loader; }
-
- SPtr<Client::SigClientInterface> sig_client();
-
- SPtr<Serialiser> serialiser();
-
- static SPtr<App> create(Ingen::World* world);
-
- void run();
-
- std::string status_text() const;
-
- sigc::signal<void, const std::string&> signal_status_text_changed;
-
- inline Ingen::World* world() const { return _world; }
- inline Ingen::URIs& uris() const { return _world->uris(); }
- inline Ingen::Log& log() const { return _world->log(); }
-
-protected:
- explicit App(Ingen::World* world);
-
- void message(const Ingen::Message& msg);
-
- bool animate();
- void response(int32_t id, Ingen::Status status, const std::string& subject);
-
- void put(const URI& uri,
- const Properties& properties,
- Resource::Graph ctx);
-
- void property_change(const URI& subject,
- const URI& key,
- const Atom& value,
- Resource::Graph ctx = Resource::Graph::DEFAULT);
-
- static Gtk::Main* _main;
-
- SPtr<Ingen::Interface> _client;
- SPtr<Client::ClientStore> _store;
- SPtr<ThreadedLoader> _loader;
- SPtr<StreamWriter> _dumper;
-
- Style* _style;
-
- ConnectWindow* _connect_window;
- MessagesWindow* _messages_window;
- GraphTreeWindow* _graph_tree_window;
- Gtk::AboutDialog* _about_dialog;
- WindowFactory* _window_factory;
-
- Ingen::World* _world;
-
- int32_t _sample_rate;
- int32_t _block_length;
- int32_t _n_threads;
- float _mean_run_load;
- float _min_run_load;
- float _max_run_load;
- std::string _status_text;
-
- typedef std::unordered_map<Port*, bool> ActivityPorts;
- ActivityPorts _activity_ports;
-
- bool _enable_signal;
- bool _requested_plugins;
- bool _is_plugin;
-};
-
-} // namespace GUI
-} // namespace Ingen
-
-#endif // INGEN_GUI_APP_HPP
diff --git a/src/gui/Arc.cpp b/src/gui/Arc.cpp
deleted file mode 100644
index c14b2e88..00000000
--- a/src/gui/Arc.cpp
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- 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 "Arc.hpp"
-#include "ingen/client/ArcModel.hpp"
-#include "ingen/client/BlockModel.hpp"
-
-#define NS_INTERNALS "http://drobilla.net/ns/ingen-internals#"
-
-namespace Ingen {
-namespace GUI {
-
-Arc::Arc(Ganv::Canvas& canvas,
- SPtr<const Client::ArcModel> model,
- Ganv::Node* src,
- Ganv::Node* dst)
- : Ganv::Edge(canvas, src, dst)
- , _arc_model(model)
-{
- SPtr<const Client::ObjectModel> tparent = model->tail()->parent();
- SPtr<const Client::BlockModel> tparent_block;
- if ((tparent_block = dynamic_ptr_cast<const Client::BlockModel>(tparent))) {
- if (tparent_block->plugin_uri() == NS_INTERNALS "BlockDelay") {
- g_object_set(_gobj, "dash-length", 4.0, NULL);
- set_constraining(false);
- }
- }
-}
-
-} // namespace GUI
-} // namespace Ingen
diff --git a/src/gui/Arc.hpp b/src/gui/Arc.hpp
deleted file mode 100644
index 382ca305..00000000
--- a/src/gui/Arc.hpp
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- 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_GUI_ARC_HPP
-#define INGEN_GUI_ARC_HPP
-
-#include <cassert>
-
-#include "ganv/Edge.hpp"
-#include "ingen/types.hpp"
-
-namespace Ingen {
-
-namespace Client { class ArcModel; }
-
-namespace GUI {
-
-/** An Arc (directed edge) in a Graph.
- *
- * \ingroup GUI
- */
-class Arc : public Ganv::Edge
-{
-public:
- Arc(Ganv::Canvas& canvas,
- SPtr<const Client::ArcModel> model,
- Ganv::Node* src,
- Ganv::Node* dst);
-
- SPtr<const Client::ArcModel> model() const { return _arc_model; }
-
-private:
- SPtr<const Client::ArcModel> _arc_model;
-};
-
-} // namespace GUI
-} // namespace Ingen
-
-#endif // INGEN_GUI_ARC_HPP
diff --git a/src/gui/BreadCrumbs.cpp b/src/gui/BreadCrumbs.cpp
deleted file mode 100644
index ae7882e3..00000000
--- a/src/gui/BreadCrumbs.cpp
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
- 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 <list>
-#include <string>
-
-#include <boost/variant/get.hpp>
-
-#include "ingen/client/SigClientInterface.hpp"
-
-#include "App.hpp"
-#include "BreadCrumbs.hpp"
-
-namespace Ingen {
-namespace GUI {
-
-using std::string;
-
-BreadCrumbs::BreadCrumbs(App& app)
- : Gtk::HBox()
- , _active_path("/")
- , _full_path("/")
- , _enable_signal(true)
-{
- app.sig_client()->signal_message().connect(
- sigc::mem_fun(this, &BreadCrumbs::message));
-
- set_can_focus(false);
-}
-
-SPtr<GraphView>
-BreadCrumbs::view(const Raul::Path& path)
-{
- for (const auto& b : _breadcrumbs) {
- if (b->path() == path) {
- return b->view();
- }
- }
-
- return SPtr<GraphView>();
-}
-
-/** Sets up the crumbs to display `path`.
- *
- * If `path` is already part of the shown path, it will be selected and the
- * children preserved.
- */
-void
-BreadCrumbs::build(Raul::Path path, SPtr<GraphView> view)
-{
- bool old_enable_signal = _enable_signal;
- _enable_signal = false;
-
- if (!_breadcrumbs.empty() && (path.is_parent_of(_full_path) || path == _full_path)) {
- // Moving to a path we already contain, just switch the active button
- for (const auto& b : _breadcrumbs) {
- if (b->path() == path) {
- b->set_active(true);
- if (!b->view()) {
- b->set_view(view);
- }
-
- // views are expensive, having two around for the same graph is a bug
- assert(b->view() == view);
-
- } else {
- b->set_active(false);
- }
- }
-
- _active_path = path;
- _enable_signal = old_enable_signal;
-
- } else if (!_breadcrumbs.empty() && path.is_child_of(_full_path)) {
- // Moving to a child of the full path, just append crumbs (preserve view cache)
-
- string suffix = path.substr(_full_path.length());
- while (suffix.length() > 0) {
- if (suffix[0] == '/') {
- suffix = suffix.substr(1);
- }
- const string name = suffix.substr(0, suffix.find("/"));
- _full_path = _full_path.child(Raul::Symbol(name));
- BreadCrumb* but = create_crumb(_full_path, view);
- pack_start(*but, false, false, 1);
- _breadcrumbs.push_back(but);
- but->show();
- if (suffix.find("/") == string::npos) {
- break;
- } else {
- suffix = suffix.substr(suffix.find("/")+1);
- }
- }
-
- for (const auto& b : _breadcrumbs) {
- b->set_active(false);
- }
- _breadcrumbs.back()->set_active(true);
-
- } else {
- // Rebuild from scratch
- // Getting here is bad unless absolutely necessary, since the GraphView cache is lost
-
- _full_path = path;
- _active_path = path;
-
- // Empty existing breadcrumbs
- for (const auto& b : _breadcrumbs) {
- remove(*b);
- }
- _breadcrumbs.clear();
-
- // Add root
- BreadCrumb* root_but = create_crumb(Raul::Path("/"), view);
- pack_start(*root_but, false, false, 1);
- _breadcrumbs.push_front(root_but);
- root_but->set_active(root_but->path() == _active_path);
-
- Raul::Path working_path("/");
- string suffix = path.substr(1);
- while (suffix.length() > 0) {
- if (suffix[0] == '/') {
- suffix = suffix.substr(1);
- }
- const string name = suffix.substr(0, suffix.find("/"));
- working_path = working_path.child(Raul::Symbol(name));
- BreadCrumb* but = create_crumb(working_path, view);
- pack_start(*but, false, false, 1);
- _breadcrumbs.push_back(but);
- but->set_active(working_path == _active_path);
- but->show();
- if (suffix.find("/") == string::npos) {
- break;
- } else {
- suffix = suffix.substr(suffix.find("/")+1);
- }
- }
- }
-
- _enable_signal = old_enable_signal;
-}
-
-/** Create a new crumb, assigning it a reference to `view` if their paths
- * match, otherwise ignoring `view`.
- */
-BreadCrumbs::BreadCrumb*
-BreadCrumbs::create_crumb(const Raul::Path& path,
- SPtr<GraphView> view)
-{
- BreadCrumb* but = manage(
- new BreadCrumb(path,
- ((view && path == view->graph()->path())
- ? view : SPtr<GraphView>())));
-
- but->signal_toggled().connect(
- sigc::bind(sigc::mem_fun(this, &BreadCrumbs::breadcrumb_clicked),
- but));
-
- return but;
-}
-
-void
-BreadCrumbs::breadcrumb_clicked(BreadCrumb* crumb)
-{
- if (_enable_signal) {
- _enable_signal = false;
-
- if (!crumb->get_active()) {
- // Tried to turn off the current active button, bad user, no cookie
- crumb->set_active(true);
- } else {
- signal_graph_selected.emit(crumb->path(), crumb->view());
- if (crumb->path() != _active_path) {
- crumb->set_active(false);
- }
- }
- _enable_signal = true;
- }
-}
-
-void
-BreadCrumbs::message(const Message& msg)
-{
- if (const Del* const del = boost::get<Del>(&msg)) {
- object_destroyed(del->uri);
- }
-}
-
-void
-BreadCrumbs::object_destroyed(const URI& uri)
-{
- for (auto i = _breadcrumbs.begin(); i != _breadcrumbs.end(); ++i) {
- if ((*i)->path() == uri.c_str()) {
- // Remove all crumbs after the removed one (inclusive)
- for (auto j = i; j != _breadcrumbs.end(); ) {
- BreadCrumb* bc = *j;
- j = _breadcrumbs.erase(j);
- remove(*bc);
- }
- break;
- }
- }
-}
-
-void
-BreadCrumbs::object_moved(const Raul::Path& old_path, const Raul::Path& new_path)
-{
- for (const auto& b : _breadcrumbs) {
- if (b->path() == old_path) {
- b->set_path(new_path);
- }
- }
-}
-
-} // namespace GUI
-} // namespace Ingen
diff --git a/src/gui/BreadCrumbs.hpp b/src/gui/BreadCrumbs.hpp
deleted file mode 100644
index 467d3bfc..00000000
--- a/src/gui/BreadCrumbs.hpp
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- 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_GUI_BREADCRUMBS_HPP
-#define INGEN_GUI_BREADCRUMBS_HPP
-
-#include <list>
-
-#include <gtkmm/box.h>
-#include <gtkmm/label.h>
-#include <gtkmm/togglebutton.h>
-
-#include "raul/Path.hpp"
-
-#include "ingen/client/GraphModel.hpp"
-#include "ingen/types.hpp"
-
-#include "GraphView.hpp"
-
-namespace Ingen {
-namespace GUI {
-
-/** Collection of breadcrumb buttons forming a path.
- * This doubles as a cache for GraphViews.
- *
- * \ingroup GUI
- */
-class BreadCrumbs : public Gtk::HBox
-{
-public:
- explicit BreadCrumbs(App& app);
-
- SPtr<GraphView> view(const Raul::Path& path);
-
- void build(Raul::Path path, SPtr<GraphView> view);
-
- sigc::signal<void, const Raul::Path&, SPtr<GraphView> > signal_graph_selected;
-
-private:
- /** Breadcrumb button.
- *
- * Each Breadcrumb stores a reference to a GraphView for quick switching.
- * So, the amount of allocated GraphViews at a given time is equal to the
- * number of visible breadcrumbs (which is the perfect cache for GUI
- * responsiveness balanced with mem consumption).
- *
- * \ingroup GUI
- */
- class BreadCrumb : public Gtk::ToggleButton
- {
- public:
- BreadCrumb(const Raul::Path& path, SPtr<GraphView> view = SPtr<GraphView>())
- : _path(path)
- , _view(view)
- {
- assert(!view || view->graph()->path() == path);
- set_border_width(0);
- set_path(path);
- set_can_focus(false);
- show_all();
- }
-
- void set_view(SPtr<GraphView> view) {
- assert(!view || view->graph()->path() == _path);
- _view = view;
- }
-
- const Raul::Path& path() const { return _path; }
- SPtr<GraphView> view() const { return _view; }
-
- void set_path(const Raul::Path& path) {
- remove();
- const char* text = (path.is_root()) ? "/" : path.symbol();
- Gtk::Label* lab = manage(new Gtk::Label(text));
- lab->set_padding(0, 0);
- lab->show();
- add(*lab);
-
- if (_view && _view->graph()->path() != path)
- _view.reset();
- }
-
- private:
- Raul::Path _path;
- SPtr<GraphView> _view;
- };
-
- BreadCrumb* create_crumb(const Raul::Path& path,
- SPtr<GraphView> view = SPtr<GraphView>());
-
- void breadcrumb_clicked(BreadCrumb* crumb);
-
- void message(const Message& msg);
- void object_destroyed(const URI& uri);
- void object_moved(const Raul::Path& old_path, const Raul::Path& new_path);
-
- Raul::Path _active_path;
- Raul::Path _full_path;
- bool _enable_signal;
- std::list<BreadCrumb*> _breadcrumbs;
-};
-
-} // namespace GUI
-} // namespace Ingen
-
-#endif // INGEN_GUI_BREADCRUMBS_HPP
diff --git a/src/gui/ConnectWindow.cpp b/src/gui/ConnectWindow.cpp
deleted file mode 100644
index 458a43dd..00000000
--- a/src/gui/ConnectWindow.cpp
+++ /dev/null
@@ -1,572 +0,0 @@
-/*
- 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 <cstdlib>
-#include <limits>
-#include <sstream>
-#include <string>
-
-#include <boost/variant/get.hpp>
-#include <gtkmm/stock.h>
-
-#include "raul/Process.hpp"
-
-#include "ingen/Configuration.hpp"
-#include "ingen/EngineBase.hpp"
-#include "ingen/Interface.hpp"
-#include "ingen/Log.hpp"
-#include "ingen/Module.hpp"
-#include "ingen/QueuedInterface.hpp"
-#include "ingen/World.hpp"
-#include "ingen/client/ClientStore.hpp"
-#include "ingen/client/GraphModel.hpp"
-#include "ingen/client/SigClientInterface.hpp"
-#include "ingen/client/SocketClient.hpp"
-#include "ingen_config.h"
-
-#include "App.hpp"
-#include "ConnectWindow.hpp"
-#include "WindowFactory.hpp"
-
-using namespace Ingen::Client;
-
-namespace Ingen {
-namespace GUI {
-
-ConnectWindow::ConnectWindow(BaseObjectType* cobject,
- Glib::RefPtr<Gtk::Builder> xml)
- : Dialog(cobject)
- , _xml(std::move(xml))
- , _icon(nullptr)
- , _progress_bar(nullptr)
- , _progress_label(nullptr)
- , _url_entry(nullptr)
- , _server_radio(nullptr)
- , _port_spinbutton(nullptr)
- , _launch_radio(nullptr)
- , _internal_radio(nullptr)
- , _activate_button(nullptr)
- , _deactivate_button(nullptr)
- , _disconnect_button(nullptr)
- , _connect_button(nullptr)
- , _quit_button(nullptr)
- , _mode(Mode::CONNECT_REMOTE)
- , _connect_uri("unix:///tmp/ingen.sock")
- , _ping_id(-1)
- , _attached(false)
- , _finished_connecting(false)
- , _widgets_loaded(false)
- , _connect_stage(0)
- , _quit_flag(false)
-{
-}
-
-void
-ConnectWindow::message(const Message& msg)
-{
- if (const Response* const r = boost::get<Response>(&msg)) {
- ingen_response(r->id, r->status, r->subject);
- } else if (const Error* const e = boost::get<Error>(&msg)) {
- error(e->message);
- }
-}
-
-void
-ConnectWindow::error(const std::string& msg)
-{
- if (!is_visible()) {
- present();
- set_connecting_widget_states();
- }
-
- if (_progress_label) {
- _progress_label->set_text(msg);
- }
-
- if (_app && _app->world()) {
- _app->world()->log().error(msg + "\n");
- }
-}
-
-void
-ConnectWindow::start(App& app, Ingen::World* world)
-{
- _app = &app;
-
- if (world->engine()) {
- _mode = Mode::INTERNAL;
- }
-
- set_connected_to(world->interface());
- connect(bool(world->interface()));
-}
-
-void
-ConnectWindow::ingen_response(int32_t id,
- Status status,
- const std::string& subject)
-{
- if (id == _ping_id) {
- if (status != Status::SUCCESS) {
- error("Failed to get root patch");
- } else {
- _attached = true;
- }
- }
-}
-
-void
-ConnectWindow::set_connected_to(SPtr<Ingen::Interface> engine)
-{
- _app->world()->set_interface(engine);
-
- if (!_widgets_loaded) {
- return;
- }
-
- if (engine) {
- _icon->set(Gtk::Stock::CONNECT, Gtk::ICON_SIZE_LARGE_TOOLBAR);
- _progress_bar->set_fraction(1.0);
- _progress_label->set_text("Connected to engine");
- _url_entry->set_sensitive(false);
- _url_entry->set_text(engine->uri().string());
- _connect_button->set_sensitive(false);
- _disconnect_button->set_label("gtk-disconnect");
- _disconnect_button->set_sensitive(true);
- _port_spinbutton->set_sensitive(false);
- _launch_radio->set_sensitive(false);
- _internal_radio->set_sensitive(false);
- _activate_button->set_sensitive(true);
- _deactivate_button->set_sensitive(true);
-
- } else {
- _icon->set(Gtk::Stock::DISCONNECT, Gtk::ICON_SIZE_LARGE_TOOLBAR);
- _progress_bar->set_fraction(0.0);
- _connect_button->set_sensitive(true);
- _disconnect_button->set_sensitive(false);
- _internal_radio->set_sensitive(true);
- _server_radio->set_sensitive(true);
- _launch_radio->set_sensitive(true);
- _activate_button->set_sensitive(false);
- _deactivate_button->set_sensitive(false);
-
- if (_mode == Mode::CONNECT_REMOTE) {
- _url_entry->set_sensitive(true);
- } else if (_mode == Mode::LAUNCH_REMOTE) {
- _port_spinbutton->set_sensitive(true);
- }
-
- _progress_label->set_text(std::string("Disconnected"));
- }
-}
-
-void
-ConnectWindow::set_connecting_widget_states()
-{
- if (!_widgets_loaded) {
- return;
- }
-
- _connect_button->set_sensitive(false);
- _disconnect_button->set_label("gtk-cancel");
- _disconnect_button->set_sensitive(true);
- _server_radio->set_sensitive(false);
- _launch_radio->set_sensitive(false);
- _internal_radio->set_sensitive(false);
- _url_entry->set_sensitive(false);
- _port_spinbutton->set_sensitive(false);
-}
-
-bool
-ConnectWindow::connect_remote(const URI& uri)
-{
- Ingen::World* world = _app->world();
-
- SPtr<SigClientInterface> sci(new SigClientInterface());
- SPtr<QueuedInterface> qi(new QueuedInterface(sci));
-
- SPtr<Ingen::Interface> iface(world->new_interface(uri, qi));
- if (iface) {
- world->set_interface(iface);
- _app->attach(qi);
- _app->register_callbacks();
- return true;
- }
-
- return false;
-}
-
-/** Set up initial connect stage and launch connect callback. */
-void
-ConnectWindow::connect(bool existing)
-{
- if (_app->client()) {
- error("Already connected");
- return;
- } else if (_attached) {
- _attached = false;
- }
-
- set_connecting_widget_states();
- _connect_stage = 0;
-
- Ingen::World* world = _app->world();
-
- if (_mode == Mode::CONNECT_REMOTE) {
- std::string uri_str = world->conf().option("connect").ptr<char>();
- if (existing) {
- uri_str = world->interface()->uri();
- _connect_stage = 1;
- SPtr<Client::SocketClient> client = dynamic_ptr_cast<Client::SocketClient>(world->interface());
- if (client) {
- _app->attach(client->respondee());
- _app->register_callbacks();
- } else {
- error("Connected with invalid client interface type");
- return;
- }
- } else if (_widgets_loaded) {
- uri_str = _url_entry->get_text();
- }
-
- if (!URI::is_valid(uri_str)) {
- error((fmt("Invalid socket URI %1%") % uri_str).str());
- return;
- }
-
- _connect_uri = URI(uri_str);
-
- } else if (_mode == Mode::LAUNCH_REMOTE) {
- const std::string port = std::to_string(_port_spinbutton->get_value_as_int());
- const char* cmd[] = { "ingen", "-e", "-E", port.c_str(), nullptr };
-
- if (!Raul::Process::launch(cmd)) {
- error("Failed to launch engine process");
- return;
- }
-
- _connect_uri = URI(std::string("tcp://localhost:") + port);
-
- } else if (_mode == Mode::INTERNAL) {
- if (!world->engine()) {
- if (!world->load_module("server")) {
- error("Failed to load server module");
- return;
- } else if (!world->load_module("jack")) {
- error("Failed to load jack module");
- return;
- } else if (!world->engine()->activate()) {
- error("Failed to activate engine");
- return;
- }
- }
- }
-
- set_connecting_widget_states();
- if (_widgets_loaded) {
- _progress_label->set_text("Connecting...");
- }
- Glib::signal_timeout().connect(
- sigc::mem_fun(this, &ConnectWindow::gtk_callback), 33);
-}
-
-void
-ConnectWindow::disconnect()
-{
- _connect_stage = -1;
- _attached = false;
-
- _app->detach();
- set_connected_to(SPtr<Ingen::Interface>());
-
- if (!_widgets_loaded) {
- return;
- }
-
- _activate_button->set_sensitive(false);
- _deactivate_button->set_sensitive(false);
-
- _progress_bar->set_fraction(0.0);
- _connect_button->set_sensitive(true);
- _disconnect_button->set_sensitive(false);
-}
-
-void
-ConnectWindow::activate()
-{
- if (!_app->interface()) {
- return;
- }
-
- _app->interface()->set_property(URI("ingen:/driver"),
- _app->uris().ingen_enabled,
- _app->forge().make(true));
-}
-
-void
-ConnectWindow::deactivate()
-{
- if (!_app->interface()) {
- return;
- }
-
- _app->interface()->set_property(URI("ingen:/driver"),
- _app->uris().ingen_enabled,
- _app->forge().make(false));
-}
-
-void
-ConnectWindow::on_show()
-{
- if (!_widgets_loaded) {
- load_widgets();
- }
-
- if (_attached) {
- set_connected_to(_app->interface());
- }
-
- Gtk::Dialog::on_show();
-}
-
-void
-ConnectWindow::load_widgets()
-{
- _xml->get_widget("connect_icon", _icon);
- _xml->get_widget("connect_progress_bar", _progress_bar);
- _xml->get_widget("connect_progress_label", _progress_label);
- _xml->get_widget("connect_server_radiobutton", _server_radio);
- _xml->get_widget("connect_url_entry", _url_entry);
- _xml->get_widget("connect_launch_radiobutton", _launch_radio);
- _xml->get_widget("connect_port_spinbutton", _port_spinbutton);
- _xml->get_widget("connect_internal_radiobutton", _internal_radio);
- _xml->get_widget("connect_activate_button", _activate_button);
- _xml->get_widget("connect_deactivate_button", _deactivate_button);
- _xml->get_widget("connect_disconnect_button", _disconnect_button);
- _xml->get_widget("connect_connect_button", _connect_button);
- _xml->get_widget("connect_quit_button", _quit_button);
-
- _server_radio->signal_toggled().connect(
- sigc::mem_fun(this, &ConnectWindow::server_toggled));
- _launch_radio->signal_toggled().connect(
- sigc::mem_fun(this, &ConnectWindow::launch_toggled));
- _internal_radio->signal_clicked().connect(
- sigc::mem_fun(this, &ConnectWindow::internal_toggled));
- _activate_button->signal_clicked().connect(
- sigc::mem_fun(this, &ConnectWindow::activate));
- _deactivate_button->signal_clicked().connect(
- sigc::mem_fun(this, &ConnectWindow::deactivate));
- _disconnect_button->signal_clicked().connect(
- sigc::mem_fun(this, &ConnectWindow::disconnect));
- _connect_button->signal_clicked().connect(
- sigc::bind(sigc::mem_fun(this, &ConnectWindow::connect), false));
- _quit_button->signal_clicked().connect(
- sigc::mem_fun(this, &ConnectWindow::quit_clicked));
-
- _url_entry->set_text(_app->world()->conf().option("connect").ptr<char>());
- if (URI::is_valid(_url_entry->get_text())) {
- _connect_uri = URI(_url_entry->get_text());
- }
-
- _port_spinbutton->set_range(1, std::numeric_limits<uint16_t>::max());
- _port_spinbutton->set_increments(1, 100);
- _port_spinbutton->set_value(
- _app->world()->conf().option("engine-port").get<int32_t>());
-
- _progress_bar->set_pulse_step(0.01);
- _widgets_loaded = true;
-
- server_toggled();
-}
-
-void
-ConnectWindow::on_hide()
-{
- Gtk::Dialog::on_hide();
- if (_app->window_factory()->num_open_graph_windows() == 0) {
- quit();
- }
-}
-
-void
-ConnectWindow::quit_clicked()
-{
- if (_app->quit(this)) {
- _quit_flag = true;
- }
-}
-
-void
-ConnectWindow::server_toggled()
-{
- _url_entry->set_sensitive(true);
- _port_spinbutton->set_sensitive(false);
- _mode = Mode::CONNECT_REMOTE;
-}
-
-void
-ConnectWindow::launch_toggled()
-{
- _url_entry->set_sensitive(false);
- _port_spinbutton->set_sensitive(true);
- _mode = Mode::LAUNCH_REMOTE;
-}
-
-void
-ConnectWindow::internal_toggled()
-{
- _url_entry->set_sensitive(false);
- _port_spinbutton->set_sensitive(false);
- _mode = Mode::INTERNAL;
-}
-
-void
-ConnectWindow::next_stage()
-{
- static const char* labels[] = {
- "Connecting...",
- "Pinging engine...",
- "Attaching to engine...",
- "Requesting root graph...",
- "Loading plugins...",
- "Connected"
- };
-
-
- ++_connect_stage;
- if (_widgets_loaded) {
- _progress_label->set_text(labels[_connect_stage]);
- }
-}
-
-bool
-ConnectWindow::gtk_callback()
-{
- /* If I call this a "state machine" it's not ugly code any more */
-
- if (_quit_flag) {
- return false; // deregister this callback
- }
-
- // Timing stuff for repeated attach attempts
- timeval now;
- gettimeofday(&now, nullptr);
- static const timeval start = now;
- static timeval last = now;
- static unsigned attempts = 0;
-
- // Show if attempted connection goes on for a noticeable amount of time
- if (!is_visible()) {
- const float ms_since_start = (now.tv_sec - start.tv_sec) * 1000.0f +
- (now.tv_usec - start.tv_usec) * 0.001f;
- if (ms_since_start > 500) {
- present();
- set_connecting_widget_states();
- }
- }
-
- if (_connect_stage == 0) {
- const float ms_since_last = (now.tv_sec - last.tv_sec) * 1000.0f +
- (now.tv_usec - last.tv_usec) * 0.001f;
- if (ms_since_last >= 250) {
- last = now;
- if (_mode == Mode::INTERNAL) {
- SPtr<SigClientInterface> client(new SigClientInterface());
- _app->world()->interface()->set_respondee(client);
- _app->attach(client);
- _app->register_callbacks();
- next_stage();
- } else if (connect_remote(_connect_uri)) {
- next_stage();
- }
- }
- } else if (_connect_stage == 1) {
- _attached = false;
- _app->sig_client()->signal_message().connect(
- sigc::mem_fun(this, &ConnectWindow::message));
-
- _ping_id = g_random_int_range(1, std::numeric_limits<int32_t>::max());
- _app->interface()->set_response_id(_ping_id);
- _app->interface()->get(URI("ingen:/engine"));
- last = now;
- attempts = 0;
- next_stage();
-
- } else if (_connect_stage == 2) {
- if (_attached) {
- next_stage();
- } else {
- const float ms_since_last = (now.tv_sec - last.tv_sec) * 1000.0f +
- (now.tv_usec - last.tv_usec) * 0.001f;
- if (attempts > 10) {
- error("Failed to ping engine");
- _connect_stage = -1;
- } else if (ms_since_last > 1000) {
- _app->interface()->set_response_id(_ping_id);
- _app->interface()->get(URI("ingen:/engine"));
- last = now;
- ++attempts;
- }
- }
- } else if (_connect_stage == 3) {
- _app->interface()->get(URI(main_uri().string() + "/"));
- next_stage();
- } else if (_connect_stage == 4) {
- if (_app->store()->size() > 0) {
- SPtr<const GraphModel> root = dynamic_ptr_cast<const GraphModel>(
- _app->store()->object(Raul::Path("/")));
- if (root) {
- set_connected_to(_app->interface());
- _app->window_factory()->present_graph(root);
- next_stage();
- }
- }
- } else if (_connect_stage == 5) {
- hide();
- _connect_stage = 0; // set ourselves up for next time (if there is one)
- _finished_connecting = true;
- _app->interface()->set_response_id(1);
- return false; // deregister this callback
- }
-
- if (_widgets_loaded) {
- _progress_bar->pulse();
- }
-
- if (_connect_stage == -1) { // we were cancelled
- if (_widgets_loaded) {
- _icon->set(Gtk::Stock::DISCONNECT, Gtk::ICON_SIZE_LARGE_TOOLBAR);
- _progress_bar->set_fraction(0.0);
- _connect_button->set_sensitive(true);
- _disconnect_button->set_sensitive(false);
- _disconnect_button->set_label("gtk-disconnect");
- _progress_label->set_text(std::string("Disconnected"));
- }
- return false;
- } else {
- return true;
- }
-}
-
-void
-ConnectWindow::quit()
-{
- _quit_flag = true;
- Gtk::Main::quit();
-}
-
-} // namespace GUI
-} // namespace Ingen
diff --git a/src/gui/ConnectWindow.hpp b/src/gui/ConnectWindow.hpp
deleted file mode 100644
index 08560361..00000000
--- a/src/gui/ConnectWindow.hpp
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- 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_GUI_CONNECTWINDOW_HPP
-#define INGEN_GUI_CONNECTWINDOW_HPP
-
-#include <gtkmm/builder.h>
-#include <gtkmm/button.h>
-#include <gtkmm/entry.h>
-#include <gtkmm/image.h>
-#include <gtkmm/label.h>
-#include <gtkmm/progressbar.h>
-#include <gtkmm/radiobutton.h>
-#include <gtkmm/spinbutton.h>
-
-#include "ingen/types.hpp"
-#include "lilv/lilv.h"
-
-#include "Window.hpp"
-
-namespace Ingen {
-namespace GUI {
-
-class App;
-
-/** The initially visible "Connect to engine" window.
- *
- * This handles actually connecting to the engine and making sure everything
- * is ready before really launching the app.
- *
- * \ingroup GUI
- */
-class ConnectWindow : public Dialog
-{
-public:
- ConnectWindow(BaseObjectType* cobject,
- Glib::RefPtr<Gtk::Builder> xml);
-
- void set_connected_to(SPtr<Ingen::Interface> engine);
- void start(App& app, Ingen::World* world);
-
- bool attached() const { return _finished_connecting; }
- bool quit_flag() const { return _quit_flag; }
-
-private:
- enum class Mode { CONNECT_REMOTE, LAUNCH_REMOTE, INTERNAL };
-
- void message(const Message& msg);
-
- void error(const std::string& msg);
-
- void ingen_response(int32_t id, Status status, const std::string& subject);
-
- void server_toggled();
- void launch_toggled();
- void internal_toggled();
-
- void disconnect();
- void next_stage();
- bool connect_remote(const URI& uri);
- void connect(bool existing);
- void activate();
- void deactivate();
- void quit_clicked();
- void on_show();
- void on_hide();
-
- void load_widgets();
- void set_connecting_widget_states();
-
- bool gtk_callback();
- void quit();
-
- const Glib::RefPtr<Gtk::Builder> _xml;
-
- Gtk::Image* _icon;
- Gtk::ProgressBar* _progress_bar;
- Gtk::Label* _progress_label;
- Gtk::Entry* _url_entry;
- Gtk::RadioButton* _server_radio;
- Gtk::SpinButton* _port_spinbutton;
- Gtk::RadioButton* _launch_radio;
- Gtk::RadioButton* _internal_radio;
- Gtk::Button* _activate_button;
- Gtk::Button* _deactivate_button;
- Gtk::Button* _disconnect_button;
- Gtk::Button* _connect_button;
- Gtk::Button* _quit_button;
-
- Mode _mode;
- URI _connect_uri;
- int32_t _ping_id;
- bool _attached;
- bool _finished_connecting;
- bool _widgets_loaded;
- int _connect_stage;
- bool _quit_flag;
-};
-
-} // namespace GUI
-} // namespace Ingen
-
-#endif // INGEN_GUI_CONNECTWINDOW_HPP
diff --git a/src/gui/GraphBox.cpp b/src/gui/GraphBox.cpp
deleted file mode 100644
index 6f9969be..00000000
--- a/src/gui/GraphBox.cpp
+++ /dev/null
@@ -1,922 +0,0 @@
-/*
- 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/>.
-*/
-
-#include <cassert>
-#include <sstream>
-#include <string>
-
-#include <boost/format.hpp>
-#include <glib/gstdio.h>
-#include <glibmm/fileutils.h>
-#include <gtkmm/stock.h>
-
-#include "ingen/Configuration.hpp"
-#include "ingen/Interface.hpp"
-#include "ingen/Log.hpp"
-#include "ingen/client/ClientStore.hpp"
-#include "ingen/client/GraphModel.hpp"
-
-#include "App.hpp"
-#include "BreadCrumbs.hpp"
-#include "ConnectWindow.hpp"
-#include "GraphCanvas.hpp"
-#include "GraphTreeWindow.hpp"
-#include "GraphView.hpp"
-#include "GraphWindow.hpp"
-#include "LoadGraphWindow.hpp"
-#include "LoadPluginWindow.hpp"
-#include "MessagesWindow.hpp"
-#include "NewSubgraphWindow.hpp"
-#include "Style.hpp"
-#include "ThreadedLoader.hpp"
-#include "WidgetFactory.hpp"
-#include "WindowFactory.hpp"
-#include "ingen_config.h"
-
-#ifdef HAVE_WEBKIT
-#include <webkit/webkit.h>
-#endif
-
-namespace Ingen {
-
-using namespace Client;
-
-namespace GUI {
-
-static const int STATUS_CONTEXT_ENGINE = 0;
-static const int STATUS_CONTEXT_GRAPH = 1;
-static const int STATUS_CONTEXT_HOVER = 2;
-
-GraphBox::GraphBox(BaseObjectType* cobject,
- const Glib::RefPtr<Gtk::Builder>& xml)
- : Gtk::VBox(cobject)
- , _app(nullptr)
- , _window(nullptr)
- , _breadcrumbs(nullptr)
- , _has_shown_documentation(false)
- , _enable_signal(true)
-{
- property_visible() = false;
-
- xml->get_widget("graph_win_alignment", _alignment);
- xml->get_widget("graph_win_status_bar", _status_bar);
- xml->get_widget("graph_import_menuitem", _menu_import);
- xml->get_widget("graph_save_menuitem", _menu_save);
- xml->get_widget("graph_save_as_menuitem", _menu_save_as);
- xml->get_widget("graph_export_image_menuitem", _menu_export_image);
- xml->get_widget("graph_redo_menuitem", _menu_redo);
- xml->get_widget("graph_undo_menuitem", _menu_undo);
- xml->get_widget("graph_cut_menuitem", _menu_cut);
- xml->get_widget("graph_copy_menuitem", _menu_copy);
- xml->get_widget("graph_paste_menuitem", _menu_paste);
- xml->get_widget("graph_delete_menuitem", _menu_delete);
- xml->get_widget("graph_select_all_menuitem", _menu_select_all);
- xml->get_widget("graph_close_menuitem", _menu_close);
- xml->get_widget("graph_quit_menuitem", _menu_quit);
- xml->get_widget("graph_view_control_window_menuitem", _menu_view_control_window);
- xml->get_widget("graph_view_engine_window_menuitem", _menu_view_engine_window);
- xml->get_widget("graph_properties_menuitem", _menu_view_graph_properties);
- xml->get_widget("graph_parent_menuitem", _menu_parent);
- xml->get_widget("graph_refresh_menuitem", _menu_refresh);
- xml->get_widget("graph_fullscreen_menuitem", _menu_fullscreen);
- xml->get_widget("graph_animate_signals_menuitem", _menu_animate_signals);
- xml->get_widget("graph_sprung_layout_menuitem", _menu_sprung_layout);
- xml->get_widget("graph_human_names_menuitem", _menu_human_names);
- xml->get_widget("graph_show_port_names_menuitem", _menu_show_port_names);
- xml->get_widget("graph_zoom_in_menuitem", _menu_zoom_in);
- xml->get_widget("graph_zoom_out_menuitem", _menu_zoom_out);
- xml->get_widget("graph_zoom_normal_menuitem", _menu_zoom_normal);
- xml->get_widget("graph_zoom_full_menuitem", _menu_zoom_full);
- xml->get_widget("graph_increase_font_size_menuitem", _menu_increase_font_size);
- xml->get_widget("graph_decrease_font_size_menuitem", _menu_decrease_font_size);
- xml->get_widget("graph_normal_font_size_menuitem", _menu_normal_font_size);
- xml->get_widget("graph_doc_pane_menuitem", _menu_show_doc_pane);
- xml->get_widget("graph_status_bar_menuitem", _menu_show_status_bar);
- xml->get_widget("graph_arrange_menuitem", _menu_arrange);
- xml->get_widget("graph_view_messages_window_menuitem", _menu_view_messages_window);
- xml->get_widget("graph_view_graph_tree_window_menuitem", _menu_view_graph_tree_window);
- xml->get_widget("graph_help_about_menuitem", _menu_help_about);
- xml->get_widget("graph_documentation_paned", _doc_paned);
- xml->get_widget("graph_documentation_scrolledwindow", _doc_scrolledwindow);
-
- _menu_view_control_window->property_sensitive() = false;
- _menu_import->signal_activate().connect(
- sigc::mem_fun(this, &GraphBox::event_import));
- _menu_save->signal_activate().connect(
- sigc::mem_fun(this, &GraphBox::event_save));
- _menu_save_as->signal_activate().connect(
- sigc::mem_fun(this, &GraphBox::event_save_as));
- _menu_export_image->signal_activate().connect(
- sigc::mem_fun(this, &GraphBox::event_export_image));
- _menu_redo->signal_activate().connect(
- sigc::mem_fun(this, &GraphBox::event_redo));
- _menu_undo->signal_activate().connect(
- sigc::mem_fun(this, &GraphBox::event_undo));
- _menu_copy->signal_activate().connect(
- sigc::mem_fun(this, &GraphBox::event_copy));
- _menu_paste->signal_activate().connect(
- sigc::mem_fun(this, &GraphBox::event_paste));
- _menu_delete->signal_activate().connect(
- sigc::mem_fun(this, &GraphBox::event_delete));
- _menu_select_all->signal_activate().connect(
- sigc::mem_fun(this, &GraphBox::event_select_all));
- _menu_close->signal_activate().connect(
- sigc::mem_fun(this, &GraphBox::event_close));
- _menu_quit->signal_activate().connect(
- sigc::mem_fun(this, &GraphBox::event_quit));
- _menu_parent->signal_activate().connect(
- sigc::mem_fun(this, &GraphBox::event_parent_activated));
- _menu_refresh->signal_activate().connect(
- sigc::mem_fun(this, &GraphBox::event_refresh_activated));
- _menu_fullscreen->signal_activate().connect(
- sigc::mem_fun(this, &GraphBox::event_fullscreen_toggled));
- _menu_animate_signals->signal_activate().connect(
- sigc::mem_fun(this, &GraphBox::event_animate_signals_toggled));
- _menu_sprung_layout->signal_activate().connect(
- sigc::mem_fun(this, &GraphBox::event_sprung_layout_toggled));
- _menu_human_names->signal_activate().connect(
- sigc::mem_fun(this, &GraphBox::event_human_names_toggled));
- _menu_show_doc_pane->signal_activate().connect(
- sigc::mem_fun(this, &GraphBox::event_doc_pane_toggled));
- _menu_show_status_bar->signal_activate().connect(
- sigc::mem_fun(this, &GraphBox::event_status_bar_toggled));
- _menu_show_port_names->signal_activate().connect(
- sigc::mem_fun(this, &GraphBox::event_port_names_toggled));
- _menu_arrange->signal_activate().connect(
- sigc::mem_fun(this, &GraphBox::event_arrange));
- _menu_zoom_in->signal_activate().connect(
- sigc::mem_fun(this, &GraphBox::event_zoom_in));
- _menu_zoom_out->signal_activate().connect(
- sigc::mem_fun(this, &GraphBox::event_zoom_out));
- _menu_zoom_normal->signal_activate().connect(
- sigc::mem_fun(this, &GraphBox::event_zoom_normal));
- _menu_zoom_full->signal_activate().connect(
- sigc::mem_fun(this, &GraphBox::event_zoom_full));
- _menu_increase_font_size->signal_activate().connect(
- sigc::mem_fun(this, &GraphBox::event_increase_font_size));
- _menu_decrease_font_size->signal_activate().connect(
- sigc::mem_fun(this, &GraphBox::event_decrease_font_size));
- _menu_normal_font_size->signal_activate().connect(
- sigc::mem_fun(this, &GraphBox::event_normal_font_size));
- _menu_view_engine_window->signal_activate().connect(
- sigc::mem_fun(this, &GraphBox::event_show_engine));
- _menu_view_graph_properties->signal_activate().connect(
- sigc::mem_fun(this, &GraphBox::event_show_properties));
-
- Glib::RefPtr<Gtk::Clipboard> clipboard = Gtk::Clipboard::get();
- clipboard->signal_owner_change().connect(
- sigc::mem_fun(this, &GraphBox::event_clipboard_changed));
-
-#ifdef __APPLE__
- _menu_paste->set_sensitive(true);
-#endif
-
- _status_label = Gtk::manage(new Gtk::Label("STATUS"));
- _status_bar->pack_start(*_status_label, false, true, 0);
- _status_label->show();
-}
-
-GraphBox::~GraphBox()
-{
- delete _breadcrumbs;
-}
-
-SPtr<GraphBox>
-GraphBox::create(App& app, SPtr<const GraphModel> graph)
-{
- GraphBox* result = nullptr;
- Glib::RefPtr<Gtk::Builder> xml = WidgetFactory::create("graph_win");
- xml->get_widget_derived("graph_win_vbox", result);
- result->init_box(app);
- result->set_graph(graph, SPtr<GraphView>());
-
- if (app.is_plugin()) {
- result->_menu_close->set_sensitive(false);
- result->_menu_quit->set_sensitive(false);
- }
-
- return SPtr<GraphBox>(result);
-}
-
-void
-GraphBox::init_box(App& app)
-{
- _app = &app;
-
- const URI engine_uri(_app->interface()->uri());
- if (engine_uri == "ingen:/clients/event_writer") {
- _status_bar->push("Running internal engine", STATUS_CONTEXT_ENGINE);
- } else {
- _status_bar->push(
- (fmt("Connected to %1%") % engine_uri).str(),
- STATUS_CONTEXT_ENGINE);
- }
-
- _menu_view_messages_window->signal_activate().connect(
- sigc::mem_fun<void>(_app->messages_dialog(), &MessagesWindow::present));
- _menu_view_graph_tree_window->signal_activate().connect(
- sigc::mem_fun<void>(_app->graph_tree(), &GraphTreeWindow::present));
-
- _menu_help_about->signal_activate().connect(
- sigc::hide_return(sigc::mem_fun(_app, &App::show_about)));
-
- _breadcrumbs = new BreadCrumbs(*_app);
- _breadcrumbs->signal_graph_selected.connect(
- sigc::mem_fun(this, &GraphBox::set_graph_from_path));
-
- _status_label->set_markup(app.status_text());
- app.signal_status_text_changed.connect(
- sigc::mem_fun(*this, &GraphBox::set_status_text));
-}
-
-void
-GraphBox::set_status_text(const std::string& text)
-{
- _status_label->set_markup(text);
-}
-
-void
-GraphBox::set_graph_from_path(const Raul::Path& path, SPtr<GraphView> view)
-{
- if (view) {
- assert(view->graph()->path() == path);
- _app->window_factory()->present_graph(view->graph(), _window, view);
- } else {
- SPtr<const GraphModel> model = dynamic_ptr_cast<const GraphModel>(
- _app->store()->object(path));
- if (model) {
- _app->window_factory()->present_graph(model, _window);
- }
- }
-}
-
-/** Sets the graph for this box and initializes everything.
- *
- * If `view` is NULL, a new view will be created.
- */
-void
-GraphBox::set_graph(SPtr<const GraphModel> graph,
- SPtr<GraphView> view)
-{
- if (!graph || graph == _graph) {
- return;
- }
-
- _enable_signal = false;
-
- new_port_connection.disconnect();
- removed_port_connection.disconnect();
- edit_mode_connection.disconnect();
- _entered_connection.disconnect();
- _left_connection.disconnect();
-
- _status_bar->pop(STATUS_CONTEXT_GRAPH);
-
- _graph = graph;
- _view = view;
-
- if (!_view) {
- _view = _breadcrumbs->view(graph->path());
- }
-
- if (!_view) {
- _view = GraphView::create(*_app, graph);
- }
-
- assert(_view);
-
- graph->signal_property().connect(
- sigc::mem_fun(this, &GraphBox::property_changed));
-
- if (!_view->canvas()->supports_sprung_layout()) {
- _menu_sprung_layout->set_active(false);
- _menu_sprung_layout->set_sensitive(false);
- }
-
- // Add view to our alignment
- if (_view->get_parent()) {
- _view->get_parent()->remove(*_view.get());
- }
-
- _alignment->remove();
- _alignment->add(*_view.get());
-
- if (_breadcrumbs->get_parent()) {
- _breadcrumbs->get_parent()->remove(*_breadcrumbs);
- }
-
- _view->breadcrumb_container()->remove();
- _view->breadcrumb_container()->add(*_breadcrumbs);
- _view->breadcrumb_container()->show();
-
- _breadcrumbs->build(graph->path(), _view);
- _breadcrumbs->show();
-
- _menu_view_control_window->property_sensitive() = false;
-
- for (const auto& p : graph->ports()) {
- if (_app->can_control(p.get())) {
- _menu_view_control_window->property_sensitive() = true;
- break;
- }
- }
-
- _menu_parent->property_sensitive() = bool(graph->parent());
-
- new_port_connection = graph->signal_new_port().connect(
- sigc::mem_fun(this, &GraphBox::graph_port_added));
- removed_port_connection = graph->signal_removed_port().connect(
- sigc::mem_fun(this, &GraphBox::graph_port_removed));
-
- show();
- _alignment->show_all();
-
- _menu_human_names->set_active(
- _app->world()->conf().option("human-names").get<int32_t>());
- _menu_show_port_names->set_active(
- _app->world()->conf().option("port-labels").get<int32_t>());
-
- _doc_paned->set_position(std::numeric_limits<int>::max());
- _doc_scrolledwindow->hide();
-
- _enable_signal = true;
-}
-
-void
-GraphBox::graph_port_added(SPtr<const PortModel> port)
-{
- if (port->is_input() && _app->can_control(port.get())) {
- _menu_view_control_window->property_sensitive() = true;
- }
-}
-
-void
-GraphBox::graph_port_removed(SPtr<const PortModel> port)
-{
- if (!(port->is_input() && _app->can_control(port.get()))) {
- return;
- }
-
- for (const auto& p : _graph->ports()) {
- if (p->is_input() && _app->can_control(p.get())) {
- _menu_view_control_window->property_sensitive() = true;
- return;
- }
- }
-
- _menu_view_control_window->property_sensitive() = false;
-}
-
-void
-GraphBox::property_changed(const URI& predicate, const Atom& value)
-{
- if (predicate == _app->uris().ingen_sprungLayout) {
- if (value.type() == _app->uris().forge.Bool) {
- _menu_sprung_layout->set_active(value.get<int32_t>());
- }
- }
-}
-
-void
-GraphBox::set_documentation(const std::string& doc, bool html)
-{
- _doc_scrolledwindow->remove();
- if (doc.empty()) {
- _doc_scrolledwindow->hide();
- return;
- }
-#ifdef HAVE_WEBKIT
- WebKitWebView* view = WEBKIT_WEB_VIEW(webkit_web_view_new());
- webkit_web_view_load_html_string(view, doc.c_str(), "");
- Gtk::Widget* widget = Gtk::manage(Glib::wrap(GTK_WIDGET(view)));
- _doc_scrolledwindow->add(*widget);
- widget->show();
-#else
- Gtk::TextView* view = Gtk::manage(new Gtk::TextView());
- view->get_buffer()->set_text(doc);
- view->set_wrap_mode(Gtk::WRAP_WORD);
- _doc_scrolledwindow->add(*view);
- view->show();
-#endif
-}
-
-void
-GraphBox::show_status(const ObjectModel* model)
-{
- std::stringstream msg;
- msg << model->path();
-
- const PortModel* port = nullptr;
- const BlockModel* block = nullptr;
-
- if ((port = dynamic_cast<const PortModel*>(model))) {
- show_port_status(port, port->value());
-
- } else if ((block = dynamic_cast<const BlockModel*>(model))) {
- const PluginModel* plugin = dynamic_cast<const PluginModel*>(block->plugin());
- if (plugin) {
- msg << ((boost::format(" (%1%)") % plugin->human_name()).str());
- }
- _status_bar->push(msg.str(), STATUS_CONTEXT_HOVER);
- }
-}
-
-void
-GraphBox::show_port_status(const PortModel* port, const Atom& value)
-{
- std::stringstream msg;
- msg << port->path();
-
- const BlockModel* parent = dynamic_cast<const BlockModel*>(port->parent().get());
- if (parent) {
- const PluginModel* plugin = dynamic_cast<const PluginModel*>(parent->plugin());
- if (plugin) {
- const std::string& human_name = plugin->port_human_name(port->index());
- if (!human_name.empty()) {
- msg << " (" << human_name << ")";
- }
- }
- }
-
- if (value.is_valid()) {
- msg << " = " << _app->forge().str(value, true);
- }
-
- _status_bar->pop(STATUS_CONTEXT_HOVER);
- _status_bar->push(msg.str(), STATUS_CONTEXT_HOVER);
-}
-
-void
-GraphBox::object_entered(const ObjectModel* model)
-{
- show_status(model);
-}
-
-void
-GraphBox::object_left(const ObjectModel* model)
-{
- _status_bar->pop(STATUS_CONTEXT_GRAPH);
- _status_bar->pop(STATUS_CONTEXT_HOVER);
-}
-
-void
-GraphBox::event_show_engine()
-{
- if (_graph) {
- _app->connect_window()->show();
- }
-}
-
-void
-GraphBox::event_clipboard_changed(GdkEventOwnerChange* ev)
-{
- Glib::RefPtr<Gtk::Clipboard> clipboard = Gtk::Clipboard::get();
- _menu_paste->set_sensitive(clipboard->wait_is_text_available());
-}
-
-void
-GraphBox::event_show_properties()
-{
- _app->window_factory()->present_properties(_graph);
-}
-
-void
-GraphBox::event_import()
-{
- _app->window_factory()->present_load_graph(_graph);
-}
-
-void
-GraphBox::event_save()
-{
- const Atom& document = _graph->get_property(_app->uris().ingen_file);
- if (!document.is_valid() || document.type() != _app->uris().forge.URI) {
- event_save_as();
- } else {
- save_graph(URI(document.ptr<char>()));
- }
-}
-
-void
-GraphBox::error(const Glib::ustring& message,
- const Glib::ustring& secondary_text)
-{
- Gtk::MessageDialog dialog(
- message, true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
- dialog.set_secondary_text(secondary_text);
- if (_window) {
- dialog.set_transient_for(*_window);
- }
- dialog.run();
-}
-
-bool
-GraphBox::confirm(const Glib::ustring& message,
- const Glib::ustring& secondary_text)
-{
- Gtk::MessageDialog dialog(
- message, true, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_YES_NO, true);
- dialog.set_secondary_text(secondary_text);
- if (_window) {
- dialog.set_transient_for(*_window);
- }
- return dialog.run() == Gtk::RESPONSE_YES;
-}
-
-void
-GraphBox::save_graph(const URI& uri)
-{
- if (_app->interface()->uri().string().substr(0, 3) == "tcp") {
- _status_bar->push(
- (boost::format("Saved %1% to %2% on client")
- % _graph->path() % uri).str(),
- STATUS_CONTEXT_GRAPH);
- _app->loader()->save_graph(_graph, uri);
- } else {
- _status_bar->push(
- (boost::format("Saved %1% to %2% on server")
- % _graph->path() % uri).str(),
- STATUS_CONTEXT_GRAPH);
- _app->interface()->copy(_graph->uri(), uri);
- }
-}
-
-void
-GraphBox::event_save_as()
-{
- const URIs& uris = _app->uris();
- while (true) {
- Gtk::FileChooserDialog dialog(
- "Save Graph", Gtk::FILE_CHOOSER_ACTION_SAVE);
- if (_window) {
- dialog.set_transient_for(*_window);
- }
-
- dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
- Gtk::Button* save_button = dialog.add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_OK);
- save_button->property_has_default() = true;
-
- Gtk::FileFilter filt;
- filt.add_pattern("*.ingen");
- filt.set_name("Ingen bundles");
- dialog.set_filter(filt);
-
- // Set current folder to most sensible default
- const Atom& document = _graph->get_property(uris.ingen_file);
- const Atom& dir = _app->world()->conf().option("graph-directory");
- if (document.type() == uris.forge.URI) {
- dialog.set_uri(document.ptr<char>());
- } else if (dir.is_valid()) {
- dialog.set_current_folder(dir.ptr<char>());
- }
-
- if (dialog.run() != Gtk::RESPONSE_OK) {
- break;
- }
-
- std::string filename = dialog.get_filename();
- std::string basename = Glib::path_get_basename(filename);
-
- if (basename.find('.') == std::string::npos) {
- filename += ".ingen";
- basename += ".ingen";
- } else if (filename.substr(filename.length() - 4) == ".ttl") {
- const Glib::ustring dir = Glib::path_get_dirname(filename);
- if (dir.substr(dir.length() - 6) != ".ingen") {
- error("<b>File does not appear to be in an Ingen bundle.");
- }
- } else if (filename.substr(filename.length() - 6) != ".ingen") {
- error("<b>Ingen bundles must end in \".ingen\"</b>");
- continue;
- }
-
- const std::string symbol(basename.substr(0, basename.find('.')));
-
- if (!Raul::Symbol::is_valid(symbol)) {
- error(
- "<b>Ingen bundle names must be valid symbols.</b>",
- "All characters must be _, a-z, A-Z, or 0-9, but the first may not be 0-9.");
- continue;
- }
-
- //_graph->set_property(uris.lv2_symbol, Atom(symbol.c_str()));
-
- bool confirmed = true;
- if (Glib::file_test(filename, Glib::FILE_TEST_IS_DIR)) {
- if (Glib::file_test(Glib::build_filename(filename, "manifest.ttl"),
- Glib::FILE_TEST_EXISTS)) {
- confirmed = confirm(
- (boost::format("<b>The bundle \"%1%\" already exists."
- " Replace it?</b>") % basename).str());
- } else {
- confirmed = confirm(
- (boost::format("<b>A directory named \"%1%\" already exists,"
- "but is not an Ingen bundle. "
- "Save into it anyway?</b>") % basename).str(),
- "This will create at least 2 .ttl files in this directory,"
- "and possibly several more files and/or directories, recursively. "
- "Existing files will be overwritten.");
- }
- } else if (Glib::file_test(filename, Glib::FILE_TEST_EXISTS)) {
- confirmed = confirm(
- (boost::format("<b>A file named \"%1%\" already exists. "
- "Replace it with an Ingen bundle?</b>")
- % basename).str());
- if (confirmed) {
- ::g_remove(filename.c_str());
- }
- }
-
- if (confirmed) {
- const Glib::ustring uri = Glib::filename_to_uri(filename);
- save_graph(URI(uri));
-
- const_cast<GraphModel*>(_graph.get())->set_property(
- uris.ingen_file,
- _app->forge().alloc_uri(uri.c_str()));
- }
-
- _app->world()->conf().set(
- "graph-directory",
- _app->world()->forge().alloc(dialog.get_current_folder()));
-
- break;
- }
-}
-
-void
-GraphBox::event_export_image()
-{
- Gtk::FileChooserDialog dialog("Export Image", Gtk::FILE_CHOOSER_ACTION_SAVE);
- dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
- dialog.add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_OK);
- dialog.set_default_response(Gtk::RESPONSE_OK);
- if (_window) {
- dialog.set_transient_for(*_window);
- }
-
- typedef std::map<std::string, std::string> Types;
- Types types;
- types["*.dot"] = "Graphviz DOT";
- types["*.pdf"] = "Portable Document Format";
- types["*.ps"] = "PostScript";
- types["*.svg"] = "Scalable Vector Graphics";
- for (Types::const_iterator t = types.begin(); t != types.end(); ++t) {
- Gtk::FileFilter filt;
- filt.add_pattern(t->first);
- filt.set_name(t->second);
- dialog.add_filter(filt);
- if (t->first == "*.pdf") {
- dialog.set_filter(filt);
- }
- }
-
- Gtk::CheckButton* bg_but = new Gtk::CheckButton("Draw _Background", true);
- Gtk::Alignment* extra = new Gtk::Alignment(1.0, 0.5, 0.0, 0.0);
- bg_but->set_active(true);
- extra->add(*Gtk::manage(bg_but));
- extra->show_all();
- dialog.set_extra_widget(*Gtk::manage(extra));
-
- if (dialog.run() == Gtk::RESPONSE_OK) {
- const std::string filename = dialog.get_filename();
- if (Glib::file_test(filename, Glib::FILE_TEST_EXISTS)) {
- Gtk::MessageDialog confirm(
- std::string("File exists! Overwrite ") + filename + "?",
- true, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_YES_NO, true);
- confirm.set_transient_for(dialog);
- if (confirm.run() != Gtk::RESPONSE_YES) {
- return;
- }
- }
- _view->canvas()->export_image(filename.c_str(), bg_but->get_active());
- _status_bar->push((boost::format("Rendered %1% to %2%")
- % _graph->path() % filename).str(),
- STATUS_CONTEXT_GRAPH);
- }
-}
-
-void
-GraphBox::event_copy()
-{
- if (_view) {
- _view->canvas()->copy_selection();
- }
-}
-
-void
-GraphBox::event_redo()
-{
- _app->interface()->redo();
-}
-
-void
-GraphBox::event_undo()
-{
- _app->interface()->undo();
-}
-
-void
-GraphBox::event_paste()
-{
- if (_view) {
- _view->canvas()->paste();
- }
-}
-
-void
-GraphBox::event_delete()
-{
- if (_view) {
- _view->canvas()->destroy_selection();
- }
-}
-
-void
-GraphBox::event_select_all()
-{
- if (_view) {
- _view->canvas()->select_all();
- }
-}
-
-void
-GraphBox::event_close()
-{
- if (_window) {
- _app->window_factory()->remove_graph_window(_window);
- }
-}
-
-void
-GraphBox::event_quit()
-{
- _app->quit(_window);
-}
-
-void
-GraphBox::event_zoom_in()
-{
- _view->canvas()->set_font_size(_view->canvas()->get_font_size() + 1.0);
-}
-
-void
-GraphBox::event_zoom_out()
-{
- _view->canvas()->set_font_size(_view->canvas()->get_font_size() - 1.0);
-}
-
-void
-GraphBox::event_zoom_normal()
-{
- _view->canvas()->set_zoom(1.0);
-}
-
-void
-GraphBox::event_zoom_full()
-{
- _view->canvas()->zoom_full();
-}
-
-void
-GraphBox::event_increase_font_size()
-{
- _view->canvas()->set_font_size(_view->canvas()->get_font_size() + 1.0);
-}
-void
-GraphBox::event_decrease_font_size()
-{
- _view->canvas()->set_font_size(_view->canvas()->get_font_size() - 1.0);
-}
-void
-GraphBox::event_normal_font_size()
-{
- _view->canvas()->set_font_size(_view->canvas()->get_default_font_size());
-}
-
-void
-GraphBox::event_arrange()
-{
- _app->interface()->bundle_begin();
- _view->canvas()->arrange();
- _app->interface()->bundle_end();
-}
-
-void
-GraphBox::event_parent_activated()
-{
- SPtr<Client::GraphModel> parent = dynamic_ptr_cast<Client::GraphModel>(_graph->parent());
- if (parent) {
- _app->window_factory()->present_graph(parent, _window);
- }
-}
-
-void
-GraphBox::event_refresh_activated()
-{
- _app->interface()->get(_graph->uri());
-}
-
-void
-GraphBox::event_fullscreen_toggled()
-{
- // FIXME: ugh, use GTK signals to track state and know for sure
- static bool is_fullscreen = false;
-
- if (_window) {
- if (!is_fullscreen) {
- _window->fullscreen();
- is_fullscreen = true;
- } else {
- _window->unfullscreen();
- is_fullscreen = false;
- }
- }
-}
-
-void
-GraphBox::event_doc_pane_toggled()
-{
- if (_menu_show_doc_pane->get_active()) {
- _doc_scrolledwindow->show_all();
- if (!_has_shown_documentation) {
- const Gtk::Allocation allocation = get_allocation();
- _doc_paned->set_position(allocation.get_width() / 1.61803399);
- _has_shown_documentation = true;
- }
- } else {
- _doc_scrolledwindow->hide();
- }
-}
-
-void
-GraphBox::event_status_bar_toggled()
-{
- if (_menu_show_status_bar->get_active()) {
- _status_bar->show();
- } else {
- _status_bar->hide();
- }
-}
-
-void
-GraphBox::event_animate_signals_toggled()
-{
- _app->interface()->set_property(
- URI("ingen:/clients/this"),
- _app->uris().ingen_broadcast,
- _app->forge().make((bool)_menu_animate_signals->get_active()));
-}
-
-void
-GraphBox::event_sprung_layout_toggled()
-{
- const bool sprung = _menu_sprung_layout->get_active();
-
- _view->canvas()->set_sprung_layout(sprung);
-
- Properties properties;
- properties.emplace(_app->uris().ingen_sprungLayout,
- _app->forge().make(sprung));
- _app->interface()->put(_graph->uri(), properties);
-}
-
-void
-GraphBox::event_human_names_toggled()
-{
- _view->canvas()->show_human_names(_menu_human_names->get_active());
- _app->world()->conf().set(
- "human-names",
- _app->world()->forge().make(_menu_human_names->get_active()));
-}
-
-void
-GraphBox::event_port_names_toggled()
-{
- _app->world()->conf().set(
- "port-labels",
- _app->world()->forge().make(_menu_show_port_names->get_active()));
- if (_menu_show_port_names->get_active()) {
- _view->canvas()->set_direction(GANV_DIRECTION_RIGHT);
- _view->canvas()->show_port_names(true);
- } else {
- _view->canvas()->set_direction(GANV_DIRECTION_DOWN);
- _view->canvas()->show_port_names(false);
- }
-}
-
-} // namespace GUI
-} // namespace Ingen
diff --git a/src/gui/GraphBox.hpp b/src/gui/GraphBox.hpp
deleted file mode 100644
index fd9bf9c0..00000000
--- a/src/gui/GraphBox.hpp
+++ /dev/null
@@ -1,213 +0,0 @@
-/*
- 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_GUI_GRAPH_BOX_HPP
-#define INGEN_GUI_GRAPH_BOX_HPP
-
-#include <string>
-
-#include <gtkmm/alignment.h>
-#include <gtkmm/box.h>
-#include <gtkmm/builder.h>
-#include <gtkmm/menushell.h>
-#include <gtkmm/messagedialog.h>
-#include <gtkmm/paned.h>
-#include <gtkmm/scrolledwindow.h>
-#include <gtkmm/statusbar.h>
-
-#include "ingen/ingen.h"
-#include "ingen/types.hpp"
-
-#include "Window.hpp"
-
-namespace Raul {
-class Atom;
-class Path;
-}
-
-namespace Ingen {
-
-class URI;
-
-namespace Client {
-class GraphModel;
-class PortModel;
-class ObjectModel;
-}
-
-namespace GUI {
-
-class BreadCrumbs;
-class LoadGraphBox;
-class LoadPluginWindow;
-class NewSubgraphWindow;
-class GraphDescriptionWindow;
-class GraphView;
-class GraphWindow;
-class SubgraphModule;
-
-/** A window for a graph.
- *
- * \ingroup GUI
- */
-class INGEN_API GraphBox : public Gtk::VBox
-{
-public:
- GraphBox(BaseObjectType* cobject,
- const Glib::RefPtr<Gtk::Builder>& xml);
- ~GraphBox();
-
- static SPtr<GraphBox> create(
- App& app, SPtr<const Client::GraphModel> graph);
-
- void init_box(App& app);
-
- void set_status_text(const std::string& text);
-
- void set_graph(SPtr<const Client::GraphModel> graph,
- SPtr<GraphView> view);
-
- void set_window(GraphWindow* win) { _window = win; }
-
- bool documentation_is_visible() { return _doc_scrolledwindow->is_visible(); }
- void set_documentation(const std::string& doc, bool html);
-
- SPtr<const Client::GraphModel> graph() const { return _graph; }
- SPtr<GraphView> view() const { return _view; }
-
- void show_port_status(const Client::PortModel* port,
- const Atom& value);
-
- void set_graph_from_path(const Raul::Path& path, SPtr<GraphView> view);
-
- void object_entered(const Client::ObjectModel* model);
- void object_left(const Client::ObjectModel* model);
-
-private:
- void graph_port_added(SPtr<const Client::PortModel> port);
- void graph_port_removed(SPtr<const Client::PortModel> port);
- void property_changed(const URI& predicate, const Atom& value);
- void show_status(const Client::ObjectModel* model);
-
- void error(const Glib::ustring& message,
- const Glib::ustring& secondary_text="");
-
- bool confirm(const Glib::ustring& message,
- const Glib::ustring& secondary_text="");
-
- void save_graph(const URI& uri);
-
- void event_import();
- void event_save();
- void event_save_as();
- void event_export_image();
- void event_redo();
- void event_undo();
- void event_copy();
- void event_paste();
- void event_delete();
- void event_select_all();
- void event_close();
- void event_quit();
- void event_parent_activated();
- void event_refresh_activated();
- void event_fullscreen_toggled();
- void event_doc_pane_toggled();
- void event_status_bar_toggled();
- void event_animate_signals_toggled();
- void event_sprung_layout_toggled();
- void event_human_names_toggled();
- void event_port_names_toggled();
- void event_zoom_in();
- void event_zoom_out();
- void event_zoom_normal();
- void event_zoom_full();
- void event_increase_font_size();
- void event_decrease_font_size();
- void event_normal_font_size();
- void event_arrange();
- void event_show_properties();
- void event_show_engine();
- void event_clipboard_changed(GdkEventOwnerChange* ev);
-
- App* _app;
- SPtr<const Client::GraphModel> _graph;
- SPtr<GraphView> _view;
- GraphWindow* _window;
-
- sigc::connection new_port_connection;
- sigc::connection removed_port_connection;
- sigc::connection edit_mode_connection;
-
- Gtk::MenuItem* _menu_import;
- Gtk::MenuItem* _menu_save;
- Gtk::MenuItem* _menu_save_as;
- Gtk::MenuItem* _menu_export_image;
- Gtk::MenuItem* _menu_redo;
- Gtk::MenuItem* _menu_undo;
- Gtk::MenuItem* _menu_cut;
- Gtk::MenuItem* _menu_copy;
- Gtk::MenuItem* _menu_paste;
- Gtk::MenuItem* _menu_delete;
- Gtk::MenuItem* _menu_select_all;
- Gtk::MenuItem* _menu_close;
- Gtk::MenuItem* _menu_quit;
- Gtk::CheckMenuItem* _menu_animate_signals;
- Gtk::CheckMenuItem* _menu_sprung_layout;
- Gtk::CheckMenuItem* _menu_human_names;
- Gtk::CheckMenuItem* _menu_show_port_names;
- Gtk::CheckMenuItem* _menu_show_doc_pane;
- Gtk::CheckMenuItem* _menu_show_status_bar;
- Gtk::MenuItem* _menu_zoom_in;
- Gtk::MenuItem* _menu_zoom_out;
- Gtk::MenuItem* _menu_zoom_normal;
- Gtk::MenuItem* _menu_zoom_full;
- Gtk::MenuItem* _menu_increase_font_size;
- Gtk::MenuItem* _menu_decrease_font_size;
- Gtk::MenuItem* _menu_normal_font_size;
- Gtk::MenuItem* _menu_parent;
- Gtk::MenuItem* _menu_refresh;
- Gtk::MenuItem* _menu_fullscreen;
- Gtk::MenuItem* _menu_arrange;
- Gtk::MenuItem* _menu_view_engine_window;
- Gtk::MenuItem* _menu_view_control_window;
- Gtk::MenuItem* _menu_view_graph_properties;
- Gtk::MenuItem* _menu_view_messages_window;
- Gtk::MenuItem* _menu_view_graph_tree_window;
- Gtk::MenuItem* _menu_help_about;
-
- Gtk::Alignment* _alignment;
- BreadCrumbs* _breadcrumbs;
- Gtk::Statusbar* _status_bar;
- Gtk::Label* _status_label;
-
- Gtk::HPaned* _doc_paned;
- Gtk::ScrolledWindow* _doc_scrolledwindow;
-
- sigc::connection _entered_connection;
- sigc::connection _left_connection;
-
- /** Invisible bin used to store breadcrumbs when not shown by a view */
- Gtk::Alignment _breadcrumb_bin;
-
- bool _has_shown_documentation;
- bool _enable_signal;
-};
-
-} // namespace GUI
-} // namespace Ingen
-
-#endif // INGEN_GUI_GRAPH_BOX_HPP
diff --git a/src/gui/GraphCanvas.cpp b/src/gui/GraphCanvas.cpp
deleted file mode 100644
index 0ae4d709..00000000
--- a/src/gui/GraphCanvas.cpp
+++ /dev/null
@@ -1,899 +0,0 @@
-/*
- 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/>.
-*/
-
-#include <algorithm>
-#include <cassert>
-#include <map>
-#include <set>
-#include <string>
-
-#include <boost/optional.hpp>
-#include <gtkmm/stock.h>
-
-#include "ganv/Canvas.hpp"
-#include "ganv/Circle.hpp"
-#include "ingen/ClashAvoider.hpp"
-#include "ingen/Configuration.hpp"
-#include "ingen/Interface.hpp"
-#include "ingen/Log.hpp"
-#include "ingen/Serialiser.hpp"
-#include "ingen/World.hpp"
-#include "ingen/client/BlockModel.hpp"
-#include "ingen/client/ClientStore.hpp"
-#include "ingen/client/GraphModel.hpp"
-#include "ingen/client/PluginModel.hpp"
-#include "ingen/ingen.h"
-#include "lv2/lv2plug.in/ns/ext/atom/atom.h"
-
-#include "App.hpp"
-#include "Arc.hpp"
-#include "GraphCanvas.hpp"
-#include "GraphPortModule.hpp"
-#include "GraphWindow.hpp"
-#include "LoadPluginWindow.hpp"
-#include "NewSubgraphWindow.hpp"
-#include "NodeModule.hpp"
-#include "PluginMenu.hpp"
-#include "Port.hpp"
-#include "SubgraphModule.hpp"
-#include "ThreadedLoader.hpp"
-#include "WidgetFactory.hpp"
-#include "WindowFactory.hpp"
-
-using std::string;
-
-namespace Ingen {
-
-using namespace Client;
-
-namespace GUI {
-
-static int
-port_order(const GanvPort* a, const GanvPort* b, void* data)
-{
- const Port* pa = dynamic_cast<const Port*>(Glib::wrap(a));
- const Port* pb = dynamic_cast<const Port*>(Glib::wrap(b));
- if (pa && pb) {
- return ((int)pa->model()->index() - (int)pb->model()->index());
- }
- return 0;
-}
-
-GraphCanvas::GraphCanvas(App& app,
- SPtr<const GraphModel> graph,
- int width,
- int height)
- : Canvas(width, height)
- , _app(app)
- , _graph(std::move(graph))
- , _auto_position_count(0)
- , _menu_x(0)
- , _menu_y(0)
- , _paste_count(0)
- , _menu(nullptr)
- , _internal_menu(nullptr)
- , _plugin_menu(nullptr)
- , _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);
-
- xml->get_widget("canvas_menu_add_audio_input", _menu_add_audio_input);
- xml->get_widget("canvas_menu_add_audio_output", _menu_add_audio_output);
- xml->get_widget("canvas_menu_add_cv_input", _menu_add_cv_input);
- xml->get_widget("canvas_menu_add_cv_output", _menu_add_cv_output);
- xml->get_widget("canvas_menu_add_control_input", _menu_add_control_input);
- xml->get_widget("canvas_menu_add_control_output", _menu_add_control_output);
- xml->get_widget("canvas_menu_add_event_input", _menu_add_event_input);
- xml->get_widget("canvas_menu_add_event_output", _menu_add_event_output);
- xml->get_widget("canvas_menu_load_plugin", _menu_load_plugin);
- xml->get_widget("canvas_menu_load_graph", _menu_load_graph);
- xml->get_widget("canvas_menu_new_graph", _menu_new_graph);
- xml->get_widget("canvas_menu_edit", _menu_edit);
- xml->get_widget("canvas_menu_properties", _menu_properties);
-
- const URIs& uris = _app.uris();
-
- // Add port menu items
- _menu_add_audio_input->signal_activate().connect(
- sigc::bind(sigc::mem_fun(this, &GraphCanvas::menu_add_port),
- "audio_in", "Audio In", uris.lv2_AudioPort, false));
- _menu_add_audio_output->signal_activate().connect(
- sigc::bind(sigc::mem_fun(this, &GraphCanvas::menu_add_port),
- "audio_out", "Audio Out", uris.lv2_AudioPort, true));
- _menu_add_cv_input->signal_activate().connect(
- sigc::bind(sigc::mem_fun(this, &GraphCanvas::menu_add_port),
- "cv_in", "CV In", uris.lv2_CVPort, false));
- _menu_add_cv_output->signal_activate().connect(
- sigc::bind(sigc::mem_fun(this, &GraphCanvas::menu_add_port),
- "cv_out", "CV Out", uris.lv2_CVPort, true));
- _menu_add_control_input->signal_activate().connect(
- sigc::bind(sigc::mem_fun(this, &GraphCanvas::menu_add_port),
- "control_in", "Control In", uris.lv2_ControlPort, false));
- _menu_add_control_output->signal_activate().connect(
- sigc::bind(sigc::mem_fun(this, &GraphCanvas::menu_add_port),
- "control_out", "Control Out", uris.lv2_ControlPort, true));
- _menu_add_event_input->signal_activate().connect(
- sigc::bind(sigc::mem_fun(this, &GraphCanvas::menu_add_port),
- "event_in", "Event In", uris.atom_AtomPort, false));
- _menu_add_event_output->signal_activate().connect(
- sigc::bind(sigc::mem_fun(this, &GraphCanvas::menu_add_port),
- "event_out", "Event Out", uris.atom_AtomPort, true));
-
- signal_event.connect(
- sigc::mem_fun(this, &GraphCanvas::on_event));
- signal_connect.connect(
- sigc::mem_fun(this, &GraphCanvas::connect));
- signal_disconnect.connect(
- sigc::mem_fun(this, &GraphCanvas::disconnect));
-
- // Connect to model signals to track state
- _graph->signal_new_block().connect(
- sigc::mem_fun(this, &GraphCanvas::add_block));
- _graph->signal_removed_block().connect(
- sigc::mem_fun(this, &GraphCanvas::remove_block));
- _graph->signal_new_port().connect(
- sigc::mem_fun(this, &GraphCanvas::add_port));
- _graph->signal_removed_port().connect(
- sigc::mem_fun(this, &GraphCanvas::remove_port));
- _graph->signal_new_arc().connect(
- sigc::mem_fun(this, &GraphCanvas::connection));
- _graph->signal_removed_arc().connect(
- sigc::mem_fun(this, &GraphCanvas::disconnection));
-
- _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(
- sigc::mem_fun(this, &GraphCanvas::menu_load_plugin));
- _menu_load_graph->signal_activate().connect(
- sigc::mem_fun(this, &GraphCanvas::menu_load_graph));
- _menu_new_graph->signal_activate().connect(
- sigc::mem_fun(this, &GraphCanvas::menu_new_graph));
- _menu_properties->signal_activate().connect(
- sigc::mem_fun(this, &GraphCanvas::menu_properties));
-
- show_human_names(app.world()->conf().option("human-names").get<int32_t>());
- show_port_names(app.world()->conf().option("port-labels").get<int32_t>());
- set_port_order(port_order, nullptr);
-}
-
-void
-GraphCanvas::show_menu(bool position, unsigned button, uint32_t time)
-{
- _app.request_plugins_if_necessary();
-
- if (!_internal_menu || _menu_dirty) {
- build_menus();
- }
-
- if (position) {
- _menu->popup(sigc::mem_fun(this, &GraphCanvas::auto_menu_position), button, time);
- } else {
- _menu->popup(button, time);
- }
-}
-
-void
-GraphCanvas::build_menus()
-{
- // Build (or clear existing) internal plugin menu
- if (_internal_menu) {
- _internal_menu->items().clear();
- } else {
- _menu->items().push_back(
- Gtk::Menu_Helpers::ImageMenuElem(
- "In_ternal",
- *(manage(new Gtk::Image(Gtk::Stock::EXECUTE, Gtk::ICON_SIZE_MENU)))));
- Gtk::MenuItem* internal_menu_item = &(_menu->items().back());
- _internal_menu = Gtk::manage(new Gtk::Menu());
- internal_menu_item->set_submenu(*_internal_menu);
- _menu->reorder_child(*internal_menu_item, 4);
- }
-
- // Build skeleton LV2 plugin class heirarchy for '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(
- "_Plugin",
- *(manage(new Gtk::Image(Gtk::Stock::EXECUTE, Gtk::ICON_SIZE_MENU)))));
- Gtk::MenuItem* plugin_menu_item = &(_menu->items().back());
- plugin_menu_item->set_submenu(*_plugin_menu);
- _menu->reorder_child(*plugin_menu_item, 5);
- _plugin_menu->signal_load_plugin.connect(
- sigc::mem_fun(this, &GraphCanvas::load_plugin));
- }
-
- // Add known plugins to menu heirarchy
- SPtr<const ClientStore::Plugins> plugins = _app.store()->plugins();
- for (const auto& p : *plugins.get()) {
- add_plugin(p.second);
- }
-
- _menu_dirty = false;
-}
-
-void
-GraphCanvas::build()
-{
- const Store::const_range kids = _app.store()->children_range(_graph);
-
- // Create modules for blocks
- for (Store::const_iterator i = kids.first; i != kids.second; ++i) {
- SPtr<BlockModel> block = dynamic_ptr_cast<BlockModel>(i->second);
- if (block && block->parent() == _graph) {
- add_block(block);
- }
- }
-
- // Create pseudo modules for ports (ports on this canvas, not on our module)
- for (const auto& p : _graph->ports()) {
- add_port(p);
- }
-
- // Create arcs
- for (const auto& a : _graph->arcs()) {
- connection(dynamic_ptr_cast<ArcModel>(a.second));
- }
-}
-
-static void
-show_module_human_names(GanvNode* node, void* data)
-{
- bool b = *(bool*)data;
- if (GANV_IS_MODULE(node)) {
- Ganv::Module* module = Glib::wrap(GANV_MODULE(node));
- NodeModule* nmod = dynamic_cast<NodeModule*>(module);
- if (nmod) {
- nmod->show_human_names(b);
- }
-
- GraphPortModule* pmod = dynamic_cast<GraphPortModule*>(module);
- if (pmod) {
- pmod->show_human_names(b);
- }
- }
-}
-
-void
-GraphCanvas::show_human_names(bool b)
-{
- _human_names = b;
- _app.world()->conf().set("human-names", _app.forge().make(b));
-
- for_each_node(show_module_human_names, &b);
-}
-
-static void
-ensure_port_labels(GanvNode* node, void* data)
-{
- if (GANV_IS_MODULE(node)) {
- Ganv::Module* module = Glib::wrap(GANV_MODULE(node));
- for (Ganv::Port* p : *module) {
- Ingen::GUI::Port* port = dynamic_cast<Ingen::GUI::Port*>(p);
- if (port) {
- port->ensure_label();
- }
- }
- }
-}
-
-void
-GraphCanvas::show_port_names(bool b)
-{
- ganv_canvas_set_direction(gobj(), b ? GANV_DIRECTION_RIGHT : GANV_DIRECTION_DOWN);
- for_each_node(ensure_port_labels, &b);
-}
-
-void
-GraphCanvas::add_plugin(SPtr<PluginModel> p)
-{
- if (_internal_menu && _app.uris().ingen_Internal == p->type()) {
- _internal_menu->items().push_back(
- Gtk::Menu_Helpers::MenuElem(
- std::string("_") + p->human_name(),
- sigc::bind(sigc::mem_fun(this, &GraphCanvas::load_plugin), p)));
- } else if (_plugin_menu) {
- _plugin_menu->add_plugin(p);
- }
-}
-
-void
-GraphCanvas::remove_plugin(const 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);
- NodeModule* module;
- if (pm) {
- module = SubgraphModule::create(*this, pm, _human_names);
- } else {
- module = NodeModule::create(*this, bm, _human_names);
- }
-
- module->show();
- _views.emplace(bm, module);
- if (_pastees.find(bm->path()) != _pastees.end()) {
- module->set_selected(true);
- }
-}
-
-void
-GraphCanvas::remove_block(SPtr<const BlockModel> bm)
-{
- auto i = _views.find(bm);
-
- if (i != _views.end()) {
- const guint n_ports = i->second->num_ports();
- for (gint p = n_ports - 1; p >= 0; --p) {
- delete i->second->get_port(p);
- }
- delete i->second;
- _views.erase(i);
- }
-}
-
-void
-GraphCanvas::add_port(SPtr<const PortModel> pm)
-{
- GraphPortModule* view = GraphPortModule::create(*this, pm);
- _views.emplace(pm, view);
- view->show();
-}
-
-void
-GraphCanvas::remove_port(SPtr<const PortModel> pm)
-{
- auto i = _views.find(pm);
-
- // Port on this graph
- if (i != _views.end()) {
- delete i->second;
- _views.erase(i);
-
- } else {
- NodeModule* module = dynamic_cast<NodeModule*>(_views[pm->parent()]);
- module->delete_port_view(pm);
- }
-
- assert(_views.find(pm) == _views.end());
-}
-
-Ganv::Port*
-GraphCanvas::get_port_view(SPtr<PortModel> port)
-{
- Ganv::Module* module = _views[port];
-
- // Port on this graph
- if (module) {
- GraphPortModule* ppm = dynamic_cast<GraphPortModule*>(module);
- return ppm
- ? *ppm->begin()
- : dynamic_cast<Ganv::Port*>(module);
- } else {
- module = dynamic_cast<NodeModule*>(_views[port->parent()]);
- if (module) {
- for (const auto& p : *module) {
- GUI::Port* pv = dynamic_cast<GUI::Port*>(p);
- if (pv && pv->model() == port) {
- return pv;
- }
- }
- }
- }
-
- return nullptr;
-}
-
-/** Called when a connection is added to the model. */
-void
-GraphCanvas::connection(SPtr<const ArcModel> arc)
-{
- Ganv::Port* const tail = get_port_view(arc->tail());
- Ganv::Port* const head = get_port_view(arc->head());
-
- if (tail && head) {
- new GUI::Arc(*this, arc, tail, head);
- } else {
- _app.log().error(fmt("Unable to find ports to connect %1% => %2%\n")
- % arc->tail_path() % arc->head_path());
- }
-}
-
-/** Called when a connection is removed from the model. */
-void
-GraphCanvas::disconnection(SPtr<const ArcModel> arc)
-{
- Ganv::Port* const tail = get_port_view(arc->tail());
- Ganv::Port* const head = get_port_view(arc->head());
-
- if (tail && head) {
- remove_edge_between(tail, head);
- if (arc->head()->is_a(_app.uris().lv2_AudioPort)) {
- GUI::Port* const h = dynamic_cast<GUI::Port*>(head);
- if (h) {
- h->activity(_app.forge().make(0.0f)); // Reset peaks
- }
- }
- } else {
- _app.log().error(fmt("Unable to find ports to disconnect %1% => %2%\n")
- % arc->tail_path() % arc->head_path());
- }
-}
-
-/** Called when the user connects ports on the canvas. */
-void
-GraphCanvas::connect(Ganv::Node* tail, Ganv::Node* head)
-{
- const GUI::Port* const t = dynamic_cast<GUI::Port*>(tail);
- const GUI::Port* const h = dynamic_cast<GUI::Port*>(head);
-
- if (t && h) {
- _app.interface()->connect(t->model()->path(), h->model()->path());
- }
-}
-
-/** Called when the user disconnects ports on the canvas. */
-void
-GraphCanvas::disconnect(Ganv::Node* tail, Ganv::Node* head)
-{
- const GUI::Port* const t = dynamic_cast<GUI::Port*>(tail);
- const GUI::Port* const h = dynamic_cast<GUI::Port*>(head);
-
- if (t && h) {
- _app.interface()->disconnect(t->model()->path(), h->model()->path());
- }
-}
-
-void
-GraphCanvas::auto_menu_position(int& x, int& y, bool& push_in)
-{
- std::pair<int, int> scroll_offsets;
- get_scroll_offsets(scroll_offsets.first, scroll_offsets.second);
-
- if (_auto_position_count > 1 && scroll_offsets != _auto_position_scroll_offsets) {
- // Scroll changed since last auto position, reset
- _menu_x = 0;
- _menu_y = 0;
- _auto_position_count = 0;
- }
-
- if (_menu_x == 0 && _menu_y == 0) {
- // No menu position set, start near top left of canvas
- widget().translate_coordinates(
- *_app.window_factory()->graph_window(_graph),
- 64, 64, _menu_x, _menu_y);
-
- int origin_x;
- int origin_y;
- widget().get_window()->get_origin(origin_x, origin_y);
- _menu_x += origin_x;
- _menu_y += origin_y;
- }
-
- const int cascade = _auto_position_count * 32;
-
- x = _menu_x + cascade;
- y = _menu_y + cascade;
- push_in = true;
-
- ++_auto_position_count;
- _auto_position_scroll_offsets = scroll_offsets;
-}
-
-bool
-GraphCanvas::on_event(GdkEvent* event)
-{
- assert(event);
-
- bool ret = false;
-
- switch (event->type) {
- case GDK_BUTTON_PRESS:
- if (event->button.button == 3) {
- _auto_position_count = 1;
- _menu_x = (int)event->button.x_root;
- _menu_y = (int)event->button.y_root;
- show_menu(false, event->button.button, event->button.time);
- ret = true;
- }
- break;
-
- case GDK_KEY_PRESS:
- switch (event->key.keyval) {
- case GDK_Delete:
- destroy_selection();
- ret = true;
- break;
- case GDK_Home:
- scroll_to(0, 0);
- break;
- case GDK_space:
- case GDK_Menu:
- show_menu(true, 3, event->key.time);
- default: break;
- }
- break;
-
- case GDK_MOTION_NOTIFY:
- _paste_count = 0;
- break;
-
- default: break;
- }
-
- return ret;
-}
-
-void
-GraphCanvas::clear_selection()
-{
- GraphWindow* win = _app.window_factory()->graph_window(_graph);
- if (win) {
- win->set_documentation("", false);
- }
-
- Ganv::Canvas::clear_selection();
-}
-
-static void
-destroy_node(GanvNode* node, void* data)
-{
- if (!GANV_IS_MODULE(node)) {
- return;
- }
-
- App* app = (App*)data;
- Ganv::Module* module = Glib::wrap(GANV_MODULE(node));
- NodeModule* node_module = dynamic_cast<NodeModule*>(module);
-
- if (node_module) {
- app->interface()->del(node_module->block()->uri());
- } else {
- GraphPortModule* port_module = dynamic_cast<GraphPortModule*>(module);
- if (port_module &&
- strcmp(port_module->port()->path().symbol(), "control") &&
- strcmp(port_module->port()->path().symbol(), "notify")) {
- app->interface()->del(port_module->port()->uri());
- }
- }
-}
-
-static void
-destroy_arc(GanvEdge* arc, void* data)
-{
- App* app = (App*)data;
- Ganv::Edge* arcmm = Glib::wrap(arc);
-
- Port* tail = dynamic_cast<Port*>(arcmm->get_tail());
- Port* head = dynamic_cast<Port*>(arcmm->get_head());
- app->interface()->disconnect(tail->model()->path(), head->model()->path());
-}
-
-void
-GraphCanvas::destroy_selection()
-{
- _app.interface()->bundle_begin();
- for_each_selected_edge(destroy_arc, &_app);
- for_each_selected_node(destroy_node, &_app);
- _app.interface()->bundle_end();
-}
-
-static void
-serialise_node(GanvNode* node, void* data)
-{
- Serialiser* serialiser = (Serialiser*)data;
- if (!GANV_IS_MODULE(node)) {
- return;
- }
-
- Ganv::Module* module = Glib::wrap(GANV_MODULE(node));
- NodeModule* node_module = dynamic_cast<NodeModule*>(module);
-
- if (node_module) {
- serialiser->serialise(node_module->block());
- } else {
- GraphPortModule* port_module = dynamic_cast<GraphPortModule*>(module);
- if (port_module) {
- serialiser->serialise(port_module->port());
- }
- }
-}
-
-static void
-serialise_arc(GanvEdge* arc, void* data)
-{
- Serialiser* serialiser = (Serialiser*)data;
- if (!GANV_IS_EDGE(arc)) {
- return;
- }
-
- GUI::Arc* garc = dynamic_cast<GUI::Arc*>(Glib::wrap(GANV_EDGE(arc)));
- if (garc) {
- serialiser->serialise_arc(Sord::Node(), garc->model());
- }
-}
-
-void
-GraphCanvas::copy_selection()
-{
- std::lock_guard<std::mutex> lock(_app.world()->rdf_mutex());
-
- Serialiser serialiser(*_app.world());
- serialiser.start_to_string(_graph->path(), _graph->base_uri());
-
- for_each_selected_node(serialise_node, &serialiser);
- for_each_selected_edge(serialise_arc, &serialiser);
-
- Glib::RefPtr<Gtk::Clipboard> clipboard = Gtk::Clipboard::get();
- clipboard->set_text(serialiser.finish());
- _paste_count = 0;
-}
-
-void
-GraphCanvas::paste()
-{
- typedef Properties::const_iterator PropIter;
-
- std::lock_guard<std::mutex> lock(_app.world()->rdf_mutex());
-
- const Glib::ustring str = Gtk::Clipboard::get()->wait_for_text();
- SPtr<Parser> parser = _app.loader()->parser();
- const URIs& uris = _app.uris();
- const Raul::Path& parent = _graph->path();
- if (!parser) {
- _app.log().error("Unable to load parser, paste unavailable\n");
- return;
- }
-
- // Prepare for paste
- clear_selection();
- _pastees.clear();
- ++_paste_count;
-
- // Make a client store to serve as clipboard
- ClientStore clipboard(_app.world()->uris(), _app.log());
- clipboard.set_plugins(_app.store()->plugins());
- clipboard.put(main_uri(),
- {{uris.rdf_type, Property(uris.ingen_Graph)}});
-
- // Parse clipboard text into clipboard store
- boost::optional<URI> base_uri = parser->parse_string(
- _app.world(), &clipboard, str, main_uri());
-
- // Figure out the copy graph base path
- Raul::Path copy_root("/");
- if (base_uri) {
- std::string base = *base_uri;
- if (base[base.size() - 1] == '/') {
- base = base.substr(0, base.size() - 1);
- }
- copy_root = uri_to_path(URI(base));
- }
-
- // Find the minimum x and y coordinate of objects to be pasted
- float min_x = std::numeric_limits<float>::max();
- float min_y = std::numeric_limits<float>::max();
- for (const auto& c : clipboard) {
- if (c.first.parent() == Raul::Path("/")) {
- const Atom& x = c.second->get_property(uris.ingen_canvasX);
- const Atom& y = c.second->get_property(uris.ingen_canvasY);
- if (x.type() == uris.atom_Float) {
- min_x = std::min(min_x, x.get<float>());
- }
- if (y.type() == uris.atom_Float) {
- min_y = std::min(min_y, y.get<float>());
- }
- }
- }
-
- // Find canvas paste origin based on pointer position
- int widget_point_x, widget_point_y, scroll_x, scroll_y;
- widget().get_pointer(widget_point_x, widget_point_y);
- get_scroll_offsets(scroll_x, scroll_y);
- const int paste_x = widget_point_x + scroll_x + (20.0f * _paste_count);
- const int paste_y = widget_point_y + scroll_y + (20.0f * _paste_count);
-
- _app.interface()->bundle_begin();
-
- // Put each top level object in the clipboard store
- ClashAvoider avoider(*_app.store().get());
- for (const auto& c : clipboard) {
- if (c.first.is_root() || c.first.parent() != Raul::Path("/")) {
- continue;
- }
-
- const SPtr<Node> node = c.second;
- const Raul::Path& old_path = copy_root.child(node->path());
- const URI& old_uri = path_to_uri(old_path);
- const Raul::Path& new_path = avoider.map_path(parent.child(node->path()));
-
- Properties props{{uris.lv2_prototype,
- _app.forge().make_urid(old_uri)}};
-
- // Set the same types
- const auto t = node->properties().equal_range(uris.rdf_type);
- props.insert(t.first, t.second);
-
- // Set coordinates so paste origin is at the mouse pointer
- PropIter xi = node->properties().find(uris.ingen_canvasX);
- PropIter yi = node->properties().find(uris.ingen_canvasY);
- if (xi != node->properties().end()) {
- const float x = xi->second.get<float>() - min_x + paste_x;
- props.insert({xi->first, Property(_app.forge().make(x),
- xi->second.context())});
- }
- if (yi != node->properties().end()) {
- const float y = yi->second.get<float>() - min_y + paste_y;
- props.insert({yi->first, Property(_app.forge().make(y),
- yi->second.context())});
- }
-
- _app.interface()->put(path_to_uri(new_path), props);
- _pastees.insert(new_path);
- }
-
- // Connect objects
- for (auto a : clipboard.object(Raul::Path("/"))->arcs()) {
- _app.interface()->connect(
- avoider.map_path(parent.child(a.second->tail_path())),
- avoider.map_path(parent.child(a.second->head_path())));
- }
-
- _app.interface()->bundle_end();
-}
-
-void
-GraphCanvas::generate_port_name(
- const string& sym_base, string& symbol,
- const string& name_base, string& name)
-{
- symbol = sym_base;
- name = name_base;
-
- char num_buf[5];
- uint32_t i = 1;
- for ( ; i < 9999; ++i) {
- snprintf(num_buf, sizeof(num_buf), "%u", i);
- symbol = sym_base + "_";
- symbol += num_buf;
- if (!_graph->get_port(Raul::Symbol::symbolify(symbol))) {
- break;
- }
- }
-
- assert(Raul::Path::is_valid(string("/") + symbol));
-
- name.append(" ").append(num_buf);
-}
-
-void
-GraphCanvas::menu_add_port(const string& sym_base,
- const string& name_base,
- const URI& type,
- bool is_output)
-{
- string sym, name;
- generate_port_name(sym_base, sym, name_base, name);
- const Raul::Path& path = _graph->path().child(Raul::Symbol(sym));
-
- const URIs& uris = _app.uris();
-
- Properties props = get_initial_data(Resource::Graph::INTERNAL);
- props.emplace(uris.rdf_type, _app.forge().make_urid(type));
- if (type == uris.atom_AtomPort) {
- props.emplace(uris.atom_bufferType, Property(uris.atom_Sequence));
- }
- props.emplace(
- uris.rdf_type,
- Property(is_output ? uris.lv2_OutputPort : uris.lv2_InputPort));
- props.emplace(uris.lv2_index,
- _app.forge().make(int32_t(_graph->num_ports())));
- props.emplace(uris.lv2_name, _app.forge().alloc(name.c_str()));
- _app.interface()->put(path_to_uri(path), props);
-}
-
-void
-GraphCanvas::load_plugin(WPtr<PluginModel> weak_plugin)
-{
- SPtr<PluginModel> plugin = weak_plugin.lock();
- if (!plugin) {
- return;
- }
-
- Raul::Symbol symbol = plugin->default_block_symbol();
- unsigned offset = _app.store()->child_name_offset(_graph->path(), symbol);
- if (offset != 0) {
- std::stringstream ss;
- ss << symbol << "_" << offset;
- symbol = Raul::Symbol(ss.str());
- }
-
- const URIs& uris = _app.uris();
- const Raul::Path path = _graph->path().child(symbol);
-
- // FIXME: polyphony?
- Properties props = get_initial_data();
- props.emplace(uris.rdf_type, Property(uris.ingen_Block));
- props.emplace(uris.lv2_prototype, uris.forge.make_urid(plugin->uri()));
- _app.interface()->put(path_to_uri(path), props);
-}
-
-/** Try to guess a suitable location for a new module.
- */
-void
-GraphCanvas::get_new_module_location(double& x, double& y)
-{
- int scroll_x;
- int scroll_y;
- get_scroll_offsets(scroll_x, scroll_y);
- x = scroll_x + 20;
- y = scroll_y + 20;
-}
-
-Properties
-GraphCanvas::get_initial_data(Resource::Graph ctx)
-{
- Properties result;
- const URIs& uris = _app.uris();
- result.emplace(uris.ingen_canvasX,
- Property(_app.forge().make((float)_menu_x), ctx));
- result.emplace(uris.ingen_canvasY,
- Property(_app.forge().make((float)_menu_y), ctx));
- return result;
-}
-
-void
-GraphCanvas::menu_load_plugin()
-{
- _app.window_factory()->present_load_plugin(_graph, get_initial_data());
-}
-
-void
-GraphCanvas::menu_load_graph()
-{
- _app.window_factory()->present_load_subgraph(
- _graph, get_initial_data(Resource::Graph::EXTERNAL));
-}
-
-void
-GraphCanvas::menu_new_graph()
-{
- _app.window_factory()->present_new_subgraph(
- _graph, get_initial_data(Resource::Graph::EXTERNAL));
-}
-
-void
-GraphCanvas::menu_properties()
-{
- _app.window_factory()->present_properties(_graph);
-}
-
-} // namespace GUI
-} // namespace Ingen
diff --git a/src/gui/GraphCanvas.hpp b/src/gui/GraphCanvas.hpp
deleted file mode 100644
index a7340744..00000000
--- a/src/gui/GraphCanvas.hpp
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- 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_GUI_GRAPHCANVAS_HPP
-#define INGEN_GUI_GRAPHCANVAS_HPP
-
-#include <string>
-#include <map>
-#include <set>
-
-#include "lilv/lilv.h"
-
-#include "ganv/Canvas.hpp"
-#include "ganv/Module.hpp"
-#include "ingen/Node.hpp"
-#include "ingen/client/ArcModel.hpp"
-#include "ingen/types.hpp"
-#include "raul/Path.hpp"
-
-#include "NodeModule.hpp"
-
-namespace Ingen {
-
-namespace Client { class GraphModel; }
-
-namespace GUI {
-
-class NodeModule;
-class PluginMenu;
-
-/** Graph canvas widget.
- *
- * \ingroup GUI
- */
-class GraphCanvas : public Ganv::Canvas
-{
-public:
- GraphCanvas(App& app,
- SPtr<const Client::GraphModel> graph,
- int width,
- int height);
-
- virtual ~GraphCanvas() {}
-
- App& app() { return _app; }
-
- void build();
- void show_human_names(bool b);
- void show_port_names(bool b);
- bool show_port_names() const { return _show_port_names; }
-
- void add_plugin(SPtr<Client::PluginModel> p);
- void remove_plugin(const 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);
- void remove_port(SPtr<const Client::PortModel> pm);
- void connection(SPtr<const Client::ArcModel> arc);
- void disconnection(SPtr<const Client::ArcModel> arc);
-
- void get_new_module_location(double& x, double& y);
-
- void clear_selection();
- void destroy_selection();
- void copy_selection();
- void paste();
-
- void show_menu(bool position, unsigned button, uint32_t time);
-
- bool on_event(GdkEvent* event);
-
-private:
- enum class ControlType { NUMBER, BUTTON };
- void generate_port_name(
- const std::string& sym_base, std::string& symbol,
- const std::string& name_base, std::string& name);
-
- void menu_add_port(const std::string& sym_base,
- const std::string& name_base,
- const URI& type,
- bool is_output);
-
- void menu_load_plugin();
- void menu_new_graph();
- void menu_load_graph();
- void menu_properties();
- void load_plugin(WPtr<Client::PluginModel> weak_plugin);
-
- void build_menus();
-
- void auto_menu_position(int& x, int& y, bool& push_in);
-
- typedef std::multimap<const std::string, const LilvPluginClass*> LV2Children;
-
- Properties get_initial_data(Resource::Graph ctx=Resource::Graph::DEFAULT);
-
- Ganv::Port* get_port_view(SPtr<Client::PortModel> port);
-
- void connect(Ganv::Node* tail,
- Ganv::Node* head);
-
- void disconnect(Ganv::Node* tail,
- Ganv::Node* head);
-
- App& _app;
- SPtr<const Client::GraphModel> _graph;
-
- typedef std::map<SPtr<const Client::ObjectModel>, Ganv::Module*> Views;
- Views _views;
-
- int _auto_position_count;
- std::pair<int, int> _auto_position_scroll_offsets;
-
- int _menu_x;
- int _menu_y;
- int _paste_count;
-
- // Track pasted objects so they can be selected when they arrive
- std::set<Raul::Path> _pastees;
-
- Gtk::Menu* _menu;
- Gtk::Menu* _internal_menu;
- PluginMenu* _plugin_menu;
- Gtk::MenuItem* _menu_add_audio_input;
- Gtk::MenuItem* _menu_add_audio_output;
- Gtk::MenuItem* _menu_add_control_input;
- Gtk::MenuItem* _menu_add_control_output;
- Gtk::MenuItem* _menu_add_cv_input;
- Gtk::MenuItem* _menu_add_cv_output;
- Gtk::MenuItem* _menu_add_event_input;
- Gtk::MenuItem* _menu_add_event_output;
- Gtk::MenuItem* _menu_load_plugin;
- Gtk::MenuItem* _menu_load_graph;
- Gtk::MenuItem* _menu_new_graph;
- Gtk::MenuItem* _menu_properties;
- Gtk::CheckMenuItem* _menu_edit;
-
- bool _human_names;
- bool _show_port_names;
- bool _menu_dirty;
-};
-
-} // namespace GUI
-} // namespace Ingen
-
-#endif // INGEN_GUI_GRAPHCANVAS_HPP
diff --git a/src/gui/GraphPortModule.cpp b/src/gui/GraphPortModule.cpp
deleted file mode 100644
index 5987b0e3..00000000
--- a/src/gui/GraphPortModule.cpp
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- 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 <cassert>
-#include <string>
-#include <utility>
-
-#include "ingen/Configuration.hpp"
-#include "ingen/Interface.hpp"
-#include "ingen/client/BlockModel.hpp"
-#include "ingen/client/GraphModel.hpp"
-
-#include "App.hpp"
-#include "Style.hpp"
-#include "GraphCanvas.hpp"
-#include "GraphPortModule.hpp"
-#include "GraphWindow.hpp"
-#include "Port.hpp"
-#include "PortMenu.hpp"
-#include "RenameWindow.hpp"
-#include "WidgetFactory.hpp"
-#include "WindowFactory.hpp"
-
-namespace Ingen {
-
-using namespace Client;
-
-namespace GUI {
-
-GraphPortModule::GraphPortModule(GraphCanvas& canvas,
- SPtr<const Client::PortModel> model)
- : Ganv::Module(canvas, "", 0, 0, false) // FIXME: coords?
- , _model(model)
- , _port(nullptr)
-{
- assert(model);
-
- assert(dynamic_ptr_cast<const GraphModel>(model->parent()));
-
- set_stacked(model->polyphonic());
- if (model->is_input() && !model->is_numeric()) {
- set_is_source(true);
- }
-
- model->signal_property().connect(
- sigc::mem_fun(this, &GraphPortModule::property_changed));
-
- signal_moved().connect(
- sigc::mem_fun(this, &GraphPortModule::store_location));
-}
-
-GraphPortModule*
-GraphPortModule::create(GraphCanvas& canvas,
- SPtr<const PortModel> model)
-{
- GraphPortModule* ret = new GraphPortModule(canvas, model);
- Port* port = Port::create(canvas.app(), *ret, model, true);
-
- ret->set_port(port);
- if (model->is_numeric()) {
- port->show_control();
- }
-
- for (const auto& p : model->properties()) {
- ret->property_changed(p.first, p.second);
- }
-
- return ret;
-}
-
-App&
-GraphPortModule::app() const
-{
- return ((GraphCanvas*)canvas())->app();
-}
-
-bool
-GraphPortModule::show_menu(GdkEventButton* ev)
-{
- return _port->show_menu(ev);
-}
-
-void
-GraphPortModule::store_location(double ax, double ay)
-{
- const URIs& uris = app().uris();
-
- const Atom x(app().forge().make(static_cast<float>(ax)));
- const Atom y(app().forge().make(static_cast<float>(ay)));
-
- if (x != _model->get_property(uris.ingen_canvasX) ||
- y != _model->get_property(uris.ingen_canvasY))
- {
- app().interface()->put(
- _model->uri(),
- {{uris.ingen_canvasX, Property(x, Property::Graph::INTERNAL)},
- {uris.ingen_canvasY, Property(y, Property::Graph::INTERNAL)}});
- }
-}
-
-void
-GraphPortModule::show_human_names(bool b)
-{
- const URIs& uris = app().uris();
- const Atom& name = _model->get_property(uris.lv2_name);
- if (b && name.type() == uris.forge.String) {
- set_name(name.ptr<char>());
- } else {
- set_name(_model->symbol().c_str());
- }
-}
-
-void
-GraphPortModule::set_name(const std::string& n)
-{
- _port->set_label(n.c_str());
-}
-
-void
-GraphPortModule::property_changed(const URI& key, const Atom& value)
-{
- const URIs& uris = app().uris();
- if (value.type() == uris.forge.Float) {
- if (key == uris.ingen_canvasX) {
- move_to(value.get<float>(), get_y());
- } else if (key == uris.ingen_canvasY) {
- move_to(get_x(), value.get<float>());
- }
- } else if (value.type() == uris.forge.String) {
- if (key == uris.lv2_name &&
- app().world()->conf().option("human-names").get<int32_t>()) {
- set_name(value.ptr<char>());
- } else if (key == uris.lv2_symbol &&
- !app().world()->conf().option("human-names").get<int32_t>()) {
- set_name(value.ptr<char>());
- }
- } else if (value.type() == uris.forge.Bool) {
- if (key == uris.ingen_polyphonic) {
- set_stacked(value.get<int32_t>());
- }
- }
-}
-
-void
-GraphPortModule::set_selected(gboolean b)
-{
- if (b != get_selected()) {
- Module::set_selected(b);
- }
-}
-
-} // namespace GUI
-} // namespace Ingen
diff --git a/src/gui/GraphPortModule.hpp b/src/gui/GraphPortModule.hpp
deleted file mode 100644
index 97bc2e5b..00000000
--- a/src/gui/GraphPortModule.hpp
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- 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_GUI_GRAPHPORTMODULE_HPP
-#define INGEN_GUI_GRAPHPORTMODULE_HPP
-
-#include <string>
-
-#include "ganv/Module.hpp"
-
-#include "Port.hpp"
-
-namespace Raul { class Atom; }
-
-namespace Ingen { namespace Client {
-class PortModel;
-} }
-
-namespace Ingen {
-namespace GUI {
-
-class GraphCanvas;
-class Port;
-class PortMenu;
-
-/** A "module" to represent a graph's port on its own canvas.
- *
- * Translation: This is the nameless single port pseudo module thingy.
- *
- * \ingroup GUI
- */
-class GraphPortModule : public Ganv::Module
-{
-public:
- static GraphPortModule* create(
- GraphCanvas& canvas,
- SPtr<const Client::PortModel> model);
-
- App& app() const;
-
- virtual void store_location(double ax, double ay);
- void show_human_names(bool b);
-
- void set_name(const std::string& n);
-
- SPtr<const Client::PortModel> port() const { return _model; }
-
-protected:
- GraphPortModule(GraphCanvas& canvas,
- SPtr<const Client::PortModel> model);
-
- bool show_menu(GdkEventButton* ev);
- void set_selected(gboolean b);
-
- void set_port(Port* port) { _port = port; }
-
- void property_changed(const URI& key, const Atom& value);
-
- SPtr<const Client::PortModel> _model;
- Port* _port;
-};
-
-} // namespace GUI
-} // namespace Ingen
-
-#endif // INGEN_GUI_GRAPHPORTMODULE_HPP
diff --git a/src/gui/GraphTreeWindow.cpp b/src/gui/GraphTreeWindow.cpp
deleted file mode 100644
index 1eb6557b..00000000
--- a/src/gui/GraphTreeWindow.cpp
+++ /dev/null
@@ -1,235 +0,0 @@
-/*
- 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 "App.hpp"
-#include "GraphTreeWindow.hpp"
-#include "SubgraphModule.hpp"
-#include "WindowFactory.hpp"
-#include "ingen/Interface.hpp"
-#include "ingen/Log.hpp"
-#include "ingen/client/ClientStore.hpp"
-#include "ingen/client/GraphModel.hpp"
-#include "raul/Path.hpp"
-
-namespace Ingen {
-
-using namespace Client;
-
-namespace GUI {
-
-GraphTreeWindow::GraphTreeWindow(BaseObjectType* cobject,
- const Glib::RefPtr<Gtk::Builder>& xml)
- : Window(cobject)
- , _app(nullptr)
- , _enable_signal(true)
-{
- xml->get_widget_derived("graphs_treeview", _graphs_treeview);
-
- _graph_treestore = Gtk::TreeStore::create(_graph_tree_columns);
- _graphs_treeview->set_window(this);
- _graphs_treeview->set_model(_graph_treestore);
- Gtk::TreeViewColumn* name_col = Gtk::manage(
- new Gtk::TreeViewColumn("Graph", _graph_tree_columns.name_col));
- Gtk::TreeViewColumn* enabled_col = Gtk::manage(
- new Gtk::TreeViewColumn("Run", _graph_tree_columns.enabled_col));
- name_col->set_resizable(true);
- name_col->set_expand(true);
-
- _graphs_treeview->append_column(*name_col);
- _graphs_treeview->append_column(*enabled_col);
- Gtk::CellRendererToggle* enabled_renderer = dynamic_cast<Gtk::CellRendererToggle*>(
- _graphs_treeview->get_column_cell_renderer(1));
- enabled_renderer->property_activatable() = true;
-
- _graph_tree_selection = _graphs_treeview->get_selection();
-
- _graphs_treeview->signal_row_activated().connect(
- sigc::mem_fun(this, &GraphTreeWindow::event_graph_activated));
- enabled_renderer->signal_toggled().connect(
- sigc::mem_fun(this, &GraphTreeWindow::event_graph_enabled_toggled));
-
- _graphs_treeview->columns_autosize();
-}
-
-void
-GraphTreeWindow::init(App& app, ClientStore& store)
-{
- _app = &app;
- store.signal_new_object().connect(
- sigc::mem_fun(this, &GraphTreeWindow::new_object));
-}
-
-void
-GraphTreeWindow::new_object(SPtr<ObjectModel> object)
-{
- SPtr<GraphModel> graph = dynamic_ptr_cast<GraphModel>(object);
- if (graph) {
- add_graph(graph);
- }
-}
-
-void
-GraphTreeWindow::add_graph(SPtr<GraphModel> pm)
-{
- if (!pm->parent()) {
- Gtk::TreeModel::iterator iter = _graph_treestore->append();
- Gtk::TreeModel::Row row = *iter;
- if (pm->path().is_root()) {
- row[_graph_tree_columns.name_col] = _app->interface()->uri().string();
- } else {
- row[_graph_tree_columns.name_col] = pm->symbol().c_str();
- }
- row[_graph_tree_columns.enabled_col] = pm->enabled();
- row[_graph_tree_columns.graph_model_col] = pm;
- _graphs_treeview->expand_row(_graph_treestore->get_path(iter), true);
- } else {
- Gtk::TreeModel::Children children = _graph_treestore->children();
- Gtk::TreeModel::iterator c = find_graph(children, pm->parent());
-
- if (c != children.end()) {
- Gtk::TreeModel::iterator iter = _graph_treestore->append(c->children());
- Gtk::TreeModel::Row row = *iter;
- row[_graph_tree_columns.name_col] = pm->symbol().c_str();
- row[_graph_tree_columns.enabled_col] = pm->enabled();
- row[_graph_tree_columns.graph_model_col] = pm;
- _graphs_treeview->expand_row(_graph_treestore->get_path(iter), true);
- }
- }
-
- pm->signal_property().connect(
- sigc::bind(sigc::mem_fun(this, &GraphTreeWindow::graph_property_changed),
- pm));
-
- pm->signal_moved().connect(
- sigc::bind(sigc::mem_fun(this, &GraphTreeWindow::graph_moved),
- pm));
-
- pm->signal_destroyed().connect(
- sigc::bind(sigc::mem_fun(this, &GraphTreeWindow::remove_graph),
- pm));
-}
-
-void
-GraphTreeWindow::remove_graph(SPtr<GraphModel> pm)
-{
- Gtk::TreeModel::iterator i = find_graph(_graph_treestore->children(), pm);
- if (i != _graph_treestore->children().end()) {
- _graph_treestore->erase(i);
- }
-}
-
-Gtk::TreeModel::iterator
-GraphTreeWindow::find_graph(Gtk::TreeModel::Children root,
- SPtr<Client::ObjectModel> graph)
-{
- for (Gtk::TreeModel::iterator c = root.begin(); c != root.end(); ++c) {
- SPtr<GraphModel> pm = (*c)[_graph_tree_columns.graph_model_col];
- if (graph == pm) {
- return c;
- } else if ((*c)->children().size() > 0) {
- Gtk::TreeModel::iterator ret = find_graph(c->children(), graph);
- if (ret != c->children().end()) {
- return ret;
- }
- }
- }
- return root.end();
-}
-
-/** Show the context menu for the selected graph in the graphs treeview.
- */
-void
-GraphTreeWindow::show_graph_menu(GdkEventButton* ev)
-{
- Gtk::TreeModel::iterator active = _graph_tree_selection->get_selected();
- if (active) {
- Gtk::TreeModel::Row row = *active;
- SPtr<GraphModel> pm = row[_graph_tree_columns.graph_model_col];
- if (pm) {
- _app->log().warn("TODO: graph menu from tree window");
- }
- }
-}
-
-void
-GraphTreeWindow::event_graph_activated(const Gtk::TreeModel::Path& path,
- Gtk::TreeView::Column* col)
-{
- Gtk::TreeModel::iterator active = _graph_treestore->get_iter(path);
- Gtk::TreeModel::Row row = *active;
- SPtr<GraphModel> pm = row[_graph_tree_columns.graph_model_col];
-
- _app->window_factory()->present_graph(pm);
-}
-
-void
-GraphTreeWindow::event_graph_enabled_toggled(const Glib::ustring& path_str)
-{
- Gtk::TreeModel::Path path(path_str);
- Gtk::TreeModel::iterator active = _graph_treestore->get_iter(path);
- Gtk::TreeModel::Row row = *active;
-
- SPtr<GraphModel> pm = row[_graph_tree_columns.graph_model_col];
- assert(pm);
-
- if (_enable_signal) {
- _app->set_property(pm->uri(),
- _app->uris().ingen_enabled,
- _app->forge().make((bool)!pm->enabled()));
- }
-}
-
-void
-GraphTreeWindow::graph_property_changed(const URI& key,
- const Atom& value,
- SPtr<GraphModel> graph)
-{
- const URIs& uris = _app->uris();
- _enable_signal = false;
- if (key == uris.ingen_enabled && value.type() == uris.forge.Bool) {
- Gtk::TreeModel::iterator i = find_graph(_graph_treestore->children(), graph);
- if (i != _graph_treestore->children().end()) {
- Gtk::TreeModel::Row row = *i;
- row[_graph_tree_columns.enabled_col] = value.get<int32_t>();
- } else {
- _app->log().error(fmt("Unable to find graph %1%\n")
- % graph->path());
- }
- }
- _enable_signal = true;
-}
-
-void
-GraphTreeWindow::graph_moved(SPtr<GraphModel> graph)
-{
- _enable_signal = false;
-
- Gtk::TreeModel::iterator i
- = find_graph(_graph_treestore->children(), graph);
-
- if (i != _graph_treestore->children().end()) {
- Gtk::TreeModel::Row row = *i;
- row[_graph_tree_columns.name_col] = graph->symbol().c_str();
- } else {
- _app->log().error(fmt("Unable to find graph %1%\n")
- % graph->path());
- }
-
- _enable_signal = true;
-}
-
-} // namespace GUI
-} // namespace Ingen
diff --git a/src/gui/GraphTreeWindow.hpp b/src/gui/GraphTreeWindow.hpp
deleted file mode 100644
index 005f39a8..00000000
--- a/src/gui/GraphTreeWindow.hpp
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- 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_GUI_GRAPHTREEWINDOW_HPP
-#define INGEN_GUI_GRAPHTREEWINDOW_HPP
-
-#include <gtkmm/builder.h>
-#include <gtkmm/treemodel.h>
-#include <gtkmm/treestore.h>
-#include <gtkmm/treeview.h>
-
-#include "Window.hpp"
-
-namespace Raul { class Path; }
-
-namespace Ingen {
-
-namespace Client { class ClientStore; class ObjectModel; }
-
-namespace GUI {
-
-class GraphWindow;
-class GraphTreeView;
-
-/** Window with a TreeView of all loaded graphs.
- *
- * \ingroup GUI
- */
-class GraphTreeWindow : public Window
-{
-public:
- GraphTreeWindow(BaseObjectType* cobject,
- const Glib::RefPtr<Gtk::Builder>& xml);
-
- void init(App& app, Client::ClientStore& store);
-
- void new_object(SPtr<Client::ObjectModel> object);
-
- void graph_property_changed(const URI& key,
- const Atom& value,
- SPtr<Client::GraphModel> graph);
-
- void graph_moved(SPtr<Client::GraphModel> graph);
-
- void add_graph(SPtr<Client::GraphModel> pm);
- void remove_graph(SPtr<Client::GraphModel> pm);
- void show_graph_menu(GdkEventButton* ev);
-
-protected:
- void event_graph_activated(const Gtk::TreeModel::Path& path,
- Gtk::TreeView::Column* col);
-
- void event_graph_enabled_toggled(const Glib::ustring& path_str);
-
- Gtk::TreeModel::iterator find_graph(
- Gtk::TreeModel::Children root,
- SPtr<Client::ObjectModel> graph);
-
- GraphTreeView* _graphs_treeview;
-
- struct GraphTreeModelColumns : public Gtk::TreeModel::ColumnRecord
- {
- GraphTreeModelColumns() {
- add(name_col);
- add(enabled_col);
- add(graph_model_col);
- }
-
- Gtk::TreeModelColumn<Glib::ustring> name_col;
- Gtk::TreeModelColumn<bool> enabled_col;
- Gtk::TreeModelColumn<SPtr<Client::GraphModel> > graph_model_col;
- };
-
- App* _app;
- GraphTreeModelColumns _graph_tree_columns;
- Glib::RefPtr<Gtk::TreeStore> _graph_treestore;
- Glib::RefPtr<Gtk::TreeSelection> _graph_tree_selection;
- bool _enable_signal;
-};
-
-/** Derived TreeView class to support context menus for graphs */
-class GraphTreeView : public Gtk::TreeView
-{
-public:
- GraphTreeView(BaseObjectType* cobject,
- const Glib::RefPtr<Gtk::Builder>& xml)
- : Gtk::TreeView(cobject)
- , _window(NULL)
- {}
-
- void set_window(GraphTreeWindow* win) { _window = win; }
-
- bool on_button_press_event(GdkEventButton* ev) {
- bool ret = Gtk::TreeView::on_button_press_event(ev);
-
- if ((ev->type == GDK_BUTTON_PRESS) && (ev->button == 3))
- _window->show_graph_menu(ev);
-
- return ret;
- }
-
-private:
- GraphTreeWindow* _window;
-
-}; // struct GraphTreeView
-
-} // namespace GUI
-} // namespace Ingen
-
-#endif // INGEN_GUI_GRAPHTREEWINDOW_HPP
diff --git a/src/gui/GraphView.cpp b/src/gui/GraphView.cpp
deleted file mode 100644
index e6361249..00000000
--- a/src/gui/GraphView.cpp
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- 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 <cassert>
-#include <fstream>
-
-#include "ingen/Interface.hpp"
-#include "ingen/client/GraphModel.hpp"
-
-#include "App.hpp"
-#include "LoadPluginWindow.hpp"
-#include "NewSubgraphWindow.hpp"
-#include "GraphCanvas.hpp"
-#include "GraphTreeWindow.hpp"
-#include "GraphView.hpp"
-#include "WidgetFactory.hpp"
-
-namespace Ingen {
-
-using namespace Client;
-
-namespace GUI {
-
-GraphView::GraphView(BaseObjectType* cobject,
- const Glib::RefPtr<Gtk::Builder>& xml)
- : Gtk::Box(cobject)
- , _app(nullptr)
- , _breadcrumb_container(nullptr)
- , _enable_signal(true)
-{
- property_visible() = false;
-
- xml->get_widget("graph_view_breadcrumb_container", _breadcrumb_container);
- xml->get_widget("graph_view_toolbar", _toolbar);
- xml->get_widget("graph_view_process_but", _process_but);
- xml->get_widget("graph_view_poly_spin", _poly_spin);
- xml->get_widget("graph_view_scrolledwindow", _canvas_scrolledwindow);
-
- _toolbar->set_toolbar_style(Gtk::TOOLBAR_ICONS);
- _canvas_scrolledwindow->property_hadjustment().get_value()->set_step_increment(10);
- _canvas_scrolledwindow->property_vadjustment().get_value()->set_step_increment(10);
-}
-
-GraphView::~GraphView()
-{
- _canvas_scrolledwindow->remove();
-}
-
-void
-GraphView::init(App& app)
-{
- _app = &app;
-}
-
-void
-GraphView::set_graph(SPtr<const GraphModel> graph)
-{
- assert(!_canvas); // FIXME: remove
-
- assert(_breadcrumb_container); // ensure created
-
- _graph = graph;
- _canvas = SPtr<GraphCanvas>(new GraphCanvas(*_app, graph, 1600*2, 1200*2));
- _canvas->build();
-
- _canvas_scrolledwindow->add(_canvas->widget());
-
- _poly_spin->set_range(1, 128);
- _poly_spin->set_increments(1, 4);
- _poly_spin->set_value(graph->internal_poly());
-
- for (const auto& p : graph->properties()) {
- property_changed(p.first, p.second);
- }
-
- // Connect model signals to track state
- graph->signal_property().connect(
- sigc::mem_fun(this, &GraphView::property_changed));
-
- // Connect widget signals to do things
- _process_but->signal_toggled().connect(
- sigc::mem_fun(this, &GraphView::process_toggled));
-
- _poly_spin->signal_value_changed().connect(
- sigc::mem_fun(*this, &GraphView::poly_changed));
-
- _canvas->widget().grab_focus();
-}
-
-SPtr<GraphView>
-GraphView::create(App& app, SPtr<const GraphModel> graph)
-{
- GraphView* result = nullptr;
- Glib::RefPtr<Gtk::Builder> xml = WidgetFactory::create("warehouse_win");
- xml->get_widget_derived("graph_view_box", result);
- result->init(app);
- result->set_graph(graph);
- return SPtr<GraphView>(result);
-}
-
-void
-GraphView::process_toggled()
-{
- if (!_enable_signal) {
- return;
- }
-
- _app->set_property(_graph->uri(),
- _app->uris().ingen_enabled,
- _app->forge().make((bool)_process_but->get_active()));
-}
-
-void
-GraphView::poly_changed()
-{
- const int poly = _poly_spin->get_value_as_int();
- if (_enable_signal && poly != (int)_graph->internal_poly()) {
- _app->set_property(_graph->uri(),
- _app->uris().ingen_polyphony,
- _app->forge().make(poly));
- }
-}
-
-void
-GraphView::property_changed(const URI& predicate, const Atom& value)
-{
- _enable_signal = false;
- if (predicate == _app->uris().ingen_enabled) {
- if (value.type() == _app->uris().forge.Bool) {
- _process_but->set_active(value.get<int32_t>());
- }
- } else if (predicate == _app->uris().ingen_polyphony) {
- if (value.type() == _app->uris().forge.Int) {
- _poly_spin->set_value(value.get<int32_t>());
- }
- }
- _enable_signal = true;
-}
-
-} // namespace GUI
-} // namespace Ingen
diff --git a/src/gui/GraphView.hpp b/src/gui/GraphView.hpp
deleted file mode 100644
index 03569831..00000000
--- a/src/gui/GraphView.hpp
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- 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_GUI_GRAPHVIEW_HPP
-#define INGEN_GUI_GRAPHVIEW_HPP
-
-#include <gtkmm/box.h>
-#include <gtkmm/builder.h>
-#include <gtkmm/scrolledwindow.h>
-#include <gtkmm/spinbutton.h>
-#include <gtkmm/toggletoolbutton.h>
-#include <gtkmm/toolbar.h>
-#include <gtkmm/toolitem.h>
-#include <gtkmm/toolitem.h>
-
-#include "ingen/types.hpp"
-
-namespace Raul { class Atom; }
-
-namespace Ingen {
-
-namespace Client {
-class PortModel;
-class MetadataModel;
-class GraphModel;
-class ObjectModel;
-}
-
-namespace GUI {
-
-class App;
-class LoadPluginWindow;
-class NewSubgraphWindow;
-class GraphCanvas;
-class GraphDescriptionWindow;
-class SubgraphModule;
-
-/** The graph specific contents of a GraphWindow (ie the canvas and whatever else).
- *
- * \ingroup GUI
- */
-class GraphView : public Gtk::Box
-{
-public:
- GraphView(BaseObjectType* cobject,
- const Glib::RefPtr<Gtk::Builder>& xml);
-
- ~GraphView();
-
- void init(App& app);
-
- SPtr<GraphCanvas> canvas() const { return _canvas; }
- SPtr<const Client::GraphModel> graph() const { return _graph; }
- Gtk::ToolItem* breadcrumb_container() const { return _breadcrumb_container; }
-
- static SPtr<GraphView> create(App& app,
- SPtr<const Client::GraphModel> graph);
-
-private:
- void set_graph(SPtr<const Client::GraphModel> graph);
-
- void process_toggled();
- void poly_changed();
- void clear_clicked();
-
- void property_changed(const URI& predicate, const Atom& value);
-
- App* _app;
-
- SPtr<const Client::GraphModel> _graph;
- SPtr<GraphCanvas> _canvas;
-
- Gtk::ScrolledWindow* _canvas_scrolledwindow;
- Gtk::Toolbar* _toolbar;
- Gtk::ToggleToolButton* _process_but;
- Gtk::SpinButton* _poly_spin;
- Gtk::ToolItem* _breadcrumb_container;
-
- bool _enable_signal;
-};
-
-} // namespace GUI
-} // namespace Ingen
-
-#endif // INGEN_GUI_GRAPHVIEW_HPP
diff --git a/src/gui/GraphWindow.cpp b/src/gui/GraphWindow.cpp
deleted file mode 100644
index b5a89c79..00000000
--- a/src/gui/GraphWindow.cpp
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- 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/client/ClientStore.hpp"
-#include "ingen/client/GraphModel.hpp"
-
-#include "App.hpp"
-#include "GraphCanvas.hpp"
-#include "GraphView.hpp"
-#include "GraphWindow.hpp"
-#include "WindowFactory.hpp"
-
-namespace Ingen {
-namespace GUI {
-
-GraphWindow::GraphWindow(BaseObjectType* cobject,
- const Glib::RefPtr<Gtk::Builder>& xml)
- : Window(cobject)
- , _box(nullptr)
- , _position_stored(false)
- , _x(0)
- , _y(0)
-{
- property_visible() = false;
-
- xml->get_widget_derived("graph_win_vbox", _box);
-
- set_title("Ingen");
-}
-
-GraphWindow::~GraphWindow()
-{
- delete _box;
-}
-
-void
-GraphWindow::init_window(App& app)
-{
- Window::init_window(app);
- _box->init_box(app);
- _box->set_window(this);
-}
-
-void
-GraphWindow::on_show()
-{
- if (_position_stored) {
- move(_x, _y);
- }
-
- Gtk::Window::on_show();
-
- _box->view()->canvas()->widget().grab_focus();
-}
-
-void
-GraphWindow::on_hide()
-{
- _position_stored = true;
- get_position(_x, _y);
- Gtk::Window::on_hide();
-}
-
-bool
-GraphWindow::on_key_press_event(GdkEventKey* event)
-{
- // Disable Window C-w handling so quit works correctly
- return Gtk::Window::on_key_press_event(event);
-}
-
-} // namespace GUI
-} // namespace Ingen
diff --git a/src/gui/GraphWindow.hpp b/src/gui/GraphWindow.hpp
deleted file mode 100644
index b4e51d7b..00000000
--- a/src/gui/GraphWindow.hpp
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- 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_GUI_GRAPH_WINDOW_HPP
-#define INGEN_GUI_GRAPH_WINDOW_HPP
-
-#include <string>
-
-#include <gtkmm/builder.h>
-
-#include "ingen/types.hpp"
-
-#include "GraphBox.hpp"
-#include "Window.hpp"
-
-namespace Ingen {
-
-namespace Client {
-class GraphModel;
-}
-
-namespace GUI {
-
-/** A window for a graph.
- *
- * \ingroup GUI
- */
-class GraphWindow : public Window
-{
-public:
- GraphWindow(BaseObjectType* cobject,
- const Glib::RefPtr<Gtk::Builder>& xml);
-
- ~GraphWindow();
-
- void init_window(App& app);
-
- SPtr<const Client::GraphModel> graph() const { return _box->graph(); }
- GraphBox* box() const { return _box; }
-
- bool documentation_is_visible() { return _box->documentation_is_visible(); }
-
- void set_documentation(const std::string& doc, bool html) {
- _box->set_documentation(doc, html);
- }
-
- void show_port_status(const Client::PortModel* model,
- const Atom& value) {
- _box->show_port_status(model, value);
- }
-
-protected:
- void on_hide();
- void on_show();
- bool on_key_press_event(GdkEventKey* event);
-
-private:
- GraphBox* _box;
- bool _position_stored;
- int _x;
- int _y;
-};
-
-} // namespace GUI
-} // namespace Ingen
-
-#endif // INGEN_GUI_GRAPH_WINDOW_HPP
diff --git a/src/gui/LoadGraphWindow.cpp b/src/gui/LoadGraphWindow.cpp
deleted file mode 100644
index b02ca510..00000000
--- a/src/gui/LoadGraphWindow.cpp
+++ /dev/null
@@ -1,257 +0,0 @@
-/*
- 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 <cassert>
-#include <list>
-#include <string>
-
-#include <boost/optional.hpp>
-#include <glibmm/miscutils.h>
-
-#include "ingen/Configuration.hpp"
-#include "ingen/Interface.hpp"
-#include "ingen/client/BlockModel.hpp"
-#include "ingen/client/ClientStore.hpp"
-#include "ingen/client/GraphModel.hpp"
-#include "ingen/runtime_paths.hpp"
-
-#include "App.hpp"
-#include "GraphView.hpp"
-#include "LoadGraphWindow.hpp"
-#include "Style.hpp"
-#include "ThreadedLoader.hpp"
-
-namespace Ingen {
-
-using namespace Client;
-
-namespace GUI {
-
-LoadGraphWindow::LoadGraphWindow(BaseObjectType* cobject,
- const Glib::RefPtr<Gtk::Builder>& xml)
- : Gtk::FileChooserDialog(cobject)
- , _app(nullptr)
- , _merge_ports(false)
-{
- xml->get_widget("load_graph_symbol_label", _symbol_label);
- xml->get_widget("load_graph_symbol_entry", _symbol_entry);
- xml->get_widget("load_graph_ports_label", _ports_label);
- xml->get_widget("load_graph_merge_ports_radio", _merge_ports_radio);
- xml->get_widget("load_graph_insert_ports_radio", _insert_ports_radio);
- xml->get_widget("load_graph_poly_voices_radio", _poly_voices_radio);
- xml->get_widget("load_graph_poly_from_file_radio", _poly_from_file_radio);
- xml->get_widget("load_graph_poly_spinbutton", _poly_spinbutton);
- xml->get_widget("load_graph_ok_button", _ok_button);
- xml->get_widget("load_graph_cancel_button", _cancel_button);
-
- _cancel_button->signal_clicked().connect(
- sigc::mem_fun(this, &LoadGraphWindow::cancel_clicked));
- _ok_button->signal_clicked().connect(
- sigc::mem_fun(this, &LoadGraphWindow::ok_clicked));
- _merge_ports_radio->signal_toggled().connect(
- sigc::mem_fun(this, &LoadGraphWindow::merge_ports_selected));
- _insert_ports_radio->signal_toggled().connect(
- sigc::mem_fun(this, &LoadGraphWindow::insert_ports_selected));
- _poly_from_file_radio->signal_toggled().connect(
- sigc::bind(sigc::mem_fun(_poly_spinbutton, &Gtk::SpinButton::set_sensitive),
- false));
- _poly_voices_radio->signal_toggled().connect(
- sigc::bind(sigc::mem_fun(_poly_spinbutton, &Gtk::SpinButton::set_sensitive),
- true));
-
- signal_selection_changed().connect(
- sigc::mem_fun(this, &LoadGraphWindow::selection_changed));
-
- Gtk::FileFilter file_filter;
- file_filter.add_pattern("*.ttl");
- file_filter.set_name("Ingen graph files (*.ttl)");
- add_filter(file_filter);
-
- Gtk::FileFilter bundle_filter;
- bundle_filter.add_pattern("*.ingen");
- bundle_filter.set_name("Ingen bundles (*.ingen)");
- add_filter(bundle_filter);
-
- property_select_multiple() = true;
-
- // Add global examples directory to "shortcut folders" (bookmarks)
- const FilePath examples_dir = Ingen::data_file_path("graphs");
- if (Glib::file_test(examples_dir, Glib::FILE_TEST_IS_DIR)) {
- add_shortcut_folder(examples_dir.string());
- }
-}
-
-void
-LoadGraphWindow::present(SPtr<const GraphModel> graph,
- bool import,
- Properties data)
-{
- _import = import;
- set_graph(graph);
- _symbol_label->property_visible() = !import;
- _symbol_entry->property_visible() = !import;
- _ports_label->property_visible() = _import;
- _merge_ports_radio->property_visible() = _import;
- _insert_ports_radio->property_visible() = _import;
- _initial_data = data;
- Gtk::Window::present();
-}
-
-/** Sets the graph model for this window and initializes everything.
- *
- * This function MUST be called before using the window in any way!
- */
-void
-LoadGraphWindow::set_graph(SPtr<const GraphModel> graph)
-{
- _graph = graph;
- _symbol_entry->set_text("");
- _symbol_entry->set_sensitive(!_import);
- _poly_spinbutton->set_value(graph->internal_poly());
-}
-
-void
-LoadGraphWindow::on_show()
-{
- const Atom& dir = _app->world()->conf().option("graph-directory");
- if (dir.is_valid()) {
- set_current_folder(dir.ptr<char>());
- }
- Gtk::FileChooserDialog::on_show();
-}
-
-void
-LoadGraphWindow::merge_ports_selected()
-{
- _merge_ports = true;
-}
-
-void
-LoadGraphWindow::insert_ports_selected()
-{
- _merge_ports = false;
-}
-
-void
-LoadGraphWindow::ok_clicked()
-{
- if (!_graph) {
- hide();
- return;
- }
-
- const URIs& uris = _app->uris();
-
- if (_poly_voices_radio->get_active()) {
- _initial_data.emplace(
- uris.ingen_polyphony,
- _app->forge().make(_poly_spinbutton->get_value_as_int()));
- }
-
- if (get_uri() == "") {
- return;
- }
-
- if (_import) {
- // If unset load_graph will load value
- boost::optional<Raul::Path> parent;
- boost::optional<Raul::Symbol> symbol;
- if (!_graph->path().is_root()) {
- parent = _graph->path().parent();
- symbol = _graph->symbol();
- }
-
- _app->loader()->load_graph(
- true, FilePath(get_filename()), parent, symbol, _initial_data);
-
- } else {
- std::list<Glib::ustring> uri_list = get_filenames();
- for (auto u : uri_list) {
- // Cascade
- Atom& x = _initial_data.find(uris.ingen_canvasX)->second;
- x = _app->forge().make(x.get<float>() + 20.0f);
- Atom& y = _initial_data.find(uris.ingen_canvasY)->second;
- y = _app->forge().make(y.get<float>() + 20.0f);
-
- Raul::Symbol symbol(symbol_from_filename(u));
- if (uri_list.size() == 1 && _symbol_entry->get_text() != "") {
- symbol = Raul::Symbol::symbolify(_symbol_entry->get_text());
- }
-
- symbol = avoid_symbol_clash(symbol);
-
- _app->loader()->load_graph(
- false, FilePath(URI(u).path()), _graph->path(), symbol, _initial_data);
- }
- }
-
- _graph.reset();
- hide();
-
- _app->world()->conf().set(
- "graph-directory",
- _app->world()->forge().alloc(get_current_folder()));
-}
-
-void
-LoadGraphWindow::cancel_clicked()
-{
- _graph.reset();
- hide();
-}
-
-Raul::Symbol
-LoadGraphWindow::symbol_from_filename(const Glib::ustring& filename)
-{
- std::string symbol_str = Glib::path_get_basename(get_filename());
- symbol_str = symbol_str.substr(0, symbol_str.find('.'));
- return Raul::Symbol::symbolify(symbol_str);
-}
-
-Raul::Symbol
-LoadGraphWindow::avoid_symbol_clash(const Raul::Symbol& symbol)
-{
- unsigned offset = _app->store()->child_name_offset(
- _graph->path(), symbol);
-
- if (offset != 0) {
- std::stringstream ss;
- ss << symbol << "_" << offset;
- return Raul::Symbol(ss.str());
- } else {
- return symbol;
- }
-}
-
-void
-LoadGraphWindow::selection_changed()
-{
- if (_import) {
- return;
- }
-
- if (get_filenames().size() != 1) {
- _symbol_entry->set_text("");
- _symbol_entry->set_sensitive(false);
- } else {
- _symbol_entry->set_text(
- avoid_symbol_clash(symbol_from_filename(get_filename())).c_str());
- _symbol_entry->set_sensitive(true);
- }
-}
-
-} // namespace GUI
-} // namespace Ingen
diff --git a/src/gui/LoadGraphWindow.hpp b/src/gui/LoadGraphWindow.hpp
deleted file mode 100644
index 8ec5ed4b..00000000
--- a/src/gui/LoadGraphWindow.hpp
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- 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_GUI_LOADGRAPHWINDOW_HPP
-#define INGEN_GUI_LOADGRAPHWINDOW_HPP
-
-#include <gtkmm/builder.h>
-#include <gtkmm/button.h>
-#include <gtkmm/entry.h>
-#include <gtkmm/filechooserdialog.h>
-#include <gtkmm/label.h>
-#include <gtkmm/radiobutton.h>
-#include <gtkmm/spinbutton.h>
-
-#include "ingen/Node.hpp"
-#include "ingen/types.hpp"
-
-namespace Ingen {
-
-namespace Client { class GraphModel; }
-
-namespace GUI {
-
-/** 'Load Graph' Window.
- *
- * Loaded from XML as a derived object.
- *
- * \ingroup GUI
- */
-class LoadGraphWindow : public Gtk::FileChooserDialog
-{
-public:
- LoadGraphWindow(BaseObjectType* cobject,
- const Glib::RefPtr<Gtk::Builder>& xml);
-
- void init(App& app) { _app = &app; }
-
- void set_graph(SPtr<const Client::GraphModel> graph);
-
- void present(SPtr<const Client::GraphModel> graph,
- bool import,
- Properties data);
-
-protected:
- void on_show();
-
-private:
- void merge_ports_selected();
- void insert_ports_selected();
-
- void selection_changed();
- void cancel_clicked();
- void ok_clicked();
-
- Raul::Symbol symbol_from_filename(const Glib::ustring& filename);
- Raul::Symbol avoid_symbol_clash(const Raul::Symbol& symbol);
-
- App* _app;
-
- Properties _initial_data;
-
- SPtr<const Client::GraphModel> _graph;
-
- Gtk::Label* _symbol_label;
- Gtk::Entry* _symbol_entry;
- Gtk::Label* _ports_label;
- Gtk::RadioButton* _merge_ports_radio;
- Gtk::RadioButton* _insert_ports_radio;
- Gtk::RadioButton* _poly_voices_radio;
- Gtk::RadioButton* _poly_from_file_radio;
- Gtk::SpinButton* _poly_spinbutton;
- Gtk::Button* _ok_button;
- Gtk::Button* _cancel_button;
-
- bool _import;
- bool _merge_ports;
-};
-
-} // namespace GUI
-} // namespace Ingen
-
-#endif // INGEN_GUI_LOADGRAPHWINDOW_HPP
diff --git a/src/gui/LoadPluginWindow.cpp b/src/gui/LoadPluginWindow.cpp
deleted file mode 100644
index bd08f457..00000000
--- a/src/gui/LoadPluginWindow.cpp
+++ /dev/null
@@ -1,511 +0,0 @@
-/*
- 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/>.
-*/
-
-#include <string>
-
-#include <stddef.h>
-
-#include <cassert>
-#include <algorithm>
-
-#include "ingen/Interface.hpp"
-#include "ingen/client/ClientStore.hpp"
-#include "ingen/client/GraphModel.hpp"
-
-#include "App.hpp"
-#include "LoadPluginWindow.hpp"
-#include "GraphCanvas.hpp"
-#include "GraphView.hpp"
-#include "GraphWindow.hpp"
-
-#include "ingen_config.h"
-
-using std::string;
-
-namespace Ingen {
-
-using namespace Client;
-
-namespace GUI {
-
-LoadPluginWindow::LoadPluginWindow(BaseObjectType* cobject,
- const Glib::RefPtr<Gtk::Builder>& xml)
- : Window(cobject)
- , _name_offset(0)
- , _has_shown(false)
- , _refresh_list(true)
-{
- xml->get_widget("load_plugin_plugins_treeview", _plugins_treeview);
- xml->get_widget("load_plugin_polyphonic_checkbutton", _polyphonic_checkbutton);
- xml->get_widget("load_plugin_name_entry", _name_entry);
- xml->get_widget("load_plugin_add_button", _add_button);
- xml->get_widget("load_plugin_close_button", _close_button);
-
- xml->get_widget("load_plugin_filter_combo", _filter_combo);
- xml->get_widget("load_plugin_search_entry", _search_entry);
-
- // Set up the plugins list
- _plugins_liststore = Gtk::ListStore::create(_plugins_columns);
- _plugins_treeview->set_model(_plugins_liststore);
- _plugins_treeview->append_column("_Name", _plugins_columns._col_name);
- _plugins_treeview->append_column("_Type", _plugins_columns._col_type);
- _plugins_treeview->append_column("_Project", _plugins_columns._col_project);
- _plugins_treeview->append_column("_Author", _plugins_columns._col_author);
- _plugins_treeview->append_column("_URI", _plugins_columns._col_uri);
-
- // This could be nicer.. store the TreeViewColumns locally maybe?
- _plugins_treeview->get_column(0)->set_sort_column(_plugins_columns._col_name);
- _plugins_treeview->get_column(1)->set_sort_column(_plugins_columns._col_type);
- _plugins_treeview->get_column(2)->set_sort_column(_plugins_columns._col_project);
- _plugins_treeview->get_column(2)->set_sort_column(_plugins_columns._col_author);
- _plugins_treeview->get_column(3)->set_sort_column(_plugins_columns._col_uri);
- for (int i = 0; i < 5; ++i) {
- _plugins_treeview->get_column(i)->set_resizable(true);
- }
-
- // Set up the search criteria combobox
- _criteria_liststore = Gtk::ListStore::create(_criteria_columns);
- _filter_combo->set_model(_criteria_liststore);
-
- Gtk::TreeModel::iterator iter = _criteria_liststore->append();
- Gtk::TreeModel::Row row = *iter;
- row[_criteria_columns._col_label] = "Name contains";
- row[_criteria_columns._col_criteria] = CriteriaColumns::Criteria::NAME;
- _filter_combo->set_active(iter);
-
- row = *(iter = _criteria_liststore->append());
- row[_criteria_columns._col_label] = "Type contains";
- row[_criteria_columns._col_criteria] = CriteriaColumns::Criteria::TYPE;
-
- row = *(iter = _criteria_liststore->append());
- row[_criteria_columns._col_label] = "Project contains";
- row[_criteria_columns._col_criteria] = CriteriaColumns::Criteria::PROJECT;
-
- row = *(iter = _criteria_liststore->append());
- row[_criteria_columns._col_label] = "Author contains";
- row[_criteria_columns._col_criteria] = CriteriaColumns::Criteria::AUTHOR;
-
- row = *(iter = _criteria_liststore->append());
- row[_criteria_columns._col_label] = "URI contains";
- row[_criteria_columns._col_criteria] = CriteriaColumns::Criteria::URI;
- _filter_combo->pack_start(_criteria_columns._col_label);
-
- _add_button->signal_clicked().connect(
- sigc::mem_fun(this, &LoadPluginWindow::add_clicked));
- _close_button->signal_clicked().connect(
- sigc::mem_fun(this, &Window::hide));
- _plugins_treeview->signal_row_activated().connect(
- sigc::mem_fun(this, &LoadPluginWindow::plugin_activated));
- _search_entry->signal_activate().connect(
- sigc::mem_fun(this, &LoadPluginWindow::add_clicked));
- _search_entry->signal_changed().connect(
- sigc::mem_fun(this, &LoadPluginWindow::filter_changed));
- _name_entry->signal_changed().connect(
- sigc::mem_fun(this, &LoadPluginWindow::name_changed));
-
- _search_entry->signal_icon_release().connect(
- sigc::mem_fun(this, &LoadPluginWindow::name_cleared));
-
- _selection = _plugins_treeview->get_selection();
- _selection->set_mode(Gtk::SELECTION_MULTIPLE);
- _selection->signal_changed().connect(
- sigc::mem_fun(this, &LoadPluginWindow::plugin_selection_changed));
-
- //m_add_button->grab_default();
-}
-
-void
-LoadPluginWindow::present(SPtr<const GraphModel> graph,
- Properties data)
-{
- set_graph(graph);
- _initial_data = data;
- Gtk::Window::present();
-}
-
-/** Called every time the user types into the name input box.
- * Used to display warning messages, and enable/disable the OK button.
- */
-void
-LoadPluginWindow::name_changed()
-{
- // Toggle add button sensitivity according name legality
- if (_selection->get_selected_rows().size() == 1) {
- const string sym = _name_entry->get_text();
- if (!Raul::Symbol::is_valid(sym)) {
- _add_button->property_sensitive() = false;
- } else if (_app->store()->find(_graph->path().child(Raul::Symbol(sym)))
- != _app->store()->end()) {
- _add_button->property_sensitive() = false;
- } else {
- _add_button->property_sensitive() = true;
- }
- }
-}
-
-void
-LoadPluginWindow::name_cleared(Gtk::EntryIconPosition pos, const GdkEventButton* event)
-{
- _search_entry->set_text("");
-}
-
-/** Sets the graph controller for this window and initializes everything.
- *
- * This function MUST be called before using the window in any way!
- */
-void
-LoadPluginWindow::set_graph(SPtr<const GraphModel> graph)
-{
- if (_graph) {
- _graph = graph;
- plugin_selection_changed();
- } else {
- _graph = graph;
- }
-}
-
-/** Populates the plugin list on the first show.
- *
- * This is done here instead of construction time as the list population is
- * really expensive and bogs down creation of a graph. This is especially
- * important when many graph notifications are sent at one time from the
- * engine.
- */
-void
-LoadPluginWindow::on_show()
-{
- if (!_has_shown) {
- _app->store()->signal_new_plugin().connect(
- sigc::mem_fun(this, &LoadPluginWindow::add_plugin));
- _has_shown = true;
- }
-
- if (_refresh_list) {
- set_plugins(_app->store()->plugins());
- _refresh_list = false;
- }
-
- Gtk::Window::on_show();
-}
-
-void
-LoadPluginWindow::set_plugins(SPtr<const ClientStore::Plugins> plugins)
-{
- _rows.clear();
- _plugins_liststore->clear();
-
- for (const auto& p : *plugins.get()) {
- add_plugin(p.second);
- }
-
- _plugins_liststore->set_sort_column(1, Gtk::SORT_ASCENDING);
- _plugins_treeview->columns_autosize();
-}
-
-void
-LoadPluginWindow::new_plugin(SPtr<const PluginModel> pm)
-{
- if (is_visible()) {
- add_plugin(pm);
- } else {
- _refresh_list = true;
- }
-}
-
-static std::string
-get_project_name(SPtr<const PluginModel> plugin)
-{
- std::string name;
- if (plugin->lilv_plugin()) {
- LilvNode* project = lilv_plugin_get_project(plugin->lilv_plugin());
- if (!project) {
- return "";
- }
-
- LilvNode* doap_name = lilv_new_uri(
- plugin->lilv_world(), "http://usefulinc.com/ns/doap#name");
- LilvNodes* names = lilv_world_find_nodes(
- plugin->lilv_world(), project, doap_name, nullptr);
-
- if (names) {
- name = lilv_node_as_string(lilv_nodes_get_first(names));
- }
-
- lilv_nodes_free(names);
- lilv_node_free(doap_name);
- lilv_node_free(project);
- }
- return name;
-}
-
-static std::string
-get_author_name(SPtr<const PluginModel> plugin)
-{
- std::string name;
- if (plugin->lilv_plugin()) {
- LilvNode* author = lilv_plugin_get_author_name(plugin->lilv_plugin());
- if (author) {
- name = lilv_node_as_string(author);
- }
- lilv_node_free(author);
- }
- return name;
-}
-
-void
-LoadPluginWindow::set_row(Gtk::TreeModel::Row& row,
- SPtr<const PluginModel> plugin)
-{
- const URIs& uris = _app->uris();
- const Atom& name = plugin->get_property(uris.doap_name);
- if (name.is_valid() && name.type() == uris.forge.String) {
- row[_plugins_columns._col_name] = name.ptr<char>();
- }
-
- if (uris.lv2_Plugin == plugin->type()) {
- row[_plugins_columns._col_type] = lilv_node_as_string(
- lilv_plugin_class_get_label(
- lilv_plugin_get_class(plugin->lilv_plugin())));
-
- row[_plugins_columns._col_project] = get_project_name(plugin);
- row[_plugins_columns._col_author] = get_author_name(plugin);
- } else if (uris.ingen_Internal == plugin->type()) {
- row[_plugins_columns._col_type] = "Internal";
- row[_plugins_columns._col_project] = "Ingen";
- row[_plugins_columns._col_author] = "David Robillard";
- } else if (uris.ingen_Graph == plugin->type()) {
- row[_plugins_columns._col_type] = "Graph";
- } else {
- row[_plugins_columns._col_type] = "";
- }
-
- row[_plugins_columns._col_uri] = plugin->uri().string();
- row[_plugins_columns._col_plugin] = plugin;
-}
-
-void
-LoadPluginWindow::add_plugin(SPtr<const PluginModel> plugin)
-{
- if (plugin->lilv_plugin() && lilv_plugin_is_replaced(plugin->lilv_plugin())) {
- return;
- }
-
- Gtk::TreeModel::iterator iter = _plugins_liststore->append();
- Gtk::TreeModel::Row row = *iter;
- _rows.emplace(plugin->uri(), iter);
-
- set_row(row, plugin);
-
- plugin->signal_property().connect(
- sigc::bind<0>(sigc::mem_fun(this, &LoadPluginWindow::plugin_property_changed),
- plugin->uri()));
-}
-
-///// Event Handlers //////
-
-void
-LoadPluginWindow::plugin_activated(const Gtk::TreeModel::Path& path,
- Gtk::TreeViewColumn* col)
-{
- add_clicked();
-}
-
-void
-LoadPluginWindow::plugin_selection_changed()
-{
- size_t n_selected = _selection->get_selected_rows().size();
- if (n_selected == 0) {
- _name_offset = 0;
- _name_entry->set_text("");
- _name_entry->set_sensitive(false);
- } else if (n_selected == 1) {
- Gtk::TreeModel::iterator iter = _plugins_liststore->get_iter(
- *_selection->get_selected_rows().begin());
- if (iter) {
- Gtk::TreeModel::Row row = *iter;
- SPtr<const PluginModel> p = row.get_value(
- _plugins_columns._col_plugin);
- _name_offset = _app->store()->child_name_offset(
- _graph->path(), p->default_block_symbol());
- _name_entry->set_text(generate_module_name(p, _name_offset));
- _name_entry->set_sensitive(true);
- } else {
- _name_offset = 0;
- _name_entry->set_text("");
- _name_entry->set_sensitive(false);
- }
- } else {
- _name_entry->set_text("");
- _name_entry->set_sensitive(false);
- }
-}
-
-/** Generate an automatic name for this Node.
- *
- * Offset is an offset of the number that will be appended to the plugin's
- * label, needed if the user adds multiple plugins faster than the engine
- * sends the notification back.
- */
-string
-LoadPluginWindow::generate_module_name(SPtr<const PluginModel> plugin,
- int offset)
-{
- std::stringstream ss;
- ss << plugin->default_block_symbol();
- if (offset != 0) {
- ss << "_" << offset;
- }
- return ss.str();
-}
-
-void
-LoadPluginWindow::load_plugin(const Gtk::TreeModel::iterator& iter)
-{
- const URIs& uris = _app->uris();
- Gtk::TreeModel::Row row = *iter;
- SPtr<const PluginModel> plugin = row.get_value(_plugins_columns._col_plugin);
- bool polyphonic = _polyphonic_checkbutton->get_active();
- string name = _name_entry->get_text();
-
- if (name.empty()) {
- name = generate_module_name(plugin, _name_offset);
- }
-
- if (name.empty() || !Raul::Symbol::is_valid(name)) {
- Gtk::MessageDialog dialog(
- *this,
- "Unable to choose a default name, please provide one",
- false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
-
- dialog.run();
- } else {
- Raul::Path path = _graph->path().child(Raul::Symbol::symbolify(name));
- Properties props = _initial_data;
- props.emplace(uris.rdf_type, Property(uris.ingen_Block));
- props.emplace(uris.lv2_prototype, _app->forge().make_urid(plugin->uri()));
- props.emplace(uris.ingen_polyphonic, _app->forge().make(polyphonic));
- _app->interface()->put(path_to_uri(path), props);
-
- if (_selection->get_selected_rows().size() == 1) {
- _name_offset = (_name_offset == 0) ? 2 : _name_offset + 1;
- _name_entry->set_text(generate_module_name(plugin, _name_offset));
- }
-
- // Cascade next block
- Atom& x = _initial_data.find(uris.ingen_canvasX)->second;
- x = _app->forge().make(x.get<float>() + 20.0f);
- Atom& y = _initial_data.find(uris.ingen_canvasY)->second;
- y = _app->forge().make(y.get<float>() + 20.0f);
- }
-}
-
-void
-LoadPluginWindow::add_clicked()
-{
- _selection->selected_foreach_iter(
- sigc::mem_fun(*this, &LoadPluginWindow::load_plugin));
-}
-
-void
-LoadPluginWindow::filter_changed()
-{
- _rows.clear();
- _plugins_liststore->clear();
- string search = _search_entry->get_text();
- transform(search.begin(), search.end(), search.begin(), ::toupper);
-
- // Get selected criteria
- const Gtk::TreeModel::Row row = *(_filter_combo->get_active());
- CriteriaColumns::Criteria criteria = row[_criteria_columns._col_criteria];
-
- string field;
-
- Gtk::TreeModel::Row model_row;
- Gtk::TreeModel::iterator model_iter;
- size_t num_visible = 0;
- const URIs& uris = _app->uris();
-
- for (const auto& p : *_app->store()->plugins().get()) {
- const SPtr<PluginModel> plugin = p.second;
- const Atom& name = plugin->get_property(uris.doap_name);
-
- switch (criteria) {
- case CriteriaColumns::Criteria::NAME:
- if (name.is_valid() && name.type() == uris.forge.String) {
- field = name.ptr<char>();
- }
- break;
- case CriteriaColumns::Criteria::TYPE:
- if (plugin->lilv_plugin()) {
- field = lilv_node_as_string(
- lilv_plugin_class_get_label(
- lilv_plugin_get_class(plugin->lilv_plugin())));
- }
- break;
- case CriteriaColumns::Criteria::PROJECT:
- field = get_project_name(plugin);
- break;
- case CriteriaColumns::Criteria::AUTHOR:
- field = get_author_name(plugin);
- break;
- case CriteriaColumns::Criteria::URI:
- field = plugin->uri();
- break;
- }
-
- transform(field.begin(), field.end(), field.begin(), ::toupper);
-
- if (field.find(search) != string::npos) {
- model_iter = _plugins_liststore->append();
- model_row = *model_iter;
- set_row(model_row, plugin);
- ++num_visible;
- }
- }
-
- if (num_visible == 1) {
- _selection->unselect_all();
- _selection->select(model_iter);
- }
-}
-
-bool
-LoadPluginWindow::on_key_press_event(GdkEventKey* event)
-{
- if (event->keyval == GDK_w && event->state & GDK_CONTROL_MASK) {
- hide();
- return true;
- } else {
- return Gtk::Window::on_key_press_event(event);
- }
-}
-
-void
-LoadPluginWindow::plugin_property_changed(const URI& plugin,
- const URI& predicate,
- const Atom& value)
-{
- const URIs& uris = _app->uris();
- if (predicate == uris.doap_name) {
- Rows::const_iterator i = _rows.find(plugin);
- if (i != _rows.end() && value.type() == uris.forge.String) {
- (*i->second)[_plugins_columns._col_name] = value.ptr<char>();
- }
- }
-}
-
-} // namespace GUI
-} // namespace Ingen
diff --git a/src/gui/LoadPluginWindow.hpp b/src/gui/LoadPluginWindow.hpp
deleted file mode 100644
index 29314c7a..00000000
--- a/src/gui/LoadPluginWindow.hpp
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- 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_GUI_LOADPLUGINWINDOW_HPP
-#define INGEN_GUI_LOADPLUGINWINDOW_HPP
-
-#include <map>
-#include <string>
-
-#include <gtkmm/builder.h>
-#include <gtkmm/combobox.h>
-#include <gtkmm/liststore.h>
-#include <gtkmm/treemodel.h>
-#include <gtkmm/treeview.h>
-
-#include "ingen/Node.hpp"
-#include "ingen/client/ClientStore.hpp"
-#include "ingen/types.hpp"
-#include "ingen_config.h"
-
-#include "Window.hpp"
-
-namespace Ingen {
-
-namespace Client {
-class GraphModel;
-class PluginModel;
-}
-
-namespace GUI {
-
-/** 'Load Plugin' window.
- *
- * Loaded from XML as a derived object.
- *
- * \ingroup GUI
- */
-class LoadPluginWindow : public Window
-{
-public:
- LoadPluginWindow(BaseObjectType* cobject,
- const Glib::RefPtr<Gtk::Builder>& xml);
-
- void set_graph(SPtr<const Client::GraphModel> graph);
- void set_plugins(SPtr<const Client::ClientStore::Plugins> plugins);
-
- void add_plugin(SPtr<const Client::PluginModel> plugin);
-
- void present(SPtr<const Client::GraphModel> graph,
- Properties data);
-
-protected:
- void on_show();
- bool on_key_press_event(GdkEventKey* event);
-
-private:
- /** Columns for the plugin list */
- class ModelColumns : public Gtk::TreeModel::ColumnRecord {
- public:
- ModelColumns() {
- add(_col_name);
- add(_col_type);
- add(_col_project);
- add(_col_author);
- add(_col_uri);
- add(_col_plugin);
- }
-
- Gtk::TreeModelColumn<Glib::ustring> _col_name;
- Gtk::TreeModelColumn<Glib::ustring> _col_type;
- Gtk::TreeModelColumn<Glib::ustring> _col_project;
- Gtk::TreeModelColumn<Glib::ustring> _col_author;
- Gtk::TreeModelColumn<Glib::ustring> _col_uri;
-
- // Not displayed:
- Gtk::TreeModelColumn< SPtr<const Client::PluginModel> > _col_plugin;
- };
-
- /** Column for the filter criteria combo box. */
- class CriteriaColumns : public Gtk::TreeModel::ColumnRecord {
- public:
- enum class Criteria { NAME, TYPE, PROJECT, AUTHOR, URI, };
-
- CriteriaColumns() {
- add(_col_label);
- add(_col_criteria);
- }
-
- Gtk::TreeModelColumn<Glib::ustring> _col_label;
- Gtk::TreeModelColumn<Criteria> _col_criteria;
- };
-
- void add_clicked();
- void filter_changed();
- void clear_clicked();
- void name_changed();
- void name_cleared(Gtk::EntryIconPosition pos, const GdkEventButton* event);
-
- void set_row(Gtk::TreeModel::Row& row,
- SPtr<const Client::PluginModel> plugin);
-
- void new_plugin(SPtr<const Client::PluginModel> pm);
-
- void plugin_property_changed(const URI& plugin,
- const URI& predicate,
- const Atom& value);
-
- void plugin_activated(const Gtk::TreeModel::Path& path, Gtk::TreeViewColumn* col);
- void plugin_selection_changed();
-
- std::string generate_module_name(SPtr<const Client::PluginModel> plugin,
- int offset=0);
-
- void load_plugin(const Gtk::TreeModel::iterator& iter);
-
- Properties _initial_data;
-
- SPtr<const Client::GraphModel> _graph;
-
- typedef std::map<URI, Gtk::TreeModel::iterator> Rows;
- Rows _rows;
-
- Glib::RefPtr<Gtk::ListStore> _plugins_liststore;
- ModelColumns _plugins_columns;
-
- Glib::RefPtr<Gtk::ListStore> _criteria_liststore;
- CriteriaColumns _criteria_columns;
-
- Glib::RefPtr<Gtk::TreeSelection> _selection;
-
- int _name_offset; // see comments for generate_plugin_name
-
- bool _has_shown;
- bool _refresh_list;
- Gtk::TreeView* _plugins_treeview;
- Gtk::CheckButton* _polyphonic_checkbutton;
- Gtk::Entry* _name_entry;
- Gtk::Button* _close_button;
- Gtk::Button* _add_button;
- Gtk::ComboBox* _filter_combo;
- Gtk::Entry* _search_entry;
-};
-
-} // namespace GUI
-} // namespace Ingen
-
-#endif // INGEN_GUI_LOADPLUGINWINDOW_HPP
diff --git a/src/gui/MessagesWindow.cpp b/src/gui/MessagesWindow.cpp
deleted file mode 100644
index 581e732c..00000000
--- a/src/gui/MessagesWindow.cpp
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- 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/>.
-*/
-
-#include <string>
-
-#include "ingen/URIs.hpp"
-
-#include "App.hpp"
-#include "MessagesWindow.hpp"
-
-namespace Ingen {
-namespace GUI {
-using std::string;
-
-MessagesWindow::MessagesWindow(BaseObjectType* cobject,
- const Glib::RefPtr<Gtk::Builder>& xml)
- : Window(cobject)
-{
- xml->get_widget("messages_textview", _textview);
- xml->get_widget("messages_clear_button", _clear_button);
- xml->get_widget("messages_close_button", _close_button);
-
- _clear_button->signal_clicked().connect(sigc::mem_fun(this, &MessagesWindow::clear_clicked));
- _close_button->signal_clicked().connect(sigc::mem_fun(this, &Window::hide));
-
- for (int s = Gtk::STATE_NORMAL; s <= Gtk::STATE_INSENSITIVE; ++s) {
- _textview->modify_base((Gtk::StateType)s, Gdk::Color("#000000"));
- _textview->modify_text((Gtk::StateType)s, Gdk::Color("#EEEEEC"));
- }
-}
-
-void
-MessagesWindow::init_window(App& app)
-{
- Glib::RefPtr<Gtk::TextTag> tag = Gtk::TextTag::create();
- tag->property_foreground() = "#EF2929";
- _tags.emplace(app.uris().log_Error, tag);
- _error_tag = tag;
-
- tag = Gtk::TextTag::create();
- tag->property_foreground() = "#FCAF3E";
- _tags.emplace(app.uris().log_Warning, tag);
-
- tag = Gtk::TextTag::create();
- tag->property_foreground() = "#8AE234";
- _tags.emplace(app.uris().log_Trace, tag);
-
- for (const auto& t : _tags) {
- _textview->get_buffer()->get_tag_table()->add(t.second);
- }
-}
-
-void
-MessagesWindow::post_error(const string& msg)
-{
- Glib::RefPtr<Gtk::TextBuffer> text_buf = _textview->get_buffer();
- text_buf->insert_with_tag(text_buf->end(), msg, _error_tag);
- text_buf->insert(text_buf->end(), "\n");
-
- if (!_clear_button->is_sensitive()) {
- _clear_button->set_sensitive(true);
- }
-
- set_urgency_hint(true);
- if (!is_visible()) {
- present();
- }
-}
-
-int
-MessagesWindow::log(LV2_URID type, const char* fmt, va_list args)
-{
- std::lock_guard<std::mutex> lock(_mutex);
-
-#ifdef HAVE_VASPRINTF
- char* buf = nullptr;
- const int len = vasprintf(&buf, fmt, args);
-#else
- char* buf = g_strdup_vprintf(fmt, args);
- const int len = strlen(buf);
-#endif
-
- _stream << type << ' ' << buf << '\0';
- free(buf);
-
- return len;
-}
-
-void
-MessagesWindow::flush()
-{
- while (true) {
- LV2_URID type;
- std::string line;
- {
- std::lock_guard<std::mutex> lock(_mutex);
- if (!_stream.rdbuf()->in_avail()) {
- return;
- }
- _stream >> type;
- std::getline(_stream, line, '\0');
- }
-
- Glib::RefPtr<Gtk::TextBuffer> text_buf = _textview->get_buffer();
-
- auto t = _tags.find(type);
- if (t != _tags.end()) {
- text_buf->insert_with_tag(text_buf->end(), line, t->second);
- } else {
- text_buf->insert(text_buf->end(), line);
- }
- }
-
- if (!_clear_button->is_sensitive()) {
- _clear_button->set_sensitive(true);
- }
-}
-
-void
-MessagesWindow::clear_clicked()
-{
- Glib::RefPtr<Gtk::TextBuffer> text_buf = _textview->get_buffer();
- text_buf->erase(text_buf->begin(), text_buf->end());
- _clear_button->set_sensitive(false);
-}
-
-} // namespace GUI
-} // namespace Ingen
diff --git a/src/gui/MessagesWindow.hpp b/src/gui/MessagesWindow.hpp
deleted file mode 100644
index fa9eae1d..00000000
--- a/src/gui/MessagesWindow.hpp
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- 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_GUI_MESSAGESWINDOW_HPP
-#define INGEN_GUI_MESSAGESWINDOW_HPP
-
-#include <mutex>
-#include <sstream>
-#include <string>
-
-#include <gtkmm/builder.h>
-#include <gtkmm/button.h>
-#include <gtkmm/textview.h>
-#include "lv2/lv2plug.in/ns/ext/log/log.h"
-
-#include "Window.hpp"
-
-namespace Ingen {
-namespace GUI {
-
-/** Messages Window.
- *
- * Loaded from XML as a derived object.
- * This is shown when errors occur (e.g. during graph loading).
- *
- * \ingroup GUI
- */
-class MessagesWindow : public Window
-{
-public:
- MessagesWindow(BaseObjectType* cobject,
- const Glib::RefPtr<Gtk::Builder>& xml);
-
- void init_window(App& app);
-
- int log(LV2_URID type, const char* fmt, va_list args);
- void flush();
-
- void post_error(const std::string& msg);
-
-private:
- void clear_clicked();
-
- std::mutex _mutex;
- std::stringstream _stream;
- Gtk::TextView* _textview;
- Gtk::Button* _clear_button;
- Gtk::Button* _close_button;
-
- Glib::RefPtr<Gtk::TextTag> _error_tag;
- std::map< LV2_URID, Glib::RefPtr<Gtk::TextTag> > _tags;
-};
-
-} // namespace GUI
-} // namespace Ingen
-
-#endif // INGEN_GUI_MESSAGESWINDOW_HPP
diff --git a/src/gui/NewSubgraphWindow.cpp b/src/gui/NewSubgraphWindow.cpp
deleted file mode 100644
index f9dc8fc4..00000000
--- a/src/gui/NewSubgraphWindow.cpp
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- 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 <string>
-
-#include "ingen/Interface.hpp"
-#include "ingen/client/ClientStore.hpp"
-#include "ingen/client/GraphModel.hpp"
-
-#include "App.hpp"
-#include "NewSubgraphWindow.hpp"
-#include "GraphView.hpp"
-
-namespace Ingen {
-namespace GUI {
-
-NewSubgraphWindow::NewSubgraphWindow(BaseObjectType* cobject,
- const Glib::RefPtr<Gtk::Builder>& xml)
- : Window(cobject)
-{
- xml->get_widget("new_subgraph_name_entry", _name_entry);
- xml->get_widget("new_subgraph_message_label", _message_label);
- xml->get_widget("new_subgraph_polyphony_spinbutton", _poly_spinbutton);
- xml->get_widget("new_subgraph_ok_button", _ok_button);
- xml->get_widget("new_subgraph_cancel_button", _cancel_button);
-
- _name_entry->signal_changed().connect(sigc::mem_fun(this, &NewSubgraphWindow::name_changed));
- _ok_button->signal_clicked().connect(sigc::mem_fun(this, &NewSubgraphWindow::ok_clicked));
- _cancel_button->signal_clicked().connect(sigc::mem_fun(this, &NewSubgraphWindow::cancel_clicked));
-
- _ok_button->property_sensitive() = false;
-
- _poly_spinbutton->get_adjustment()->configure(1.0, 1.0, 128, 1.0, 10.0, 0);
-}
-
-void
-NewSubgraphWindow::present(SPtr<const Client::GraphModel> graph,
- Properties data)
-{
- set_graph(graph);
- _initial_data = data;
- Gtk::Window::present();
-}
-
-/** Sets the graph controller for this window and initializes everything.
- *
- * This function MUST be called before using the window in any way!
- */
-void
-NewSubgraphWindow::set_graph(SPtr<const Client::GraphModel> graph)
-{
- _graph = graph;
-}
-
-/** Called every time the user types into the name input box.
- * Used to display warning messages, and enable/disable the OK button.
- */
-void
-NewSubgraphWindow::name_changed()
-{
- std::string name = _name_entry->get_text();
- if (!Raul::Symbol::is_valid(name)) {
- _message_label->set_text("Name contains invalid characters.");
- _ok_button->property_sensitive() = false;
- } else if (_app->store()->find(_graph->path().child(Raul::Symbol(name)))
- != _app->store()->end()) {
- _message_label->set_text("An object already exists with that name.");
- _ok_button->property_sensitive() = false;
- } else {
- _message_label->set_text("");
- _ok_button->property_sensitive() = true;
- }
-}
-
-void
-NewSubgraphWindow::ok_clicked()
-{
- const uint32_t poly = _poly_spinbutton->get_value_as_int();
- const Raul::Path path = _graph->path().child(
- Raul::Symbol::symbolify(_name_entry->get_text()));
-
- // Create graph
- Properties props;
- props.emplace(_app->uris().rdf_type, Property(_app->uris().ingen_Graph));
- props.emplace(_app->uris().ingen_polyphony, _app->forge().make(int32_t(poly)));
- props.emplace(_app->uris().ingen_enabled, _app->forge().make(bool(true)));
- _app->interface()->put(
- path_to_uri(path), props, Resource::Graph::INTERNAL);
-
- // Set external (block perspective) properties
- props = _initial_data;
- props.emplace(_app->uris().rdf_type, Property(_app->uris().ingen_Graph));
- _app->interface()->put(
- path_to_uri(path), _initial_data, Resource::Graph::EXTERNAL);
-
- hide();
-}
-
-void
-NewSubgraphWindow::cancel_clicked()
-{
- hide();
-}
-
-} // namespace GUI
-} // namespace Ingen
diff --git a/src/gui/NewSubgraphWindow.hpp b/src/gui/NewSubgraphWindow.hpp
deleted file mode 100644
index 395856ba..00000000
--- a/src/gui/NewSubgraphWindow.hpp
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- 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_GUI_NEWSUBGRAPHWINDOW_HPP
-#define INGEN_GUI_NEWSUBGRAPHWINDOW_HPP
-
-#include <gtkmm/builder.h>
-#include <gtkmm/button.h>
-#include <gtkmm/entry.h>
-#include <gtkmm/label.h>
-#include <gtkmm/spinbutton.h>
-
-#include "ingen/Node.hpp"
-#include "ingen/types.hpp"
-
-#include "Window.hpp"
-
-namespace Ingen {
-
-namespace Client { class GraphModel; }
-
-namespace GUI {
-
-/** 'New Subgraph' window.
- *
- * Loaded from XML as a derived object.
- *
- * \ingroup GUI
- */
-class NewSubgraphWindow : public Window
-{
-public:
- NewSubgraphWindow(BaseObjectType* cobject,
- const Glib::RefPtr<Gtk::Builder>& xml);
-
- void set_graph(SPtr<const Client::GraphModel> graph);
-
- void present(SPtr<const Client::GraphModel> graph,
- Properties data);
-
-private:
- void name_changed();
- void ok_clicked();
- void cancel_clicked();
-
- Properties _initial_data;
- SPtr<const Client::GraphModel> _graph;
-
- Gtk::Entry* _name_entry;
- Gtk::Label* _message_label;
- Gtk::SpinButton* _poly_spinbutton;
- Gtk::Button* _ok_button;
- Gtk::Button* _cancel_button;
-};
-
-} // namespace GUI
-} // namespace Ingen
-
-#endif // INGEN_GUI_NEWSUBGRAPHWINDOW_HPP
diff --git a/src/gui/NodeMenu.cpp b/src/gui/NodeMenu.cpp
deleted file mode 100644
index 1b1b1677..00000000
--- a/src/gui/NodeMenu.cpp
+++ /dev/null
@@ -1,253 +0,0 @@
-/*
- 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 <string>
-
-#include <gtkmm/entry.h>
-#include <gtkmm/filechooserdialog.h>
-#include <gtkmm/image.h>
-#include <gtkmm/stock.h>
-
-#include "ingen/Interface.hpp"
-#include "ingen/Log.hpp"
-#include "ingen/URIMap.hpp"
-#include "ingen/client/BlockModel.hpp"
-#include "ingen/client/PluginModel.hpp"
-#include "lv2/lv2plug.in/ns/ext/presets/presets.h"
-
-#include "App.hpp"
-#include "NodeMenu.hpp"
-#include "WidgetFactory.hpp"
-#include "WindowFactory.hpp"
-
-namespace Ingen {
-
-using namespace Client;
-
-namespace GUI {
-
-NodeMenu::NodeMenu(BaseObjectType* cobject,
- const Glib::RefPtr<Gtk::Builder>& xml)
- : ObjectMenu(cobject, xml)
- , _presets_menu(nullptr)
-{
- xml->get_widget("node_popup_gui_menuitem", _popup_gui_menuitem);
- xml->get_widget("node_embed_gui_menuitem", _embed_gui_menuitem);
- xml->get_widget("node_enabled_menuitem", _enabled_menuitem);
- xml->get_widget("node_randomize_menuitem", _randomize_menuitem);
-}
-
-void
-NodeMenu::init(App& app, SPtr<const Client::BlockModel> block)
-{
- ObjectMenu::init(app, block);
-
- _learn_menuitem->signal_activate().connect(
- sigc::mem_fun(this, &NodeMenu::on_menu_learn));
- _popup_gui_menuitem->signal_activate().connect(
- sigc::mem_fun(signal_popup_gui, &sigc::signal<void>::emit));
- _embed_gui_menuitem->signal_toggled().connect(
- sigc::mem_fun(this, &NodeMenu::on_menu_embed_gui));
- _enabled_menuitem->signal_toggled().connect(
- sigc::mem_fun(this, &NodeMenu::on_menu_enabled));
- _randomize_menuitem->signal_activate().connect(
- sigc::mem_fun(this, &NodeMenu::on_menu_randomize));
-
- SPtr<PluginModel> plugin = block->plugin_model();
- if (plugin) {
- // Get the plugin to receive related presets
- _preset_connection = plugin->signal_preset().connect(
- sigc::mem_fun(this, &NodeMenu::add_preset));
-
- if (!plugin->fetched()) {
- _app->interface()->get(plugin->uri());
- plugin->set_fetched(true);
- }
- }
-
- if (plugin && plugin->has_ui()) {
- _popup_gui_menuitem->show();
- _embed_gui_menuitem->show();
- const Atom& ui_embedded = block->get_property(
- _app->uris().ingen_uiEmbedded);
- _embed_gui_menuitem->set_active(
- ui_embedded.is_valid() && ui_embedded.get<int32_t>());
- } else {
- _popup_gui_menuitem->hide();
- _embed_gui_menuitem->hide();
- }
-
- const Atom& enabled = block->get_property(_app->uris().ingen_enabled);
- _enabled_menuitem->set_active(!enabled.is_valid() || enabled.get<int32_t>());
-
- if (plugin && _app->uris().lv2_Plugin == plugin->type()) {
- _presets_menu = Gtk::manage(new Gtk::Menu());
- _presets_menu->items().push_back(
- Gtk::Menu_Helpers::MenuElem(
- "_Save Preset...",
- sigc::mem_fun(this, &NodeMenu::on_save_preset_activated)));
- _presets_menu->items().push_back(Gtk::Menu_Helpers::SeparatorElem());
-
- for (const auto& p : plugin->presets()) {
- add_preset(p.first, p.second);
- }
-
- items().push_front(
- Gtk::Menu_Helpers::ImageMenuElem(
- "_Presets",
- *(manage(new Gtk::Image(Gtk::Stock::INDEX, Gtk::ICON_SIZE_MENU)))));
-
- Gtk::MenuItem* presets_menu_item = &(items().front());
- presets_menu_item->set_submenu(*_presets_menu);
- }
-
- if (has_control_inputs()) {
- _randomize_menuitem->show();
- } else {
- _randomize_menuitem->hide();
- }
-
- if (plugin && (plugin->uri() == "http://drobilla.net/ns/ingen-internals#Controller"
- || plugin->uri() == "http://drobilla.net/ns/ingen-internals#Trigger")) {
- _learn_menuitem->show();
- } else {
- _learn_menuitem->hide();
- }
-
- if (!_popup_gui_menuitem->is_visible() &&
- !_embed_gui_menuitem->is_visible() &&
- !_randomize_menuitem->is_visible()) {
- _separator_menuitem->hide();
- }
-
- _enable_signal = true;
-}
-
-void
-NodeMenu::add_preset(const URI& uri, const std::string& label)
-{
- if (_presets_menu) {
- _presets_menu->items().push_back(
- Gtk::Menu_Helpers::MenuElem(
- label,
- sigc::bind(sigc::mem_fun(this, &NodeMenu::on_preset_activated),
- uri)));
- }
-}
-
-void
-NodeMenu::on_menu_embed_gui()
-{
- signal_embed_gui.emit(_embed_gui_menuitem->get_active());
-}
-
-void
-NodeMenu::on_menu_enabled()
-{
- _app->set_property(_object->uri(),
- _app->uris().ingen_enabled,
- _app->forge().make(bool(_enabled_menuitem->get_active())));
-}
-
-void
-NodeMenu::on_menu_randomize()
-{
- _app->interface()->bundle_begin();
-
- const SPtr<const BlockModel> bm = block();
- for (const auto& p : bm->ports()) {
- if (p->is_input() && _app->can_control(p.get())) {
- float min = 0.0f, max = 1.0f;
- bm->port_value_range(p, min, max, _app->sample_rate());
- const float val = g_random_double_range(0.0, 1.0) * (max - min) + min;
- _app->set_property(p->uri(),
- _app->uris().ingen_value,
- _app->forge().make(val));
- }
- }
-
- _app->interface()->bundle_end();
-}
-
-void
-NodeMenu::on_menu_disconnect()
-{
- _app->interface()->disconnect_all(_object->parent()->path(), _object->path());
-}
-
-void
-NodeMenu::on_save_preset_activated()
-{
- Gtk::FileChooserDialog dialog("Save Preset", Gtk::FILE_CHOOSER_ACTION_SAVE);
- dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
- dialog.add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_OK);
- dialog.set_default_response(Gtk::RESPONSE_OK);
- dialog.set_current_folder(Glib::build_filename(Glib::get_home_dir(), ".lv2"));
-
- Gtk::HBox* extra = Gtk::manage(new Gtk::HBox());
- Gtk::Label* label = Gtk::manage(new Gtk::Label("URI (Optional): "));
- Gtk::Entry* entry = Gtk::manage(new Gtk::Entry());
- extra->pack_start(*label, false, true, 4);
- extra->pack_start(*entry, true, true, 4);
- extra->show_all();
- dialog.set_extra_widget(*Gtk::manage(extra));
-
- if (dialog.run() == Gtk::RESPONSE_OK) {
- const std::string user_uri = dialog.get_uri();
- const std::string user_path = Glib::filename_from_uri(user_uri);
- const std::string dirname = Glib::path_get_dirname(user_path);
- const std::string basename = Glib::path_get_basename(user_path);
- const std::string sym = Raul::Symbol::symbolify(basename);
- const std::string plugname = block()->plugin_model()->human_name();
- const std::string prefix = Raul::Symbol::symbolify(plugname);
- const std::string bundle = prefix + "_" + sym + ".preset.lv2/";
- const std::string file = sym + ".ttl";
- const std::string real_path = Glib::build_filename(dirname, bundle, file);
- const std::string real_uri = Glib::filename_to_uri(real_path);
-
- Properties props{
- { _app->uris().rdf_type,
- _app->uris().pset_Preset },
- { _app->uris().rdfs_label,
- _app->forge().alloc(basename) },
- { _app->uris().lv2_prototype,
- _app->forge().make_urid(block()->uri()) }};
- _app->interface()->put(URI(real_uri), props);
- }
-}
-
-void
-NodeMenu::on_preset_activated(const std::string& uri)
-{
- _app->set_property(block()->uri(),
- _app->uris().pset_preset,
- _app->forge().make_urid(URI(uri)));
-}
-
-bool
-NodeMenu::has_control_inputs()
-{
- for (const auto& p : block()->ports()) {
- if (p->is_input() && p->is_numeric()) {
- return true;
- }
- }
-
- return false;
-}
-
-} // namespace GUI
-} // namespace Ingen
diff --git a/src/gui/NodeMenu.hpp b/src/gui/NodeMenu.hpp
deleted file mode 100644
index 5d9f1e6d..00000000
--- a/src/gui/NodeMenu.hpp
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- 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_GUI_NODEMENU_HPP
-#define INGEN_GUI_NODEMENU_HPP
-
-#include <string>
-
-#include <gtkmm/builder.h>
-#include <gtkmm/menu.h>
-#include <gtkmm/menushell.h>
-
-#include "ObjectMenu.hpp"
-#include "ingen/client/BlockModel.hpp"
-#include "ingen/types.hpp"
-
-namespace Ingen {
-namespace GUI {
-
-/** Menu for a Node.
- *
- * \ingroup GUI
- */
-class NodeMenu : public ObjectMenu
-{
-public:
- NodeMenu(BaseObjectType* cobject,
- const Glib::RefPtr<Gtk::Builder>& xml);
-
- void init(App& app, SPtr<const Client::BlockModel> block);
-
- bool has_control_inputs();
-
- sigc::signal<void> signal_popup_gui;
- sigc::signal<void, bool> signal_embed_gui;
-
-protected:
- SPtr<const Client::BlockModel> block() const {
- return dynamic_ptr_cast<const Client::BlockModel>(_object);
- }
-
- void add_preset(const URI& uri, const std::string& label);
-
- void on_menu_disconnect();
- void on_menu_embed_gui();
- void on_menu_enabled();
- void on_menu_randomize();
- void on_save_preset_activated();
- void on_preset_activated(const std::string& uri);
-
- Gtk::MenuItem* _popup_gui_menuitem;
- Gtk::CheckMenuItem* _embed_gui_menuitem;
- Gtk::CheckMenuItem* _enabled_menuitem;
- Gtk::MenuItem* _randomize_menuitem;
- Gtk::Menu* _presets_menu;
- sigc::connection _preset_connection;
-};
-
-} // namespace GUI
-} // namespace Ingen
-
-#endif // INGEN_GUI_NODEMENU_HPP
diff --git a/src/gui/NodeModule.cpp b/src/gui/NodeModule.cpp
deleted file mode 100644
index dadffff0..00000000
--- a/src/gui/NodeModule.cpp
+++ /dev/null
@@ -1,518 +0,0 @@
-/*
- 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/>.
-*/
-
-#include <cassert>
-#include <string>
-
-#include <gtkmm/eventbox.h>
-
-#include "lv2/lv2plug.in/ns/ext/atom/util.h"
-
-#include "ingen/Atom.hpp"
-#include "ingen/Configuration.hpp"
-#include "ingen/Interface.hpp"
-#include "ingen/Log.hpp"
-#include "ingen/client/BlockModel.hpp"
-#include "ingen/client/GraphModel.hpp"
-#include "ingen/client/PluginModel.hpp"
-#include "ingen/client/PluginUI.hpp"
-
-#include "App.hpp"
-#include "GraphCanvas.hpp"
-#include "GraphWindow.hpp"
-#include "NodeMenu.hpp"
-#include "NodeModule.hpp"
-#include "Port.hpp"
-#include "RenameWindow.hpp"
-#include "Style.hpp"
-#include "SubgraphModule.hpp"
-#include "WidgetFactory.hpp"
-#include "WindowFactory.hpp"
-#include "ingen_config.h"
-
-namespace Ingen {
-
-using namespace Client;
-
-namespace GUI {
-
-NodeModule::NodeModule(GraphCanvas& canvas,
- SPtr<const BlockModel> block)
- : Ganv::Module(canvas, block->path().symbol(), 0, 0, true)
- , _block(block)
- , _gui_widget(nullptr)
- , _gui_window(nullptr)
- , _initialised(false)
-{
- block->signal_new_port().connect(
- sigc::mem_fun(this, &NodeModule::new_port_view));
- block->signal_removed_port().connect(
- sigc::hide_return(sigc::mem_fun(this, &NodeModule::delete_port_view)));
- block->signal_property().connect(
- sigc::mem_fun(this, &NodeModule::property_changed));
- block->signal_moved().connect(
- sigc::mem_fun(this, &NodeModule::rename));
-
- signal_event().connect(
- sigc::mem_fun(this, &NodeModule::on_event));
-
- signal_moved().connect(
- sigc::mem_fun(this, &NodeModule::store_location));
-
- signal_selected().connect(
- sigc::mem_fun(this, &NodeModule::on_selected));
-
- const PluginModel* plugin = dynamic_cast<const PluginModel*>(block->plugin());
- if (plugin) {
- plugin->signal_changed().connect(
- sigc::mem_fun(this, &NodeModule::plugin_changed));
- }
-
- for (const auto& p : block->properties()) {
- property_changed(p.first, p.second);
- }
-
- if (_block->has_property(app().uris().ingen_uiEmbedded,
- app().uris().forge.make(true))) {
- // Schedule idle callback to embed GUI once ports arrive
- Glib::signal_timeout().connect(
- sigc::mem_fun(*this, &NodeModule::idle_init), 25, G_PRIORITY_DEFAULT_IDLE);
- } else {
- _initialised = true;
- }
-}
-
-NodeModule::~NodeModule()
-{
- delete _gui_widget;
- delete _gui_window;
-}
-
-bool
-NodeModule::idle_init()
-{
- if (_block->ports().size() == 0) {
- return true; // Need to embed GUI, but ports haven't shown up yet
- }
-
- // Ports have arrived, embed GUI and deregister this callback
- embed_gui(true);
- _initialised = true;
- return false;
-}
-
-bool
-NodeModule::show_menu(GdkEventButton* ev)
-{
- WidgetFactory::get_widget_derived("object_menu", _menu);
- if (!_menu) {
- app().log().error("Failed to load object menu widget\n");
- return false;
- }
-
- _menu->init(app(), _block);
- _menu->signal_embed_gui.connect(
- sigc::mem_fun(this, &NodeModule::on_embed_gui_toggled));
- _menu->signal_popup_gui.connect(
- sigc::hide_return(sigc::mem_fun(this, &NodeModule::popup_gui)));
- _menu->popup(ev->button, ev->time);
- return true;
-}
-
-NodeModule*
-NodeModule::create(GraphCanvas& canvas,
- SPtr<const BlockModel> block,
- bool human)
-{
- SPtr<const GraphModel> graph = dynamic_ptr_cast<const GraphModel>(block);
-
- NodeModule* ret = (graph)
- ? new SubgraphModule(canvas, graph)
- : new NodeModule(canvas, block);
-
- for (const auto& p : block->properties()) {
- ret->property_changed(p.first, p.second);
- }
-
- for (const auto& p : block->ports()) {
- ret->new_port_view(p);
- }
-
- ret->set_stacked(block->polyphonic());
-
- if (human) {
- ret->show_human_names(human); // FIXME: double port iteration
- }
-
- return ret;
-}
-
-App&
-NodeModule::app() const
-{
- return ((GraphCanvas*)canvas())->app();
-}
-
-void
-NodeModule::show_human_names(bool b)
-{
- const URIs& uris = app().uris();
-
- if (b) {
- set_label(block()->label().c_str());
- } else {
- set_label(block()->symbol().c_str());
- }
-
- for (iterator i = begin(); i != end(); ++i) {
- Ingen::GUI::Port* const port = dynamic_cast<Ingen::GUI::Port*>(*i);
- Glib::ustring label(port->model()->symbol().c_str());
- if (b) {
- const Atom& name_property = port->model()->get_property(uris.lv2_name);
- if (name_property.type() == uris.forge.String) {
- label = name_property.ptr<char>();
- } else {
- Glib::ustring hn = block()->plugin_model()->port_human_name(
- port->model()->index());
- if (!hn.empty()) {
- label = hn;
- }
- }
- }
- (*i)->set_label(label.c_str());
- }
-}
-
-void
-NodeModule::port_activity(uint32_t index, const Atom& value)
-{
- const URIs& uris = app().uris();
- if (!_plugin_ui) {
- return;
- }
-
- if (_block->get_port(index)->is_a(uris.atom_AtomPort)) {
- _plugin_ui->port_event(index,
- lv2_atom_total_size(value.atom()),
- uris.atom_eventTransfer,
- value.atom());
- }
-}
-
-void
-NodeModule::port_value_changed(uint32_t index, const Atom& value)
-{
- const URIs& uris = app().uris();
- if (!_plugin_ui) {
- return;
- }
-
- if (value.type() == uris.atom_Float &&
- _block->get_port(index)->is_numeric()) {
- _plugin_ui->port_event(index, sizeof(float), 0, value.ptr<float>());
- } else {
- _plugin_ui->port_event(index,
- lv2_atom_total_size(value.atom()),
- uris.atom_eventTransfer,
- value.atom());
- }
-}
-
-void
-NodeModule::plugin_changed()
-{
- for (iterator p = begin(); p != end(); ++p) {
- dynamic_cast<Ingen::GUI::Port*>(*p)->update_metadata();
- }
-}
-
-void
-NodeModule::on_embed_gui_toggled(bool embed)
-{
- embed_gui(embed);
- app().set_property(_block->uri(),
- app().uris().ingen_uiEmbedded,
- app().forge().make(embed));
-}
-
-void
-NodeModule::embed_gui(bool embed)
-{
- if (embed) {
- if (_gui_window) {
- app().log().warn("LV2 GUI already popped up, cannot embed\n");
- return;
- }
-
- if (!_plugin_ui) {
- _plugin_ui = _block->plugin_model()->ui(app().world(), _block);
- }
-
- if (_plugin_ui) {
- _plugin_ui->signal_property_changed().connect(
- sigc::mem_fun(app(), &App::set_property));
-
- if (!_plugin_ui->instantiate()) {
- app().log().error("Failed to instantiate LV2 UI\n");
- } else {
- GtkWidget* c_widget = (GtkWidget*)_plugin_ui->get_widget();
- _gui_widget = Glib::wrap(c_widget);
-
- Gtk::Container* container = new Gtk::EventBox();
- container->set_name("IngenEmbeddedUI");
- container->set_border_width(4.0);
- container->add(*_gui_widget);
- Ganv::Module::embed(container);
- }
- } else {
- app().log().error("Failed to create LV2 UI\n");
- }
-
- if (_gui_widget) {
- _gui_widget->show_all();
- set_control_values();
- }
-
- } else { // un-embed
- Ganv::Module::embed(nullptr);
- _plugin_ui.reset();
- }
-}
-
-void
-NodeModule::rename()
-{
- if (app().world()->conf().option("port-labels").get<int32_t>() &&
- !app().world()->conf().option("human-names").get<int32_t>()) {
- set_label(_block->path().symbol());
- }
-}
-
-void
-NodeModule::new_port_view(SPtr<const PortModel> port)
-{
- Port::create(app(), *this, port);
-
- port->signal_value_changed().connect(
- sigc::bind<0>(sigc::mem_fun(this, &NodeModule::port_value_changed),
- port->index()));
-
- port->signal_activity().connect(
- sigc::bind<0>(sigc::mem_fun(this, &NodeModule::port_activity),
- port->index()));
-}
-
-Port*
-NodeModule::port(SPtr<const PortModel> model)
-{
- for (iterator p = begin(); p != end(); ++p) {
- Port* const port = dynamic_cast<Port*>(*p);
- if (port->model() == model) {
- return port;
- }
- }
- return nullptr;
-}
-
-void
-NodeModule::delete_port_view(SPtr<const PortModel> model)
-{
- Port* p = port(model);
- if (p) {
- delete p;
- } else {
- app().log().warn(fmt("Failed to find port %1% on module %2%\n")
- % model->path() % _block->path());
- }
-}
-
-bool
-NodeModule::popup_gui()
-{
- if (_block->plugin() && app().uris().lv2_Plugin == _block->plugin_model()->type()) {
- if (_plugin_ui) {
- app().log().warn("LV2 GUI already embedded, cannot pop up\n");
- return false;
- }
-
- const PluginModel* const plugin = dynamic_cast<const PluginModel*>(_block->plugin());
- assert(plugin);
-
- _plugin_ui = plugin->ui(app().world(), _block);
-
- if (_plugin_ui) {
- _plugin_ui->signal_property_changed().connect(
- sigc::mem_fun(app(), &App::set_property));
-
- if (!_plugin_ui->instantiated() && !_plugin_ui->instantiate()) {
- app().log().error("Failed to instantiate LV2 UI\n");
- return false;
- }
-
- GtkWidget* c_widget = (GtkWidget*)_plugin_ui->get_widget();
- _gui_widget = Glib::wrap(c_widget);
-
- _gui_window = new Gtk::Window();
- if (!_plugin_ui->is_resizable()) {
- _gui_window->set_resizable(false);
- }
- _gui_window->set_title(_block->path() + " UI - Ingen");
- _gui_window->set_role("plugin_ui");
- _gui_window->add(*_gui_widget);
- _gui_widget->show_all();
- set_control_values();
-
- _gui_window->signal_unmap().connect(
- sigc::mem_fun(this, &NodeModule::on_gui_window_close));
- _gui_window->present();
-
- return true;
- } else {
- app().log().warn(fmt("No LV2 GUI for %1%\n") % _block->path());
- }
- }
-
- return false;
-}
-
-void
-NodeModule::on_gui_window_close()
-{
- delete _gui_window;
- _gui_window = nullptr;
- _plugin_ui.reset();
- _gui_widget = nullptr;
-}
-
-void
-NodeModule::set_control_values()
-{
- uint32_t index = 0;
- for (const auto& p : _block->ports()) {
- if (app().can_control(p.get()) && p->value().is_valid()) {
- port_value_changed(index, p->value());
- }
- ++index;
- }
-}
-
-bool
-NodeModule::on_double_click(GdkEventButton* event)
-{
- popup_gui();
- return true;
-}
-
-bool
-NodeModule::on_event(GdkEvent* ev)
-{
- if (ev->type == GDK_BUTTON_PRESS && ev->button.button == 3) {
- return show_menu(&ev->button);
- } else if (ev->type == GDK_2BUTTON_PRESS) {
- return on_double_click(&ev->button);
- } else if (ev->type == GDK_ENTER_NOTIFY) {
- GraphBox* const box = app().window_factory()->graph_box(
- dynamic_ptr_cast<const GraphModel>(_block->parent()));
- if (box) {
- box->object_entered(_block.get());
- }
- } else if (ev->type == GDK_LEAVE_NOTIFY) {
- GraphBox* const box = app().window_factory()->graph_box(
- dynamic_ptr_cast<const GraphModel>(_block->parent()));
- if (box) {
- box->object_left(_block.get());
- }
- }
-
- return false;
-}
-
-void
-NodeModule::store_location(double ax, double ay)
-{
- const URIs& uris = app().uris();
-
- const Atom x(app().forge().make(static_cast<float>(ax)));
- const Atom y(app().forge().make(static_cast<float>(ay)));
-
- if (x != _block->get_property(uris.ingen_canvasX) ||
- y != _block->get_property(uris.ingen_canvasY))
- {
- app().interface()->put(_block->uri(), {{uris.ingen_canvasX, x},
- {uris.ingen_canvasY, y}});
- }
-}
-
-void
-NodeModule::property_changed(const URI& key, const Atom& value)
-{
- const URIs& uris = app().uris();
- if (value.type() == uris.forge.Float) {
- if (key == uris.ingen_canvasX) {
- move_to(value.get<float>(), get_y());
- } else if (key == uris.ingen_canvasY) {
- move_to(get_x(), value.get<float>());
- }
- } else if (value.type() == uris.forge.Bool) {
- if (key == uris.ingen_polyphonic) {
- set_stacked(value.get<int32_t>());
- } else if (key == uris.ingen_uiEmbedded && _initialised) {
- if (value.get<int32_t>() && !_gui_widget) {
- embed_gui(true);
- } else if (!value.get<int32_t>() && _gui_widget) {
- embed_gui(false);
- }
- } else if (key == uris.ingen_enabled) {
- if (value.get<int32_t>()) {
- set_dash_length(0.0);
- } else {
- set_dash_length(5.0);
- }
- }
- } else if (value.type() == uris.forge.String) {
- if (key == uris.lv2_name
- && app().world()->conf().option("human-names").get<int32_t>()) {
- set_label(value.ptr<char>());
- }
- }
-}
-
-bool
-NodeModule::on_selected(gboolean selected)
-{
- GraphWindow* win = app().window_factory()->parent_graph_window(block());
- if (!win) {
- return true;
- }
-
- if (selected && win->documentation_is_visible()) {
- GraphWindow* win = app().window_factory()->parent_graph_window(block());
- std::string doc;
- bool html = false;
-#ifdef HAVE_WEBKIT
- html = true;
-#endif
- if (block()->plugin_model()) {
- doc = block()->plugin_model()->documentation(html);
- }
- win->set_documentation(doc, html);
- }
-
- return true;
-}
-
-} // namespace GUI
-} // namespace Ingen
diff --git a/src/gui/NodeModule.hpp b/src/gui/NodeModule.hpp
deleted file mode 100644
index 863b6ffb..00000000
--- a/src/gui/NodeModule.hpp
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- 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_GUI_NODEMODULE_HPP
-#define INGEN_GUI_NODEMODULE_HPP
-
-#include "ganv/Module.hpp"
-#include "ingen/types.hpp"
-
-#include "Port.hpp"
-
-namespace Raul { class Atom; }
-
-namespace Ingen { namespace Client {
-class BlockModel;
-class PluginUI;
-class PortModel;
-} }
-
-namespace Ingen {
-namespace GUI {
-
-class GraphCanvas;
-class Port;
-class NodeMenu;
-
-/** A module in a graphn.
- *
- * This base class is extended for various types of modules.
- *
- * \ingroup GUI
- */
-class NodeModule : public Ganv::Module
-{
-public:
- static NodeModule* create(
- GraphCanvas& canvas,
- SPtr<const Client::BlockModel> block,
- bool human);
-
- virtual ~NodeModule();
-
- App& app() const;
-
- Port* port(SPtr<const Client::PortModel> model);
-
- void delete_port_view(SPtr<const Client::PortModel> model);
-
- virtual void store_location(double ax, double ay);
- void show_human_names(bool b);
-
- SPtr<const Client::BlockModel> block() const { return _block; }
-
-protected:
- NodeModule(GraphCanvas& canvas, SPtr<const Client::BlockModel> block);
-
- virtual bool on_double_click(GdkEventButton* ev);
-
- bool idle_init();
- bool on_event(GdkEvent* ev);
-
- void on_embed_gui_toggled(bool embed);
- void embed_gui(bool embed);
- bool popup_gui();
- void on_gui_window_close();
- bool on_selected(gboolean selected);
-
- void rename();
- void property_changed(const URI& key, const Atom& value);
-
- void new_port_view(SPtr<const Client::PortModel> port);
-
- void port_activity(uint32_t index, const Atom& value);
- void port_value_changed(uint32_t index, const Atom& value);
- void plugin_changed();
- void set_control_values();
-
- bool show_menu(GdkEventButton* ev);
-
- SPtr<const Client::BlockModel> _block;
- NodeMenu* _menu;
- SPtr<Client::PluginUI> _plugin_ui;
- Gtk::Widget* _gui_widget;
- Gtk::Window* _gui_window; ///< iff popped up
- bool _initialised;
-};
-
-} // namespace GUI
-} // namespace Ingen
-
-#endif // INGEN_GUI_NODEMODULE_HPP
diff --git a/src/gui/ObjectMenu.cpp b/src/gui/ObjectMenu.cpp
deleted file mode 100644
index bfce4248..00000000
--- a/src/gui/ObjectMenu.cpp
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- 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 <utility>
-
-#include "ingen/Forge.hpp"
-#include "ingen/Interface.hpp"
-#include "ingen/client/ObjectModel.hpp"
-
-#include "App.hpp"
-#include "ObjectMenu.hpp"
-#include "WidgetFactory.hpp"
-#include "WindowFactory.hpp"
-
-namespace Ingen {
-
-using namespace Client;
-
-namespace GUI {
-
-ObjectMenu::ObjectMenu(BaseObjectType* cobject,
- const Glib::RefPtr<Gtk::Builder>& xml)
- : Gtk::Menu(cobject)
- , _app(nullptr)
- , _polyphonic_menuitem(nullptr)
- , _disconnect_menuitem(nullptr)
- , _rename_menuitem(nullptr)
- , _destroy_menuitem(nullptr)
- , _properties_menuitem(nullptr)
- , _enable_signal(false)
-{
- xml->get_widget("object_learn_menuitem", _learn_menuitem);
- xml->get_widget("object_unlearn_menuitem", _unlearn_menuitem);
- xml->get_widget("object_polyphonic_menuitem", _polyphonic_menuitem);
- xml->get_widget("object_disconnect_menuitem", _disconnect_menuitem);
- xml->get_widget("object_rename_menuitem", _rename_menuitem);
- xml->get_widget("object_destroy_menuitem", _destroy_menuitem);
- xml->get_widget("object_properties_menuitem", _properties_menuitem);
- xml->get_widget("object_menu_separator", _separator_menuitem);
-}
-
-void
-ObjectMenu::init(App& app, SPtr<const ObjectModel> object)
-{
- _app = &app;
- _object = object;
-
- _polyphonic_menuitem->signal_toggled().connect(
- sigc::mem_fun(this, &ObjectMenu::on_menu_polyphonic));
-
- _polyphonic_menuitem->set_active(object->polyphonic());
-
- _learn_menuitem->signal_activate().connect(
- sigc::mem_fun(this, &ObjectMenu::on_menu_learn));
-
- _unlearn_menuitem->signal_activate().connect(
- sigc::mem_fun(this, &ObjectMenu::on_menu_unlearn));
-
- _disconnect_menuitem->signal_activate().connect(
- sigc::mem_fun(this, &ObjectMenu::on_menu_disconnect));
-
- _rename_menuitem->signal_activate().connect(
- sigc::bind(sigc::mem_fun(_app->window_factory(), &WindowFactory::present_rename),
- object));
-
- _destroy_menuitem->signal_activate().connect(
- sigc::mem_fun(this, &ObjectMenu::on_menu_destroy));
-
- _properties_menuitem->signal_activate().connect(
- sigc::mem_fun(this, &ObjectMenu::on_menu_properties));
-
- object->signal_property().connect(sigc::mem_fun(this, &ObjectMenu::property_changed));
-
- _learn_menuitem->hide();
- _unlearn_menuitem->hide();
-
- _enable_signal = true;
-}
-
-void
-ObjectMenu::on_menu_learn()
-{
- _app->interface()->set_property(_object->uri(),
- _app->uris().midi_binding,
- _app->uris().patch_wildcard.urid);
-}
-
-void
-ObjectMenu::on_menu_unlearn()
-{
- Properties remove;
- remove.emplace(_app->uris().midi_binding,
- Property(_app->uris().patch_wildcard));
- _app->interface()->delta(_object->uri(), remove, Properties());
-}
-
-void
-ObjectMenu::on_menu_polyphonic()
-{
- if (_enable_signal) {
- _app->set_property(
- _object->uri(),
- _app->uris().ingen_polyphonic,
- _app->forge().make(bool(_polyphonic_menuitem->get_active())));
- }
-}
-
-void
-ObjectMenu::property_changed(const URI& predicate, const Atom& value)
-{
- const URIs& uris = _app->uris();
- _enable_signal = false;
- if (predicate == uris.ingen_polyphonic && value.type() == uris.forge.Bool) {
- _polyphonic_menuitem->set_active(value.get<int32_t>());
- }
- _enable_signal = true;
-}
-
-void
-ObjectMenu::on_menu_destroy()
-{
- _app->interface()->del(_object->uri());
-}
-
-void
-ObjectMenu::on_menu_properties()
-{
- _app->window_factory()->present_properties(_object);
-}
-
-} // namespace GUI
-} // namespace Ingen
diff --git a/src/gui/ObjectMenu.hpp b/src/gui/ObjectMenu.hpp
deleted file mode 100644
index a9b07fd5..00000000
--- a/src/gui/ObjectMenu.hpp
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- 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_GUI_OBJECTMENU_HPP
-#define INGEN_GUI_OBJECTMENU_HPP
-
-#include <gtkmm/builder.h>
-#include <gtkmm/checkmenuitem.h>
-#include <gtkmm/menu.h>
-#include <gtkmm/menuitem.h>
-
-#include "ingen/client/ObjectModel.hpp"
-#include "ingen/types.hpp"
-
-namespace Ingen {
-namespace GUI {
-
-class ObjectControlWindow;
-class ObjectPropertiesWindow;
-class GraphCanvas;
-
-/** Menu for a Object.
- *
- * \ingroup GUI
- */
-class ObjectMenu : public Gtk::Menu
-{
-public:
- ObjectMenu(BaseObjectType* cobject,
- const Glib::RefPtr<Gtk::Builder>& xml);
-
- void init(App& app, SPtr<const Client::ObjectModel> object);
-
- SPtr<const Client::ObjectModel> object() const { return _object; }
- App* app() const { return _app; }
-
-protected:
- void on_menu_learn();
- void on_menu_unlearn();
- virtual void on_menu_disconnect() = 0;
- void on_menu_polyphonic();
- void on_menu_destroy();
- void on_menu_properties();
-
- void property_changed(const URI& predicate, const Atom& value);
-
- App* _app;
- SPtr<const Client::ObjectModel> _object;
- Gtk::MenuItem* _learn_menuitem;
- Gtk::MenuItem* _unlearn_menuitem;
- Gtk::CheckMenuItem* _polyphonic_menuitem;
- Gtk::MenuItem* _disconnect_menuitem;
- Gtk::MenuItem* _rename_menuitem;
- Gtk::MenuItem* _destroy_menuitem;
- Gtk::MenuItem* _properties_menuitem;
- Gtk::SeparatorMenuItem* _separator_menuitem;
-
- bool _enable_signal;
-};
-
-} // namespace GUI
-} // namespace Ingen
-
-#endif // INGEN_GUI_OBJECTMENU_HPP
diff --git a/src/gui/PluginMenu.cpp b/src/gui/PluginMenu.cpp
deleted file mode 100644
index fc385773..00000000
--- a/src/gui/PluginMenu.cpp
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- This file is part of Ingen.
- Copyright 2014-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 "PluginMenu.hpp"
-#include "ingen/Log.hpp"
-#include "ingen/client/PluginModel.hpp"
-
-namespace Ingen {
-namespace GUI {
-
-PluginMenu::PluginMenu(Ingen::World& world)
- : _world(world)
- , _classless_menu(nullptr, nullptr)
-{
- 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(nullptr, nullptr);
- _class_menus.clear();
- items().clear();
-
- // Build skeleton
- LV2Children children;
- LILV_FOREACH(plugin_classes, i, classes) {
- const LilvPluginClass* c = lilv_plugin_classes_get(classes, i);
- const LilvNode* p = lilv_plugin_class_get_parent_uri(c);
- if (!p) {
- p = lilv_plugin_class_get_uri(lv2_plugin);
- }
- children.emplace(lilv_node_as_string(p), c);
- }
-
- std::set<const char*> ancestors;
- build_plugin_class_menu(this, lv2_plugin, classes, children, ancestors);
-
- items().push_back(Gtk::Menu_Helpers::MenuElem("_Uncategorized"));
- _classless_menu.item = &(items().back());
- _classless_menu.menu = Gtk::manage(new Gtk::Menu());
- _classless_menu.item->set_submenu(*_classless_menu.menu);
- _classless_menu.item->hide();
-}
-
-void
-PluginMenu::add_plugin(SPtr<Client::PluginModel> p)
-{
- typedef ClassMenus::iterator iterator;
-
- if (!p->lilv_plugin() || lilv_plugin_is_replaced(p->lilv_plugin())) {
- return;
- }
-
- const LilvPluginClass* pc = lilv_plugin_get_class(p->lilv_plugin());
- const LilvNode* class_uri = lilv_plugin_class_get_uri(pc);
- const char* class_uri_str = lilv_node_as_string(class_uri);
-
- std::pair<iterator, iterator> range = _class_menus.equal_range(class_uri_str);
- if (range.first == _class_menus.end() || range.first == range.second
- || range.first->second.menu == this) {
- // Add to uncategorized plugin menu
- add_plugin_to_menu(_classless_menu, p);
- } else {
- // For each menu that represents plugin's class (possibly several)
- for (auto i = range.first; i != range.second ; ++i) {
- add_plugin_to_menu(i->second, p);
- }
- }
-}
-
-size_t
-PluginMenu::build_plugin_class_menu(Gtk::Menu* menu,
- const LilvPluginClass* plugin_class,
- const LilvPluginClasses* classes,
- const LV2Children& children,
- std::set<const char*>& ancestors)
-{
- size_t num_items = 0;
- const LilvNode* class_uri = lilv_plugin_class_get_uri(plugin_class);
- const char* class_uri_str = lilv_node_as_string(class_uri);
-
- const std::pair<LV2Children::const_iterator, LV2Children::const_iterator> kids
- = children.equal_range(class_uri_str);
-
- if (kids.first == children.end()) {
- return 0;
- }
-
- // Add submenus
- ancestors.insert(class_uri_str);
- for (LV2Children::const_iterator i = kids.first; i != kids.second; ++i) {
- const LilvPluginClass* c = i->second;
- const char* sub_label_str = lilv_node_as_string(lilv_plugin_class_get_label(c));
- const char* sub_uri_str = lilv_node_as_string(lilv_plugin_class_get_uri(c));
- if (ancestors.find(sub_uri_str) != ancestors.end()) {
- _world.log().warn(fmt("Infinite LV2 class recursion: %1% <: %2%\n")
- % class_uri_str % sub_uri_str);
- return 0;
- }
-
- Gtk::Menu_Helpers::MenuElem menu_elem = Gtk::Menu_Helpers::MenuElem(
- std::string("_") + sub_label_str);
- menu->items().push_back(menu_elem);
- Gtk::MenuItem* menu_item = &(menu->items().back());
-
- Gtk::Menu* submenu = Gtk::manage(new Gtk::Menu());
- menu_item->set_submenu(*submenu);
-
- size_t num_child_items = build_plugin_class_menu(
- submenu, c, classes, children, ancestors);
-
- _class_menus.emplace(sub_uri_str, MenuRecord(menu_item, submenu));
- if (num_child_items == 0) {
- menu_item->hide();
- }
-
- ++num_items;
- }
- ancestors.erase(class_uri_str);
-
- return num_items;
-}
-
-void
-PluginMenu::add_plugin_to_menu(MenuRecord& menu, SPtr<Client::PluginModel> p)
-{
- const URIs& uris = _world.uris();
- LilvWorld* lworld = _world.lilv_world();
- LilvNode* ingen_Graph = lilv_new_uri(lworld, uris.ingen_Graph.c_str());
- LilvNode* rdf_type = lilv_new_uri(lworld, uris.rdf_type.c_str());
-
- bool is_graph = lilv_world_ask(lworld,
- lilv_plugin_get_uri(p->lilv_plugin()),
- rdf_type,
- ingen_Graph);
-
- menu.menu->items().push_back(
- Gtk::Menu_Helpers::MenuElem(
- std::string("_") + p->human_name() + (is_graph ? " ⚙" : ""),
- sigc::bind(sigc::mem_fun(this, &PluginMenu::load_plugin), p)));
-
- if (!menu.item->is_visible()) {
- menu.item->show();
- }
-
- lilv_node_free(rdf_type);
- lilv_node_free(ingen_Graph);
-}
-
-void
-PluginMenu::load_plugin(WPtr<Client::PluginModel> weak_plugin)
-{
- signal_load_plugin.emit(weak_plugin);
-}
-
-} // namespace GUI
-} // namespace Ingen
diff --git a/src/gui/PluginMenu.hpp b/src/gui/PluginMenu.hpp
deleted file mode 100644
index bc654db5..00000000
--- a/src/gui/PluginMenu.hpp
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- This file is part of Ingen.
- Copyright 2014-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_GUI_PLUGINMENU_HPP
-#define INGEN_GUI_PLUGINMENU_HPP
-
-#include <map>
-#include <set>
-#include <string>
-
-#include <gtkmm/menu.h>
-
-#include "ingen/World.hpp"
-#include "ingen/types.hpp"
-#include "lilv/lilv.h"
-
-namespace Ingen {
-
-namespace Client { class PluginModel; }
-
-namespace GUI {
-
-/**
- Type-hierarchical plugin menu.
-
- @ingroup GUI
-*/
-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;
-
-private:
- struct MenuRecord {
- MenuRecord(Gtk::MenuItem* i, Gtk::Menu* m) : item(i), menu(m) {}
- Gtk::MenuItem* item;
- Gtk::Menu* menu;
- };
-
- typedef std::multimap<const std::string, const LilvPluginClass*> LV2Children;
- typedef std::multimap<const std::string, MenuRecord> ClassMenus;
-
- /// Recursively add hierarchy rooted at `plugin_class` to `menu`.
- size_t build_plugin_class_menu(Gtk::Menu* menu,
- const LilvPluginClass* plugin_class,
- const LilvPluginClasses* classes,
- const LV2Children& children,
- std::set<const char*>& ancestors);
-
- void add_plugin_to_menu(MenuRecord& menu, SPtr<Client::PluginModel> p);
-
- void load_plugin(WPtr<Client::PluginModel> weak_plugin);
-
- Ingen::World& _world;
- MenuRecord _classless_menu;
- ClassMenus _class_menus;
-};
-
-} // namespace GUI
-} // namespace Ingen
-
-#endif // INGEN_GUI_PLUGINMENU_HPP
diff --git a/src/gui/Port.cpp b/src/gui/Port.cpp
deleted file mode 100644
index 9742cee3..00000000
--- a/src/gui/Port.cpp
+++ /dev/null
@@ -1,534 +0,0 @@
-/*
- 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/>.
-*/
-
-#include <cassert>
-#include <string>
-
-#include "ganv/Module.hpp"
-#include "ingen/Configuration.hpp"
-#include "ingen/Interface.hpp"
-#include "ingen/Log.hpp"
-#include "ingen/URIMap.hpp"
-#include "ingen/client/GraphModel.hpp"
-#include "ingen/client/PortModel.hpp"
-
-#include "App.hpp"
-#include "GraphWindow.hpp"
-#include "Port.hpp"
-#include "PortMenu.hpp"
-#include "RDFS.hpp"
-#include "Style.hpp"
-#include "WidgetFactory.hpp"
-#include "WindowFactory.hpp"
-#include "ingen_config.h"
-#include "rgba.hpp"
-
-using namespace Ingen::Client;
-
-namespace Ingen {
-namespace GUI {
-
-Port*
-Port::create(App& app,
- Ganv::Module& module,
- SPtr<const PortModel> pm,
- bool flip)
-{
- return new Port(app, module, pm, port_label(app, pm), flip);
-}
-
-/** @param flip Make an input port appear as an output port, and vice versa.
- */
-Port::Port(App& app,
- Ganv::Module& module,
- SPtr<const PortModel> pm,
- const std::string& name,
- bool flip)
- : Ganv::Port(module, name,
- flip ? (!pm->is_input()) : pm->is_input(),
- app.style()->get_port_color(pm.get()))
- , _app(app)
- , _port_model(pm)
- , _entered(false)
- , _flipped(flip)
-{
- assert(pm);
-
- if (app.can_control(pm.get())) {
- show_control();
- pm->signal_value_changed().connect(
- sigc::mem_fun(this, &Port::value_changed));
- }
-
- port_properties_changed();
-
- pm->signal_property().connect(
- sigc::mem_fun(this, &Port::property_changed));
- pm->signal_property_removed().connect(
- sigc::mem_fun(this, &Port::property_removed));
- pm->signal_activity().connect(
- sigc::mem_fun(this, &Port::activity));
- pm->signal_moved().connect(
- sigc::mem_fun(this, &Port::moved));
-
- signal_value_changed.connect(
- sigc::mem_fun(this, &Port::on_value_changed));
-
- signal_event().connect(
- sigc::mem_fun(this, &Port::on_event));
-
- set_is_controllable(pm->is_numeric() && pm->is_input());
-
- Ganv::Port::set_beveled(model()->is_a(_app.uris().lv2_ControlPort) ||
- model()->has_property(_app.uris().atom_bufferType,
- _app.uris().atom_Sequence));
-
- for (const auto& p : pm->properties()) {
- property_changed(p.first, p.second);
- }
-
- update_metadata();
- value_changed(pm->value());
-}
-
-Port::~Port()
-{
- _app.activity_port_destroyed(this);
-}
-
-std::string
-Port::port_label(App& app, SPtr<const PortModel> pm)
-{
- if (!pm) {
- return "";
- }
-
- std::string label;
- if (app.world()->conf().option("port-labels").get<int32_t>()) {
- if (app.world()->conf().option("human-names").get<int32_t>()) {
- const Atom& name = pm->get_property(app.uris().lv2_name);
- if (name.type() == app.forge().String) {
- label = name.ptr<char>();
- } else {
- const SPtr<const BlockModel> parent(
- dynamic_ptr_cast<const BlockModel>(pm->parent()));
- if (parent && parent->plugin_model()) {
- label = parent->plugin_model()->port_human_name(pm->index());
- }
- }
- } else {
- label = pm->path().symbol();
- }
- }
- return label;
-}
-
-void
-Port::ensure_label()
-{
- if (!get_label()) {
- set_label(port_label(_app, _port_model.lock()).c_str());
- }
-}
-
-void
-Port::update_metadata()
-{
- SPtr<const PortModel> pm = _port_model.lock();
- if (pm && _app.can_control(pm.get()) && pm->is_numeric()) {
- SPtr<const BlockModel> parent = dynamic_ptr_cast<const BlockModel>(pm->parent());
- if (parent) {
- float min = 0.0f;
- float max = 1.0f;
- parent->port_value_range(pm, min, max, _app.sample_rate());
- set_control_min(min);
- set_control_max(max);
- }
- }
-}
-
-bool
-Port::show_menu(GdkEventButton* ev)
-{
- PortMenu* menu = nullptr;
- WidgetFactory::get_widget_derived("object_menu", menu);
- if (!menu) {
- _app.log().error("Failed to load port menu widget\n");
- return false;
- }
-
- menu->init(_app, model(), _flipped);
- menu->popup(ev->button, ev->time);
- return true;
-}
-
-void
-Port::moved()
-{
- if (_app.world()->conf().option("port-labels").get<int32_t>() &&
- !_app.world()->conf().option("human-names").get<int32_t>()) {
- set_label(model()->symbol().c_str());
- }
-}
-
-void
-Port::on_value_changed(double value)
-{
- const URIs& uris = _app.uris();
- const Atom& current_value = model()->value();
- if (current_value.type() != uris.forge.Float) {
- return; // Non-float, unsupported
- }
-
- if (current_value.get<float>() == (float)value) {
- return; // No change
- }
-
- const Atom atom = _app.forge().make(float(value));
- _app.set_property(model()->uri(),
- _app.world()->uris().ingen_value,
- atom);
-
- if (_entered) {
- GraphBox* box = get_graph_box();
- if (box) {
- box->show_port_status(model().get(), atom);
- }
- }
-}
-
-void
-Port::value_changed(const Atom& value)
-{
- if (value.type() == _app.forge().Float && !get_grabbed()) {
- Ganv::Port::set_control_value(value.get<float>());
- }
-}
-
-void
-Port::on_scale_point_activated(float f)
-{
- _app.set_property(model()->uri(),
- _app.world()->uris().ingen_value,
- _app.world()->forge().make(f));
-}
-
-Gtk::Menu*
-Port::build_enum_menu()
-{
- SPtr<const BlockModel> block = dynamic_ptr_cast<BlockModel>(model()->parent());
- Gtk::Menu* menu = Gtk::manage(new Gtk::Menu());
-
- PluginModel::ScalePoints points = block->plugin_model()->port_scale_points(
- model()->index());
- for (auto i = points.begin(); i != points.end(); ++i) {
- menu->items().push_back(Gtk::Menu_Helpers::MenuElem(i->second));
- Gtk::MenuItem* menu_item = &(menu->items().back());
- menu_item->signal_activate().connect(
- sigc::bind(sigc::mem_fun(this, &Port::on_scale_point_activated),
- i->first));
- }
-
- return menu;
-}
-
-void
-Port::on_uri_activated(const URI& uri)
-{
- _app.set_property(model()->uri(),
- _app.world()->uris().ingen_value,
- _app.world()->forge().make_urid(
- _app.world()->uri_map().map_uri(uri.c_str())));
-}
-
-Gtk::Menu*
-Port::build_uri_menu()
-{
- World* world = _app.world();
- SPtr<const BlockModel> block = dynamic_ptr_cast<BlockModel>(model()->parent());
- Gtk::Menu* menu = Gtk::manage(new Gtk::Menu());
-
- // Get the port designation, which should be a rdf:Property
- const Atom& designation_atom = model()->get_property(
- _app.uris().lv2_designation);
- if (!designation_atom.is_valid()) {
- return nullptr;
- }
-
- LilvNode* designation = lilv_new_uri(
- world->lilv_world(), world->forge().str(designation_atom, false).c_str());
- LilvNode* rdfs_range = lilv_new_uri(
- world->lilv_world(), LILV_NS_RDFS "range");
-
- // Get every class in the range of the port's property
- RDFS::URISet ranges;
- LilvNodes* range = lilv_world_find_nodes(
- world->lilv_world(), designation, rdfs_range, nullptr);
- LILV_FOREACH(nodes, r, range) {
- ranges.insert(URI(lilv_node_as_string(lilv_nodes_get(range, r))));
- }
- RDFS::classes(world, ranges, false);
-
- // Get all objects in range
- RDFS::Objects values = RDFS::instances(world, ranges);
-
- // Add a menu item for each such class
- for (const auto& v : values) {
- if (!v.first.empty()) {
- const std::string qname = world->rdf_world()->prefixes().qualify(v.second);
- const std::string label = qname + " - " + v.first;
- menu->items().push_back(Gtk::Menu_Helpers::MenuElem(label));
- Gtk::MenuItem* menu_item = &(menu->items().back());
- menu_item->signal_activate().connect(
- sigc::bind(sigc::mem_fun(this, &Port::on_uri_activated),
- v.second));
- }
- }
-
- return menu;
-}
-
-bool
-Port::on_event(GdkEvent* ev)
-{
- GraphBox* box = nullptr;
- switch (ev->type) {
- case GDK_ENTER_NOTIFY:
- _entered = true;
- if ((box = get_graph_box())) {
- box->object_entered(model().get());
- }
- return false;
- case GDK_LEAVE_NOTIFY:
- _entered = false;
- if ((box = get_graph_box())) {
- box->object_left(model().get());
- }
- return false;
- case GDK_BUTTON_PRESS:
- if (ev->button.button == 1) {
- if (model()->is_enumeration()) {
- Gtk::Menu* menu = build_enum_menu();
- menu->popup(ev->button.button, ev->button.time);
- return true;
- } else if (model()->is_uri()) {
- Gtk::Menu* menu = build_uri_menu();
- if (menu) {
- menu->popup(ev->button.button, ev->button.time);
- return true;
- }
- }
- } else if (ev->button.button == 3) {
- return show_menu(&ev->button);
- }
- break;
- default:
- break;
- }
-
- return false;
-}
-
-inline static uint32_t
-peak_color(float peak)
-{
- static const uint32_t min = 0x4A8A0EC0;
- static const uint32_t max = 0xFFCE1FC0;
- static const uint32_t peak_min = 0xFF561FC0;
- static const uint32_t peak_max = 0xFF0A38C0;
-
- if (peak < 1.0) {
- return rgba_interpolate(min, max, peak);
- } else {
- return rgba_interpolate(peak_min, peak_max, fminf(peak, 2.0f) - 1.0f);
- }
-}
-
-void
-Port::activity(const Atom& value)
-{
- if (model()->is_a(_app.uris().lv2_AudioPort)) {
- set_fill_color(peak_color(value.get<float>()));
- } else if (_app.can_control(model().get()) && value.type() == _app.uris().atom_Float) {
- Ganv::Port::set_control_value(value.get<float>());
- } else {
- _app.port_activity(this);
- }
-}
-
-GraphBox*
-Port::get_graph_box() const
-{
- SPtr<const GraphModel> graph = dynamic_ptr_cast<const GraphModel>(model()->parent());
- GraphBox* box = _app.window_factory()->graph_box(graph);
- if (!box) {
- graph = dynamic_ptr_cast<const GraphModel>(model()->parent()->parent());
- box = _app.window_factory()->graph_box(graph);
- }
- return box;
-}
-
-void
-Port::set_type_tag()
-{
- const URIs& uris = _app.uris();
- std::string tag;
- if (model()->is_a(_app.uris().lv2_AudioPort)) {
- tag = "~";
- } else if (model()->is_a(_app.uris().lv2_CVPort)) {
- tag = "ℝ̰";
- } else if (model()->is_a(_app.uris().lv2_ControlPort)) {
- if (model()->is_enumeration()) {
- tag = "…";
- } else if (model()->is_integer()) {
- tag = "ℤ";
- } else if (model()->is_toggle()) {
- tag = ((model()->value() != _app.uris().forge.make(0.0f))
- ? "☑" : "☐");
-
- } else {
- tag = "ℝ";
- }
- } else if (model()->is_a(_app.uris().atom_AtomPort)) {
- if (model()->supports(_app.uris().atom_Float)) {
- if (model()->is_toggle()) {
- tag = ((model()->value() != _app.uris().forge.make(0.0f))
- ? "☑" : "☐");
- } else {
- tag = "ℝ";
- }
- }
- if (model()->supports(_app.uris().atom_Int)) {
- tag += "ℤ";
- }
- if (model()->supports(_app.uris().midi_MidiEvent)) {
- tag += "𝕄";
- }
- if (model()->supports(_app.uris().patch_Message)) {
- if (tag.empty()) {
- tag += "=";
- } else {
- tag += "̿";
- }
- }
- if (tag.empty()) {
- tag = "*";
- }
-
- if (model()->has_property(uris.atom_bufferType, uris.atom_Sequence)) {
- tag += "̤";
- }
- }
-
- if (!tag.empty()) {
- set_value_label(tag.c_str());
- }
-}
-
-void
-Port::port_properties_changed()
-{
- if (model()->is_toggle()) {
- set_control_is_toggle(true);
- } else if (model()->is_integer()) {
- set_control_is_integer(true);
- }
- set_type_tag();
-}
-
-void
-Port::property_changed(const URI& key, const Atom& value)
-{
- const URIs& uris = _app.uris();
- if (value.type() == uris.forge.Float) {
- float val = value.get<float>();
- if (key == uris.ingen_value && !get_grabbed()) {
- Ganv::Port::set_control_value(val);
- if (model()->is_toggle()) {
- std::string tag = (val == 0.0f) ? "☐" : "☑";
- if (model()->is_a(_app.uris().lv2_CVPort)) {
- tag += "̰";
- } else if (model()->has_property(uris.atom_bufferType,
- uris.atom_Sequence)) {
- tag += "̤";
- }
- set_value_label(tag.c_str());
- }
- } else if (key == uris.lv2_minimum) {
- if (model()->port_property(uris.lv2_sampleRate)) {
- val *= _app.sample_rate();
- }
- set_control_min(val);
- } else if (key == uris.lv2_maximum) {
- if (model()->port_property(uris.lv2_sampleRate)) {
- val *= _app.sample_rate();
- }
- set_control_max(val);
- }
- } else if (key == uris.lv2_portProperty) {
- port_properties_changed();
- } else if (key == uris.lv2_name) {
- if (value.type() == uris.forge.String &&
- _app.world()->conf().option("port-labels").get<int32_t>() &&
- _app.world()->conf().option("human-names").get<int32_t>()) {
- set_label(value.ptr<char>());
- }
- } else if (key == uris.rdf_type || key == uris.atom_bufferType) {
- set_fill_color(_app.style()->get_port_color(model().get()));
- Ganv::Port::set_beveled(model()->is_a(uris.lv2_ControlPort) ||
- model()->has_property(uris.atom_bufferType,
- uris.atom_Sequence));
- }
-}
-
-void
-Port::property_removed(const URI& key, const Atom& value)
-{
- const URIs& uris = _app.uris();
- if (key == uris.lv2_minimum || key == uris.lv2_maximum) {
- update_metadata();
- } else if (key == uris.rdf_type || key == uris.atom_bufferType) {
- Ganv::Port::set_beveled(model()->is_a(uris.lv2_ControlPort) ||
- model()->has_property(uris.atom_bufferType,
- uris.atom_Sequence));
- }
-}
-
-bool
-Port::on_selected(gboolean b)
-{
- if (b) {
- SPtr<const PortModel> pm = _port_model.lock();
- if (pm) {
- SPtr<const BlockModel> block = dynamic_ptr_cast<const BlockModel>(pm->parent());
- GraphWindow* win = _app.window_factory()->parent_graph_window(block);
- if (win && win->documentation_is_visible() && block->plugin_model()) {
- bool html = false;
-#ifdef HAVE_WEBKIT
- html = true;
-#endif
- const std::string& doc = block->plugin_model()->port_documentation(
- pm->index(), html);
- win->set_documentation(doc, html);
- }
- }
- }
-
- return true;
-}
-
-} // namespace GUI
-} // namespace Ingen
diff --git a/src/gui/Port.hpp b/src/gui/Port.hpp
deleted file mode 100644
index c714feae..00000000
--- a/src/gui/Port.hpp
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- 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_GUI_PORT_HPP
-#define INGEN_GUI_PORT_HPP
-
-#include <cassert>
-#include <string>
-
-#include <gtkmm/menu.h>
-
-#include "ganv/Port.hpp"
-#include "ingen/types.hpp"
-
-namespace Raul {
-class Atom;
-}
-
-namespace Ingen {
-
-class URI;
-
-namespace Client { class PortModel; }
-
-namespace GUI {
-
-class App;
-class GraphBox;
-
-/** A Port on an Module.
- *
- * \ingroup GUI
- */
-class Port : public Ganv::Port
-{
-public:
- static Port* create(
- App& app,
- Ganv::Module& module,
- SPtr<const Client::PortModel> pm,
- bool flip = false);
-
- ~Port();
-
- SPtr<const Client::PortModel> model() const { return _port_model.lock(); }
-
- bool show_menu(GdkEventButton* ev);
- void update_metadata();
- void ensure_label();
-
- void value_changed(const Atom& value);
- void activity(const Atom& value);
-
- bool on_selected(gboolean b);
-
-private:
- Port(App& app,
- Ganv::Module& module,
- SPtr<const Client::PortModel> pm,
- const std::string& name,
- bool flip = false);
-
- static std::string port_label(App& app, SPtr<const Client::PortModel> pm);
-
- Gtk::Menu* build_enum_menu();
- Gtk::Menu* build_uri_menu();
- GraphBox* get_graph_box() const;
-
- void property_changed(const URI& key, const Atom& value);
- void property_removed(const URI& key, const Atom& value);
- void moved();
-
- void on_value_changed(double value);
- void on_scale_point_activated(float f);
- void on_uri_activated(const URI& uri);
- bool on_event(GdkEvent* ev);
- void port_properties_changed();
- void set_type_tag();
-
- App& _app;
- WPtr<const Client::PortModel> _port_model;
- bool _entered : 1;
- bool _flipped : 1;
-};
-
-} // namespace GUI
-} // namespace Ingen
-
-#endif // INGEN_GUI_PORT_HPP
diff --git a/src/gui/PortMenu.cpp b/src/gui/PortMenu.cpp
deleted file mode 100644
index c6ec8fa1..00000000
--- a/src/gui/PortMenu.cpp
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- 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 <cmath>
-
-#include "ingen/Interface.hpp"
-#include "ingen/client/GraphModel.hpp"
-#include "ingen/client/PortModel.hpp"
-#include "ingen/types.hpp"
-
-#include "App.hpp"
-#include "PortMenu.hpp"
-#include "WindowFactory.hpp"
-
-namespace Ingen {
-
-using namespace Client;
-
-namespace GUI {
-
-PortMenu::PortMenu(BaseObjectType* cobject,
- const Glib::RefPtr<Gtk::Builder>& xml)
- : ObjectMenu(cobject, xml)
- , _internal_graph_port(false)
-{
- xml->get_widget("object_menu", _port_menu);
- xml->get_widget("port_set_min_menuitem", _set_min_menuitem);
- xml->get_widget("port_set_max_menuitem", _set_max_menuitem);
- xml->get_widget("port_reset_range_menuitem", _reset_range_menuitem);
- xml->get_widget("port_expose_menuitem", _expose_menuitem);
-}
-
-void
-PortMenu::init(App& app, SPtr<const PortModel> port, bool internal_graph_port)
-{
- const URIs& uris = app.uris();
-
- ObjectMenu::init(app, port);
- _internal_graph_port = internal_graph_port;
-
- _set_min_menuitem->signal_activate().connect(
- sigc::mem_fun(this, &PortMenu::on_menu_set_min));
-
- _set_max_menuitem->signal_activate().connect(
- sigc::mem_fun(this, &PortMenu::on_menu_set_max));
-
- _reset_range_menuitem->signal_activate().connect(
- sigc::mem_fun(this, &PortMenu::on_menu_reset_range));
-
- _expose_menuitem->signal_activate().connect(
- sigc::mem_fun(this, &PortMenu::on_menu_expose));
-
- const bool is_control(app.can_control(port.get()) && port->is_numeric());
- const bool is_on_graph(dynamic_ptr_cast<GraphModel>(port->parent()));
- const bool is_input(port->is_input());
-
- if (!is_on_graph) {
- _polyphonic_menuitem->set_sensitive(false);
- _rename_menuitem->set_sensitive(false);
- _destroy_menuitem->set_sensitive(false);
- }
-
- if (port->is_a(uris.atom_AtomPort)) {
- _polyphonic_menuitem->hide();
- }
-
- _reset_range_menuitem->set_visible(is_input && is_control && !is_on_graph);
- _set_max_menuitem->set_visible(is_input && is_control);
- _set_min_menuitem->set_visible(is_input && is_control);
- _expose_menuitem->set_visible(!is_on_graph);
- _learn_menuitem->set_visible(is_input && is_control);
- _unlearn_menuitem->set_visible(is_input && is_control);
-
- if (!is_control && is_on_graph) {
- _separator_menuitem->hide();
- }
-
- _enable_signal = true;
-}
-
-void
-PortMenu::on_menu_disconnect()
-{
- if (_internal_graph_port) {
- _app->interface()->disconnect_all(
- _object->parent()->path(), _object->path());
- } else {
- _app->interface()->disconnect_all(
- _object->parent()->path().parent(), _object->path());
- }
-}
-
-void
-PortMenu::on_menu_set_min()
-{
- const URIs& uris = _app->uris();
- SPtr<const PortModel> model = dynamic_ptr_cast<const PortModel>(_object);
- const Atom& value = model->get_property(uris.ingen_value);
- if (value.is_valid()) {
- _app->set_property(_object->uri(), uris.lv2_minimum, value);
- }
-}
-
-void
-PortMenu::on_menu_set_max()
-{
- const URIs& uris = _app->uris();
- SPtr<const PortModel> model = dynamic_ptr_cast<const PortModel>(_object);
- const Atom& value = model->get_property(uris.ingen_value);
- if (value.is_valid()) {
- _app->set_property(_object->uri(), uris.lv2_maximum, value);
- }
-}
-
-void
-PortMenu::on_menu_reset_range()
-{
- const URIs& uris = _app->uris();
- SPtr<const PortModel> model = dynamic_ptr_cast<const PortModel>(_object);
-
- // Remove lv2:minimum and lv2:maximum properties
- Properties remove;
- remove.insert({uris.lv2_minimum, Property(uris.patch_wildcard)});
- remove.insert({uris.lv2_maximum, Property(uris.patch_wildcard)});
- _app->interface()->delta(_object->uri(), remove, Properties());
-}
-
-void
-PortMenu::on_menu_expose()
-{
- const URIs& uris = _app->uris();
- SPtr<const PortModel> port = dynamic_ptr_cast<const PortModel>(_object);
- SPtr<const BlockModel> block = dynamic_ptr_cast<const BlockModel>(port->parent());
-
- const std::string label = block->label() + " " + block->port_label(port);
- const Raul::Path path = Raul::Path(block->path() + Raul::Symbol("_" + port->symbol()));
-
- Ingen::Resource r(*_object.get());
- r.remove_property(uris.lv2_index, uris.patch_wildcard);
- r.set_property(uris.lv2_symbol, _app->forge().alloc(path.symbol()));
- r.set_property(uris.lv2_name, _app->forge().alloc(label.c_str()));
-
- // TODO: Pretty kludgey coordinates
- const float block_x = block->get_property(uris.ingen_canvasX).get<float>();
- const float block_y = block->get_property(uris.ingen_canvasY).get<float>();
- const float x_off = (label.length() * 16.0f) * (port->is_input() ? -1 : 1);
- const float y_off = port->index() * 32.0f;
- r.set_property(uris.ingen_canvasX, _app->forge().make(block_x + x_off));
- r.set_property(uris.ingen_canvasY, _app->forge().make(block_y + y_off));
-
- _app->interface()->put(path_to_uri(path), r.properties());
-
- if (port->is_input()) {
- _app->interface()->connect(path, _object->path());
- } else {
- _app->interface()->connect(_object->path(), path);
- }
-}
-
-} // namespace GUI
-} // namespace Ingen
diff --git a/src/gui/PortMenu.hpp b/src/gui/PortMenu.hpp
deleted file mode 100644
index db567980..00000000
--- a/src/gui/PortMenu.hpp
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- 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_GUI_PORTMENU_HPP
-#define INGEN_GUI_PORTMENU_HPP
-
-#include <gtkmm/builder.h>
-#include <gtkmm/menu.h>
-#include <gtkmm/menushell.h>
-
-#include "ingen/client/PortModel.hpp"
-#include "ingen/types.hpp"
-
-#include "ObjectMenu.hpp"
-
-namespace Ingen {
-namespace GUI {
-
-/** Menu for a Port.
- *
- * \ingroup GUI
- */
-class PortMenu : public ObjectMenu
-{
-public:
- PortMenu(BaseObjectType* cobject,
- const Glib::RefPtr<Gtk::Builder>& xml);
-
- void init(App& app,
- SPtr<const Client::PortModel> port,
- bool internal_graph_port = false);
-
-private:
- void on_menu_disconnect();
- void on_menu_set_min();
- void on_menu_set_max();
- void on_menu_reset_range();
- void on_menu_expose();
-
- Gtk::Menu* _port_menu;
- Gtk::MenuItem* _set_min_menuitem;
- Gtk::MenuItem* _set_max_menuitem;
- Gtk::MenuItem* _reset_range_menuitem;
- Gtk::MenuItem* _expose_menuitem;
-
- /// True iff this is a (flipped) port on a GraphPortModule in its graph
- bool _internal_graph_port;
-};
-
-} // namespace GUI
-} // namespace Ingen
-
-#endif // INGEN_GUI_PORTMENU_HPP
diff --git a/src/gui/PropertiesWindow.cpp b/src/gui/PropertiesWindow.cpp
deleted file mode 100644
index 4d47b3ae..00000000
--- a/src/gui/PropertiesWindow.cpp
+++ /dev/null
@@ -1,591 +0,0 @@
-/*
- 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 <algorithm>
-#include <cassert>
-#include <set>
-
-#include <gtkmm/label.h>
-#include <gtkmm/spinbutton.h>
-
-#include "ingen/Interface.hpp"
-#include "ingen/Log.hpp"
-#include "ingen/URIMap.hpp"
-#include "ingen/World.hpp"
-#include "ingen/client/BlockModel.hpp"
-#include "ingen/client/PluginModel.hpp"
-
-#include "App.hpp"
-#include "PropertiesWindow.hpp"
-#include "RDFS.hpp"
-#include "URIEntry.hpp"
-
-namespace Ingen {
-
-using namespace Client;
-
-namespace GUI {
-
-typedef std::set<URI> URISet;
-
-PropertiesWindow::PropertiesWindow(BaseObjectType* cobject,
- const Glib::RefPtr<Gtk::Builder>& xml)
- : Window(cobject)
- , _value_type(0)
-{
- xml->get_widget("properties_vbox", _vbox);
- xml->get_widget("properties_scrolledwindow", _scrolledwindow);
- xml->get_widget("properties_table", _table);
- xml->get_widget("properties_key_combo", _key_combo);
- xml->get_widget("properties_value_bin", _value_bin);
- xml->get_widget("properties_add_button", _add_button);
- xml->get_widget("properties_cancel_button", _cancel_button);
- xml->get_widget("properties_apply_button", _apply_button);
- xml->get_widget("properties_ok_button", _ok_button);
-
- _key_store = Gtk::ListStore::create(_combo_columns);
- _key_combo->set_model(_key_store);
- _key_combo->pack_start(_combo_columns.label_col);
-
- _key_combo->signal_changed().connect(
- sigc::mem_fun(this, &PropertiesWindow::key_changed));
-
- _add_button->signal_clicked().connect(
- sigc::mem_fun(this, &PropertiesWindow::add_clicked));
-
- _cancel_button->signal_clicked().connect(
- sigc::mem_fun(this, &PropertiesWindow::cancel_clicked));
-
- _apply_button->signal_clicked().connect(
- sigc::mem_fun(this, &PropertiesWindow::apply_clicked));
-
- _ok_button->signal_clicked().connect(
- sigc::mem_fun(this, &PropertiesWindow::ok_clicked));
-}
-
-void
-PropertiesWindow::reset()
-{
- _property_connection.disconnect();
- _property_removed_connection.disconnect();
-
- _key_store->clear();
- _records.clear();
-
- _model.reset();
-
- _table->children().clear();
- _table->resize(1, 3);
- _table->property_n_rows() = 1;
-}
-
-void
-PropertiesWindow::present(SPtr<const ObjectModel> model)
-{
- set_object(model);
- Gtk::Window::present();
-}
-
-void
-PropertiesWindow::add_property(const URI& key, const Atom& value)
-{
- World* world = _app->world();
-
- const unsigned n_rows = _table->property_n_rows() + 1;
- _table->property_n_rows() = n_rows;
-
- // Column 0: Property
- LilvNode* prop = lilv_new_uri(world->lilv_world(), key.c_str());
- std::string name = RDFS::label(world, prop);
- if (name.empty()) {
- name = world->rdf_world()->prefixes().qualify(key);
- }
- Gtk::Label* label = new Gtk::Label(
- std::string("<a href=\"") + key.string() + "\">" + name + "</a>",
- 1.0,
- 0.5);
- label->set_use_markup(true);
- _app->set_tooltip(label, prop);
- _table->attach(*Gtk::manage(label), 0, 1, n_rows, n_rows + 1,
- Gtk::FILL|Gtk::SHRINK, Gtk::SHRINK);
-
- // Column 1: Value
- Gtk::Alignment* align = manage(new Gtk::Alignment(0.0, 0.5, 1.0, 1.0));
- Gtk::CheckButton* present = manage(new Gtk::CheckButton());
- const char* type = _app->world()->uri_map().unmap_uri(value.type());
- Gtk::Widget* val_widget = create_value_widget(key, type, value);
-
- present->set_active();
- if (val_widget) {
- align->add(*Gtk::manage(val_widget));
- _app->set_tooltip(val_widget, prop);
- }
-
- _table->attach(*align, 1, 2, n_rows, n_rows + 1,
- Gtk::FILL|Gtk::EXPAND, Gtk::SHRINK);
- _table->attach(*present, 2, 3, n_rows, n_rows + 1,
- Gtk::FILL, Gtk::SHRINK);
- _records.emplace(key, Record(value, align, n_rows, present));
- _table->show_all();
-
- lilv_node_free(prop);
-}
-
-bool
-PropertiesWindow::datatype_supported(const RDFS::URISet& types,
- URI* widget_type)
-{
- if (types.find(_app->uris().atom_Int) != types.end()) {
- *widget_type = _app->uris().atom_Int;
- return true;
- } else if (types.find(_app->uris().atom_Float) != types.end()) {
- *widget_type = _app->uris().atom_Float;
- return true;
- } else if (types.find(_app->uris().atom_Bool) != types.end()) {
- *widget_type = _app->uris().atom_Bool;
- return true;
- } else if (types.find(_app->uris().atom_String) != types.end()) {
- *widget_type = _app->uris().atom_String;
- return true;
- } else if (types.find(_app->uris().atom_URID) != types.end()) {
- *widget_type = _app->uris().atom_URID;
- return true;
- }
-
- return false;
-}
-
-bool
-PropertiesWindow::class_supported(const RDFS::URISet& types)
-{
- World* world = _app->world();
- LilvNode* rdf_type = lilv_new_uri(
- world->lilv_world(), LILV_NS_RDF "type");
-
- for (const auto& t : types) {
- LilvNode* range = lilv_new_uri(world->lilv_world(), t.c_str());
- LilvNodes* instances = lilv_world_find_nodes(
- world->lilv_world(), nullptr, rdf_type, range);
-
- const bool has_instance = (lilv_nodes_size(instances) > 0);
-
- lilv_nodes_free(instances);
- lilv_node_free(range);
- if (has_instance) {
- lilv_node_free(rdf_type);
- return true;
- }
- }
-
- lilv_node_free(rdf_type);
- return false;
-}
-
-/** Set the node this window is associated with.
- * This function MUST be called before using this object in any way.
- */
-void
-PropertiesWindow::set_object(SPtr<const ObjectModel> model)
-{
- reset();
- _model = model;
-
- set_title(model->path() + " Properties - Ingen");
-
- World* world = _app->world();
-
- LilvNode* rdf_type = lilv_new_uri(
- world->lilv_world(), LILV_NS_RDF "type");
- LilvNode* rdfs_DataType = lilv_new_uri(
- world->lilv_world(), LILV_NS_RDFS "Datatype");
-
- // Populate key combo
- const URISet props = RDFS::properties(world, model);
- std::map<std::string, URI> entries;
- for (const auto& p : props) {
- LilvNode* prop = lilv_new_uri(world->lilv_world(), p.c_str());
- const std::string label = RDFS::label(world, prop);
- URISet ranges = RDFS::range(world, prop, true);
-
- lilv_node_free(prop);
- if (label.empty() || ranges.empty()) {
- // Property has no label or range, can't show a widget for it
- continue;
- }
-
- LilvNode* range = lilv_new_uri(world->lilv_world(), (*ranges.begin()).c_str());
- if (RDFS::is_a(world, range, rdfs_DataType)) {
- // Range is a datatype, show if type or any subtype is supported
- RDFS::datatypes(_app->world(), ranges, false);
- URI widget_type("urn:nothing");
- if (datatype_supported(ranges, &widget_type)) {
- entries.emplace(label, p);
- }
- } else {
- // Range is presumably a class, show if any instances are known
- if (class_supported(ranges)) {
- entries.emplace(label, p);
- }
- }
- }
-
- for (const auto& e : entries) {
- Gtk::ListStore::iterator ki = _key_store->append();
- Gtk::ListStore::Row row = *ki;
- row[_combo_columns.uri_col] = e.second.string();
- row[_combo_columns.label_col] = e.first;
- }
-
- lilv_node_free(rdfs_DataType);
- lilv_node_free(rdf_type);
-
- for (const auto& p : model->properties()) {
- add_property(p.first, p.second);
- }
-
- _table->show_all();
-
- _property_connection = model->signal_property().connect(
- sigc::mem_fun(this, &PropertiesWindow::add_property));
- _property_removed_connection = model->signal_property_removed().connect(
- sigc::mem_fun(this, &PropertiesWindow::remove_property));
-}
-
-Gtk::Widget*
-PropertiesWindow::create_value_widget(const URI& key,
- const char* type_uri,
- const Atom& value)
-{
- if (!type_uri || !URI::is_valid(type_uri)) {
- return nullptr;
- }
-
- URI type(type_uri);
- Ingen::World* world = _app->world();
- LilvWorld* lworld = world->lilv_world();
-
- // See if type is a datatype we support
- std::set<URI> types{type};
- RDFS::datatypes(_app->world(), types, false);
-
- URI widget_type("urn:nothing");
- const bool supported = datatype_supported(types, &widget_type);
- if (supported) {
- type = widget_type;
- _value_type = _app->world()->uri_map().map_uri(type);
- }
-
- if (type == _app->uris().atom_Int) {
- Gtk::SpinButton* widget = manage(new Gtk::SpinButton(0.0, 0));
- widget->property_numeric() = true;
- widget->set_range(INT_MIN, INT_MAX);
- widget->set_increments(1, 10);
- if (value.is_valid()) {
- widget->set_value(value.get<int32_t>());
- }
- widget->signal_value_changed().connect(
- sigc::bind(sigc::mem_fun(this, &PropertiesWindow::on_change), key));
- return widget;
- } else if (type == _app->uris().atom_Float) {
- Gtk::SpinButton* widget = manage(new Gtk::SpinButton(0.0, 4));
- widget->property_numeric() = true;
- widget->set_snap_to_ticks(false);
- widget->set_range(-FLT_MAX, FLT_MAX);
- widget->set_increments(0.1, 1.0);
- if (value.is_valid()) {
- widget->set_value(value.get<float>());
- }
- widget->signal_value_changed().connect(
- sigc::bind(sigc::mem_fun(this, &PropertiesWindow::on_change), key));
- return widget;
- } else if (type == _app->uris().atom_Bool) {
- Gtk::CheckButton* widget = manage(new Gtk::CheckButton());
- if (value.is_valid()) {
- widget->set_active(value.get<int32_t>());
- }
- widget->signal_toggled().connect(
- sigc::bind(sigc::mem_fun(this, &PropertiesWindow::on_change), key));
- return widget;
- } else if (type == _app->uris().atom_String) {
- Gtk::Entry* widget = manage(new Gtk::Entry());
- if (value.is_valid()) {
- widget->set_text(value.ptr<char>());
- }
- widget->signal_changed().connect(
- sigc::bind(sigc::mem_fun(this, &PropertiesWindow::on_change), key));
- return widget;
- } else if (type == _app->uris().atom_URID) {
- const char* str = (value.is_valid()
- ? world->uri_map().unmap_uri(value.get<int32_t>())
- : "");
-
- LilvNode* pred = lilv_new_uri(lworld, key.c_str());
- URISet ranges = RDFS::range(world, pred, true);
- URIEntry* widget = manage(new URIEntry(_app, ranges, str ? str : ""));
- widget->signal_changed().connect(
- sigc::bind(sigc::mem_fun(this, &PropertiesWindow::on_change), key));
- lilv_node_free(pred);
- return widget;
- }
-
- LilvNode* type_node = lilv_new_uri(lworld, type.c_str());
- LilvNode* rdfs_Class = lilv_new_uri(lworld, LILV_NS_RDFS "Class");
- const bool is_class = RDFS::is_a(world, type_node, rdfs_Class);
- lilv_node_free(rdfs_Class);
- lilv_node_free(type_node);
-
- if (type == _app->uris().atom_URI ||
- type == _app->uris().rdfs_Class ||
- is_class) {
- LilvNode* pred = lilv_new_uri(lworld, key.c_str());
- URISet ranges = RDFS::range(world, pred, true);
- const char* str = value.is_valid() ? value.ptr<const char>() : "";
- URIEntry* widget = manage(new URIEntry(_app, ranges, str));
- widget->signal_changed().connect(
- sigc::bind(sigc::mem_fun(this, &PropertiesWindow::on_change), key));
- lilv_node_free(pred);
- return widget;
- }
-
- _app->log().error(fmt("No widget for value type %1%\n") % type);
-
- return nullptr;
-}
-
-void
-PropertiesWindow::on_show()
-{
- static const int WIN_PAD = 64;
- static const int VBOX_PAD = 16;
-
- int width = 0;
- int height = 0;
-
- for (const auto& c : _vbox->children()) {
- const Gtk::Requisition& req = c.get_widget()->size_request();
-
- width = std::max(width, req.width);
- height += req.height + VBOX_PAD;
- }
-
- const Gtk::Requisition& req = _table->size_request();
-
- width = 1.2 * std::max(width, req.width + 128);
- height += req.height;
-
- set_default_size(width + WIN_PAD, height + WIN_PAD);
- resize(width + WIN_PAD, height + WIN_PAD);
- Gtk::Window::on_show();
-}
-
-void
-PropertiesWindow::change_property(const URI& key, const Atom& value)
-{
- auto r = _records.find(key);
- if (r == _records.end()) {
- add_property(key, value);
- _table->show_all();
- return;
- }
-
- Record& record = r->second;
- const char* type = _app->world()->uri_map().unmap_uri(value.type());
- Gtk::Widget* val_widget = create_value_widget(key, type, value);
-
- if (val_widget) {
- record.value_widget->remove();
- record.value_widget->add(*Gtk::manage(val_widget));
- val_widget->show_all();
- }
-
- record.value = value;
-}
-
-void
-PropertiesWindow::remove_property(const URI& key, const Atom& value)
-{
- // Bleh, there doesn't seem to be an easy way to remove a Gtk::Table row...
- _records.clear();
- _table->children().clear();
- _table->resize(1, 3);
- _table->property_n_rows() = 1;
-
- for (const auto& p : _model->properties()) {
- add_property(p.first, p.second);
- }
- _table->show_all();
-}
-
-Atom
-PropertiesWindow::get_value(LV2_URID type, Gtk::Widget* value_widget)
-{
- Forge& forge = _app->forge();
-
- if (type == forge.Int) {
- Gtk::SpinButton* spin = dynamic_cast<Gtk::SpinButton*>(value_widget);
- if (spin) {
- return _app->forge().make(spin->get_value_as_int());
- }
- } else if (type == forge.Float) {
- Gtk::SpinButton* spin = dynamic_cast<Gtk::SpinButton*>(value_widget);
- if (spin) {
- return _app->forge().make(static_cast<float>(spin->get_value()));
- }
- } else if (type == forge.Bool) {
- Gtk::CheckButton* check = dynamic_cast<Gtk::CheckButton*>(value_widget);
- if (check) {
- return _app->forge().make(check->get_active());
- }
- } else if (type == forge.URI || type == forge.URID) {
- URIEntry* uri_entry = dynamic_cast<URIEntry*>(value_widget);
- if (uri_entry && URI::is_valid(uri_entry->get_text())) {
- return _app->forge().make_urid(URI(uri_entry->get_text()));
- } else {
- _app->log().error(fmt("Invalid URI <%1%>\n") % uri_entry->get_text());
- }
- } else if (type == forge.String) {
- Gtk::Entry* entry = dynamic_cast<Gtk::Entry*>(value_widget);
- if (entry) {
- return _app->forge().alloc(entry->get_text());
- }
- }
-
- return Atom();
-}
-
-void
-PropertiesWindow::on_change(const URI& key)
-{
- auto r = _records.find(key);
- if (r == _records.end()) {
- return;
- }
-
- Record& record = r->second;
- const Atom value = get_value(record.value.type(),
- record.value_widget->get_child());
-
- if (value.is_valid()) {
- record.value = value;
- } else {
- _app->log().error(fmt("Failed to get `%1%' value from widget\n") % key);
- }
-}
-
-std::string
-PropertiesWindow::active_key() const
-{
- const Gtk::ListStore::iterator iter = _key_combo->get_active();
- if (!iter) {
- return "";
- }
-
- Glib::ustring prop_uri = (*iter)[_combo_columns.uri_col];
- return prop_uri;
-}
-
-void
-PropertiesWindow::key_changed()
-{
- _value_bin->remove();
- if (!_key_combo->get_active()) {
- return;
- }
-
- LilvWorld* lworld = _app->world()->lilv_world();
- const Gtk::ListStore::Row key_row = *(_key_combo->get_active());
- const Glib::ustring key_uri = key_row[_combo_columns.uri_col];
- LilvNode* prop = lilv_new_uri(lworld, key_uri.c_str());
-
- // Try to create a value widget in the range of this property
- const URISet ranges = RDFS::range(_app->world(), prop, true);
- for (const auto& r : ranges) {
- Gtk::Widget* value_widget = create_value_widget(
- URI(key_uri), r.c_str(), Atom());
-
- if (value_widget) {
- _add_button->set_sensitive(true);
- _value_bin->remove();
- _value_bin->add(*Gtk::manage(value_widget));
- _value_bin->show_all();
- break;
- }
- }
-
- lilv_node_free(prop);
-}
-
-void
-PropertiesWindow::add_clicked()
-{
- if (!_key_combo->get_active() || !_value_type || !_value_bin->get_child()) {
- return;
- }
-
- // Get selected key URI
- const Gtk::ListStore::Row key_row = *(_key_combo->get_active());
- const Glib::ustring key_uri = key_row[_combo_columns.uri_col];
-
- // Try to get value from value widget
- const Atom& value = get_value(_value_type, _value_bin->get_child());
- if (value.is_valid()) {
- // Send property to engine
- Properties properties;
- properties.emplace(URI(key_uri.c_str()), Property(value));
- _app->interface()->put(_model->uri(), properties);
- }
-}
-
-void
-PropertiesWindow::cancel_clicked()
-{
- reset();
- Gtk::Window::hide();
-}
-
-void
-PropertiesWindow::apply_clicked()
-{
- Properties remove;
- Properties add;
- for (const auto& r : _records) {
- const URI& uri = r.first;
- const Record& record = r.second;
- if (record.present_button->get_active()) {
- if (!_model->has_property(uri, record.value)) {
- add.emplace(uri, record.value);
- }
- } else {
- remove.emplace(uri, record.value);
- }
- }
-
- if (remove.empty()) {
- _app->interface()->put(_model->uri(), add);
- } else {
- _app->interface()->delta(_model->uri(), remove, add);
- }
-}
-
-void
-PropertiesWindow::ok_clicked()
-{
- apply_clicked();
- Gtk::Window::hide();
-}
-
-} // namespace GUI
-} // namespace Ingen
diff --git a/src/gui/PropertiesWindow.hpp b/src/gui/PropertiesWindow.hpp
deleted file mode 100644
index f4a8dd0d..00000000
--- a/src/gui/PropertiesWindow.hpp
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- 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_GUI_PROPERTIES_WINDOW_HPP
-#define INGEN_GUI_PROPERTIES_WINDOW_HPP
-
-#include <map>
-
-#include <gtkmm/alignment.h>
-#include <gtkmm/box.h>
-#include <gtkmm/builder.h>
-#include <gtkmm/button.h>
-#include <gtkmm/checkbutton.h>
-#include <gtkmm/combobox.h>
-#include <gtkmm/liststore.h>
-#include <gtkmm/scrolledwindow.h>
-#include <gtkmm/table.h>
-
-#include "ingen/client/BlockModel.hpp"
-#include "ingen/types.hpp"
-
-#include "Window.hpp"
-
-namespace Ingen {
-
-namespace Client { class ObjectModel; }
-
-namespace GUI {
-
-/** Object properties window.
- *
- * Loaded from XML as a derived object.
- *
- * \ingroup GUI
- */
-class PropertiesWindow : public Window
-{
-public:
- PropertiesWindow(BaseObjectType* cobject,
- const Glib::RefPtr<Gtk::Builder>& xml);
-
- void present(SPtr<const Client::ObjectModel> model);
- void set_object(SPtr<const Client::ObjectModel> model);
-
-private:
- /** Record of a property (row in the table) */
- struct Record {
- Record(const Atom& v, Gtk::Alignment* vw, int r, Gtk::CheckButton* cb)
- : value(v), value_widget(vw), row(r), present_button(cb)
- {}
- Atom value;
- Gtk::Alignment* value_widget;
- int row;
- Gtk::CheckButton* present_button;
- };
-
- struct ComboColumns : public Gtk::TreeModel::ColumnRecord {
- ComboColumns() {
- add(label_col);
- add(uri_col);
- }
- Gtk::TreeModelColumn<Glib::ustring> label_col;
- Gtk::TreeModelColumn<Glib::ustring> uri_col;
- };
-
- void add_property(const URI& key, const Atom& value);
- void change_property(const URI& key, const Atom& value);
- void remove_property(const URI& key, const Atom& value);
- void on_change(const URI& key);
-
- bool datatype_supported(const std::set<URI>& types,
- URI* widget_type);
-
- bool class_supported(const std::set<URI>& types);
-
- Gtk::Widget* create_value_widget(const URI& key,
- const char* type_uri,
- const Atom& value = Atom());
-
- Atom get_value(LV2_URID type, Gtk::Widget* value_widget);
-
- void reset();
- void on_show();
-
- std::string active_key() const;
-
- void key_changed();
- void add_clicked();
- void cancel_clicked();
- void apply_clicked();
- void ok_clicked();
-
- typedef std::map<URI, Record> Records;
- Records _records;
-
- SPtr<const Client::ObjectModel> _model;
- ComboColumns _combo_columns;
- Glib::RefPtr<Gtk::ListStore> _key_store;
- sigc::connection _property_connection;
- sigc::connection _property_removed_connection;
- Gtk::VBox* _vbox;
- Gtk::ScrolledWindow* _scrolledwindow;
- Gtk::Table* _table;
- Gtk::ComboBox* _key_combo;
- LV2_URID _value_type;
- Gtk::Bin* _value_bin;
- Gtk::Button* _add_button;
- Gtk::Button* _cancel_button;
- Gtk::Button* _apply_button;
- Gtk::Button* _ok_button;
-};
-
-} // namespace GUI
-} // namespace Ingen
-
-#endif // INGEN_GUI_PROPERTIES_WINDOW_HPP
diff --git a/src/gui/RDFS.cpp b/src/gui/RDFS.cpp
deleted file mode 100644
index 71b3441a..00000000
--- a/src/gui/RDFS.cpp
+++ /dev/null
@@ -1,259 +0,0 @@
-/*
- 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/Forge.hpp"
-#include "ingen/Log.hpp"
-#include "ingen/Resource.hpp"
-#include "ingen/World.hpp"
-#include "ingen/client/ObjectModel.hpp"
-#include "lilv/lilv.h"
-
-#include "RDFS.hpp"
-
-namespace Ingen {
-namespace GUI {
-namespace RDFS {
-
-std::string
-label(World* world, const LilvNode* node)
-{
- LilvNode* rdfs_label = lilv_new_uri(
- world->lilv_world(), LILV_NS_RDFS "label");
- LilvNodes* labels = lilv_world_find_nodes(
- world->lilv_world(), node, rdfs_label, nullptr);
-
- const LilvNode* first = lilv_nodes_get_first(labels);
- std::string label = first ? lilv_node_as_string(first) : "";
-
- lilv_nodes_free(labels);
- lilv_node_free(rdfs_label);
- return label;
-}
-
-std::string
-comment(World* world, const LilvNode* node)
-{
- LilvNode* rdfs_comment = lilv_new_uri(
- world->lilv_world(), LILV_NS_RDFS "comment");
- LilvNodes* comments = lilv_world_find_nodes(
- world->lilv_world(), node, rdfs_comment, nullptr);
-
- const LilvNode* first = lilv_nodes_get_first(comments);
- std::string comment = first ? lilv_node_as_string(first) : "";
-
- lilv_nodes_free(comments);
- lilv_node_free(rdfs_comment);
- return comment;
-}
-
-static void
-closure(World* world, const LilvNode* pred, URISet& types, bool super)
-{
- unsigned added = 0;
- do {
- added = 0;
- URISet klasses;
- for (const auto& t : types) {
- LilvNode* type = lilv_new_uri(world->lilv_world(), t.c_str());
- LilvNodes* matches = (super)
- ? lilv_world_find_nodes(
- world->lilv_world(), type, pred, nullptr)
- : lilv_world_find_nodes(
- world->lilv_world(), nullptr, pred, type);
- LILV_FOREACH(nodes, m, matches) {
- const LilvNode* klass_node = lilv_nodes_get(matches, m);
- if (lilv_node_is_uri(klass_node)) {
- URI klass(lilv_node_as_uri(klass_node));
- if (!types.count(klass)) {
- ++added;
- klasses.insert(klass);
- }
- }
- }
- lilv_nodes_free(matches);
- lilv_node_free(type);
- }
- types.insert(klasses.begin(), klasses.end());
- } while (added > 0);
-}
-
-void
-classes(World* world, URISet& types, bool super)
-{
- LilvNode* rdfs_subClassOf = lilv_new_uri(
- world->lilv_world(), LILV_NS_RDFS "subClassOf");
-
- closure(world, rdfs_subClassOf, types, super);
-
- lilv_node_free(rdfs_subClassOf);
-}
-
-void
-datatypes(World* world, URISet& types, bool super)
-{
- LilvNode* owl_onDatatype = lilv_new_uri(
- world->lilv_world(), LILV_NS_OWL "onDatatype");
-
- closure(world, owl_onDatatype, types, super);
-
- lilv_node_free(owl_onDatatype);
-}
-
-URISet
-types(World* world, SPtr<const Client::ObjectModel> model)
-{
- typedef Properties::const_iterator PropIter;
- typedef std::pair<PropIter, PropIter> PropRange;
-
- // Start with every rdf:type
- URISet types;
- types.insert(URI(LILV_NS_RDFS "Resource"));
- PropRange range = model->properties().equal_range(world->uris().rdf_type);
- for (auto t = range.first; t != range.second; ++t) {
- if (t->second.type() == world->forge().URI ||
- t->second.type() == world->forge().URID) {
- const URI type(world->forge().str(t->second, false));
- types.insert(type);
- if (world->uris().ingen_Graph == type) {
- // Add lv2:Plugin as a type for graphs so plugin properties show up
- types.insert(world->uris().lv2_Plugin);
- }
- } else {
- world->log().error(fmt("<%1%> has non-URI type\n") % model->uri());
- }
- }
-
- // Add every superclass of every type, recursively
- RDFS::classes(world, types, true);
-
- return types;
-}
-
-URISet
-properties(World* world, SPtr<const Client::ObjectModel> model)
-{
- URISet properties;
- URISet types = RDFS::types(world, model);
-
- LilvNode* rdf_type = lilv_new_uri(world->lilv_world(),
- LILV_NS_RDF "type");
- LilvNode* rdf_Property = lilv_new_uri(world->lilv_world(),
- LILV_NS_RDF "Property");
- LilvNode* rdfs_domain = lilv_new_uri(world->lilv_world(),
- LILV_NS_RDFS "domain");
-
- LilvNodes* props = lilv_world_find_nodes(
- world->lilv_world(), nullptr, rdf_type, rdf_Property);
- LILV_FOREACH(nodes, p, props) {
- const LilvNode* prop = lilv_nodes_get(props, p);
- if (lilv_node_is_uri(prop)) {
- LilvNodes* domains = lilv_world_find_nodes(
- world->lilv_world(), prop, rdfs_domain, nullptr);
- unsigned n_matching_domains = 0;
- LILV_FOREACH(nodes, d, domains) {
- const LilvNode* domain_node = lilv_nodes_get(domains, d);
- if (!lilv_node_is_uri(domain_node)) {
- // TODO: Blank node domains (e.g. unions)
- continue;
- }
-
- const URI domain(lilv_node_as_uri(domain_node));
- if (types.count(domain)) {
- ++n_matching_domains;
- }
- }
-
- if (lilv_nodes_size(domains) == 0 || (
- n_matching_domains > 0 &&
- n_matching_domains == lilv_nodes_size(domains))) {
- properties.insert(URI(lilv_node_as_uri(prop)));
- }
-
- lilv_nodes_free(domains);
- }
- }
-
- lilv_node_free(rdfs_domain);
- lilv_node_free(rdf_Property);
- lilv_node_free(rdf_type);
-
- return properties;
-}
-
-Objects
-instances(World* world, const URISet& types)
-{
- LilvNode* rdf_type = lilv_new_uri(
- world->lilv_world(), LILV_NS_RDF "type");
-
- Objects result;
- for (const auto& t : types) {
- LilvNode* type = lilv_new_uri(world->lilv_world(), t.c_str());
- LilvNodes* objects = lilv_world_find_nodes(
- world->lilv_world(), nullptr, rdf_type, type);
- LILV_FOREACH(nodes, o, objects) {
- const LilvNode* object = lilv_nodes_get(objects, o);
- if (!lilv_node_is_uri(object)) {
- continue;
- }
- const std::string label = RDFS::label(world, object);
- result.emplace(label, URI(lilv_node_as_string(object)));
- }
- lilv_node_free(type);
- }
-
- lilv_node_free(rdf_type);
- return result;
-}
-
-URISet
-range(World* world, const LilvNode* prop, bool recursive)
-{
- LilvNode* rdfs_range = lilv_new_uri(
- world->lilv_world(), LILV_NS_RDFS "range");
-
- LilvNodes* nodes = lilv_world_find_nodes(
- world->lilv_world(), prop, rdfs_range, nullptr);
-
- URISet ranges;
- LILV_FOREACH(nodes, n, nodes) {
- ranges.insert(URI(lilv_node_as_string(lilv_nodes_get(nodes, n))));
- }
-
- if (recursive) {
- RDFS::classes(world, ranges, false);
- }
-
- lilv_nodes_free(nodes);
- lilv_node_free(rdfs_range);
- return ranges;
-}
-
-bool
-is_a(World* world, const LilvNode* inst, const LilvNode* klass)
-{
- LilvNode* rdf_type = lilv_new_uri(world->lilv_world(), LILV_NS_RDF "type");
-
- const bool is_instance = lilv_world_ask(
- world->lilv_world(), inst, rdf_type, klass);
-
- lilv_node_free(rdf_type);
- return is_instance;
-}
-
-} // namespace RDFS
-} // namespace GUI
-} // namespace Ingen
diff --git a/src/gui/RDFS.hpp b/src/gui/RDFS.hpp
deleted file mode 100644
index f59bbdf5..00000000
--- a/src/gui/RDFS.hpp
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- This file is part of Ingen.
- Copyright 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_GUI_RDF_HPP
-#define INGEN_GUI_RDF_HPP
-
-#include <map>
-#include <set>
-#include <string>
-
-#include "ingen/types.hpp"
-#include "lilv/lilv.h"
-
-namespace Ingen {
-
-class World;
-
-namespace Client { class ObjectModel; }
-
-namespace GUI {
-
-namespace RDFS {
-
-/** Set of URIs. */
-typedef std::set<URI> URISet;
-
-/** Label => Resource map. */
-typedef std::map<std::string, URI> Objects;
-
-/** Return the label of `node`. */
-std::string label(World* world, const LilvNode* node);
-
-/** Return the comment of `node`. */
-std::string comment(World* world, const LilvNode* node);
-
-/** Set `types` to its super/sub class closure.
- * @param super If true, find all superclasses, otherwise all subclasses
- */
-void classes(World* world, URISet& types, bool super);
-
-/** Set `types` to its super/sub datatype closure.
- * @param super If true, find all supertypes, otherwise all subtypes.
- */
-void datatypes(World* world, URISet& types, bool super);
-
-/** Get all instances of any class in `types`. */
-Objects instances(World* world, const URISet& types);
-
-/** Get all the types which `model` is an instance of. */
-URISet types(World* world, SPtr<const Client::ObjectModel> model);
-
-/** Get all the properties with domains appropriate for `model`. */
-URISet properties(World* world, SPtr<const Client::ObjectModel> model);
-
-/** Return the range (value types) of `prop`.
- * @param recursive If true, include all subclasses.
- */
-URISet range(World* world, const LilvNode* prop, bool recursive);
-
-/** Return true iff `inst` is-a `klass`. */
-bool is_a(World* world, const LilvNode* inst, const LilvNode* klass);
-
-} // namespace RDFS
-} // namespace GUI
-} // namespace Ingen
-
-#endif // INGEN_GUI_RDF_HPP
diff --git a/src/gui/RenameWindow.cpp b/src/gui/RenameWindow.cpp
deleted file mode 100644
index c83143d9..00000000
--- a/src/gui/RenameWindow.cpp
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- 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 <cassert>
-#include <string>
-
-#include "ingen/Forge.hpp"
-#include "ingen/Interface.hpp"
-#include "ingen/client/ClientStore.hpp"
-#include "ingen/client/ObjectModel.hpp"
-#include "lv2/lv2plug.in/ns/lv2core/lv2.h"
-
-#include "App.hpp"
-#include "RenameWindow.hpp"
-
-namespace Ingen {
-
-using namespace Client;
-
-namespace GUI {
-
-RenameWindow::RenameWindow(BaseObjectType* cobject,
- const Glib::RefPtr<Gtk::Builder>& xml)
- : Window(cobject)
-{
- xml->get_widget("rename_symbol_entry", _symbol_entry);
- xml->get_widget("rename_label_entry", _label_entry);
- xml->get_widget("rename_message_label", _message_label);
- xml->get_widget("rename_cancel_button", _cancel_button);
- xml->get_widget("rename_ok_button", _ok_button);
-
- _symbol_entry->signal_changed().connect(
- sigc::mem_fun(this, &RenameWindow::values_changed));
- _label_entry->signal_changed().connect(
- sigc::mem_fun(this, &RenameWindow::values_changed));
- _cancel_button->signal_clicked().connect(
- sigc::mem_fun(this, &RenameWindow::cancel_clicked));
- _ok_button->signal_clicked().connect(
- sigc::mem_fun(this, &RenameWindow::ok_clicked));
-
- _ok_button->property_sensitive() = false;
-}
-
-/** Set the object this window is renaming.
- * This function MUST be called before using this object in any way.
- */
-void
-RenameWindow::set_object(SPtr<const ObjectModel> object)
-{
- _object = object;
- _symbol_entry->set_text(object->path().symbol());
- const Atom& name_atom = object->get_property(_app->uris().lv2_name);
- _label_entry->set_text(
- (name_atom.type() == _app->forge().String) ? name_atom.ptr<char>() : "");
-}
-
-void
-RenameWindow::present(SPtr<const ObjectModel> object)
-{
- set_object(object);
- _symbol_entry->grab_focus();
- Gtk::Window::present();
-}
-
-void
-RenameWindow::values_changed()
-{
- const std::string& symbol = _symbol_entry->get_text();
- if (!Raul::Symbol::is_valid(symbol)) {
- _message_label->set_text("Invalid symbol");
- _ok_button->property_sensitive() = false;
- } else if (_object->symbol() != symbol &&
- _app->store()->object(
- _object->parent()->path().child(Raul::Symbol(symbol)))) {
- _message_label->set_text("An object already exists with that path");
- _ok_button->property_sensitive() = false;
- } else {
- _message_label->set_text("");
- _ok_button->property_sensitive() = true;
- }
-}
-
-void
-RenameWindow::cancel_clicked()
-{
- _symbol_entry->set_text("");
- hide();
-}
-
-/** Rename the object.
- *
- * It shouldn't be possible for this to be called with an invalid name set
- * (since the Rename button should be deactivated). This is just shinification
- * though - the engine will handle invalid names gracefully.
- */
-void
-RenameWindow::ok_clicked()
-{
- const URIs& uris = _app->uris();
- const std::string& symbol_str = _symbol_entry->get_text();
- const std::string& label = _label_entry->get_text();
- Raul::Path path = _object->path();
- const Atom& name_atom = _object->get_property(uris.lv2_name);
-
- if (!label.empty() && (name_atom.type() != uris.forge.String ||
- label != name_atom.ptr<char>())) {
- _app->set_property(path_to_uri(path),
- uris.lv2_name,
- _app->forge().alloc(label));
- }
-
- if (Raul::Symbol::is_valid(symbol_str)) {
- const Raul::Symbol symbol(symbol_str);
- if (symbol != _object->symbol()) {
- path = _object->path().parent().child(symbol);
- _app->interface()->move(_object->path(), path);
- }
- }
-
- hide();
-}
-
-} // namespace GUI
-} // namespace Ingen
diff --git a/src/gui/RenameWindow.hpp b/src/gui/RenameWindow.hpp
deleted file mode 100644
index 36264879..00000000
--- a/src/gui/RenameWindow.hpp
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- 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_GUI_RENAMEWINDOW_HPP
-#define INGEN_GUI_RENAMEWINDOW_HPP
-
-#include <gtkmm/builder.h>
-#include <gtkmm/button.h>
-#include <gtkmm/entry.h>
-#include <gtkmm/label.h>
-
-#include "ingen/client/ObjectModel.hpp"
-#include "ingen/types.hpp"
-
-#include "Window.hpp"
-
-namespace Ingen {
-namespace GUI {
-
-/** Rename window. Handles renaming of any (Ingen) object.
- *
- * \ingroup GUI
- */
-class RenameWindow : public Window
-{
-public:
- RenameWindow(BaseObjectType* cobject,
- const Glib::RefPtr<Gtk::Builder>& xml);
-
- void present(SPtr<const Client::ObjectModel> object);
-
-private:
- void set_object(SPtr<const Client::ObjectModel> object);
-
- void values_changed();
- void cancel_clicked();
- void ok_clicked();
-
- SPtr<const Client::ObjectModel> _object;
-
- Gtk::Entry* _symbol_entry;
- Gtk::Entry* _label_entry;
- Gtk::Label* _message_label;
- Gtk::Button* _cancel_button;
- Gtk::Button* _ok_button;
-};
-
-} // namespace GUI
-} // namespace Ingen
-
-#endif // INGEN_GUI_RENAMEWINDOW_HPP
diff --git a/src/gui/Style.cpp b/src/gui/Style.cpp
deleted file mode 100644
index 81e6fb6c..00000000
--- a/src/gui/Style.cpp
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- 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 <cassert>
-#include <cstdlib>
-#include <fstream>
-#include <map>
-#include <string>
-
-#include "ganv/Port.hpp"
-#include "ingen/Log.hpp"
-#include "ingen/Parser.hpp"
-#include "ingen/client/PluginModel.hpp"
-#include "ingen/client/PortModel.hpp"
-
-#include "App.hpp"
-#include "Style.hpp"
-#include "Port.hpp"
-
-namespace Ingen {
-namespace GUI {
-
-using namespace Ingen::Client;
-
-Style::Style(App& app)
- // Colours from the Tango palette with modified V
- : _app(app)
-#ifdef INGEN_USE_LIGHT_THEME
- , _audio_port_color(0xC8E6ABFF) // Green
- , _control_port_color(0xAAC0E6FF) // Blue
- , _cv_port_color(0xACE6E0FF) // Teal (between audio and control)
- , _event_port_color(0xE6ABABFF) // Red
- , _string_port_color(0xD8ABE6FF) // Plum
-#else
- , _audio_port_color(0x4A8A0EFF) // Green
- , _control_port_color(0x244678FF) // Blue
- , _cv_port_color(0x248780FF) // Teal (between audio and control)
- , _event_port_color(0x960909FF) // Red
- , _string_port_color(0x5C3566FF) // Plum
-#endif
-{
-}
-
-/** Loads settings from the rc file. Passing no parameter will load from
- * the default location.
- */
-void
-Style::load_settings(std::string filename)
-{
- /* ... */
-}
-
-/** Saves settings to rc file. Passing no parameter will save to the
- * default location.
- */
-void
-Style::save_settings(std::string filename)
-{
- /* ... */
-}
-
-/** Applies the current loaded settings to whichever parts of the app
- * need updating.
- */
-void
-Style::apply_settings()
-{
- /* ... */
-}
-
-uint32_t
-Style::get_port_color(const Client::PortModel* p)
-{
- const URIs& uris = _app.uris();
- if (p->is_a(uris.lv2_AudioPort)) {
- return _audio_port_color;
- } else if (p->is_a(uris.lv2_ControlPort)) {
- return _control_port_color;
- } else if (p->is_a(uris.lv2_CVPort)) {
- return _cv_port_color;
- } else if (p->supports(uris.atom_String)) {
- return _string_port_color;
- } else if (_app.can_control(p)) {
- return _control_port_color;
- } else if (p->is_a(uris.atom_AtomPort)) {
- return _event_port_color;
- }
-
- return 0x555555FF;
-}
-
-} // namespace GUI
-} // namespace Ingen
diff --git a/src/gui/Style.hpp b/src/gui/Style.hpp
deleted file mode 100644
index 8e628a3d..00000000
--- a/src/gui/Style.hpp
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- 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_GUI_STYLE_HPP
-#define INGEN_GUI_STYLE_HPP
-
-#include <cstdint>
-#include <string>
-
-namespace Ingen { namespace Client { class PortModel; } }
-
-namespace Ingen {
-namespace GUI {
-
-class App;
-class Port;
-
-class Style
-{
-public:
- explicit Style(App& app);
-
- void load_settings(std::string filename = "");
- void save_settings(std::string filename = "");
-
- void apply_settings();
-
- uint32_t get_port_color(const Client::PortModel* p);
-
-private:
- App& _app;
-
- uint32_t _audio_port_color;
- uint32_t _control_port_color;
- uint32_t _cv_port_color;
- uint32_t _event_port_color;
- uint32_t _string_port_color;
-};
-
-} // namespace GUI
-} // namespace Ingen
-
-#endif // INGEN_GUI_STYLE_HPP
diff --git a/src/gui/SubgraphModule.cpp b/src/gui/SubgraphModule.cpp
deleted file mode 100644
index 6bbcf534..00000000
--- a/src/gui/SubgraphModule.cpp
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- 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 <cassert>
-#include <utility>
-
-#include "ingen/Interface.hpp"
-#include "ingen/client/GraphModel.hpp"
-
-#include "App.hpp"
-#include "NodeModule.hpp"
-#include "GraphCanvas.hpp"
-#include "GraphWindow.hpp"
-#include "Port.hpp"
-#include "SubgraphModule.hpp"
-#include "WindowFactory.hpp"
-
-namespace Ingen {
-
-using namespace Client;
-
-namespace GUI {
-
-SubgraphModule::SubgraphModule(GraphCanvas& canvas,
- SPtr<const GraphModel> graph)
- : NodeModule(canvas, graph)
- , _graph(graph)
-{
- assert(graph);
-}
-
-bool
-SubgraphModule::on_double_click(GdkEventButton* event)
-{
- assert(_graph);
-
- SPtr<GraphModel> parent = dynamic_ptr_cast<GraphModel>(_graph->parent());
-
- GraphWindow* const preferred = ( (parent && (event->state & GDK_SHIFT_MASK))
- ? nullptr
- : app().window_factory()->graph_window(parent) );
-
- app().window_factory()->present_graph(_graph, preferred);
- return true;
-}
-
-void
-SubgraphModule::store_location(double ax, double ay)
-{
- const URIs& uris = app().uris();
-
- const Atom x(app().forge().make(static_cast<float>(ax)));
- const Atom y(app().forge().make(static_cast<float>(ay)));
-
- if (x != _block->get_property(uris.ingen_canvasX) ||
- y != _block->get_property(uris.ingen_canvasY))
- {
- app().interface()->put(_graph->uri(),
- {{uris.ingen_canvasX, x},
- {uris.ingen_canvasY, y}},
- Resource::Graph::EXTERNAL);
- }
-}
-
-/** Browse to this graph in current (parent's) window
- * (unless an existing window is displaying it)
- */
-void
-SubgraphModule::browse_to_graph()
-{
- assert(_graph->parent());
-
- SPtr<GraphModel> parent = dynamic_ptr_cast<GraphModel>(_graph->parent());
-
- GraphWindow* const preferred = (parent)
- ? app().window_factory()->graph_window(parent)
- : nullptr;
-
- app().window_factory()->present_graph(_graph, preferred);
-}
-
-void
-SubgraphModule::menu_remove()
-{
- app().interface()->del(_graph->uri());
-}
-
-} // namespace GUI
-} // namespace Ingen
diff --git a/src/gui/SubgraphModule.hpp b/src/gui/SubgraphModule.hpp
deleted file mode 100644
index 1b8df2fa..00000000
--- a/src/gui/SubgraphModule.hpp
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- 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_GUI_SUBGRAPHMODULE_HPP
-#define INGEN_GUI_SUBGRAPHMODULE_HPP
-
-#include "ingen/types.hpp"
-
-#include "NodeModule.hpp"
-#include "GraphPortModule.hpp"
-
-namespace Ingen { namespace Client {
-class GraphModel;
-class GraphWindow;
-class PortModel;
-} }
-
-namespace Ingen {
-namespace GUI {
-
-class GraphCanvas;
-
-/** A module to represent a subgraph
- *
- * \ingroup GUI
- */
-class SubgraphModule : public NodeModule
-{
-public:
- SubgraphModule(GraphCanvas& canvas,
- SPtr<const Client::GraphModel> graph);
-
- virtual ~SubgraphModule() {}
-
- bool on_double_click(GdkEventButton* event);
-
- void store_location(double ax, double ay);
-
- void browse_to_graph();
- void menu_remove();
-
- SPtr<const Client::GraphModel> graph() const { return _graph; }
-
-protected:
- SPtr<const Client::GraphModel> _graph;
-};
-
-} // namespace GUI
-} // namespace Ingen
-
-#endif // INGEN_GUI_SUBGRAPHMODULE_HPP
diff --git a/src/gui/ThreadedLoader.cpp b/src/gui/ThreadedLoader.cpp
deleted file mode 100644
index 7a80fa6e..00000000
--- a/src/gui/ThreadedLoader.cpp
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- 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 <cassert>
-#include <string>
-
-#include "ingen/Log.hpp"
-#include "ingen/Module.hpp"
-#include "ingen/World.hpp"
-#include "ingen/client/GraphModel.hpp"
-
-#include "App.hpp"
-#include "ThreadedLoader.hpp"
-
-using boost::optional;
-
-namespace Ingen {
-namespace GUI {
-
-ThreadedLoader::ThreadedLoader(App& app, SPtr<Interface> engine)
- : _app(app)
- , _sem(0)
- , _engine(std::move(engine))
- , _exit_flag(false)
- , _thread(&ThreadedLoader::run, this)
-{
- if (!parser()) {
- app.log().warn("Parser unavailable, graph loading disabled\n");
- }
-}
-
-ThreadedLoader::~ThreadedLoader()
-{
- _exit_flag = true;
- _sem.post();
- if (_thread.joinable()) {
- _thread.join();
- }
-}
-
-SPtr<Parser>
-ThreadedLoader::parser()
-{
- return _app.world()->parser();
-}
-
-void
-ThreadedLoader::run()
-{
- while (_sem.wait() && !_exit_flag) {
- std::lock_guard<std::mutex> lock(_mutex);
- while (!_events.empty()) {
- _events.front()();
- _events.pop_front();
- }
- }
-}
-
-void
-ThreadedLoader::load_graph(bool merge,
- const FilePath& file_path,
- optional<Raul::Path> engine_parent,
- optional<Raul::Symbol> engine_symbol,
- optional<Properties> engine_data)
-{
- std::lock_guard<std::mutex> lock(_mutex);
-
- Glib::ustring engine_base = "";
- if (engine_parent) {
- if (merge) {
- engine_base = engine_parent.get();
- } else {
- engine_base = engine_parent.get().base();
- }
- }
-
- _events.push_back(sigc::hide_return(
- sigc::bind(sigc::mem_fun(this, &ThreadedLoader::load_graph_event),
- file_path,
- engine_parent,
- engine_symbol,
- engine_data)));
-
- _sem.post();
-}
-
-void
-ThreadedLoader::load_graph_event(const FilePath& file_path,
- optional<Raul::Path> engine_parent,
- optional<Raul::Symbol> engine_symbol,
- optional<Properties> engine_data)
-{
- std::lock_guard<std::mutex> lock(_app.world()->rdf_mutex());
-
- _app.world()->parser()->parse_file(_app.world(),
- _app.world()->interface().get(),
- file_path,
- engine_parent,
- engine_symbol,
- engine_data);
-}
-
-void
-ThreadedLoader::save_graph(SPtr<const Client::GraphModel> model, const URI& uri)
-{
- std::lock_guard<std::mutex> lock(_mutex);
-
- _events.push_back(sigc::hide_return(
- sigc::bind(sigc::mem_fun(this, &ThreadedLoader::save_graph_event),
- model,
- uri)));
-
- _sem.post();
-}
-
-void
-ThreadedLoader::save_graph_event(SPtr<const Client::GraphModel> model,
- const URI& uri)
-{
- assert(uri.scheme() == "file");
- if (_app.serialiser()) {
- std::lock_guard<std::mutex> lock(_app.world()->rdf_mutex());
-
- if (uri.string().find(".ingen") != std::string::npos) {
- _app.serialiser()->write_bundle(model, uri);
- } else {
- _app.serialiser()->start_to_file(model->path(), std::string(uri.path()));
- _app.serialiser()->serialise(model);
- _app.serialiser()->finish();
- }
- }
-}
-
-} // namespace GUI
-} // namespace Ingen
diff --git a/src/gui/ThreadedLoader.hpp b/src/gui/ThreadedLoader.hpp
deleted file mode 100644
index 79ef6466..00000000
--- a/src/gui/ThreadedLoader.hpp
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- 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_GUI_THREADEDLOADER_HPP
-#define INGEN_GUI_THREADEDLOADER_HPP
-
-#include <thread>
-
-#include <cassert>
-#include <list>
-#i