Provide a KWindowShadow implementation for internal clients

Reviewers: #kwin, davidedmundson

Reviewed By: #kwin, davidedmundson

Subscribers: davidedmundson, kwin

Tags: #kwin

Maniphest Tasks: T12496

Differential Revision: https://phabricator.kde.org/D26459
This commit is contained in:
Vlad Zahorodnii 2020-01-01 03:11:17 +02:00
parent 9bdb9229c0
commit fb598c65b8
8 changed files with 236 additions and 1 deletions

View file

@ -31,6 +31,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
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 @@ InternalClient::InternalClient(QWindow *window)
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 @@ bool InternalClient::eventFilter(QObject *watched, QEvent *event)
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<NET::WindowType>();
workspace()->updateClientArea();

View file

@ -1,6 +1,7 @@
set(kwindowsystem_plugin_SRCS
plugin.cpp
windoweffects.cpp
windowshadow.cpp
windowsystem.cpp
)

View file

@ -18,8 +18,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#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 @@ KWindowSystemPrivate *KWindowSystemKWinPlugin::createWindowSystem()
{
return new KWin::WindowSystem();
}
KWindowShadowTilePrivate *KWindowSystemKWinPlugin::createWindowShadowTile()
{
return new KWin::WindowShadowTile();
}
KWindowShadowPrivate *KWindowSystemKWinPlugin::createWindowShadow()
{
return new KWin::WindowShadow();
}

View file

@ -33,4 +33,6 @@ public:
KWindowEffectsPrivate *createEffects() override;
KWindowSystemPrivate *createWindowSystem() override;
KWindowShadowTilePrivate *createWindowShadowTile() override;
KWindowShadowPrivate *createWindowShadow() override;
};

View file

@ -0,0 +1,95 @@
/*
* Copyright 2020 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "windowshadow.h"
#include <QVariant>
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

View file

@ -0,0 +1,42 @@
/*
* Copyright 2020 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <KWindowSystem/private/kwindowshadow_p.h>
namespace KWin
{
class WindowShadowTile final : public KWindowShadowTilePrivate
{
public:
bool create() override;
void destroy() override;
};
class WindowShadow final : public KWindowShadowPrivate
{
public:
bool create() override;
void destroy() override;
};
} // namespace KWin

View file

@ -3,6 +3,7 @@
This file is part of the KDE project.
Copyright (C) 2011 Martin Gräßlin <mgraesslin@kde.org>
Copyright (C) 2020 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
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 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#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 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <KWayland/Server/shadow_interface.h>
#include <KWayland/Server/surface_interface.h>
#include <QWindow>
Q_DECLARE_METATYPE(QMargins)
namespace KWin
{
@ -60,6 +66,9 @@ Shadow *Shadow::createShadow(Toplevel *toplevel)
if (!shadow && kwinApp()->x11Connection()) {
shadow = createShadowFromX11(toplevel);
}
if (!shadow) {
shadow = createShadowFromInternalWindow(toplevel);
}
if (!shadow) {
return nullptr;
}
@ -121,6 +130,24 @@ Shadow *Shadow::createShadowFromWayland(Toplevel *toplevel)
return shadow;
}
Shadow *Shadow::createShadowFromInternalWindow(Toplevel *toplevel)
{
const InternalClient *client = qobject_cast<InternalClient *>(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<uint32_t> ret;
@ -240,6 +267,49 @@ bool Shadow::init(const QPointer< KWayland::Server::ShadowInterface > &shadow)
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<QImage>();
const QImage topLeftTile = window->property("kwin_shadow_top_left_tile").value<QImage>();
const QImage topTile = window->property("kwin_shadow_top_tile").value<QImage>();
const QImage topRightTile = window->property("kwin_shadow_top_right_tile").value<QImage>();
const QImage rightTile = window->property("kwin_shadow_right_tile").value<QImage>();
const QImage bottomRightTile = window->property("kwin_shadow_bottom_right_tile").value<QImage>();
const QImage bottomTile = window->property("kwin_shadow_bottom_tile").value<QImage>();
const QImage bottomLeftTile = window->property("kwin_shadow_bottom_left_tile").value<QImage>();
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<QMargins>();
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 @@ bool Shadow::updateShadow()
}
}
if (InternalClient *client = qobject_cast<InternalClient *>(m_topLevel)) {
if (init(client->internalWindow())) {
return true;
}
}
auto data = Shadow::readX11ShadowProperty(m_topLevel->window());
if (data.isEmpty()) {
return false;

View file

@ -3,6 +3,7 @@
This file is part of the KDE project.
Copyright (C) 2011 Martin Gräßlin <mgraesslin@kde.org>
Copyright (C) 2020 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
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 @@ private:
static Shadow *createShadowFromX11(Toplevel *toplevel);
static Shadow *createShadowFromDecoration(Toplevel *toplevel);
static Shadow *createShadowFromWayland(Toplevel *toplevel);
static Shadow *createShadowFromInternalWindow(Toplevel *toplevel);
static QVector<uint32_t> readX11ShadowProperty(xcb_window_t id);
bool init(const QVector<uint32_t> &data);
bool init(KDecoration2::Decoration *decoration);
bool init(const QPointer<KWayland::Server::ShadowInterface> &shadow);
bool init(const QWindow *window);
Toplevel *m_topLevel;
// shadow pixmaps
QPixmap m_shadowElements[ShadowElementsCount];