File indexing completed on 2024-05-19 16:34:48

0001 /*
0002     KWin - the KDE window manager
0003     This file is part of the KDE project.
0004 
0005     SPDX-FileCopyrightText: 2013 Martin Gräßlin <mgraesslin@kde.org>
0006 
0007     SPDX-License-Identifier: GPL-2.0-or-later
0008 */
0009 #include "workspacescene_qpainter.h"
0010 // KWin
0011 #include "decorations/decoratedclient.h"
0012 #include "scene/itemrenderer_qpainter.h"
0013 #include "window.h"
0014 
0015 // Qt
0016 #include <KDecoration2/Decoration>
0017 #include <QDebug>
0018 #include <QPainter>
0019 
0020 #include <cmath>
0021 
0022 namespace KWin
0023 {
0024 
0025 //****************************************
0026 // SceneQPainter
0027 //****************************************
0028 
0029 WorkspaceSceneQPainter::WorkspaceSceneQPainter(QPainterBackend *backend)
0030     : WorkspaceScene(std::make_unique<ItemRendererQPainter>())
0031     , m_backend(backend)
0032 {
0033 }
0034 
0035 WorkspaceSceneQPainter::~WorkspaceSceneQPainter()
0036 {
0037 }
0038 
0039 std::unique_ptr<Shadow> WorkspaceSceneQPainter::createShadow(Window *window)
0040 {
0041     return std::make_unique<SceneQPainterShadow>(window);
0042 }
0043 
0044 DecorationRenderer *WorkspaceSceneQPainter::createDecorationRenderer(Decoration::DecoratedClientImpl *impl)
0045 {
0046     return new SceneQPainterDecorationRenderer(impl);
0047 }
0048 
0049 //****************************************
0050 // QPainterShadow
0051 //****************************************
0052 SceneQPainterShadow::SceneQPainterShadow(Window *window)
0053     : Shadow(window)
0054 {
0055 }
0056 
0057 SceneQPainterShadow::~SceneQPainterShadow()
0058 {
0059 }
0060 
0061 bool SceneQPainterShadow::prepareBackend()
0062 {
0063     return true;
0064 }
0065 
0066 //****************************************
0067 // QPainterDecorationRenderer
0068 //****************************************
0069 SceneQPainterDecorationRenderer::SceneQPainterDecorationRenderer(Decoration::DecoratedClientImpl *client)
0070     : DecorationRenderer(client)
0071 {
0072 }
0073 
0074 QImage SceneQPainterDecorationRenderer::image(SceneQPainterDecorationRenderer::DecorationPart part) const
0075 {
0076     Q_ASSERT(part != DecorationPart::Count);
0077     return m_images[int(part)];
0078 }
0079 
0080 void SceneQPainterDecorationRenderer::render(const QRegion &region)
0081 {
0082     if (areImageSizesDirty()) {
0083         resizeImages();
0084         resetImageSizesDirty();
0085     }
0086 
0087     auto imageSize = [this](DecorationPart part) {
0088         return m_images[int(part)].size() / m_images[int(part)].devicePixelRatio();
0089     };
0090 
0091     const QRect top(QPoint(0, 0), imageSize(DecorationPart::Top));
0092     const QRect left(QPoint(0, top.height()), imageSize(DecorationPart::Left));
0093     const QRect right(QPoint(top.width() - imageSize(DecorationPart::Right).width(), top.height()), imageSize(DecorationPart::Right));
0094     const QRect bottom(QPoint(0, left.y() + left.height()), imageSize(DecorationPart::Bottom));
0095 
0096     const QRect geometry = region.boundingRect();
0097     auto renderPart = [this](const QRect &rect, const QRect &partRect, int index) {
0098         if (rect.isEmpty()) {
0099             return;
0100         }
0101         QPainter painter(&m_images[index]);
0102         painter.setRenderHint(QPainter::Antialiasing);
0103         painter.setWindow(QRect(partRect.topLeft(), partRect.size() * effectiveDevicePixelRatio()));
0104         painter.setClipRect(rect);
0105         painter.save();
0106         // clear existing part
0107         painter.setCompositionMode(QPainter::CompositionMode_Source);
0108         painter.fillRect(rect, Qt::transparent);
0109         painter.restore();
0110         client()->decoration()->paint(&painter, rect);
0111     };
0112 
0113     renderPart(left.intersected(geometry), left, int(DecorationPart::Left));
0114     renderPart(top.intersected(geometry), top, int(DecorationPart::Top));
0115     renderPart(right.intersected(geometry), right, int(DecorationPart::Right));
0116     renderPart(bottom.intersected(geometry), bottom, int(DecorationPart::Bottom));
0117 }
0118 
0119 void SceneQPainterDecorationRenderer::resizeImages()
0120 {
0121     QRectF left, top, right, bottom;
0122     client()->window()->layoutDecorationRects(left, top, right, bottom);
0123 
0124     auto checkAndCreate = [this](int index, const QSizeF &size) {
0125         auto dpr = effectiveDevicePixelRatio();
0126         if (m_images[index].size() != size * dpr || m_images[index].devicePixelRatio() != dpr) {
0127             m_images[index] = QImage(size.toSize() * dpr, QImage::Format_ARGB32_Premultiplied);
0128             m_images[index].setDevicePixelRatio(dpr);
0129             m_images[index].fill(Qt::transparent);
0130         }
0131     };
0132     checkAndCreate(int(DecorationPart::Left), left.size());
0133     checkAndCreate(int(DecorationPart::Right), right.size());
0134     checkAndCreate(int(DecorationPart::Top), top.size());
0135     checkAndCreate(int(DecorationPart::Bottom), bottom.size());
0136 }
0137 
0138 } // KWin