diff --git a/src/wayland/CMakeLists.txt b/src/wayland/CMakeLists.txt
index 1dbf8d286d..1cf09d3ab6 100644
--- a/src/wayland/CMakeLists.txt
+++ b/src/wayland/CMakeLists.txt
@@ -20,6 +20,7 @@ set(SERVER_LIB_SRCS
region_interface.cpp
resource.cpp
seat_interface.cpp
+ shadow_interface.cpp
shell_interface.cpp
surface_interface.cpp
subcompositor_interface.cpp
@@ -51,6 +52,11 @@ ecm_add_wayland_server_protocol(SERVER_LIB_SRCS
BASENAME fake-input
)
+ecm_add_wayland_server_protocol(SERVER_LIB_SRCS
+ PROTOCOL ${KWAYLAND_SOURCE_DIR}/src/client/protocols/shadow.xml
+ BASENAME shadow
+)
+
add_library(KF5WaylandServer ${SERVER_LIB_SRCS})
generate_export_header(KF5WaylandServer
BASE_NAME
@@ -106,6 +112,7 @@ install(FILES
region_interface.h
resource.h
seat_interface.h
+ shadow_interface.h
shell_interface.h
subcompositor_interface.h
surface_interface.h
diff --git a/src/wayland/display.cpp b/src/wayland/display.cpp
index 77632d8a68..884d7ea2fe 100644
--- a/src/wayland/display.cpp
+++ b/src/wayland/display.cpp
@@ -28,6 +28,7 @@ License along with this library. If not, see .
#include "plasmawindowmanagement_interface.h"
#include "qtsurfaceextension_interface.h"
#include "seat_interface.h"
+#include "shadow_interface.h"
#include "shell_interface.h"
#include "subcompositor_interface.h"
@@ -263,6 +264,13 @@ FakeInputInterface *Display::createFakeInput(QObject *parent)
return i;
}
+ShadowManagerInterface *Display::createShadowManager(QObject *parent)
+{
+ auto s = new ShadowManagerInterface(this, parent);
+ connect(this, &Display::aboutToTerminate, s, [this, s] { delete s; });
+ return s;
+}
+
void Display::createShm()
{
Q_ASSERT(d->display);
diff --git a/src/wayland/display.h b/src/wayland/display.h
index 56dcb6363b..4c0e0c71ef 100644
--- a/src/wayland/display.h
+++ b/src/wayland/display.h
@@ -45,6 +45,7 @@ class PlasmaShellInterface;
class PlasmaWindowManagementInterface;
class QtSurfaceExtensionInterface;
class SeatInterface;
+class ShadowManagerInterface;
class ShellInterface;
class SubCompositorInterface;
@@ -124,6 +125,7 @@ public:
QtSurfaceExtensionInterface *createQtSurfaceExtension(QObject *parent = nullptr);
IdleInterface *createIdle(QObject *parent = nullptr);
FakeInputInterface *createFakeInput(QObject *parent = nullptr);
+ ShadowManagerInterface *createShadowManager(QObject *parent = nullptr);
/**
* Gets the ClientConnection for the given @p client.
diff --git a/src/wayland/shadow_interface.cpp b/src/wayland/shadow_interface.cpp
new file mode 100644
index 0000000000..6dfc7a618e
--- /dev/null
+++ b/src/wayland/shadow_interface.cpp
@@ -0,0 +1,407 @@
+/********************************************************************
+Copyright 2015 Martin Gräßlin
+
+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 "shadow_interface.h"
+#include "buffer_interface.h"
+#include "display.h"
+#include "global_p.h"
+#include "resource_p.h"
+#include "surface_interface_p.h"
+
+#include
+#include
+
+namespace KWayland
+{
+namespace Server
+{
+
+static const quint32 s_version = 1;
+
+class ShadowManagerInterface::Private : public Global::Private
+{
+public:
+ Private(ShadowManagerInterface *q, Display *d);
+
+private:
+ void bind(wl_client *client, uint32_t version, uint32_t id) override;
+ void createShadow(wl_client *client, wl_resource *resource, uint32_t id, wl_resource *surface);
+
+ static void createCallback(wl_client *client, wl_resource *resource, uint32_t id, wl_resource *surface);
+ static void unsetCallback(wl_client *client, wl_resource *resource, wl_resource *surface);
+ static void unbind(wl_resource *resource);
+ static Private *cast(wl_resource *r) {
+ return reinterpret_cast(wl_resource_get_user_data(r));
+ }
+
+ ShadowManagerInterface *q;
+ static const struct org_kde_kwin_shadow_manager_interface s_interface;
+};
+
+const struct org_kde_kwin_shadow_manager_interface ShadowManagerInterface::Private::s_interface = {
+ createCallback,
+ unsetCallback
+};
+
+ShadowManagerInterface::Private::Private(ShadowManagerInterface *q, Display *d)
+ : Global::Private(d, &org_kde_kwin_shadow_manager_interface, s_version)
+ , q(q)
+{
+}
+
+void ShadowManagerInterface::Private::bind(wl_client *client, uint32_t version, uint32_t id)
+{
+ auto c = display->getConnection(client);
+ wl_resource *resource = c->createResource(&org_kde_kwin_shadow_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);
+ // TODO: should we track?
+}
+
+void ShadowManagerInterface::Private::unbind(wl_resource *resource)
+{
+ Q_UNUSED(resource)
+ // TODO: implement?
+}
+
+void ShadowManagerInterface::Private::createCallback(wl_client *client, wl_resource *resource, uint32_t id, wl_resource *surface)
+{
+ cast(resource)->createShadow(client, resource, id, surface);
+}
+
+void ShadowManagerInterface::Private::createShadow(wl_client *client, wl_resource *resource, uint32_t id, wl_resource *surface)
+{
+ SurfaceInterface *s = SurfaceInterface::get(surface);
+ if (!s) {
+ return;
+ }
+
+ ShadowInterface *shadow = new ShadowInterface(q, resource);
+ shadow->create(display->getConnection(client), wl_resource_get_version(resource), id);
+ if (!shadow->resource()) {
+ wl_resource_post_no_memory(resource);
+ delete shadow;
+ return;
+ }
+ QObject::connect(s, &QObject::destroyed, shadow,
+ [shadow] {
+ if (shadow->resource()) {
+ wl_resource_destroy(shadow->resource());
+ delete shadow;
+ }
+ }
+ );
+ s->d_func()->setShadow(QPointer(shadow));
+}
+
+void ShadowManagerInterface::Private::unsetCallback(wl_client *client, wl_resource *resource, wl_resource *surface)
+{
+ Q_UNUSED(client)
+ Q_UNUSED(resource)
+ SurfaceInterface *s = SurfaceInterface::get(surface);
+ if (!s) {
+ return;
+ }
+ s->d_func()->setShadow(QPointer());
+}
+
+ShadowManagerInterface::ShadowManagerInterface(Display *display, QObject *parent)
+ : Global(new Private(this, display), parent)
+{
+}
+
+ShadowManagerInterface::~ShadowManagerInterface() = default;
+
+class ShadowInterface::Private : public Resource::Private
+{
+public:
+ Private(ShadowInterface *q, ShadowManagerInterface *c, wl_resource *parentResource);
+ ~Private();
+
+ struct State {
+ enum Flags {
+ None = 0,
+ LeftBuffer = 1 << 0,
+ TopLeftBuffer = 1 << 1,
+ TopBuffer = 1 << 2,
+ TopRightBuffer = 1 << 3,
+ RightBuffer = 1 << 4,
+ BottomRightBuffer = 1 << 5,
+ BottomBuffer = 1 << 6,
+ BottomLeftBuffer = 1 << 7,
+ Offset = 1 << 8
+ };
+ BufferInterface *left = nullptr;
+ BufferInterface *topLeft = nullptr;
+ BufferInterface *top = nullptr;
+ BufferInterface *topRight = nullptr;
+ BufferInterface *right = nullptr;
+ BufferInterface *bottomRight = nullptr;
+ BufferInterface *bottom = nullptr;
+ BufferInterface *bottomLeft = nullptr;
+ QMarginsF offset;
+ Flags flags = Flags::None;
+ };
+ State current;
+ State pending;
+
+private:
+ void commit();
+ void attach(State::Flags flag, wl_resource *buffer);
+ ShadowInterface *q_func() {
+ return reinterpret_cast(q);
+ }
+
+ static void commitCallback(wl_client *client, wl_resource *resource);
+ static void attachLeftCallback(wl_client *client, wl_resource *resource, wl_resource *buffer);
+ static void attachTopLeftCallback(wl_client *client, wl_resource *resource, wl_resource *buffer);
+ static void attachTopCallback(wl_client *client, wl_resource *resource, wl_resource *buffer);
+ static void attachTopRightCallback(wl_client *client, wl_resource *resource, wl_resource *buffer);
+ static void attachRightCallback(wl_client *client, wl_resource *resource, wl_resource *buffer);
+ static void attachBottomRightCallback(wl_client *client, wl_resource *resource, wl_resource *buffer);
+ static void attachBottomCallback(wl_client *client, wl_resource *resource, wl_resource *buffer);
+ static void attachBottomLeftCallback(wl_client *client, wl_resource *resource, wl_resource *buffer);
+ static void offsetLeftCallback(wl_client *client, wl_resource *resource, wl_fixed_t offset);
+ static void offsetTopCallback(wl_client *client, wl_resource *resource, wl_fixed_t offset);
+ static void offsetRightCallback(wl_client *client, wl_resource *resource, wl_fixed_t offset);
+ static void offsetBottomCallback(wl_client *client, wl_resource *resource, wl_fixed_t offset);
+
+ static const struct org_kde_kwin_shadow_interface s_interface;
+};
+
+const struct org_kde_kwin_shadow_interface ShadowInterface::Private::s_interface = {
+ commitCallback,
+ attachLeftCallback,
+ attachTopLeftCallback,
+ attachTopCallback,
+ attachTopRightCallback,
+ attachRightCallback,
+ attachBottomRightCallback,
+ attachBottomCallback,
+ attachBottomLeftCallback,
+ offsetLeftCallback,
+ offsetTopCallback,
+ offsetRightCallback,
+ offsetBottomCallback,
+};
+
+void ShadowInterface::Private::commitCallback(wl_client *client, wl_resource *resource)
+{
+ Q_UNUSED(client)
+ cast(resource)->commit();
+}
+
+void ShadowInterface::Private::commit()
+{
+#define BUFFER( __FLAG__, __PART__ ) \
+ if (pending.flags & State::Flags::__FLAG__##Buffer) { \
+ if (current.__PART__) { \
+ current.__PART__->unref(); \
+ } \
+ if (pending.__PART__) { \
+ pending.__PART__->ref(); \
+ } \
+ current.__PART__ = pending.__PART__; \
+ }
+ BUFFER(Left, left)
+ BUFFER(TopLeft, topLeft)
+ BUFFER(Top, top)
+ BUFFER(TopRight, topRight)
+ BUFFER(Right, right)
+ BUFFER(BottomRight, bottomRight)
+ BUFFER(Bottom, bottom)
+ BUFFER(BottomLeft, bottomLeft)
+#undef BUFFER
+
+ if (pending.flags & State::Offset) {
+ current.offset = pending.offset;
+ }
+ pending = State();
+}
+
+void ShadowInterface::Private::attach(ShadowInterface::Private::State::Flags flag, wl_resource *buffer)
+{
+ BufferInterface *b = BufferInterface::get(buffer);
+ if (b) {
+ QObject::connect(b, &BufferInterface::aboutToBeDestroyed, q,
+ [this](BufferInterface *buffer) {
+ #define PENDING( __PART__ ) \
+ if (pending.__PART__ == buffer) { \
+ pending.__PART__ = nullptr; \
+ }
+ PENDING(left)
+ PENDING(topLeft)
+ PENDING(top)
+ PENDING(topRight)
+ PENDING(right)
+ PENDING(bottomRight)
+ PENDING(bottom)
+ PENDING(bottomLeft)
+ #undef PENDING
+
+ #define CURRENT( __PART__ ) \
+ if (current.__PART__ == buffer) { \
+ current.__PART__->unref(); \
+ current.__PART__ = nullptr; \
+ }
+ CURRENT(left)
+ CURRENT(topLeft)
+ CURRENT(top)
+ CURRENT(topRight)
+ CURRENT(right)
+ CURRENT(bottomRight)
+ CURRENT(bottom)
+ CURRENT(bottomLeft)
+ #undef CURRENT
+ }
+ );
+ }
+ switch (flag) {
+ case State::LeftBuffer:
+ pending.left = b;
+ break;
+ case State::TopLeftBuffer:
+ pending.topLeft = b;
+ break;
+ case State::TopBuffer:
+ pending.top = b;
+ break;
+ case State::TopRightBuffer:
+ pending.topRight = b;
+ break;
+ case State::RightBuffer:
+ pending.right = b;
+ break;
+ case State::BottomRightBuffer:
+ pending.bottomRight = b;
+ break;
+ case State::BottomBuffer:
+ pending.bottom = b;
+ break;
+ case State::BottomLeftBuffer:
+ pending.bottomLeft = b;
+ break;
+ default:
+ Q_UNREACHABLE();
+ break;
+ }
+ pending.flags = State::Flags(pending.flags | flag);
+}
+
+#define ATTACH( __PART__ ) \
+void ShadowInterface::Private::attach##__PART__##Callback(wl_client *client, wl_resource *resource, wl_resource *buffer) \
+{ \
+ Q_UNUSED(client) \
+ Private *p = cast(resource); \
+ p->attach(State::__PART__##Buffer, buffer); \
+}
+
+ATTACH(Left)
+ATTACH(TopLeft)
+ATTACH(Top)
+ATTACH(TopRight)
+ATTACH(Right)
+ATTACH(BottomRight)
+ATTACH(Bottom)
+ATTACH(BottomLeft)
+
+#undef ATTACH
+
+#define OFFSET( __PART__ ) \
+void ShadowInterface::Private::offset##__PART__##Callback(wl_client *client, wl_resource *resource, wl_fixed_t offset) \
+{ \
+ Q_UNUSED(client) \
+ Q_UNUSED(resource) \
+ Private *p = cast(resource); \
+ p->pending.flags = State::Flags(p->pending.flags | State::Offset); \
+ p->pending.offset.set##__PART__(wl_fixed_to_double(offset)); \
+}
+
+OFFSET(Left)
+OFFSET(Top)
+OFFSET(Right)
+OFFSET(Bottom)
+
+#undef OFFSET
+
+ShadowInterface::Private::Private(ShadowInterface *q, ShadowManagerInterface *c, wl_resource *parentResource)
+ : Resource::Private(q, c, parentResource, &org_kde_kwin_shadow_interface, &s_interface)
+{
+}
+
+ShadowInterface::Private::~Private()
+{
+#define CURRENT( __PART__ ) \
+ if (current.__PART__) { \
+ current.__PART__->unref(); \
+ }
+ CURRENT(left)
+ CURRENT(topLeft)
+ CURRENT(top)
+ CURRENT(topRight)
+ CURRENT(right)
+ CURRENT(bottomRight)
+ CURRENT(bottom)
+ CURRENT(bottomLeft)
+#undef CURRENT
+ if (resource) {
+ wl_resource_destroy(resource);
+ resource = nullptr;
+ }
+}
+
+ShadowInterface::ShadowInterface(ShadowManagerInterface *parent, wl_resource *parentResource)
+ : Resource(new Private(this, parent, parentResource))
+{
+}
+
+ShadowInterface::~ShadowInterface() = default;
+
+QMarginsF ShadowInterface::offset() const
+{
+ Q_D();
+ return d->current.offset;
+}
+
+#define BUFFER( __PART__ ) \
+BufferInterface *ShadowInterface::__PART__() const \
+{ \
+ Q_D(); \
+ return d->current.__PART__; \
+}
+
+BUFFER(left)
+BUFFER(topLeft)
+BUFFER(top)
+BUFFER(topRight)
+BUFFER(right)
+BUFFER(bottomRight)
+BUFFER(bottom)
+BUFFER(bottomLeft)
+
+ShadowInterface::Private *ShadowInterface::d_func() const
+{
+ return reinterpret_cast(d.data());
+}
+
+}
+}
diff --git a/src/wayland/shadow_interface.h b/src/wayland/shadow_interface.h
new file mode 100644
index 0000000000..e8fd1efdaa
--- /dev/null
+++ b/src/wayland/shadow_interface.h
@@ -0,0 +1,79 @@
+/********************************************************************
+Copyright 2015 Martin Gräßlin
+
+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_SHADOW_INTERFACE_H
+#define KWAYLAND_SERVER_SHADOW_INTERFACE_H
+
+#include "global.h"
+#include "resource.h"
+
+#include
+#include
+
+#include
+
+namespace KWayland
+{
+namespace Server
+{
+
+class BufferInterface;
+class Display;
+
+class KWAYLANDSERVER_EXPORT ShadowManagerInterface : public Global
+{
+ Q_OBJECT
+public:
+ virtual ~ShadowManagerInterface();
+
+private:
+ explicit ShadowManagerInterface(Display *display, QObject *parent = nullptr);
+ friend class Display;
+ class Private;
+};
+
+class KWAYLANDSERVER_EXPORT ShadowInterface : public Resource
+{
+ Q_OBJECT
+public:
+ virtual ~ShadowInterface();
+
+ BufferInterface *left() const;
+ BufferInterface *topLeft() const;
+ BufferInterface *top() const;
+ BufferInterface *topRight() const;
+ BufferInterface *right() const;
+ BufferInterface *bottomRight() const;
+ BufferInterface *bottom() const;
+ BufferInterface *bottomLeft() const;
+
+ QMarginsF offset() const;
+
+private:
+ explicit ShadowInterface(ShadowManagerInterface *parent, wl_resource *parentResource);
+ friend class ShadowManagerInterface;
+
+ class Private;
+ Private *d_func() const;
+};
+
+}
+}
+
+#endif
diff --git a/src/wayland/surface_interface.cpp b/src/wayland/surface_interface.cpp
index f97728b439..be885bd362 100644
--- a/src/wayland/surface_interface.cpp
+++ b/src/wayland/surface_interface.cpp
@@ -124,6 +124,12 @@ bool SurfaceInterface::Private::lowerChild(QPointer subsurf
return true;
}
+void SurfaceInterface::Private::setShadow(const QPointer &shadow)
+{
+ pending.shadow = shadow;
+ pending.shadowIsSet = true;
+}
+
const struct wl_surface_interface SurfaceInterface::Private::s_interface = {
destroyCallback,
attachCallback,
@@ -179,6 +185,7 @@ void SurfaceInterface::Private::commit()
const bool inputRegionChanged = pending.inputIsSet;
const bool scaleFactorChanged = current.scale != pending.scale;
const bool transformFactorChanged = current.transform != pending.transform;
+ const bool shadowChanged = pending.shadowIsSet;
bool sizeChanged = false;
auto buffer = current.buffer;
if (bufferChanged) {
@@ -196,12 +203,17 @@ void SurfaceInterface::Private::commit()
}
buffer = pending.buffer;
}
+ auto shadow = current.shadow;
+ if (shadowChanged) {
+ shadow = pending.shadow;
+ }
QList callbacks = current.callbacks;
callbacks.append(pending.callbacks);
// copy values
current = pending;
current.buffer = buffer;
current.callbacks = callbacks;
+ current.shadow = shadow;
pending = State{};
pending.children = current.children;
pending.input = current.input;
@@ -240,6 +252,9 @@ void SurfaceInterface::Private::commit()
if (sizeChanged) {
emit q->sizeChanged();
}
+ if (shadowChanged) {
+ emit q->shadowChanged();
+ }
}
void SurfaceInterface::Private::damage(const QRect &rect)
@@ -459,6 +474,12 @@ QSize SurfaceInterface::size() const
return QSize();
}
+QPointer< ShadowInterface > SurfaceInterface::shadow() const
+{
+ Q_D();
+ return d->current.shadow;
+}
+
SurfaceInterface::Private *SurfaceInterface::d_func() const
{
return reinterpret_cast(d.data());
diff --git a/src/wayland/surface_interface.h b/src/wayland/surface_interface.h
index ae2c6cdb9d..4935ff675e 100644
--- a/src/wayland/surface_interface.h
+++ b/src/wayland/surface_interface.h
@@ -35,6 +35,8 @@ namespace Server
{
class BufferInterface;
class CompositorInterface;
+class ShadowManagerInterface;
+class ShadowInterface;
class SubSurfaceInterface;
class KWAYLANDSERVER_EXPORT SurfaceInterface : public Resource
@@ -74,6 +76,12 @@ public:
**/
QList> childSubSurfaces() const;
+ /**
+ * @returns The Shadow for this Surface.
+ * @since 5.4
+ **/
+ QPointer shadow() const;
+
static SurfaceInterface *get(wl_resource *native);
/**
* @returns The SurfaceInterface with given @p id for @p client, if it exists, otherwise @c nullptr.
@@ -95,10 +103,15 @@ Q_SIGNALS:
* @since 5.3
**/
void sizeChanged();
+ /**
+ * @since 5.4
+ **/
+ void shadowChanged();
private:
friend class CompositorInterface;
friend class SubSurfaceInterface;
+ friend class ShadowManagerInterface;
explicit SurfaceInterface(CompositorInterface *parent, wl_resource *parentResource);
class Private;
diff --git a/src/wayland/surface_interface_p.h b/src/wayland/surface_interface_p.h
index 02a2d7b4b9..062c7e7540 100644
--- a/src/wayland/surface_interface_p.h
+++ b/src/wayland/surface_interface_p.h
@@ -40,6 +40,7 @@ public:
bool inputIsSet = false;
bool opaqueIsSet = false;
bool bufferIsSet = false;
+ bool shadowIsSet = false;
bool inputIsInfinite = true;
qint32 scale = 1;
OutputInterface::Transform transform = OutputInterface::Transform::Normal;
@@ -48,6 +49,7 @@ public:
BufferInterface *buffer = nullptr;
// stacking order: bottom (first) -> top (last)
QList> children;
+ QPointer shadow;
};
Private(SurfaceInterface *q, CompositorInterface *c, wl_resource *parentResource);
~Private();
@@ -58,6 +60,7 @@ public:
void removeChild(QPointer subsurface);
bool raiseChild(QPointer subsurface, SurfaceInterface *sibling);
bool lowerChild(QPointer subsurface, SurfaceInterface *sibling);
+ void setShadow(const QPointer &shadow);
State current;
State pending;