File indexing completed on 2024-05-12 17:00:19

0001 /*
0002     SPDX-FileCopyrightText: 2020 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0005 */
0006 
0007 #include "windowshadow.h"
0008 #include "logging.h"
0009 #include "waylandintegration.h"
0010 
0011 #include <KWayland/Client/shm_pool.h>
0012 #include <KWayland/Client/surface.h>
0013 
0014 #include <QDebug>
0015 #include <QExposeEvent>
0016 
0017 WindowShadowTile::WindowShadowTile() {}
0018 WindowShadowTile::~WindowShadowTile() {}
0019 
0020 bool WindowShadowTile::create()
0021 {
0022     m_shmPool.reset(WaylandIntegration::self()->createShmPool());
0023     if (!m_shmPool) {
0024         return false;
0025     }
0026     buffer = m_shmPool->createBuffer(image);
0027     return true;
0028 }
0029 
0030 void WindowShadowTile::destroy()
0031 {
0032     buffer = nullptr;
0033 }
0034 
0035 WindowShadowTile *WindowShadowTile::get(const KWindowShadowTile *tile)
0036 {
0037     KWindowShadowTilePrivate *d = KWindowShadowTilePrivate::get(tile);
0038     return static_cast<WindowShadowTile *>(d);
0039 }
0040 
0041 static KWayland::Client::Buffer::Ptr bufferForTile(const KWindowShadowTile::Ptr &tile)
0042 {
0043     if (!tile) {
0044         return KWayland::Client::Buffer::Ptr();
0045     }
0046     WindowShadowTile *d = WindowShadowTile::get(tile.data());
0047     return d->buffer;
0048 }
0049 
0050 bool WindowShadow::eventFilter(QObject *watched, QEvent *event)
0051 {
0052     Q_UNUSED(watched)
0053     if (event->type() == QEvent::Expose) {
0054         QExposeEvent *exposeEvent = static_cast<QExposeEvent *>(event);
0055         if (!exposeEvent->region().isNull()) {
0056             if (!internalCreate()) {
0057                 qCWarning(KWAYLAND_KWS) << "Failed to recreate shadow for" << window;
0058             }
0059         }
0060     } else if (event->type() == QEvent::Hide) {
0061         internalDestroy();
0062     }
0063     return false;
0064 }
0065 
0066 bool WindowShadow::internalCreate()
0067 {
0068     if (shadow) {
0069         return true;
0070     }
0071     KWayland::Client::ShadowManager *shadowManager = WaylandIntegration::self()->waylandShadowManager();
0072     if (!shadowManager) {
0073         return false;
0074     }
0075     KWayland::Client::Surface *surface = KWayland::Client::Surface::fromWindow(window);
0076     if (!surface) {
0077         return false;
0078     }
0079 
0080     shadow = shadowManager->createShadow(surface, surface);
0081     shadow->attachLeft(bufferForTile(leftTile));
0082     shadow->attachTopLeft(bufferForTile(topLeftTile));
0083     shadow->attachTop(bufferForTile(topTile));
0084     shadow->attachTopRight(bufferForTile(topRightTile));
0085     shadow->attachRight(bufferForTile(rightTile));
0086     shadow->attachBottomRight(bufferForTile(bottomRightTile));
0087     shadow->attachBottom(bufferForTile(bottomTile));
0088     shadow->attachBottomLeft(bufferForTile(bottomLeftTile));
0089     shadow->setOffsets(padding);
0090     shadow->commit();
0091 
0092     // Commit wl_surface at the next available time.
0093     window->requestUpdate();
0094 
0095     return true;
0096 }
0097 
0098 bool WindowShadow::create()
0099 {
0100     KWayland::Client::ShadowManager *shadowManager = WaylandIntegration::self()->waylandShadowManager();
0101     if (!shadowManager) {
0102         return false;
0103     }
0104     internalCreate();
0105     window->installEventFilter(this);
0106     return true;
0107 }
0108 
0109 void WindowShadow::internalDestroy()
0110 {
0111     if (!shadow) {
0112         return;
0113     }
0114 
0115     KWayland::Client::ShadowManager *shadowManager = WaylandIntegration::self()->waylandShadowManager();
0116     if (shadowManager) {
0117         KWayland::Client::Surface *surface = KWayland::Client::Surface::fromWindow(window);
0118         if (surface) {
0119             shadowManager->removeShadow(surface);
0120         }
0121     }
0122 
0123     delete shadow;
0124     shadow = nullptr;
0125 
0126     if (window) {
0127         window->requestUpdate();
0128     }
0129 }
0130 
0131 void WindowShadow::destroy()
0132 {
0133     if (window) {
0134         window->removeEventFilter(this);
0135     }
0136     internalDestroy();
0137 }