diff --git a/internal_client.cpp b/internal_client.cpp --- a/internal_client.cpp +++ b/internal_client.cpp @@ -31,6 +31,7 @@ Q_DECLARE_METATYPE(NET::WindowType) static const QByteArray s_skipClosePropertyName = QByteArrayLiteral("KWIN_SKIP_CLOSE_ANIMATION"); +static const QByteArray s_shadowEnabledPropertyName = QByteArrayLiteral("kwin_shadow_enabled"); namespace KWin { @@ -62,6 +63,7 @@ setOpacity(m_internalWindow->opacity()); setSkipCloseAnimation(m_internalWindow->property(s_skipClosePropertyName).toBool()); + // Create scene window, effect window, and update server-side shadow. setupCompositing(); updateColorScheme(); @@ -86,6 +88,9 @@ if (pe->propertyName() == s_skipClosePropertyName) { setSkipCloseAnimation(m_internalWindow->property(s_skipClosePropertyName).toBool()); } + if (pe->propertyName() == s_shadowEnabledPropertyName) { + updateShadow(); + } if (pe->propertyName() == "kwin_windowType") { m_windowType = m_internalWindow->property("kwin_windowType").value(); workspace()->updateClientArea(); diff --git a/plugins/windowsystem/CMakeLists.txt b/plugins/windowsystem/CMakeLists.txt --- a/plugins/windowsystem/CMakeLists.txt +++ b/plugins/windowsystem/CMakeLists.txt @@ -1,6 +1,7 @@ set(kwindowsystem_plugin_SRCS plugin.cpp windoweffects.cpp + windowshadow.cpp windowsystem.cpp ) diff --git a/plugins/windowsystem/plugin.h b/plugins/windowsystem/plugin.h --- a/plugins/windowsystem/plugin.h +++ b/plugins/windowsystem/plugin.h @@ -33,4 +33,6 @@ KWindowEffectsPrivate *createEffects() override; KWindowSystemPrivate *createWindowSystem() override; + KWindowShadowTilePrivate *createWindowShadowTile() override; + KWindowShadowPrivate *createWindowShadow() override; }; diff --git a/plugins/windowsystem/plugin.cpp b/plugins/windowsystem/plugin.cpp --- a/plugins/windowsystem/plugin.cpp +++ b/plugins/windowsystem/plugin.cpp @@ -18,8 +18,9 @@ * along with this program. If not, see . */ #include "plugin.h" -#include "windowsystem.h" #include "windoweffects.h" +#include "windowshadow.h" +#include "windowsystem.h" KWindowSystemKWinPlugin::KWindowSystemKWinPlugin(QObject *parent) : KWindowSystemPluginInterface(parent) @@ -39,3 +40,13 @@ { return new KWin::WindowSystem(); } + +KWindowShadowTilePrivate *KWindowSystemKWinPlugin::createWindowShadowTile() +{ + return new KWin::WindowShadowTile(); +} + +KWindowShadowPrivate *KWindowSystemKWinPlugin::createWindowShadow() +{ + return new KWin::WindowShadow(); +} diff --git a/plugins/windowsystem/plugin.cpp b/plugins/windowsystem/windowshadow.h copy from plugins/windowsystem/plugin.cpp copy to plugins/windowsystem/windowshadow.h --- a/plugins/windowsystem/plugin.cpp +++ b/plugins/windowsystem/windowshadow.h @@ -1,5 +1,5 @@ /* - * Copyright 2019 Martin Flöser + * Copyright 2020 Vlad Zahorodnii * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -17,25 +17,26 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -#include "plugin.h" -#include "windowsystem.h" -#include "windoweffects.h" -KWindowSystemKWinPlugin::KWindowSystemKWinPlugin(QObject *parent) - : KWindowSystemPluginInterface(parent) -{ -} +#pragma once + +#include -KWindowSystemKWinPlugin::~KWindowSystemKWinPlugin() +namespace KWin { -} -KWindowEffectsPrivate *KWindowSystemKWinPlugin::createEffects() +class WindowShadowTile final : public KWindowShadowTilePrivate { - return new KWin::WindowEffects(); -} +public: + bool create() override; + void destroy() override; +}; -KWindowSystemPrivate *KWindowSystemKWinPlugin::createWindowSystem() +class WindowShadow final : public KWindowShadowPrivate { - return new KWin::WindowSystem(); -} +public: + bool create() override; + void destroy() override; +}; + +} // namespace KWin diff --git a/plugins/windowsystem/windowshadow.cpp b/plugins/windowsystem/windowshadow.cpp new file mode 100644 --- /dev/null +++ b/plugins/windowsystem/windowshadow.cpp @@ -0,0 +1,95 @@ +/* + * Copyright 2020 Vlad Zahorodnii + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 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 14 of version 3 of the license. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "windowshadow.h" + +#include + +Q_DECLARE_METATYPE(QMargins) + +namespace KWin +{ + +bool WindowShadowTile::create() +{ + return true; +} + +void WindowShadowTile::destroy() +{ +} + +bool WindowShadow::create() +{ + // TODO: Perhaps we set way too many properties here. Alternatively we could put all shadow tiles + // in one big image and attach it rather than 8 separate images. + if (leftTile) { + window->setProperty("kwin_shadow_left_tile", QVariant::fromValue(leftTile->image())); + } + if (topLeftTile) { + window->setProperty("kwin_shadow_top_left_tile", QVariant::fromValue(topLeftTile->image())); + } + if (topTile) { + window->setProperty("kwin_shadow_top_tile", QVariant::fromValue(topTile->image())); + } + if (topRightTile) { + window->setProperty("kwin_shadow_top_right_tile", QVariant::fromValue(topRightTile->image())); + } + if (rightTile) { + window->setProperty("kwin_shadow_right_tile", QVariant::fromValue(rightTile->image())); + } + if (bottomRightTile) { + window->setProperty("kwin_shadow_bottom_right_tile", QVariant::fromValue(bottomRightTile->image())); + } + if (bottomTile) { + window->setProperty("kwin_shadow_bottom_tile", QVariant::fromValue(bottomTile->image())); + } + if (bottomLeftTile) { + window->setProperty("kwin_shadow_bottom_left_tile", QVariant::fromValue(bottomLeftTile->image())); + } + window->setProperty("kwin_shadow_padding", QVariant::fromValue(padding)); + + // Notice that the enabled property must be set last. + window->setProperty("kwin_shadow_enabled", QVariant::fromValue(true)); + + return true; +} + +void WindowShadow::destroy() +{ + // Attempting to uninstall the shadow after the decorated window has been destroyed. It's doomed. + if (!window) { + return; + } + + // Remove relevant shadow properties. + window->setProperty("kwin_shadow_left_tile", {}); + window->setProperty("kwin_shadow_top_left_tile", {}); + window->setProperty("kwin_shadow_top_tile", {}); + window->setProperty("kwin_shadow_top_right_tile", {}); + window->setProperty("kwin_shadow_right_tile", {}); + window->setProperty("kwin_shadow_bottom_right_tile", {}); + window->setProperty("kwin_shadow_bottom_tile", {}); + window->setProperty("kwin_shadow_bottom_left_tile", {}); + window->setProperty("kwin_shadow_padding", {}); + window->setProperty("kwin_shadow_enabled", {}); +} + +} // namespace KWin diff --git a/shadow.h b/shadow.h --- a/shadow.h +++ b/shadow.h @@ -3,6 +3,7 @@ This file is part of the KDE project. Copyright (C) 2011 Martin Gräßlin +Copyright (C) 2020 Vlad Zahorodnii This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -168,10 +169,12 @@ static Shadow *createShadowFromX11(Toplevel *toplevel); static Shadow *createShadowFromDecoration(Toplevel *toplevel); static Shadow *createShadowFromWayland(Toplevel *toplevel); + static Shadow *createShadowFromInternalWindow(Toplevel *toplevel); static QVector readX11ShadowProperty(xcb_window_t id); bool init(const QVector &data); bool init(KDecoration2::Decoration *decoration); bool init(const QPointer &shadow); + bool init(const QWindow *window); Toplevel *m_topLevel; // shadow pixmaps QPixmap m_shadowElements[ShadowElementsCount]; diff --git a/shadow.cpp b/shadow.cpp --- a/shadow.cpp +++ b/shadow.cpp @@ -3,6 +3,7 @@ This file is part of the KDE project. Copyright (C) 2011 Martin Gräßlin +Copyright (C) 2020 Vlad Zahorodnii This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -23,6 +24,7 @@ #include "abstract_client.h" #include "composite.h" #include "effects.h" +#include "internal_client.h" #include "toplevel.h" #include "wayland_server.h" @@ -33,6 +35,10 @@ #include #include +#include + +Q_DECLARE_METATYPE(QMargins) + namespace KWin { @@ -60,6 +66,9 @@ if (!shadow && kwinApp()->x11Connection()) { shadow = createShadowFromX11(toplevel); } + if (!shadow) { + shadow = createShadowFromInternalWindow(toplevel); + } if (!shadow) { return nullptr; } @@ -121,6 +130,24 @@ return shadow; } +Shadow *Shadow::createShadowFromInternalWindow(Toplevel *toplevel) +{ + const InternalClient *client = qobject_cast(toplevel); + if (!client) { + return nullptr; + } + const QWindow *window = client->internalWindow(); + if (!window) { + return nullptr; + } + Shadow *shadow = Compositor::self()->scene()->createShadow(toplevel); + if (!shadow->init(window)) { + delete shadow; + return nullptr; + } + return shadow; +} + QVector< uint32_t > Shadow::readX11ShadowProperty(xcb_window_t id) { QVector ret; @@ -240,6 +267,49 @@ return true; } +bool Shadow::init(const QWindow *window) +{ + const bool isEnabled = window->property("kwin_shadow_enabled").toBool(); + if (!isEnabled) { + return false; + } + + const QImage leftTile = window->property("kwin_shadow_left_tile").value(); + const QImage topLeftTile = window->property("kwin_shadow_top_left_tile").value(); + const QImage topTile = window->property("kwin_shadow_top_tile").value(); + const QImage topRightTile = window->property("kwin_shadow_top_right_tile").value(); + const QImage rightTile = window->property("kwin_shadow_right_tile").value(); + const QImage bottomRightTile = window->property("kwin_shadow_bottom_right_tile").value(); + const QImage bottomTile = window->property("kwin_shadow_bottom_tile").value(); + const QImage bottomLeftTile = window->property("kwin_shadow_bottom_left_tile").value(); + + m_shadowElements[ShadowElementLeft] = QPixmap::fromImage(leftTile); + m_shadowElements[ShadowElementTopLeft] = QPixmap::fromImage(topLeftTile); + m_shadowElements[ShadowElementTop] = QPixmap::fromImage(topTile); + m_shadowElements[ShadowElementTopRight] = QPixmap::fromImage(topRightTile); + m_shadowElements[ShadowElementRight] = QPixmap::fromImage(rightTile); + m_shadowElements[ShadowElementBottomRight] = QPixmap::fromImage(bottomRightTile); + m_shadowElements[ShadowElementBottom] = QPixmap::fromImage(bottomTile); + m_shadowElements[ShadowElementBottomLeft] = QPixmap::fromImage(bottomLeftTile); + + const QMargins padding = window->property("kwin_shadow_padding").value(); + + m_leftOffset = padding.left(); + m_topOffset = padding.top(); + m_rightOffset = padding.right(); + m_bottomOffset = padding.bottom(); + + updateShadowRegion(); + + if (!prepareBackend()) { + return false; + } + + buildQuads(); + + return true; +} + void Shadow::updateShadowRegion() { const QRect top(0, - m_topOffset, m_topLevel->width(), m_topOffset); @@ -356,6 +426,12 @@ } } + if (InternalClient *client = qobject_cast(m_topLevel)) { + if (init(client->internalWindow())) { + return true; + } + } + auto data = Shadow::readX11ShadowProperty(m_topLevel->window()); if (data.isEmpty()) { return false;