diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -11,6 +11,7 @@ kwindoweffects.cpp kwindoweffects_dummy.cpp kwindowinfo.cpp + kwindowshadow.cpp kwindowsystem.cpp platforms/wayland/kwindowsystem.cpp pluginwrapper.cpp @@ -109,6 +110,7 @@ KUserTimestamp KWindowEffects KWindowInfo + KWindowShadow,KWindowShadowTile KWindowSystem REQUIRED_HEADERS KWindowSystem_HEADERS @@ -129,6 +131,7 @@ FILES kwindoweffects_p.h kwindowinfo_p.h + kwindowshadow_p.h kwindowsystem_p.h kwindowsystemplugininterface_p.h DESTINATION diff --git a/src/kwindowshadow.h b/src/kwindowshadow.h new file mode 100644 --- /dev/null +++ b/src/kwindowshadow.h @@ -0,0 +1,236 @@ +/* + Copyright (C) 2019 Vlad Zahorodnii + + 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) any later version. + + 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 KWINDOWSHADOW_H +#define KWINDOWSHADOW_H + +#include "kwindowsystem_export.h" + +#include +#include +#include +#include + +class KWindowShadowPrivate; +class KWindowShadowTilePrivate; + +/** + * The KWindowShadowTile class provides a platform-indendent shadow tile representation. + */ +class KWINDOWSYSTEM_EXPORT KWindowShadowTile +{ +public: + using Ptr = QSharedPointer; + + KWindowShadowTile(); + ~KWindowShadowTile(); + + /** + * Returns the image stored in the KWindowShadowTile. + */ + QImage image() const; + + /** + * Sets the image on the KWindowShadowTile. + * + * Notice that once the native platform resouces have been allocated for the tile, you are + * not allowed to change the image. In order to do so, you need to create a new tile. + */ + void setImage(const QImage &image); + + /** + * Returns @c true if the platform resources associated with the tile have been allocated. + */ + bool isCreated() const; + + /** + * Allocates the native platform resources associated with the KWindowShadowTile. + * + * Normally it should not be necessary to call this method as KWindowShadow will implicitly + * call create() on your behalf. + * + * Returns @c true if the creation succeeded, otherwise returns @c false. + */ + bool create(); + +private: + QScopedPointer d; + + friend class KWindowShadowTilePrivate; +}; + +/** + * The KWindowShadow class represents a drop-shadow that is drawn by the compositor. + * + * The KWindowShadow is composed of multiple tiles. The top left tile, the top right tile, the bottom + * left tile, and the bottom right tile are rendered as they are. The top tile and the bottom tile are + * stretched in x direction; the left tile and the right tile are stretched in y direction. Several + * KWindowShadow objects can share shadow tiles to reduce memory usage. You have to specify padding() + * along the shadow tiles. The padding values indicate how much the KWindowShadow sticks outside the + * decorated window. + * + * Once the KWindowShadow is created, you're not allowed to attach or detach any shadow tiles, change + * padding(), or change window(). In order to do so, you have to destroy() the shadow first, update + * relevant properties, and create() the shadow again. + */ +class KWINDOWSYSTEM_EXPORT KWindowShadow : public QObject +{ + Q_OBJECT + +public: + explicit KWindowShadow(QObject *parent = nullptr); + ~KWindowShadow(); + + /** + * Returns the left tile attached to the KWindowShadow. + */ + KWindowShadowTile::Ptr leftTile() const; + + /** + * Attaches the left @p tile to the KWindowShadow. + */ + void setLeftTile(KWindowShadowTile::Ptr tile); + + /** + * Returns the top-left tile attached to the KWindowShadow. + */ + KWindowShadowTile::Ptr topLeftTile() const; + + /** + * Attaches the top-left @p tile to the KWindowShadow. + */ + void setTopLeftTile(KWindowShadowTile::Ptr tile); + + /** + * Returns the top tile attached to the KWindowShadow. + */ + KWindowShadowTile::Ptr topTile() const; + + /** + * Attaches the top @p tile to the KWindowShadow. + */ + void setTopTile(KWindowShadowTile::Ptr tile); + + /** + * Returns the top-right tile attached to the KWindowShadow. + */ + KWindowShadowTile::Ptr topRightTile() const; + + /** + * Attaches the top-right @p tile to the KWindowShadow. + */ + void setTopRightTile(KWindowShadowTile::Ptr tile); + + /** + * Returns the right tile attached to the KWindowShadow. + */ + KWindowShadowTile::Ptr rightTile() const; + + /** + * Attaches the right @p tile to the KWindowShadow. + */ + void setRightTile(KWindowShadowTile::Ptr tile); + + /** + * Returns the bottom-right tile attached to the KWindowShadow. + */ + KWindowShadowTile::Ptr bottomRightTile() const; + + /** + * Attaches the bottom-right tile to the KWindowShadow. + */ + void setBottomRightTile(KWindowShadowTile::Ptr tile); + + /** + * Returns the bottom tile attached to the KWindowShadow. + */ + KWindowShadowTile::Ptr bottomTile() const; + + /** + * Attaches the bottom @p tile to the KWindowShadow. + */ + void setBottomTile(KWindowShadowTile::Ptr tile); + + /** + * Returns the bottom-left tile attached to the KWindowShadow. + */ + KWindowShadowTile::Ptr bottomLeftTile() const; + + /** + * Attaches the bottom-left @p tile to the KWindowShadow. + */ + void setBottomLeftTile(KWindowShadowTile::Ptr tile); + + /** + * Returns the padding of the KWindowShadow. + * + * The padding values specify the visible extents of the shadow. The top left tile is rendered + * with an offset of -padding().left() and -padding().top(). + */ + QMargins padding() const; + + /** + * Sets the padding on the KWindowShadow. + * + * If the padding values are smaller than the sizes of the shadow tiles, then the shadow will + * overlap with the window() and will be rendered behind window(). E.g. if all padding values + * are set to 0, then the shadow will be completely occluded by the window(). + */ + void setPadding(const QMargins &padding); + + /** + * Returns the window behind which the KWindowShadow will be rendered. + */ + QWindow *window() const; + + /** + * Sets the window behind which the KWindowShadow will be rendered. + * + * Note that the KWindowShadow does not track the platform surface. If for whatever reason the + * native platform surface is deleted and then created, you must to destroy() the shadow and + * create() it again yourself. + */ + void setWindow(QWindow *window); + + /** + * Returns @c true if the platform resources associated with the shadow have been allocated. + */ + bool isCreated() const; + + /** + * Allocates the platform resources associated with the KWindowShadow. + * + * Once the native platform resouces have been allocated, you're not allowed to attach or + * detach shadow tiles, change the padding or the target window. If you want to do so, you + * must destroy() the shadow, change relevant attributes and call create() again. + * + * Returns @c true if the creation succeeded, otherwise returns @c false. + */ + bool create(); + + /** + * Releases the platform resources associated with the KWindowShadow. + * + * Calling destroy() after window() had been destroyed will result in a no-op. + */ + void destroy(); + +private: + QScopedPointer d; +}; + +#endif // KWINDOWSHADOW_H diff --git a/src/kwindowshadow.cpp b/src/kwindowshadow.cpp new file mode 100644 --- /dev/null +++ b/src/kwindowshadow.cpp @@ -0,0 +1,333 @@ +/* + Copyright (C) 2019 Vlad Zahorodnii + + 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) any later version. + + 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 "kwindowshadow.h" +#include "kwindowshadow_dummy_p.h" +#include "kwindowshadow_p.h" +#include "kwindowsystem_debug.h" +#include "pluginwrapper_p.h" + +KWindowShadowTile::KWindowShadowTile() + : d(KWindowSystemPluginWrapper::self().createWindowShadowTile()) +{ +} + +KWindowShadowTile::~KWindowShadowTile() +{ + if (d->isCreated) { + d->destroy(); + } +} + +QImage KWindowShadowTile::image() const +{ + return d->image; +} + +void KWindowShadowTile::setImage(const QImage &image) +{ + if (d->isCreated) { + qCWarning(LOG_KWINDOWSYSTEM, "Cannot change the image on a tile that already has native " + "platform resources allocated."); + return; + } + d->image = image; +} + +bool KWindowShadowTile::isCreated() const +{ + return d->isCreated; +} + +bool KWindowShadowTile::create() +{ + if (d->isCreated) { + return true; + } + d->isCreated = d->create(); + return d->isCreated; +} + +KWindowShadow::KWindowShadow(QObject *parent) + : QObject(parent) + , d(KWindowSystemPluginWrapper::self().createWindowShadow()) +{ +} + +KWindowShadow::~KWindowShadow() +{ + destroy(); +} + +KWindowShadowTile::Ptr KWindowShadow::leftTile() const +{ + return d->leftTile; +} + +void KWindowShadow::setLeftTile(KWindowShadowTile::Ptr tile) +{ + if (d->isCreated) { + qCWarning(LOG_KWINDOWSYSTEM, "Cannot attach a left tile to a shadow that already has " + "native platform resources allocated. To do so, destroy() the shadow and then " + "setLeftTile() and create()"); + return; + } + d->leftTile = tile; +} + +KWindowShadowTile::Ptr KWindowShadow::topLeftTile() const +{ + return d->topLeftTile; +} + +void KWindowShadow::setTopLeftTile(KWindowShadowTile::Ptr tile) +{ + if (d->isCreated) { + qCWarning(LOG_KWINDOWSYSTEM, "Cannot attach a top-left tile to a shadow that already has " + "native platform resources allocated. To do so, destroy() the shadow and then " + "setTopLeftTile() and create()"); + return; + } + d->topLeftTile = tile; +} + +KWindowShadowTile::Ptr KWindowShadow::topTile() const +{ + return d->topTile; +} + +void KWindowShadow::setTopTile(KWindowShadowTile::Ptr tile) +{ + if (d->isCreated) { + qCWarning(LOG_KWINDOWSYSTEM, "Cannot attach a top tile to a shadow that already has " + "native platform resources allocated. To do so, destroy() the shadow and then " + "setTopTile() and create()"); + return; + } + d->topTile = tile; +} + +KWindowShadowTile::Ptr KWindowShadow::topRightTile() const +{ + return d->topRightTile; +} + +void KWindowShadow::setTopRightTile(KWindowShadowTile::Ptr tile) +{ + if (d->isCreated) { + qCWarning(LOG_KWINDOWSYSTEM, "Cannot attach a top-right tile to a shadow that already " + "has native platform resources allocated. To do so, destroy() the shadow and " + "then setTopRightTile() and create()"); + return; + } + d->topRightTile = tile; +} + +KWindowShadowTile::Ptr KWindowShadow::rightTile() const +{ + return d->rightTile; +} + +void KWindowShadow::setRightTile(KWindowShadowTile::Ptr tile) +{ + if (d->isCreated) { + qCWarning(LOG_KWINDOWSYSTEM, "Cannot attach a right tile to a shadow that already has " + "native platform resources allocated. To do so, destroy() the shadow and then " + "setRightTile() and create()"); + return; + } + d->rightTile = tile; +} + +KWindowShadowTile::Ptr KWindowShadow::bottomRightTile() const +{ + return d->bottomRightTile; +} + +void KWindowShadow::setBottomRightTile(KWindowShadowTile::Ptr tile) +{ + if (d->isCreated) { + qCWarning(LOG_KWINDOWSYSTEM, "Cannot attach a bottom-right tile to a shadow that already " + "has native platform resources allocated. To do so, destroy() the shadow and " + "then setBottomRightTile() and create()"); + return; + } + d->bottomRightTile = tile; +} + +KWindowShadowTile::Ptr KWindowShadow::bottomTile() const +{ + return d->bottomTile; +} + +void KWindowShadow::setBottomTile(KWindowShadowTile::Ptr tile) +{ + if (d->isCreated) { + qCWarning(LOG_KWINDOWSYSTEM, "Cannot attach a bottom tile to a shadow that already has " + "native platform resources allocated. To do so, destroy() the shadow and then " + "setBottomTile() and create()"); + return; + } + d->bottomTile = tile; +} + +KWindowShadowTile::Ptr KWindowShadow::bottomLeftTile() const +{ + return d->bottomLeftTile; +} + +void KWindowShadow::setBottomLeftTile(KWindowShadowTile::Ptr tile) +{ + if (d->isCreated) { + qCWarning(LOG_KWINDOWSYSTEM, "Cannot attach a bottom-left tile to a shadow that already " + "has native platform resources allocated. To do so, destroy() the shadow and " + "then setBottomLeftTile() and create()"); + return; + } + d->bottomLeftTile = tile; +} + +QMargins KWindowShadow::padding() const +{ + return d->padding; +} + +void KWindowShadow::setPadding(const QMargins &padding) +{ + if (d->isCreated) { + qCWarning(LOG_KWINDOWSYSTEM, "Cannot set the padding on a shadow that already has " + "native platform resources allocated. To do so, destroy() the shadow and " + "then setPadding() and create()"); + return; + } + d->padding = padding; +} + +QWindow *KWindowShadow::window() const +{ + return d->window; +} + +void KWindowShadow::setWindow(QWindow *window) +{ + if (d->isCreated) { + qCWarning(LOG_KWINDOWSYSTEM, "Cannot set the target window on a shadow that already has " + "native platform resources allocated. To do so, destroy() the shadow and then " + "setWindow() and create()"); + return; + } + d->window = window; +} + +bool KWindowShadow::isCreated() const +{ + return d->isCreated; +} + +bool KWindowShadow::create() +{ + if (d->isCreated) { + return true; + } + if (!d->window) { + qCWarning(LOG_KWINDOWSYSTEM, "Cannot allocate the native platform resources for the shadow " + "because the target window is not specified."); + return false; + } + if (!d->prepareTiles()) { + return false; + } + d->isCreated = d->create(); + return d->isCreated; +} + +void KWindowShadow::destroy() +{ + if (!d->isCreated) { + return; + } + d->destroy(); + d->isCreated = false; +} + +KWindowShadowTilePrivate::~KWindowShadowTilePrivate() +{ +} + +KWindowShadowTilePrivate *KWindowShadowTilePrivate::get(const KWindowShadowTile *tile) +{ + return tile->d.data(); +} + +KWindowShadowPrivate::~KWindowShadowPrivate() +{ +} + +bool KWindowShadowPrivate::create() +{ + return false; +} + +void KWindowShadowPrivate::destroy() +{ +} + +bool KWindowShadowPrivate::prepareTiles() +{ + const std::array tiles { + leftTile.data(), + topLeftTile.data(), + topTile.data(), + topRightTile.data(), + rightTile.data(), + bottomRightTile.data(), + bottomTile.data(), + bottomLeftTile.data(), + }; + + for (KWindowShadowTile *tile : tiles) { + if (!tile) { + continue; + } + if (tile->isCreated()) { + continue; + } + if (!tile->create()) { + return false; + } + } + + return true; +} + +bool KWindowShadowTilePrivateDummy::create() +{ + return false; +} + +void KWindowShadowTilePrivateDummy::destroy() +{ +} + +bool KWindowShadowPrivateDummy::create() +{ + return false; +} + +void KWindowShadowPrivateDummy::destroy() +{ +} diff --git a/src/kwindowshadow_dummy_p.h b/src/kwindowshadow_dummy_p.h new file mode 100644 --- /dev/null +++ b/src/kwindowshadow_dummy_p.h @@ -0,0 +1,37 @@ +/* + Copyright (C) 2019 Vlad Zahorodnii + + 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) any later version. + + 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 KWINDOWSHADOW_DUMMY_P_H +#define KWINDOWSHADOW_DUMMY_P_H + +#include "kwindowshadow_p.h" + +class KWindowShadowTilePrivateDummy final : public KWindowShadowTilePrivate +{ +public: + bool create() override; + void destroy() override; +}; + +class KWindowShadowPrivateDummy final : public KWindowShadowPrivate +{ +public: + bool create() override; + void destroy() override; +}; + +#endif // KWINDOWSHADOW_DUMMY_P_H diff --git a/src/kwindowshadow_p.h b/src/kwindowshadow_p.h new file mode 100644 --- /dev/null +++ b/src/kwindowshadow_p.h @@ -0,0 +1,73 @@ +/* + Copyright (C) 2019 Vlad Zahorodnii + + 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) any later version. + + 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 KWINDOWSHADOW_P_H +#define KWINDOWSHADOW_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the KF API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "kwindowshadow.h" + +#include + +class KWINDOWSYSTEM_EXPORT KWindowShadowTilePrivate +{ +public: + virtual ~KWindowShadowTilePrivate(); + + virtual bool create() = 0; + virtual void destroy() = 0; + + static KWindowShadowTilePrivate *get(const KWindowShadowTile *tile); + + QImage image; + bool isCreated = false; +}; + +class KWINDOWSYSTEM_EXPORT KWindowShadowPrivate +{ +public: + virtual ~KWindowShadowPrivate(); + + virtual bool create() = 0; + virtual void destroy() = 0; + + bool prepareTiles(); + + QPointer window; + KWindowShadowTile::Ptr leftTile; + KWindowShadowTile::Ptr topLeftTile; + KWindowShadowTile::Ptr topTile; + KWindowShadowTile::Ptr topRightTile; + KWindowShadowTile::Ptr rightTile; + KWindowShadowTile::Ptr bottomRightTile; + KWindowShadowTile::Ptr bottomTile; + KWindowShadowTile::Ptr bottomLeftTile; + QMargins padding; + bool isCreated = false; +}; + +#endif // KWINDOWSHADOW_P_H diff --git a/src/kwindowsystemplugininterface.cpp b/src/kwindowsystemplugininterface.cpp --- a/src/kwindowsystemplugininterface.cpp +++ b/src/kwindowsystemplugininterface.cpp @@ -45,3 +45,13 @@ Q_UNUSED(properties2) return nullptr; } + +KWindowShadowPrivate *KWindowSystemPluginInterface::createWindowShadow() +{ + return nullptr; +} + +KWindowShadowTilePrivate *KWindowSystemPluginInterface::createWindowShadowTile() +{ + return nullptr; +} diff --git a/src/kwindowsystemplugininterface_p.h b/src/kwindowsystemplugininterface_p.h --- a/src/kwindowsystemplugininterface_p.h +++ b/src/kwindowsystemplugininterface_p.h @@ -27,6 +27,8 @@ class KWindowEffectsPrivate; class KWindowInfoPrivate; +class KWindowShadowPrivate; +class KWindowShadowTilePrivate; class KWindowSystemPrivate; class KWINDOWSYSTEM_EXPORT KWindowSystemPluginInterface : public QObject @@ -39,6 +41,8 @@ virtual KWindowEffectsPrivate *createEffects(); virtual KWindowSystemPrivate *createWindowSystem(); virtual KWindowInfoPrivate *createWindowInfo(WId window, NET::Properties properties, NET::Properties2 properties2); + virtual KWindowShadowPrivate *createWindowShadow(); + virtual KWindowShadowTilePrivate *createWindowShadowTile(); }; Q_DECLARE_INTERFACE(KWindowSystemPluginInterface, "org.kde.kwindowsystem.KWindowSystemPluginInterface") diff --git a/src/platforms/xcb/CMakeLists.txt b/src/platforms/xcb/CMakeLists.txt --- a/src/platforms/xcb/CMakeLists.txt +++ b/src/platforms/xcb/CMakeLists.txt @@ -1,6 +1,7 @@ set(xcb_plugin_SRCS kwindoweffects.cpp kwindowinfo.cpp + kwindowshadow.cpp kwindowsystem.cpp kxerrorhandler.cpp kxutils.cpp diff --git a/src/platforms/xcb/kwindowshadow.cpp b/src/platforms/xcb/kwindowshadow.cpp new file mode 100644 --- /dev/null +++ b/src/platforms/xcb/kwindowshadow.cpp @@ -0,0 +1,200 @@ +/* + Copyright (C) 2019 Vlad Zahorodnii + + 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) any later version. + + 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 "kwindowshadow_p_x11.h" + +#include + +static const QByteArray s_atomName = QByteArrayLiteral("_KDE_NET_WM_SHADOW"); + +bool KWindowShadowTilePrivateX11::create() +{ + xcb_connection_t *connection = QX11Info::connection(); + xcb_window_t rootWindow = QX11Info::appRootWindow(); + + const uint16_t width = uint16_t(image.width()); + const uint16_t height = uint16_t(image.height()); + const uint8_t depth = uint8_t(image.depth()); + + pixmap = xcb_generate_id(connection); + gc = xcb_generate_id(connection); + + xcb_create_pixmap(connection, depth, pixmap, rootWindow, width, height); + xcb_create_gc(connection, gc, pixmap, 0, nullptr); + + xcb_put_image(connection, XCB_IMAGE_FORMAT_Z_PIXMAP, pixmap, gc, width, height, + 0, 0, 0, depth, image.sizeInBytes(), image.constBits()); + + return true; +} + +void KWindowShadowTilePrivateX11::destroy() +{ + xcb_connection_t *connection = QX11Info::connection(); + + xcb_free_pixmap(connection, pixmap); + xcb_free_gc(connection, gc); + + pixmap = XCB_PIXMAP_NONE; + gc = XCB_NONE; +} + +KWindowShadowTilePrivateX11 *KWindowShadowTilePrivateX11::get(const KWindowShadowTile *tile) +{ + KWindowShadowTilePrivate *d = KWindowShadowTilePrivate::get(tile); + return static_cast(d); +} + +static xcb_atom_t lookupAtom(const QByteArray &atomName) +{ + xcb_connection_t *connection = QX11Info::connection(); + if (!connection) { + return XCB_ATOM_NONE; + } + + xcb_intern_atom_cookie_t atomCookie = xcb_intern_atom_unchecked(connection, false, + atomName.size(), + atomName.constData()); + xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(connection, atomCookie, nullptr); + + if (!reply) { + return XCB_ATOM_NONE; + } + + xcb_atom_t atom = reply->atom; + free(reply); + + return atom; +} + +static xcb_pixmap_t nativeHandleForTile(const KWindowShadowTile::Ptr &tile) +{ + const auto d = KWindowShadowTilePrivateX11::get(tile.data()); + return d->pixmap; +} + +bool KWindowShadowPrivateX11::create() +{ + xcb_connection_t *connection = QX11Info::connection(); + + const xcb_atom_t atom = lookupAtom(s_atomName); + if (atom == XCB_ATOM_NONE) { + return false; + } + + QVector data(12); + int i = 0; + + // Unfortunately we cannot use handle of XCB_PIXMAP_NONE for missing shadow tiles because + // KWin expects **all** shadow tile handles to be valid. Maybe we could address this small + // inconvenience and then remove the empty tile stuff. + + if (topTile) { + data[i++] = nativeHandleForTile(topTile); + } else { + data[i++] = nativeHandleForTile(getOrCreateEmptyTile()); + } + + if (topRightTile) { + data[i++] = nativeHandleForTile(topRightTile); + } else { + data[i++] = nativeHandleForTile(getOrCreateEmptyTile()); + } + + if (rightTile) { + data[i++] = nativeHandleForTile(rightTile); + } else { + data[i++] = nativeHandleForTile(getOrCreateEmptyTile()); + } + + if (bottomRightTile) { + data[i++] = nativeHandleForTile(bottomRightTile); + } else { + data[i++] = nativeHandleForTile(getOrCreateEmptyTile()); + } + + if (bottomTile) { + data[i++] = nativeHandleForTile(bottomTile); + } else { + data[i++] = nativeHandleForTile(getOrCreateEmptyTile()); + } + + if (bottomLeftTile) { + data[i++] = nativeHandleForTile(bottomLeftTile); + } else { + data[i++] = nativeHandleForTile(getOrCreateEmptyTile()); + } + + if (leftTile) { + data[i++] = nativeHandleForTile(leftTile); + } else { + data[i++] = nativeHandleForTile(getOrCreateEmptyTile()); + } + + if (topLeftTile) { + data[i++] = nativeHandleForTile(topLeftTile); + } else { + data[i++] = nativeHandleForTile(getOrCreateEmptyTile()); + } + + data[i++] = uint32_t(padding.top()); + data[i++] = uint32_t(padding.right()); + data[i++] = uint32_t(padding.bottom()); + data[i++] = uint32_t(padding.left()); + + xcb_change_property(connection, XCB_PROP_MODE_REPLACE, window->winId(), atom, + XCB_ATOM_CARDINAL, 32, data.size(), data.constData()); + xcb_flush(connection); + + return true; +} + +void KWindowShadowPrivateX11::destroy() +{ + emptyTile = nullptr; + + // For some reason, QWindow changes visibility of QSurface::surfaceHandle(). + const QSurface *surface = window; + + // Attempting to uninstall the shadow after the platform window had been destroyed. + if (!(surface && surface->surfaceHandle())) { + return; + } + + xcb_connection_t *connection = QX11Info::connection(); + + const xcb_atom_t atom = lookupAtom(s_atomName); + if (atom == XCB_ATOM_NONE) { + return; + } + + xcb_delete_property(connection, window->winId(), atom); +} + +KWindowShadowTile::Ptr KWindowShadowPrivateX11::getOrCreateEmptyTile() +{ + if (!emptyTile) { + QImage image(QSize(1, 1), QImage::Format_ARGB32); + image.fill(Qt::transparent); + + emptyTile = KWindowShadowTile::Ptr::create(); + emptyTile->setImage(image); + emptyTile->create(); + } + + return emptyTile; +} diff --git a/src/platforms/xcb/kwindowshadow_p_x11.h b/src/platforms/xcb/kwindowshadow_p_x11.h new file mode 100644 --- /dev/null +++ b/src/platforms/xcb/kwindowshadow_p_x11.h @@ -0,0 +1,48 @@ +/* + Copyright (C) 2019 Vlad Zahorodnii + + 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) any later version. + + 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 KWINDOWSHADOW_P_X11_H +#define KWINDOWSHADOW_P_X11_H + +#include "kwindowshadow_p.h" + +#include + +class KWindowShadowTilePrivateX11 final : public KWindowShadowTilePrivate +{ +public: + bool create() override; + void destroy() override; + + static KWindowShadowTilePrivateX11 *get(const KWindowShadowTile *tile); + + xcb_pixmap_t pixmap = XCB_PIXMAP_NONE; + xcb_gcontext_t gc = XCB_NONE; +}; + +class KWindowShadowPrivateX11 final : public KWindowShadowPrivate +{ +public: + bool create() override; + void destroy() override; + + KWindowShadowTile::Ptr getOrCreateEmptyTile(); + + KWindowShadowTile::Ptr emptyTile; +}; + +#endif // KWINDOWSHADOW_P_X11_H diff --git a/src/platforms/xcb/plugin.h b/src/platforms/xcb/plugin.h --- a/src/platforms/xcb/plugin.h +++ b/src/platforms/xcb/plugin.h @@ -35,6 +35,8 @@ KWindowEffectsPrivate *createEffects() override; KWindowSystemPrivate *createWindowSystem() override; KWindowInfoPrivate *createWindowInfo(WId window, NET::Properties properties, NET::Properties2 properties2) override; + KWindowShadowPrivate *createWindowShadow() override final; + KWindowShadowTilePrivate *createWindowShadowTile() override final; }; #endif diff --git a/src/platforms/xcb/plugin.cpp b/src/platforms/xcb/plugin.cpp --- a/src/platforms/xcb/plugin.cpp +++ b/src/platforms/xcb/plugin.cpp @@ -20,6 +20,7 @@ #include "plugin.h" #include "kwindoweffects_x11.h" #include "kwindowinfo_p_x11.h" +#include "kwindowshadow_p_x11.h" #include "kwindowsystem_p_x11.h" X11Plugin::X11Plugin(QObject *parent) @@ -45,3 +46,13 @@ { return new KWindowInfoPrivateX11(window, properties, properties2); } + +KWindowShadowPrivate *X11Plugin::createWindowShadow() +{ + return new KWindowShadowPrivateX11(); +} + +KWindowShadowTilePrivate *X11Plugin::createWindowShadowTile() +{ + return new KWindowShadowTilePrivateX11(); +} diff --git a/src/pluginwrapper.cpp b/src/pluginwrapper.cpp --- a/src/pluginwrapper.cpp +++ b/src/pluginwrapper.cpp @@ -21,6 +21,7 @@ #include "kwindowinfo_dummy_p.h" #include "kwindowsystemplugininterface_p.h" #include "kwindoweffects_dummy_p.h" +#include "kwindowshadow_dummy_p.h" #include "kwindowsystem_dummy_p.h" #include "kwindowsystem_debug.h" @@ -128,6 +129,30 @@ return p; } +KWindowShadowPrivate *KWindowSystemPluginWrapper::createWindowShadow() const +{ + KWindowShadowPrivate *p = nullptr; + if (!m_plugin.isNull()) { + p = m_plugin->createWindowShadow(); + } + if (!p) { + p = new KWindowShadowPrivateDummy(); + } + return p; +} + +KWindowShadowTilePrivate *KWindowSystemPluginWrapper::createWindowShadowTile() const +{ + KWindowShadowTilePrivate *p = nullptr; + if (!m_plugin.isNull()) { + p = m_plugin->createWindowShadowTile(); + } + if (!p) { + p = new KWindowShadowTilePrivateDummy(); + } + return p; +} + const KWindowSystemPluginWrapper &KWindowSystemPluginWrapper::self() { return *s_pluginWrapper; diff --git a/src/pluginwrapper_p.h b/src/pluginwrapper_p.h --- a/src/pluginwrapper_p.h +++ b/src/pluginwrapper_p.h @@ -27,6 +27,8 @@ class KWindowEffectsPrivate; class KWindowInfoPrivate; +class KWindowShadowPrivate; +class KWindowShadowTilePrivate; class KWindowSystemPluginInterface; class KWindowSystemPrivate; @@ -40,6 +42,8 @@ KWindowEffectsPrivate *effects() const; KWindowSystemPrivate *createWindowSystem() const; KWindowInfoPrivate *createWindowInfo(WId window, NET::Properties properties, NET::Properties2 properties2) const; + KWindowShadowPrivate *createWindowShadow() const; + KWindowShadowTilePrivate *createWindowShadowTile() const; private: QScopedPointer m_plugin;