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;