File indexing completed on 2024-12-22 04:31:07

0001 /*
0002  * Copyright (C) 2021 CutefishOS Team.
0003  *
0004  * Author:     revenmartin <revenmartin@gmail.com>
0005  *
0006  * This program is free software: you can redistribute it and/or modify
0007  * it under the terms of the GNU General Public License as published by
0008  * the Free Software Foundation, either version 3 of the License, or
0009  * any later version.
0010  *
0011  * This program is distributed in the hope that it will be useful,
0012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0014  * GNU General Public License for more details.
0015  *
0016  * You should have received a copy of the GNU General Public License
0017  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
0018  */
0019 
0020 #include "windowshadow.h"
0021 #include "boxshadowrenderer.h"
0022 #include <QDebug>
0023 #include <QCoreApplication>
0024 #include <QDBusInterface>
0025 
0026 #include <KWindowSystem>
0027 #include <KWindowEffects>
0028 
0029 enum {
0030     ShadowNone,
0031     ShadowSmall,
0032     ShadowMedium,
0033     ShadowLarge,
0034     ShadowVeryLarge
0035 };
0036 
0037 const CompositeShadowParams s_shadowParams[] = {
0038     // None
0039     CompositeShadowParams(),
0040     // Small
0041     CompositeShadowParams(
0042         QPoint(0, 3),
0043         ShadowParams(QPoint(0, 0), 16, 0.26),
0044         ShadowParams(QPoint(0, -2), 8, 0.16)),
0045     // Medium
0046     CompositeShadowParams(
0047         QPoint(0, 4),
0048         ShadowParams(QPoint(0, 0), 20, 0.24),
0049         ShadowParams(QPoint(0, -2), 10, 0.14)),
0050     // Large
0051     CompositeShadowParams(
0052         QPoint(0, 5),
0053         ShadowParams(QPoint(0, 0), 24, 0.22),
0054         ShadowParams(QPoint(0, -3), 12, 0.12)),
0055     // Very Large
0056     CompositeShadowParams(
0057         QPoint(0, 6),
0058         ShadowParams(QPoint(0, 0), 36, 0.12),
0059         ShadowParams(QPoint(0, -3), 20, 0.05))
0060 };
0061 
0062 WindowShadow::WindowShadow(QObject *parent) noexcept
0063     : QObject(parent)
0064     , m_view(nullptr)
0065     , m_shadow(new KWindowShadow(this))
0066 {
0067 
0068 }
0069 
0070 WindowShadow::~WindowShadow()
0071 {
0072     m_shadow->destroy();
0073 }
0074 
0075 CompositeShadowParams WindowShadow::lookupShadowParams(int shadowSizeEnum)
0076 {
0077     switch (shadowSizeEnum) {
0078     case ShadowNone:
0079         return s_shadowParams[0];
0080     case ShadowSmall:
0081         return s_shadowParams[1];
0082     case ShadowMedium:
0083         return s_shadowParams[2];
0084     case ShadowLarge:
0085         return s_shadowParams[3];
0086     case ShadowVeryLarge:
0087         return s_shadowParams[4];
0088     default:
0089         // Fallback to the Large size.
0090         return s_shadowParams[3];
0091     }
0092 }
0093 
0094 void WindowShadow::classBegin()
0095 {
0096     m_shadowTiles = this->shadowTiles();
0097 
0098     QVector<KWindowShadowTile::Ptr> tiles = {
0099         createTile(m_shadowTiles.pixmap(1)),
0100         createTile(m_shadowTiles.pixmap(2)),
0101         createTile(m_shadowTiles.pixmap(5)),
0102         createTile(m_shadowTiles.pixmap(8)),
0103         createTile(m_shadowTiles.pixmap(7)),
0104         createTile(m_shadowTiles.pixmap(6)),
0105         createTile(m_shadowTiles.pixmap(3)),
0106         createTile(m_shadowTiles.pixmap(0))
0107     };
0108 
0109     m_tile = tiles;
0110 }
0111 
0112 void WindowShadow::componentComplete()
0113 {    
0114     configureTiles();    
0115 }
0116 
0117 void WindowShadow::setView(QWindow *view)
0118 {
0119     if (view != m_view) {
0120         m_view = view;
0121         Q_EMIT viewChanged();
0122         configureTiles();
0123 
0124         connect(m_view, &QWindow::visibleChanged, this, &WindowShadow::onViewVisibleChanged);
0125     }
0126 }
0127 
0128 QWindow *WindowShadow::view() const 
0129 {
0130     return m_view;
0131 }
0132 
0133 void WindowShadow::setGeometry(const QRect &rect)
0134 {
0135     if (rect != m_rect) {
0136         m_rect = rect;
0137         Q_EMIT geometryChanged();
0138         configureTiles();
0139     }
0140 }
0141 
0142 QRect WindowShadow::geometry() const
0143 {
0144     return m_rect;
0145 }
0146 
0147 void WindowShadow::setRadius(qreal value)
0148 {
0149     if (m_radius != value) {
0150         m_radius = value;
0151         Q_EMIT radiusChanged();
0152 
0153         this->classBegin();
0154 
0155         configureTiles();
0156     }
0157 }
0158 
0159 qreal WindowShadow::strength() const
0160 {
0161     return m_strength;
0162 }
0163 
0164 void WindowShadow::setStrength(qreal strength)
0165 {
0166     if (m_strength != strength) {
0167         m_strength = strength;
0168 
0169         this->classBegin();
0170         configureTiles();
0171 
0172         Q_EMIT strengthChanged();
0173     }
0174 }
0175 
0176 void WindowShadow::onViewVisibleChanged(bool visible)
0177 {
0178     if (visible && m_view) {
0179         configureTiles();
0180     }
0181 }
0182 
0183 void WindowShadow::configureTiles()
0184 {
0185     //only for cask
0186     // if(qEnvironmentVariableIsSet("XDG_CURRENT_DESKTOP") && qEnvironmentVariable("XDG_CURRENT_DESKTOP") == "Cask")
0187     // {
0188         auto chromeInterface = new QDBusInterface ("org.cask.Server",
0189                                                    "/Chrome",
0190                                                    "org.cask.Chrome",
0191                                                    QDBusConnection::sessionBus(), this);
0192         qDebug() << "TRYING TO HOOK TO THE CASKSERVER" << qApp->desktopFileName() << qApp->desktopFileName();
0193         
0194     if(chromeInterface->isValid())
0195     {
0196         qDebug() << "TRYING TO HOOK TO THE CASKSERVER IS VAL:ID";
0197         
0198         chromeInterface->call("dropShadow", static_cast<int>(m_radius), qApp->desktopFileName());
0199     }else
0200     {
0201         qDebug() << "COULD NTO HOOK TO THE CASKSERVER";
0202     } 
0203     
0204     // return;
0205     // }    
0206     
0207     
0208     //only for plasma
0209     m_shadow->destroy();
0210 
0211     if (!m_view)
0212         return;
0213 
0214     m_shadow->setWindow(m_view);
0215     m_shadow->setTopTile(m_tile[0]);
0216     m_shadow->setTopRightTile(m_tile[1]);
0217     m_shadow->setRightTile(m_tile[2]);
0218     m_shadow->setBottomRightTile(m_tile[3]);
0219     m_shadow->setBottomTile(m_tile[4]);
0220     m_shadow->setBottomLeftTile(m_tile[5]);
0221     m_shadow->setLeftTile(m_tile[6]);
0222     m_shadow->setTopLeftTile(m_tile[7]);
0223     m_shadow->setPadding(shadowMargins(m_shadowTiles));
0224     m_shadow->create();
0225 }
0226 
0227 KWindowShadowTile::Ptr WindowShadow::createTile(const QPixmap& source)
0228 {
0229     KWindowShadowTile::Ptr tile = KWindowShadowTile::Ptr::create();
0230     tile->setImage(source.toImage());
0231     return tile;
0232 }
0233 
0234 TileSet WindowShadow::shadowTiles()
0235 {
0236     const qreal frameRadius = m_radius;
0237     const CompositeShadowParams params = lookupShadowParams(ShadowVeryLarge);
0238 
0239     if (params.isNone())
0240         return TileSet();
0241 
0242     auto withOpacity = [](const QColor &color, qreal opacity) -> QColor {
0243         QColor c(color);
0244         c.setAlphaF(opacity);
0245         return c;
0246     };
0247 
0248     const QColor color = Qt::black;
0249     const qreal strength = m_strength;
0250 
0251     const QSize boxSize = BoxShadowRenderer::calculateMinimumBoxSize(params.shadow1.radius)
0252         .expandedTo(BoxShadowRenderer::calculateMinimumBoxSize(params.shadow2.radius));
0253 
0254     const qreal dpr = qApp->devicePixelRatio();
0255 
0256     BoxShadowRenderer shadowRenderer;
0257     shadowRenderer.setBorderRadius(frameRadius);
0258     shadowRenderer.setBoxSize(boxSize);
0259     shadowRenderer.setDevicePixelRatio(dpr);
0260 
0261     shadowRenderer.addShadow(params.shadow1.offset, params.shadow1.radius,
0262         withOpacity(color, params.shadow1.opacity * strength));
0263     shadowRenderer.addShadow(params.shadow2.offset, params.shadow2.radius,
0264         withOpacity(color, params.shadow2.opacity * strength));
0265 
0266     QImage shadowTexture = shadowRenderer.render();
0267 
0268     const QRect outerRect(QPoint(0, 0), shadowTexture.size() / dpr);
0269 
0270     QRect boxRect(QPoint(0, 0), boxSize);
0271     boxRect.moveCenter(outerRect.center());
0272 
0273     // Mask out inner rect.
0274     QPainter painter(&shadowTexture);
0275     painter.setRenderHint(QPainter::Antialiasing);
0276 
0277     int Shadow_Overlap = 3;
0278     const QMargins margins = QMargins(
0279         boxRect.left() - outerRect.left() - Shadow_Overlap - params.offset.x(),
0280         boxRect.top() - outerRect.top() - Shadow_Overlap - params.offset.y(),
0281         outerRect.right() - boxRect.right() - Shadow_Overlap + params.offset.x(),
0282         outerRect.bottom() - boxRect.bottom() - Shadow_Overlap + params.offset.y());
0283 
0284     painter.setPen(Qt::NoPen);
0285     painter.setBrush(Qt::black);
0286     painter.setCompositionMode(QPainter::CompositionMode_DestinationOut);
0287     painter.drawRoundedRect(
0288         outerRect - margins,
0289         frameRadius,
0290         frameRadius);
0291 
0292     // We're done.
0293     painter.end();
0294 
0295     const QPoint innerRectTopLeft = outerRect.center();
0296     TileSet tiles = TileSet(
0297         QPixmap::fromImage(shadowTexture),
0298         innerRectTopLeft.x(),
0299         innerRectTopLeft.y(),
0300         1, 1);
0301 
0302     return tiles;
0303 }
0304 
0305 QMargins WindowShadow::shadowMargins(TileSet shadowTiles) const
0306 {
0307     const CompositeShadowParams params = lookupShadowParams(ShadowVeryLarge);
0308     if (params.isNone())
0309         return QMargins();
0310 
0311     const QSize boxSize = BoxShadowRenderer::calculateMinimumBoxSize(params.shadow1.radius)
0312         .expandedTo(BoxShadowRenderer::calculateMinimumBoxSize(params.shadow2.radius));
0313 
0314     const QSize shadowSize = BoxShadowRenderer::calculateMinimumShadowTextureSize(boxSize, params.shadow1.radius, params.shadow1.offset)
0315         .expandedTo(BoxShadowRenderer::calculateMinimumShadowTextureSize(boxSize, params.shadow2.radius, params.shadow2.offset));
0316 
0317     const QRect shadowRect(QPoint(0, 0), shadowSize);
0318 
0319     QRect boxRect(QPoint(0, 0), boxSize);
0320     boxRect.moveCenter(shadowRect.center());
0321 
0322     int Shadow_Overlap = 4;
0323     QMargins margins(
0324         boxRect.left() - shadowRect.left() - Shadow_Overlap - params.offset.x(),
0325         boxRect.top() - shadowRect.top() - Shadow_Overlap - params.offset.y(),
0326         shadowRect.right() - boxRect.right() - Shadow_Overlap + params.offset.x(),
0327         shadowRect.bottom() - boxRect.bottom() - Shadow_Overlap + params.offset.y());
0328 
0329     margins *= shadowTiles.pixmap(0).devicePixelRatio();
0330 
0331     return margins;
0332 }