diff --git a/src/client/CMakeLists.txt b/src/client/CMakeLists.txt
--- a/src/client/CMakeLists.txt
+++ b/src/client/CMakeLists.txt
@@ -22,6 +22,7 @@
fullscreen_shell.cpp
idle.cpp
keyboard.cpp
+ remote_access.cpp
outputconfiguration.cpp
outputmanagement.cpp
outputdevice.cpp
@@ -117,6 +118,10 @@
PROTOCOL ${KWAYLAND_SOURCE_DIR}/src/client/protocols/text-input-unstable-v2.xml
BASENAME text-input-v2
)
+ecm_add_wayland_client_protocol(CLIENT_LIB_SRCS
+ PROTOCOL ${KWAYLAND_SOURCE_DIR}/src/client/protocols/remote-access.xml
+ BASENAME remote-access
+)
add_library(KF5WaylandClient ${CLIENT_LIB_SRCS})
generate_export_header(KF5WaylandClient
@@ -164,6 +169,7 @@
fullscreen_shell.h
idle.h
keyboard.h
+ remote_access.h
outputconfiguration.h
outputmanagement.h
outputdevice.h
diff --git a/src/client/protocols/remote-access.xml b/src/client/protocols/remote-access.xml
new file mode 100644
--- /dev/null
+++ b/src/client/protocols/remote-access.xml
@@ -0,0 +1,48 @@
+
+
+ .
+ ]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/client/registry.h b/src/client/registry.h
--- a/src/client/registry.h
+++ b/src/client/registry.h
@@ -41,6 +41,7 @@
struct org_kde_kwin_outputdevice;
struct org_kde_kwin_fake_input;
struct org_kde_kwin_idle;
+struct org_kde_kwin_remote_access_manager;
struct org_kde_kwin_dpms_manager;
struct org_kde_kwin_shadow_manager;
struct org_kde_kwin_blur_manager;
@@ -65,6 +66,7 @@
class OutputManagement;
class OutputDevice;
class Idle;
+class RemoteAccessManager;
class Output;
class PlasmaShell;
class PlasmaWindowManagement;
@@ -138,7 +140,8 @@
OutputDevice, ///< Refers to the org_kde_kwin_outputdevice interface
ServerSideDecorationManager, ///< Refers to org_kde_kwin_server_decoration_manager
TextInputManagerUnstableV0, ///< Refers to wl_text_input_manager, @since 5.23
- TextInputManagerUnstableV2 ///< Refers to zwp_text_input_manager_v2, @since 5.23
+ TextInputManagerUnstableV2, ///< Refers to zwp_text_input_manager_v2, @since 5.23
+ RemoteAccessManager ///< Refers to org_kde_kwin_remote_access_manager interface, @since 5.23
};
explicit Registry(QObject *parent = nullptr);
virtual ~Registry();
@@ -374,6 +377,16 @@
**/
org_kde_kwin_idle *bindIdle(uint32_t name, uint32_t version) const;
/**
+ * Binds the org_kde_kwin_remote_access_manager with @p name and @p version.
+ * If the @p name does not exist or is not for the idle interface,
+ * @c null will be returned.
+ *
+ * Prefer using createRemoteAccessManager instead.
+ * @see createRemoteAccessManager
+ * @since 5.23
+ **/
+ org_kde_kwin_remote_access_manager *bindRemoteAccessManager(uint32_t name, uint32_t version) const;
+ /**
* Binds the org_kde_kwin_fake_input with @p name and @p version.
* If the @p name does not exist or is not for the fake input interface,
* @c null will be returned.
@@ -671,6 +684,22 @@
**/
Idle *createIdle(quint32 name, quint32 version, QObject *parent = nullptr);
/**
+ * Creates a RemoteAccessManager and sets it up to manage the interface identified by
+ * @p name and @p version.
+ *
+ * Note: in case @p name is invalid or isn't for the org_kde_kwin_remote_access_manager interface,
+ * the returned RemoteAccessManager will not be valid. Therefore it's recommended to call
+ * isValid on the created instance.
+ *
+ * @param name The name of the org_kde_kwin_remote_access_manager interface to bind
+ * @param version The version or the org_kde_kwin_remote_access_manager interface to use
+ * @param parent The parent for RemoteAccessManager
+ *
+ * @returns The created RemoteAccessManager.
+ * @since 5.23
+ **/
+ RemoteAccessManager *createRemoteAccessManager(quint32 name, quint32 version, QObject *parent = nullptr);
+ /**
* Creates a FakeInput and sets it up to manage the interface identified by
* @p name and @p version.
*
@@ -900,6 +929,13 @@
**/
void idleAnnounced(quint32 name, quint32 version);
/**
+ * Emitted whenever a org_kde_kwin_remote_access_manager interface gets announced.
+ * @param name The name for the announced interface
+ * @param version The maximum supported version of the announced interface
+ * @since 5.23
+ **/
+ void remoteAccessManagerAnnounced(quint32 name, quint32 version);
+ /**
* Emitted whenever a org_kde_kwin_fake_input interface gets announced.
* @param name The name for the announced interface
* @param version The maximum supported version of the announced interface
@@ -1038,6 +1074,12 @@
**/
void idleRemoved(quint32 name);
/**
+ * Emitted whenever a org_kde_kwin_remote_access_manager interface gets removed.
+ * @param name The name for the removed interface
+ * @since 5.23
+ **/
+ void remoteAccessManagerRemoved(quint32 name);
+ /**
* Emitted whenever a org_kde_kwin_fake_input interface gets removed.
* @param name The name for the removed interface
* @since 5.4
diff --git a/src/client/registry.cpp b/src/client/registry.cpp
--- a/src/client/registry.cpp
+++ b/src/client/registry.cpp
@@ -26,6 +26,7 @@
#include "fakeinput.h"
#include "fullscreen_shell.h"
#include "idle.h"
+#include "remote_access.h"
#include "logging_p.h"
#include "outputconfiguration.h"
#include "outputmanagement.h"
@@ -52,6 +53,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -161,6 +163,13 @@
&Registry::idleAnnounced,
&Registry::idleRemoved
}},
+ {Registry::Interface::RemoteAccessManager, {
+ 1,
+ QByteArrayLiteral("org_kde_kwin_remote_access_manager"),
+ &org_kde_kwin_remote_access_manager_interface,
+ &Registry::remoteAccessManagerAnnounced,
+ &Registry::remoteAccessManagerRemoved
+ }},
{Registry::Interface::FakeInput, {
2,
QByteArrayLiteral("org_kde_kwin_fake_input"),
@@ -532,6 +541,7 @@
BIND(PlasmaShell, org_kde_plasma_shell)
BIND(PlasmaWindowManagement, org_kde_plasma_window_management)
BIND(Idle, org_kde_kwin_idle)
+BIND(RemoteAccessManager, org_kde_kwin_remote_access_manager)
BIND(FakeInput, org_kde_kwin_fake_input)
BIND(OutputManagement, org_kde_kwin_outputmanagement)
BIND(OutputDevice, org_kde_kwin_outputdevice)
@@ -581,6 +591,7 @@
CREATE(PlasmaShell)
CREATE(PlasmaWindowManagement)
CREATE(Idle)
+CREATE(RemoteAccessManager)
CREATE(FakeInput)
CREATE(OutputManagement)
CREATE(OutputDevice)
diff --git a/src/client/remote_access.h b/src/client/remote_access.h
new file mode 100644
--- /dev/null
+++ b/src/client/remote_access.h
@@ -0,0 +1,207 @@
+/****************************************************************************
+Copyright 2016 Oleg Chernovskiy
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) version 3, or any
+later version accepted by the membership of KDE e.V. (or its
+successor approved by the membership of KDE e.V.), which shall
+act as a proxy defined in Section 6 of version 3 of the license.
+
+This library 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
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library. If not, see .
+****************************************************************************/
+#ifndef KWAYLAND_CLIENT_REMOTE_ACCESS_H
+#define KWAYLAND_CLIENT_REMOTE_ACCESS_H
+
+#include
+
+#include
+
+struct org_kde_kwin_remote_access_manager;
+struct org_kde_kwin_remote_buffer;
+
+namespace KWayland
+{
+namespace Client
+{
+
+class EventQueue;
+class RemoteBuffer;
+
+/**
+ * @short Wrapper for the org_kde_kwin_remote_access_manager interface.
+ *
+ * This class provides a convenient wrapper for the org_kde_kwin_remote_access_manager interface.
+ *
+ * To use this class one needs to interact with the Registry. There are two
+ * possible ways to create the RemoteAccessManager interface:
+ * @code
+ * RemoteAccessManager *c = registry->createRemoteAccessManager(name, version);
+ * @endcode
+ *
+ * This creates the RemoteAccessManager and sets it up directly. As an alternative this
+ * can also be done in a more low level way:
+ * @code
+ * RemoteAccessManager *c = new RemoteAccessManager;
+ * c->setup(registry->bindRemoteAccessManager(name, version));
+ * @endcode
+ *
+ * The RemoteAccessManager can be used as a drop-in replacement for any org_kde_kwin_remote_access_manager
+ * pointer as it provides matching cast operators.
+ *
+ * @see Registry
+ **/
+class KWAYLANDCLIENT_EXPORT RemoteAccessManager : public QObject
+{
+ Q_OBJECT
+public:
+ /**
+ * Creates a new RemoteAccessManager.
+ * Note: after constructing the RemoteAccessManager it is not yet valid and one needs
+ * to call setup. In order to get a ready to use RemoteAccessManager prefer using
+ * Registry::createRemoteAccessManager.
+ **/
+ explicit RemoteAccessManager(QObject *parent = nullptr);
+ virtual ~RemoteAccessManager();
+
+ /**
+ * Setup this RemoteAccessManager to manage the @p remoteaccessmanager.
+ * When using Registry::createRemoteAccessManager there is no need to call this
+ * method.
+ **/
+ void setup(org_kde_kwin_remote_access_manager *remoteaccessmanager);
+ /**
+ * @returns @c true if managing a org_kde_kwin_remote_access_manager.
+ **/
+ bool isValid() const;
+ /**
+ * Releases the org_kde_kwin_remote_access_manager interface.
+ * After the interface has been released the RemoteAccessManager instance is no
+ * longer valid and can be setup with another org_kde_kwin_remote_access_manager interface.
+ **/
+ void release();
+ /**
+ * Destroys the data held by this RemoteAccessManager.
+ * This method is supposed to be used when the connection to the Wayland
+ * server goes away. If the connection is not valid anymore, it's not
+ * possible to call release anymore as that calls into the Wayland
+ * connection and the call would fail. This method cleans up the data, so
+ * that the instance can be deleted or set up to a new org_kde_kwin_remote_access_manager interface
+ * once there is a new connection available.
+ *
+ * It is suggested to connect this method to ConnectionThread::connectionDied:
+ * @code
+ * connect(connection, &ConnectionThread::connectionDied, remoteaccessmanager, &RemoteAccessManager::destroy);
+ * @endcode
+ *
+ * @see release
+ **/
+ void destroy();
+
+ /**
+ * Sets the @p queue to use for creating objects with this RemoteAccessManager.
+ **/
+ void setEventQueue(EventQueue *queue);
+ /**
+ * @returns The event queue to use for creating objects with this RemoteAccessManager.
+ **/
+ EventQueue *eventQueue();
+
+ operator org_kde_kwin_remote_access_manager*();
+ operator org_kde_kwin_remote_access_manager*() const;
+
+Q_SIGNALS:
+ /**
+ * The corresponding global for this interface on the Registry got removed.
+ *
+ * This signal gets only emitted if the RemoteAccessManager got created by
+ * Registry::createRemoteAccessManager
+ **/
+ void removed();
+
+ /**
+ * Buffer from server is ready to be delivered to this client
+ * @param buffer_id internal buffer id to be created
+ **/
+ void bufferReady(RemoteBuffer *rbuf);
+
+private:
+ class Private;
+ QScopedPointer d;
+};
+
+/**
+ * @short Wrapper for org_kde_kwin_remote_buffer interface.
+ * The instances of this class are created by parent RemoteAccessManager.
+ * Deletion (by noLongerNeeded call) is in responsibility of underlying system.
+ */
+class KWAYLANDCLIENT_EXPORT RemoteBuffer : public QObject
+{
+ Q_OBJECT
+public:
+ virtual ~RemoteBuffer();
+ /**
+ * Setup this RemoteBuffer to manage the @p remotebuffer.
+ **/
+ void setup(org_kde_kwin_remote_buffer *remotebuffer);
+ /**
+ * @returns @c true if managing a org_kde_kwin_remote_buffer.
+ **/
+ bool isValid() const;
+ /**
+ * Releases the org_kde_kwin_remote_buffer interface.
+ * After the interface has been released the RemoteBuffer instance is no
+ * longer valid and can be setup with another org_kde_kwin_remote_buffer interface.
+ **/
+ void release();
+ /**
+ * Destroys the data held by this RemoteBuffer.
+ * This method is supposed to be used when the connection to the Wayland
+ * server goes away. If the connection is not valid anymore, it's not
+ * possible to call release anymore as that calls into the Wayland
+ * connection and the call would fail. This method cleans up the data, so
+ * that the instance can be deleted or set up to a new org_kde_kwin_remote_buffer interface
+ * once there is a new connection available.
+ *
+ * It is suggested to connect this method to ConnectionThread::connectionDied:
+ * @code
+ * connect(connection, &ConnectionThread::connectionDied, remotebuffer, &RemoteBuffer::destroy);
+ * @endcode
+ *
+ * @see release
+ **/
+ void destroy();
+
+ operator org_kde_kwin_remote_buffer*();
+ operator org_kde_kwin_remote_buffer*() const;
+
+ qint32 fd();
+ quint32 width();
+ quint32 height();
+ quint32 stride();
+ quint32 format();
+
+
+Q_SIGNALS:
+ void paramsObtained();
+
+private:
+
+ friend class RemoteAccessManager;
+ explicit RemoteBuffer(QObject *parent = nullptr);
+ class Private;
+ QScopedPointer d;
+};
+
+
+}
+}
+
+#endif
diff --git a/src/client/remote_access.cpp b/src/client/remote_access.cpp
new file mode 100644
--- /dev/null
+++ b/src/client/remote_access.cpp
@@ -0,0 +1,247 @@
+/****************************************************************************
+Copyright 2016 Oleg Chernovskiy
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) version 3, or any
+later version accepted by the membership of KDE e.V. (or its
+successor approved by the membership of KDE e.V.), which shall
+act as a proxy defined in Section 6 of version 3 of the license.
+
+This library 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
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library. If not, see .
+****************************************************************************/
+#include "remote_access.h"
+#include "event_queue.h"
+#include "wayland_pointer_p.h"
+// Wayland
+#include
+// Qt
+#include
+
+namespace KWayland
+{
+namespace Client
+{
+
+class RemoteAccessManager::Private
+{
+public:
+ explicit Private(RemoteAccessManager *ram);
+ void setup(org_kde_kwin_remote_access_manager *k);
+
+ WaylandPointer ram;
+ EventQueue *queue = nullptr;
+private:
+ static const struct org_kde_kwin_remote_access_manager_listener s_listener;
+ static void bufferReadyCallback(void *data, org_kde_kwin_remote_access_manager *org_kde_kwin_remoteaccess, quint32 buffer_id);
+
+ RemoteAccessManager *q;
+};
+
+RemoteAccessManager::Private::Private(RemoteAccessManager *q)
+ : q(q)
+{
+}
+
+const org_kde_kwin_remote_access_manager_listener RemoteAccessManager::Private::s_listener = {
+ bufferReadyCallback
+};
+
+void RemoteAccessManager::Private::bufferReadyCallback(void *data, org_kde_kwin_remote_access_manager *interface, quint32 buffer_id)
+{
+ auto ramp = reinterpret_cast(data);
+ Q_ASSERT(ramp->ram == interface);
+
+ // handle it fully internally, get the buffer immediately
+ auto requested = org_kde_kwin_remote_access_manager_get_buffer(ramp->ram, buffer_id);
+ auto rbuf = new RemoteBuffer(ramp->q);
+ rbuf->setup(requested);
+ qDebug() << "Got buffer from server, fd:" << buffer_id;
+
+ emit ramp->q->bufferReady(rbuf);
+}
+
+void RemoteAccessManager::Private::setup(org_kde_kwin_remote_access_manager *k)
+{
+ Q_ASSERT(k);
+ Q_ASSERT(!ram);
+ ram.setup(k);
+ org_kde_kwin_remote_access_manager_add_listener(k, &s_listener, this);
+}
+
+RemoteAccessManager::RemoteAccessManager(QObject *parent)
+ : QObject(parent)
+ , d(new Private(this))
+{
+}
+
+RemoteAccessManager::~RemoteAccessManager()
+{
+ release();
+}
+
+void RemoteAccessManager::setup(org_kde_kwin_remote_access_manager *ram)
+{
+ d->setup(ram);
+}
+
+void RemoteAccessManager::release()
+{
+ d->ram.release();
+}
+
+void RemoteAccessManager::destroy()
+{
+ d->ram.destroy();
+}
+
+void RemoteAccessManager::setEventQueue(EventQueue *queue)
+{
+ d->queue = queue;
+}
+
+EventQueue *RemoteAccessManager::eventQueue()
+{
+ return d->queue;
+}
+
+RemoteAccessManager::operator org_kde_kwin_remote_access_manager*() {
+ return d->ram;
+}
+
+RemoteAccessManager::operator org_kde_kwin_remote_access_manager*() const {
+ return d->ram;
+}
+
+bool RemoteAccessManager::isValid() const
+{
+ return d->ram.isValid();
+}
+
+class RemoteBuffer::Private
+{
+public:
+ Private(RemoteBuffer *q);
+ void setup(org_kde_kwin_remote_buffer *buffer);
+
+ static struct org_kde_kwin_remote_buffer_listener s_listener;
+ static void paramsCallback(void *data, org_kde_kwin_remote_buffer *rbuf,
+ qint32 fd, quint32 width, quint32 height, quint32 stride, quint32 format);
+
+ WaylandPointer remotebuffer;
+ RemoteBuffer *q;
+
+ qint32 fd = 0;
+ quint32 width = 0;
+ quint32 height = 0;
+ quint32 stride = 0;
+ quint32 format = 0;
+};
+
+RemoteBuffer::Private::Private(RemoteBuffer *q)
+ : q(q)
+{
+}
+
+void RemoteBuffer::Private::paramsCallback(void *data, org_kde_kwin_remote_buffer *rbuf,
+ qint32 fd, quint32 width, quint32 height, quint32 stride, quint32 format)
+{
+ Q_UNUSED(rbuf)
+ Private *p = reinterpret_cast(data);
+ p->fd = fd;
+ p->width = width;
+ p->height = height;
+ p->stride = stride;
+ p->format = format;
+ emit p->q->paramsObtained();
+}
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+org_kde_kwin_remote_buffer_listener RemoteBuffer::Private::s_listener = {
+ paramsCallback
+};
+#endif
+
+void RemoteBuffer::Private::setup(org_kde_kwin_remote_buffer *rbuffer)
+{
+ remotebuffer.setup(rbuffer);
+ org_kde_kwin_remote_buffer_add_listener(rbuffer, &s_listener, this);
+}
+
+RemoteBuffer::RemoteBuffer(QObject *parent)
+ : QObject(parent)
+ , d(new Private(this))
+{
+}
+
+RemoteBuffer::~RemoteBuffer()
+{
+ release();
+ qDebug() << "Buffer released";
+}
+
+void RemoteBuffer::setup(org_kde_kwin_remote_buffer *remotebuffer)
+{
+ Q_ASSERT(remotebuffer);
+ Q_ASSERT(!d->remotebuffer);
+ d->setup(remotebuffer);
+}
+
+void RemoteBuffer::release()
+{
+ d->remotebuffer.release();
+}
+
+void RemoteBuffer::destroy()
+{
+ d->remotebuffer.destroy();
+}
+
+RemoteBuffer::operator org_kde_kwin_remote_buffer*() {
+ return d->remotebuffer;
+}
+
+RemoteBuffer::operator org_kde_kwin_remote_buffer*() const {
+ return d->remotebuffer;
+}
+
+bool RemoteBuffer::isValid() const
+{
+ return d->remotebuffer.isValid();
+}
+
+qint32 RemoteBuffer::fd()
+{
+ return d->fd;
+}
+
+quint32 RemoteBuffer::width()
+{
+ return d->width;
+}
+
+quint32 RemoteBuffer::height()
+{
+ return d->height;
+}
+
+quint32 RemoteBuffer::stride()
+{
+ return d->stride;
+}
+
+quint32 RemoteBuffer::format()
+{
+ return d->format;
+}
+
+
+}
+}
\ No newline at end of file
diff --git a/src/server/CMakeLists.txt b/src/server/CMakeLists.txt
--- a/src/server/CMakeLists.txt
+++ b/src/server/CMakeLists.txt
@@ -12,6 +12,7 @@
idle_interface.cpp
fakeinput_interface.cpp
keyboard_interface.cpp
+ remote_access_interface.cpp
outputconfiguration_interface.cpp
outputchangeset.cpp
outputmanagement_interface.cpp
@@ -113,6 +114,11 @@
BASENAME text-input-unstable-v2
)
+ecm_add_wayland_server_protocol(SERVER_LIB_SRCS
+ PROTOCOL ${KWAYLAND_SOURCE_DIR}/src/client/protocols/remote-access.xml
+ BASENAME remote-access
+)
+
add_library(KF5WaylandServer ${SERVER_LIB_SRCS})
generate_export_header(KF5WaylandServer
BASE_NAME
@@ -163,6 +169,7 @@
global.h
idle_interface.h
keyboard_interface.h
+ remote_access_interface.h
outputdevice_interface.h
outputchangeset.h
outputconfiguration_interface.h
diff --git a/src/server/display.h b/src/server/display.h
--- a/src/server/display.h
+++ b/src/server/display.h
@@ -53,6 +53,7 @@
class DataDeviceManagerInterface;
class DpmsManagerInterface;
class IdleInterface;
+class RemoteAccessManagerInterface;
class FakeInputInterface;
class OutputInterface;
class OutputDeviceInterface;
@@ -162,6 +163,7 @@
PlasmaWindowManagementInterface *createPlasmaWindowManagement(QObject *parent = nullptr);
QtSurfaceExtensionInterface *createQtSurfaceExtension(QObject *parent = nullptr);
IdleInterface *createIdle(QObject *parent = nullptr);
+ RemoteAccessManagerInterface *createRemoteAccessManager(QObject *parent = nullptr);
FakeInputInterface *createFakeInput(QObject *parent = nullptr);
ShadowManagerInterface *createShadowManager(QObject *parent = nullptr);
BlurManagerInterface *createBlurManager(QObject *parent = nullptr);
diff --git a/src/server/display.cpp b/src/server/display.cpp
--- a/src/server/display.cpp
+++ b/src/server/display.cpp
@@ -25,6 +25,7 @@
#include "outputmanagement_interface.h"
#include "outputdevice_interface.h"
#include "idle_interface.h"
+#include "remote_access_interface.h"
#include "fakeinput_interface.h"
#include "logging_p.h"
#include "output_interface.h"
@@ -279,6 +280,13 @@
return s;
}
+RemoteAccessManagerInterface *Display::createRemoteAccessManager(QObject *parent)
+{
+ auto i = new RemoteAccessManagerInterface(this, parent);
+ connect(this, &Display::aboutToTerminate, i, [this, i] { delete i; });
+ return i;
+}
+
IdleInterface *Display::createIdle(QObject *parent)
{
auto i = new IdleInterface(this, parent);
diff --git a/src/server/remote_access_interface.h b/src/server/remote_access_interface.h
new file mode 100644
--- /dev/null
+++ b/src/server/remote_access_interface.h
@@ -0,0 +1,118 @@
+/****************************************************************************
+Copyright 2016 Oleg Chernovskiy
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) version 3, or any
+later version accepted by the membership of KDE e.V. (or its
+successor approved by the membership of KDE e.V.), which shall
+act as a proxy defined in Section 6 of version 3 of the license.
+
+This library 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
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library. If not, see .
+****************************************************************************/
+#ifndef KWAYLAND_SERVER_REMOTE_ACCESS_H
+#define KWAYLAND_SERVER_REMOTE_ACCESS_H
+
+#include "global.h"
+#include "resource.h"
+
+#include
+
+#include
+
+/**
+ * The structure server should fill to use this interface.
+ * Lifecycle:
+ * 1. GbmBuffer is filled and passed to RemoteAccessManager
+ * (stored in manager's sent list)
+ * 2. Client confirms that it wants this buffer, the RemoteBuffer
+ * interface is then created and wrapped around GbmBuffer.
+ * Manager purges its reference from sent list.
+ * 3. Once client is done with buffer (or disconnected),
+ * RemoteBuffer notifies manager and release signal is emitted.
+ * It's the responsibility of process to delete this GbmBuffer
+ * and release its' fd and gbm_bo afterwards.
+ **/
+struct GbmBuffer
+{
+ // relevant for server
+ qint32 fd = 0; //< also buffer_id
+
+ // Note that on client side received fd number will be different
+ // and meaningful only for client process!
+ // Thus we can use server-side fd as an implicit unique id
+
+ // relevant for client
+ quint32 width = 0;
+ quint32 height = 0;
+ quint32 stride = 0;
+ quint32 format = 0;
+};
+
+namespace KWayland
+{
+namespace Server
+{
+
+class Display;
+
+class KWAYLANDSERVER_EXPORT RemoteAccessManagerInterface : public Global
+{
+ Q_OBJECT
+public:
+ virtual ~RemoteAccessManagerInterface() = default;
+
+ /**
+ * Store buffer in sent list and notify client that we have a buffer for it
+ **/
+ void sendBufferReady(const GbmBuffer *buf);
+ /**
+ * Check whether interface has been bound
+ **/
+ bool isBound() const;
+
+Q_SIGNALS:
+ /**
+ * Previously sent buffer has been released by client
+ */
+ void bufferReleased(const GbmBuffer *buf);
+
+private:
+ explicit RemoteAccessManagerInterface(Display *display, QObject *parent = nullptr);
+ friend class Display;
+ class Private;
+
+};
+
+class KWAYLANDSERVER_EXPORT RemoteBufferInterface : public Resource
+{
+ Q_OBJECT
+public:
+ virtual ~RemoteBufferInterface() = default;
+
+ /**
+ * Sends GBM fd to the client.
+ * Note that server still has to close mirror fd from its side.
+ **/
+ void passFd();
+
+private:
+ explicit RemoteBufferInterface(RemoteAccessManagerInterface *ram, wl_resource *pResource, const GbmBuffer *buf);
+ friend class RemoteAccessManagerInterface;
+
+ class Private;
+ Private *d_func() const;
+};
+
+
+}
+}
+
+#endif
diff --git a/src/server/remote_access_interface.cpp b/src/server/remote_access_interface.cpp
new file mode 100644
--- /dev/null
+++ b/src/server/remote_access_interface.cpp
@@ -0,0 +1,267 @@
+/****************************************************************************
+Copyright 2016 Oleg Chernovskiy
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) version 3, or any
+later version accepted by the membership of KDE e.V. (or its
+successor approved by the membership of KDE e.V.), which shall
+act as a proxy defined in Section 6 of version 3 of the license.
+
+This library 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
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library. If not, see .
+****************************************************************************/
+#include "remote_access_interface.h"
+#include "display.h"
+#include "global_p.h"
+#include "resource_p.h"
+
+#include
+
+#include
+
+namespace KWayland
+{
+namespace Server
+{
+
+class RemoteAccessManagerInterface::Private : public Global::Private
+{
+public:
+ Private(RemoteAccessManagerInterface *q, Display *d);
+ virtual ~Private();
+
+ void sendBufferReady(const GbmBuffer *buf);
+ void releaseAll();
+
+ bool bound = false;
+
+private:
+ // methods
+ static void unbind(wl_resource *resource);
+ static Private *cast(wl_resource *r) {
+ return reinterpret_cast(wl_resource_get_user_data(r));
+ }
+ static void getBufferCallback(wl_client *client, wl_resource *resource, uint32_t buffer, uint32_t internalBufId);
+ void bind(wl_client *client, uint32_t version, uint32_t id) override;
+
+ // fields
+ static const struct org_kde_kwin_remote_access_manager_interface s_interface;
+ static const quint32 s_version;
+
+ RemoteAccessManagerInterface *q;
+ wl_resource *m_resource = nullptr;
+
+ /**
+ * Buffers that were acked by client
+ * with RemoteBuffer wrapped around them
+ **/
+ QList ackedBuffers;
+
+ /**
+ * Buffers that were sent but still not acked by server
+ * Keys are fd numbers as they are unique
+ **/
+ QHash sentBuffers;
+};
+
+const quint32 RemoteAccessManagerInterface::Private::s_version = 1;
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+const struct org_kde_kwin_remote_access_manager_interface RemoteAccessManagerInterface::Private::s_interface = {
+ getBufferCallback
+};
+#endif
+
+void RemoteAccessManagerInterface::Private::getBufferCallback(wl_client *client, wl_resource *resource, uint32_t buffer, uint32_t internalBufId)
+{
+ Private *p = cast(resource);
+
+ // client asks for buffer we earlier announced, we must have it
+ const GbmBuffer *buf = p->sentBuffers[internalBufId];
+ if(Q_UNLIKELY(!buf)) { // no such buffer (?)
+ wl_resource_post_no_memory(resource);
+ return;
+ }
+
+ auto rbuf = new RemoteBufferInterface(p->q, resource, buf);
+ rbuf->create(p->display->getConnection(client), wl_resource_get_version(resource), buffer);
+ if (!rbuf->resource()) {
+ wl_resource_post_no_memory(resource);
+ delete rbuf;
+ return;
+ }
+
+ // move buffer to acked buffers from sent
+ p->sentBuffers.remove(internalBufId);
+ p->ackedBuffers << rbuf;
+
+ QObject::connect(rbuf, &QObject::destroyed, [p, rbuf, buffer, internalBufId] {
+ p->ackedBuffers.removeOne(rbuf);
+ qDebug() << "Server buffer released: id" << buffer << ", fd" << internalBufId;
+ });
+
+ // send buffer params
+ rbuf->passFd();
+}
+
+RemoteAccessManagerInterface::Private::Private(RemoteAccessManagerInterface *q, Display *d)
+ : Global::Private(d, &org_kde_kwin_remote_access_manager_interface, s_version)
+ , q(q)
+{
+}
+
+void RemoteAccessManagerInterface::Private::sendBufferReady(const GbmBuffer *buf)
+{
+ // store buffer locally, client will ask it later
+ sentBuffers[buf->fd] = buf;
+ // notify client
+ qDebug() << "Server buffer sent: fd" << buf->fd;
+ org_kde_kwin_remote_access_manager_send_buffer_ready(m_resource, buf->fd);
+}
+
+void RemoteAccessManagerInterface::Private::releaseAll()
+{
+ // remote buffers are in our responsibility, delete them
+ // wrapped gbm buffers will be released anyway
+ for (RemoteBufferInterface *acked : ackedBuffers) {
+ acked->deleteLater();
+ }
+
+ // non-acked buffers should be released manually
+ for (const GbmBuffer *buf : sentBuffers) {
+ emit q->bufferReleased(buf);
+ }
+}
+
+void RemoteAccessManagerInterface::Private::bind(wl_client *client, uint32_t version, uint32_t id)
+{
+ // only 1 client permitted
+ if (bound) {
+ wl_client_post_no_memory(client);
+ return;
+ }
+
+ auto c = display->getConnection(client);
+ wl_resource *resource = c->createResource(&org_kde_kwin_remote_access_manager_interface, qMin(version, s_version), id);
+ if (!resource) {
+ wl_client_post_no_memory(client);
+ return;
+ }
+ wl_resource_set_implementation(resource, &s_interface, this, unbind);
+ m_resource = resource;
+ bound = true;
+}
+
+void RemoteAccessManagerInterface::Private::unbind(wl_resource *resource)
+{
+ Private *p = cast(resource);
+
+ // we're unbinding, hence all acked and sent buffers are now effectively invalid
+ // client won't come for them
+ p->releaseAll();
+ p->m_resource = nullptr;
+ p->bound = false;
+}
+
+RemoteAccessManagerInterface::Private::~Private()
+{
+ // server deletes created interfaces, release all held buffers
+ releaseAll();
+}
+
+RemoteAccessManagerInterface::RemoteAccessManagerInterface(Display *display, QObject *parent)
+ : Global(new Private(this, display), parent)
+{
+}
+
+void RemoteAccessManagerInterface::sendBufferReady(const GbmBuffer *buf)
+{
+ Private *priv = reinterpret_cast(d.data());
+ priv->sendBufferReady(buf);
+}
+
+bool RemoteAccessManagerInterface::isBound() const
+{
+ Private *priv = reinterpret_cast(d.data());
+ return priv->bound;
+}
+
+class RemoteBufferInterface::Private : public Resource::Private
+{
+public:
+ Private(RemoteAccessManagerInterface *ram, RemoteBufferInterface *q, wl_resource *pResource, const GbmBuffer *buf);
+ ~Private();
+
+ void passFd();
+
+private:
+ static void releaseCallback(wl_client *client, wl_resource *resource);
+
+ static const struct org_kde_kwin_remote_buffer_interface s_interface;
+
+ const GbmBuffer *const wrapped;
+};
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+const struct org_kde_kwin_remote_buffer_interface RemoteBufferInterface::Private::s_interface = {
+ releaseCallback
+};
+#endif
+
+void RemoteBufferInterface::Private::releaseCallback(wl_client *client, wl_resource *resource)
+{
+ Q_UNUSED(client)
+ Private *p = cast(resource);
+ // client wants to release this buffer, notify manager
+
+ p->q->deleteLater(); // also purges it from manager's list
+}
+
+RemoteBufferInterface::Private::Private(RemoteAccessManagerInterface *ram, RemoteBufferInterface *q, wl_resource *pResource, const GbmBuffer *buf)
+ : Resource::Private(q, ram, pResource, &org_kde_kwin_remote_buffer_interface, &s_interface), wrapped(buf)
+{
+}
+
+RemoteBufferInterface::Private::~Private()
+{
+ if (resource) {
+ wl_resource_destroy(resource);
+ resource = nullptr;
+ }
+
+ auto ram = reinterpret_cast(global);
+ emit ram->bufferReleased(wrapped);
+}
+
+void RemoteBufferInterface::Private::passFd()
+{
+ org_kde_kwin_remote_buffer_send_gbm_handle(resource, wrapped->fd,
+ wrapped->width, wrapped->height, wrapped->stride, wrapped->format);
+}
+
+RemoteBufferInterface::RemoteBufferInterface(RemoteAccessManagerInterface *ram, wl_resource *pResource, const GbmBuffer *buf)
+ : Resource(new Private(ram, this, pResource, buf), ram)
+{
+}
+
+RemoteBufferInterface::Private *RemoteBufferInterface::d_func() const
+{
+ return reinterpret_cast(d.data());
+}
+
+
+void RemoteBufferInterface::passFd()
+{
+ d_func()->passFd();
+}
+
+}
+}
+
diff --git a/src/tools/mapping.txt b/src/tools/mapping.txt
--- a/src/tools/mapping.txt
+++ b/src/tools/mapping.txt
@@ -44,3 +44,6 @@
wl_text_input_manager;TextInputManagerUnstableV0
zwp_text_input_v2;TextInputUnstableV2
zwp_text_input_manager_v2;TextInputManagerUnstableV2
+org_kde_kwin_remote_access_manager;RemoteAccessManager
+org_kde_kwin_remote_buffer;RemoteBuffer
+