File indexing completed on 2024-12-01 11:10:42

0001 /*
0002     SPDX-FileCopyrightText: 2011 Aaron Seigo <aseigo@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "panelshadows_p.h"
0008 
0009 #include <QDebug>
0010 #include <KWindowShadow>
0011 
0012 class PanelShadows::Private
0013 {
0014 public:
0015     Private(PanelShadows *shadows)
0016         : q(shadows)
0017     {
0018     }
0019 
0020     ~Private()
0021     {
0022     }
0023 
0024     void clearTiles();
0025     void setupTiles();
0026     void initTile(const QString &element);
0027     void updateShadow(QWindow *window, Plasma::FrameSvg::EnabledBorders);
0028     void clearShadow(QWindow *window);
0029     void updateShadows();
0030     bool hasShadows() const;
0031 
0032     PanelShadows *q;
0033 
0034     QHash<QWindow *, Plasma::FrameSvg::EnabledBorders> m_windows;
0035     QHash<QWindow *, KWindowShadow *> m_shadows;
0036     QVector<KWindowShadowTile::Ptr> m_tiles;
0037 };
0038 
0039 class PanelShadowsSingleton
0040 {
0041 public:
0042     PanelShadowsSingleton()
0043     {
0044     }
0045 
0046     PanelShadows self;
0047 };
0048 
0049 Q_GLOBAL_STATIC(PanelShadowsSingleton, privatePanelShadowsSelf)
0050 
0051 PanelShadows::PanelShadows(QObject *parent, const QString &prefix)
0052     : Plasma::Svg(parent)
0053     , d(new Private(this))
0054 {
0055     setImagePath(prefix);
0056     connect(this, &Plasma::Svg::repaintNeeded, this, [this]() {
0057         d->updateShadows();
0058     });
0059 }
0060 
0061 PanelShadows::~PanelShadows()
0062 {
0063     delete d;
0064 }
0065 
0066 PanelShadows *PanelShadows::self()
0067 {
0068     return &privatePanelShadowsSelf->self;
0069 }
0070 
0071 void PanelShadows::addWindow(QWindow *window, Plasma::FrameSvg::EnabledBorders enabledBorders)
0072 {
0073     if (!window) {
0074         return;
0075     }
0076 
0077     d->m_windows[window] = enabledBorders;
0078     d->updateShadow(window, enabledBorders);
0079     connect(window, &QObject::destroyed, this, [this, window]() {
0080         d->m_windows.remove(window);
0081         d->clearShadow(window);
0082         if (d->m_windows.isEmpty()) {
0083             d->clearTiles();
0084         }
0085     });
0086 }
0087 
0088 void PanelShadows::removeWindow(QWindow *window)
0089 {
0090     if (!d->m_windows.contains(window)) {
0091         return;
0092     }
0093 
0094     d->m_windows.remove(window);
0095     disconnect(window, nullptr, this, nullptr);
0096     d->clearShadow(window);
0097 
0098     if (d->m_windows.isEmpty()) {
0099         d->clearTiles();
0100     }
0101 }
0102 
0103 void PanelShadows::setEnabledBorders(QWindow *window, Plasma::FrameSvg::EnabledBorders enabledBorders)
0104 {
0105     if (!window || !d->m_windows.contains(window)) {
0106         return;
0107     }
0108 
0109     d->m_windows[window] = enabledBorders;
0110     d->updateShadow(window, enabledBorders);
0111 }
0112 
0113 void PanelShadows::Private::updateShadows()
0114 {
0115     const bool hadShadowsBefore = !m_tiles.isEmpty();
0116 
0117     // has shadows now?
0118     if (hasShadows()) {
0119         if (hadShadowsBefore) {
0120             clearTiles();
0121         }
0122         for (auto i = m_windows.constBegin(); i != m_windows.constEnd(); ++i) {
0123             updateShadow(i.key(), i.value());
0124         }
0125     } else {
0126         if (hadShadowsBefore) {
0127             for (auto i = m_windows.constBegin(); i != m_windows.constEnd(); ++i) {
0128                 clearShadow(i.key());
0129             }
0130             clearTiles();
0131         }
0132     }
0133 }
0134 
0135 void PanelShadows::Private::initTile(const QString &element)
0136 {
0137     const QImage image = q->pixmap(element).toImage();
0138 
0139     KWindowShadowTile::Ptr tile = KWindowShadowTile::Ptr::create();
0140     tile->setImage(image);
0141 
0142     m_tiles << tile;
0143 }
0144 
0145 void PanelShadows::Private::setupTiles()
0146 {
0147     clearTiles();
0148 
0149     initTile(QStringLiteral("shadow-top"));
0150     initTile(QStringLiteral("shadow-topright"));
0151     initTile(QStringLiteral("shadow-right"));
0152     initTile(QStringLiteral("shadow-bottomright"));
0153     initTile(QStringLiteral("shadow-bottom"));
0154     initTile(QStringLiteral("shadow-bottomleft"));
0155     initTile(QStringLiteral("shadow-left"));
0156     initTile(QStringLiteral("shadow-topleft"));
0157 }
0158 
0159 void PanelShadows::Private::clearTiles()
0160 {
0161     m_tiles.clear();
0162 }
0163 
0164 void PanelShadows::Private::updateShadow(QWindow *window, Plasma::FrameSvg::EnabledBorders enabledBorders)
0165 {
0166     if (!hasShadows()) {
0167         return;
0168     }
0169 
0170     if (m_tiles.isEmpty()) {
0171         setupTiles();
0172     }
0173 
0174     KWindowShadow *&shadow = m_shadows[window];
0175 
0176     if (!shadow) {
0177         shadow = new KWindowShadow(q);
0178     }
0179 
0180     if (shadow->isCreated()) {
0181         shadow->destroy();
0182     }
0183 
0184     if (enabledBorders & Plasma::FrameSvg::TopBorder) {
0185         shadow->setTopTile(m_tiles.at(0));
0186     } else {
0187         shadow->setTopTile(nullptr);
0188     }
0189 
0190     if (enabledBorders & Plasma::FrameSvg::TopBorder && enabledBorders & Plasma::FrameSvg::RightBorder) {
0191         shadow->setTopRightTile(m_tiles.at(1));
0192     } else {
0193         shadow->setTopRightTile(nullptr);
0194     }
0195 
0196     if (enabledBorders & Plasma::FrameSvg::RightBorder) {
0197         shadow->setRightTile(m_tiles.at(2));
0198     } else {
0199         shadow->setRightTile(nullptr);
0200     }
0201 
0202     if (enabledBorders & Plasma::FrameSvg::BottomBorder && enabledBorders & Plasma::FrameSvg::RightBorder) {
0203         shadow->setBottomRightTile(m_tiles.at(3));
0204     } else {
0205         shadow->setBottomRightTile(nullptr);
0206     }
0207 
0208     if (enabledBorders & Plasma::FrameSvg::BottomBorder) {
0209         shadow->setBottomTile(m_tiles.at(4));
0210     } else {
0211         shadow->setBottomTile(nullptr);
0212     }
0213 
0214     if (enabledBorders & Plasma::FrameSvg::BottomBorder && enabledBorders & Plasma::FrameSvg::LeftBorder) {
0215         shadow->setBottomLeftTile(m_tiles.at(5));
0216     } else {
0217         shadow->setBottomLeftTile(nullptr);
0218     }
0219 
0220     if (enabledBorders & Plasma::FrameSvg::LeftBorder) {
0221         shadow->setLeftTile(m_tiles.at(6));
0222     } else {
0223         shadow->setLeftTile(nullptr);
0224     }
0225 
0226     if (enabledBorders & Plasma::FrameSvg::TopBorder && enabledBorders & Plasma::FrameSvg::LeftBorder) {
0227         shadow->setTopLeftTile(m_tiles.at(7));
0228     } else {
0229         shadow->setTopLeftTile(nullptr);
0230     }
0231 
0232     QMargins padding;
0233 
0234     if (enabledBorders & Plasma::FrameSvg::TopBorder) {
0235         const QSize marginHint = q->elementSize(QStringLiteral("shadow-hint-top-margin"));
0236         if (marginHint.isValid()) {
0237             padding.setTop(marginHint.height());
0238         } else {
0239             padding.setTop(m_tiles[0]->image().height());
0240         }
0241     }
0242 
0243     if (enabledBorders & Plasma::FrameSvg::RightBorder) {
0244         const QSize marginHint = q->elementSize(QStringLiteral("shadow-hint-right-margin"));
0245         if (marginHint.isValid()) {
0246             padding.setRight(marginHint.width());
0247         } else {
0248             padding.setRight(m_tiles[2]->image().width());
0249         }
0250     }
0251 
0252     if (enabledBorders & Plasma::FrameSvg::BottomBorder) {
0253         const QSize marginHint = q->elementSize(QStringLiteral("shadow-hint-bottom-margin"));
0254         if (marginHint.isValid()) {
0255             padding.setBottom(marginHint.height());
0256         } else {
0257             padding.setBottom(m_tiles[4]->image().height());
0258         }
0259     }
0260 
0261     if (enabledBorders & Plasma::FrameSvg::LeftBorder) {
0262         const QSize marginHint = q->elementSize(QStringLiteral("shadow-hint-left-margin"));
0263         if (marginHint.isValid()) {
0264             padding.setLeft(marginHint.width());
0265         } else {
0266             padding.setLeft(m_tiles[6]->image().width());
0267         }
0268     }
0269 
0270     shadow->setPadding(padding);
0271     shadow->setWindow(window);
0272 
0273     if (!shadow->create()) {
0274         qDebug() << "Couldn't create KWindowShadow for" << window;
0275     }
0276 }
0277 
0278 void PanelShadows::Private::clearShadow(QWindow *window)
0279 {
0280     delete m_shadows.take(window);
0281 }
0282 
0283 bool PanelShadows::Private::hasShadows() const
0284 {
0285     return q->hasElement(QStringLiteral("shadow-left"));
0286 }
0287 
0288 #include "moc_panelshadows_p.cpp"