summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ingen/QueuedInterface.hpp66
-rw-r--r--ingen/client/ThreadedSigClientInterface.hpp95
-rw-r--r--src/gui/App.cpp29
-rw-r--r--src/gui/App.hpp22
-rw-r--r--src/gui/BreadCrumbs.cpp2
-rw-r--r--src/gui/ConnectWindow.cpp13
-rw-r--r--src/gui/ingen_gui.cpp24
-rw-r--r--tests/ingen_test.cpp1
8 files changed, 119 insertions, 133 deletions
diff --git a/ingen/QueuedInterface.hpp b/ingen/QueuedInterface.hpp
new file mode 100644
index 00000000..bf424edd
--- /dev/null
+++ b/ingen/QueuedInterface.hpp
@@ -0,0 +1,66 @@
+/*
+ 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/>.
+*/
+
+#ifndef INGEN_ENGINE_QUEUEDINTERFACE_HPP
+#define INGEN_ENGINE_QUEUEDINTERFACE_HPP
+
+#include <mutex>
+#include <vector>
+
+#include "ingen/Interface.hpp"
+#include "ingen/Message.hpp"
+
+namespace Ingen {
+
+/** Stores all messages and emits them to a sink on demand.
+ *
+ * This can be used to make an interface thread-safe.
+ */
+class QueuedInterface : public Interface
+{
+public:
+ explicit QueuedInterface(SPtr<Interface> sink) : _sink(std::move(sink)) {}
+
+ URI uri() const override { return URI("ingen:/QueuedInterface"); }
+
+ void message(const Message& message) override {
+ std::lock_guard<std::mutex> lock(_mutex);
+ _messages.emplace_back(message);
+ }
+
+ void emit() {
+ std::vector<Message> messages;
+ {
+ std::lock_guard<std::mutex> lock(_mutex);
+ _messages.swap(messages);
+ }
+
+ for (const auto& i : messages) {
+ _sink->message(i);
+ }
+ }
+
+ const SPtr<Interface>& sink() const { return _sink; }
+
+private:
+ std::mutex _mutex;
+ SPtr<Interface> _sink;
+ std::vector<Message> _messages;
+};
+
+} // namespace Ingen
+
+#endif // INGEN_ENGINE_QUEUEDINTERFACE_HPP
diff --git a/ingen/client/ThreadedSigClientInterface.hpp b/ingen/client/ThreadedSigClientInterface.hpp
deleted file mode 100644
index 751ea37b..00000000
--- a/ingen/client/ThreadedSigClientInterface.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_CLIENT_THREADEDSIGCLIENTINTERFACE_HPP
-#define INGEN_CLIENT_THREADEDSIGCLIENTINTERFACE_HPP
-
-#include <cstdint>
-#include <mutex>
-#include <string>
-#include <vector>
-
-#undef nil
-#include <sigc++/sigc++.h>
-
-#include "ingen/Atom.hpp"
-#include "ingen/Interface.hpp"
-#include "ingen/client/SigClientInterface.hpp"
-#include "ingen/ingen.h"
-
-/** Returns nothing and takes no parameters (because they have all been bound) */
-typedef sigc::slot<void> Closure;
-
-namespace Ingen {
-
-class Interface;
-
-namespace Client {
-
-/** A LibSigC++ signal emitting interface for clients to use.
- *
- * This emits signals (possibly) in a different thread than the ClientInterface
- * functions are called. It must be explicitly driven with the emit_signals()
- * function, which fires all enqueued signals up until the present. You can
- * use this in a GTK idle callback for receiving thread safe engine signals.
- *
- * @ingroup IngenClient
- */
-class INGEN_API ThreadedSigClientInterface : public SigClientInterface
-{
-public:
- ThreadedSigClientInterface()
- : message_slot(_signal_message.make_slot())
- {}
-
- URI uri() const override { return URI("ingen:/clients/sig_queue"); }
-
- void message(const Message& msg) override {
- std::lock_guard<std::mutex> lock(_mutex);
- _sigs.push_back(sigc::bind(message_slot, msg));
- }
-
- /** Process all queued events - Called from GTK thread to emit signals. */
- bool emit_signals() override {
- // Get pending signals
- std::vector<Closure> sigs;
- {
- std::lock_guard<std::mutex> lock(_mutex);
- std::swap(sigs, _sigs);
- }
-
- for (auto& ev : sigs) {
- ev();
- ev.disconnect();
- }
-
- return true;
- }
-
-private:
- std::mutex _mutex;
- std::vector<Closure> _sigs;
-
- using Graph = Resource::Graph;
- using Path = Raul::Path;
-
- sigc::slot<void, Message> message_slot;
-};
-
-} // namespace Client
-} // namespace Ingen
-
-#endif
diff --git a/src/gui/App.cpp b/src/gui/App.cpp
index a8128d8d..de587a7d 100644
--- a/src/gui/App.cpp
+++ b/src/gui/App.cpp
@@ -28,6 +28,7 @@
#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"
@@ -157,7 +158,7 @@ App::run()
}
void
-App::attach(SPtr<SigClientInterface> client)
+App::attach(SPtr<Ingen::Interface> client)
{
assert(!_client);
assert(!_store);
@@ -168,7 +169,7 @@ App::attach(SPtr<SigClientInterface> client)
}
_client = client;
- _store = SPtr<ClientStore>(new ClientStore(_world->uris(), _world->log(), 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);
@@ -181,12 +182,12 @@ App::attach(SPtr<SigClientInterface> client)
stderr,
ColorContext::Color::CYAN));
- client->signal_message().connect(
+ sig_client()->signal_message().connect(
sigc::mem_fun(*_dumper.get(), &StreamWriter::message));
}
_graph_tree_window->init(*this, *_store);
- _client->signal_message().connect(sigc::mem_fun(this, &App::message));
+ sig_client()->signal_message().connect(sigc::mem_fun(this, &App::message));
}
void
@@ -212,6 +213,16 @@ App::request_plugins_if_necessary()
}
}
+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()
{
@@ -264,7 +275,7 @@ App::set_property(const URI& subject,
went as planned here and fire the signal ourselves as if the server
feedback came back immediately. */
if (key != uris().ingen_activity) {
- _client->signal_message().emit(SetProperty{0, subject, key, value, ctx});
+ sig_client()->signal_message().emit(SetProperty{0, subject, key, value, ctx});
}
}
@@ -365,8 +376,6 @@ App::activity_port_destroyed(Port* port)
if (i != _activity_ports.end()) {
_activity_ports.erase(i);
}
-
- return;
}
bool
@@ -412,16 +421,16 @@ App::gtk_main_iteration()
_messages_window->flush();
}
+ _enable_signal = false;
if (_world->engine()) {
if (!_world->engine()->main_iteration()) {
Gtk::Main::quit();
return false;
}
} else {
- _enable_signal = false;
- _client->emit_signals();
- _enable_signal = true;
+ dynamic_ptr_cast<QueuedInterface>(_client)->emit();
}
+ _enable_signal = true;
return true;
}
diff --git a/src/gui/App.hpp b/src/gui/App.hpp
index 573925e6..953e1702 100644
--- a/src/gui/App.hpp
+++ b/src/gui/App.hpp
@@ -75,7 +75,7 @@ public:
void error_message(const std::string& str);
- void attach(SPtr<Client::SigClientInterface> client);
+ void attach(SPtr<Ingen::Interface> client);
void detach();
@@ -118,11 +118,13 @@ public:
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<Client::SigClientInterface> client() const { return _client; }
- SPtr<Client::ClientStore> store() const { return _store; }
- SPtr<ThreadedLoader> loader() const { return _loader; }
+ 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();
@@ -157,10 +159,10 @@ protected:
static Gtk::Main* _main;
- SPtr<Client::SigClientInterface> _client;
- SPtr<Client::ClientStore> _store;
- SPtr<ThreadedLoader> _loader;
- SPtr<StreamWriter> _dumper;
+ SPtr<Ingen::Interface> _client;
+ SPtr<Client::ClientStore> _store;
+ SPtr<ThreadedLoader> _loader;
+ SPtr<StreamWriter> _dumper;
Style* _style;
diff --git a/src/gui/BreadCrumbs.cpp b/src/gui/BreadCrumbs.cpp
index 3f69e998..ae7882e3 100644
--- a/src/gui/BreadCrumbs.cpp
+++ b/src/gui/BreadCrumbs.cpp
@@ -35,7 +35,7 @@ BreadCrumbs::BreadCrumbs(App& app)
, _full_path("/")
, _enable_signal(true)
{
- app.client()->signal_message().connect(
+ app.sig_client()->signal_message().connect(
sigc::mem_fun(this, &BreadCrumbs::message));
set_can_focus(false);
diff --git a/src/gui/ConnectWindow.cpp b/src/gui/ConnectWindow.cpp
index 8f235264..623db4a0 100644
--- a/src/gui/ConnectWindow.cpp
+++ b/src/gui/ConnectWindow.cpp
@@ -29,11 +29,12 @@
#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/client/ThreadedSigClientInterface.hpp"
#include "ingen_config.h"
#include "App.hpp"
@@ -194,13 +195,13 @@ ConnectWindow::connect_remote(const URI& uri)
{
Ingen::World* world = _app->world();
- SPtr<ThreadedSigClientInterface> tsci(
- new Client::ThreadedSigClientInterface());
+ SPtr<SigClientInterface> sci(new SigClientInterface());
+ SPtr<QueuedInterface> qi(new QueuedInterface(sci));
- SPtr<Ingen::Interface> iface(world->new_interface(uri, tsci));
+ SPtr<Ingen::Interface> iface(world->new_interface(uri, qi));
if (iface) {
world->set_interface(iface);
- _app->attach(tsci);
+ _app->attach(qi);
_app->register_callbacks();
return true;
}
@@ -231,7 +232,7 @@ ConnectWindow::connect(bool existing)
_connect_stage = 1;
SPtr<Client::SocketClient> client = dynamic_ptr_cast<Client::SocketClient>(world->interface());
if (client) {
- _app->attach(dynamic_ptr_cast<Client::SigClientInterface>(client->respondee()));
+ _app->attach(client->respondee());
_app->register_callbacks();
} else {
error("Connected with invalid client interface type");
diff --git a/src/gui/ingen_gui.cpp b/src/gui/ingen_gui.cpp
index 83e41a7e..677296fd 100644
--- a/src/gui/ingen_gui.cpp
+++ b/src/gui/ingen_gui.cpp
@@ -16,7 +16,8 @@
#include "ingen/Configuration.hpp"
#include "ingen/Module.hpp"
-#include "ingen/client/ThreadedSigClientInterface.hpp"
+#include "ingen/QueuedInterface.hpp"
+#include "ingen/client/SigClientInterface.hpp"
#include "App.hpp"
@@ -24,18 +25,16 @@ namespace Ingen {
namespace GUI {
struct GUIModule : public Module {
- void load(World* world) {
- using Client::SigClientInterface;
- using Client::ThreadedSigClientInterface;
+ using SigClientInterface = Client::SigClientInterface;
- std::string uri = world->conf().option("connect").ptr<char>();
+ void load(World* world) {
+ URI uri(world->conf().option("connect").ptr<char>());
if (!world->interface()) {
- SPtr<SigClientInterface> client(new ThreadedSigClientInterface());
- world->set_interface(world->new_interface(URI(uri), client));
- } else if (!dynamic_ptr_cast<Client::SigClientInterface>(
+ world->set_interface(
+ world->new_interface(URI(uri), make_client(world)));
+ } else if (!dynamic_ptr_cast<SigClientInterface>(
world->interface()->respondee())) {
- SPtr<SigClientInterface> client(new ThreadedSigClientInterface());
- world->interface()->set_respondee(client);
+ world->interface()->set_respondee(make_client(world));
}
app = GUI::App::create(world);
@@ -45,6 +44,11 @@ struct GUIModule : public Module {
app->run();
}
+ SPtr<Interface> make_client(World* const world) {
+ SPtr<SigClientInterface> sci(new SigClientInterface());
+ return world->engine() ? sci : SPtr<Interface>(new QueuedInterface(sci));
+ }
+
SPtr<GUI::App> app;
};
diff --git a/tests/ingen_test.cpp b/tests/ingen_test.cpp
index beac1a7f..c0a7bd32 100644
--- a/tests/ingen_test.cpp
+++ b/tests/ingen_test.cpp
@@ -42,7 +42,6 @@
#include "ingen/Store.hpp"
#include "ingen/URIMap.hpp"
#include "ingen/World.hpp"
-#include "ingen/client/ThreadedSigClientInterface.hpp"
#include "ingen/filesystem.hpp"
#include "ingen/runtime_paths.hpp"
#include "ingen/types.hpp"