File indexing completed on 2025-02-23 04:26:50

0001 /*
0002  * Copyright (C) 2021 CutefishOS Team.
0003  *
0004  * Author:     cutefish <cutefishos@foxmail.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 "windowblur.h"
0021 
0022 #include <QApplication>
0023 #include <QPainterPath>
0024 #include <QScreen>
0025 
0026 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
0027 #include <QX11Info>
0028 #endif
0029 
0030 #include <xcb/xcb.h>
0031 #include <xcb/shape.h>
0032 #include <xcb/xcb_icccm.h>
0033 #include <KWindowSystem>
0034 #include <KWindowEffects>
0035 #include "style.h"
0036 
0037 WindowBlur::WindowBlur(QObject *parent) noexcept
0038 : QObject(parent)
0039 , m_view(nullptr)
0040 , m_enabled(false)
0041 , m_windowRadius(0.0)
0042 {
0043 }
0044 
0045 WindowBlur::~WindowBlur()
0046 {
0047 }
0048 
0049 void WindowBlur::classBegin()
0050 {
0051 }
0052 
0053 void WindowBlur::componentComplete()
0054 {
0055     Style::instance()->setTranslucencyAvailable(m_enabled);
0056     updateBlur();
0057 }
0058 
0059 void WindowBlur::setView(QWindow *view)
0060 {
0061     if (view != m_view) {
0062         m_view = view;
0063         updateBlur();
0064         Q_EMIT viewChanged();
0065         
0066         connect(m_view, &QWindow::visibleChanged, this, &WindowBlur::onViewVisibleChanged);
0067     }
0068 }
0069 
0070 QWindow* WindowBlur::view() const
0071 {
0072     return m_view;
0073 }
0074 
0075 void WindowBlur::setGeometry(const QRect &rect)
0076 {
0077     if (rect != m_rect) {
0078         m_rect = rect;
0079         
0080        
0081             updateBlur();
0082         
0083         Q_EMIT geometryChanged();
0084     }
0085 }
0086 
0087 QRect WindowBlur::geometry() const
0088 {
0089     return m_rect;
0090 }
0091 
0092 void WindowBlur::setEnabled(bool enabled)
0093 {
0094     if (enabled != m_enabled) {
0095         m_enabled = enabled;
0096         updateBlur();
0097         Q_EMIT enabledChanged();
0098     }
0099 }
0100 
0101 bool WindowBlur::enabled() const
0102 {
0103     return m_enabled;
0104 }
0105 
0106 void WindowBlur::setWindowRadius(qreal radius)
0107 {
0108     if (radius != m_windowRadius) {
0109         m_windowRadius = radius;
0110         
0111             updateBlur();
0112         
0113         Q_EMIT windowRadiusChanged();
0114     }
0115 }
0116 
0117 qreal WindowBlur::windowRadius() const
0118 {
0119     return m_windowRadius;
0120 }
0121 
0122 void WindowBlur::onViewVisibleChanged(bool visible)
0123 {
0124     if (visible)
0125         updateBlur();
0126 }
0127 
0128 void WindowBlur::updateBlur()
0129 {
0130     if (!m_view)
0131         return;
0132 
0133     if(KWindowSystem::isPlatformWayland())
0134     {
0135         qDebug() << "SETTING BLURRED WINDOW BG WAYLAND KDE;" << m_enabled << m_view;
0136         KWindowEffects::enableBlurBehind(m_view, m_enabled, m_rect);
0137         KWindowEffects::enableBackgroundContrast(m_view, m_enabled);
0138         return;
0139     }
0140 
0141 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)    
0142     xcb_connection_t *c = QX11Info::connection();
0143     if (!c)
0144         return;
0145     
0146     const QByteArray effectName = QByteArrayLiteral("_KDE_NET_WM_BLUR_BEHIND_REGION");
0147     xcb_intern_atom_cookie_t atomCookie = xcb_intern_atom_unchecked(c, false, effectName.length(), effectName.constData());
0148     QScopedPointer<xcb_intern_atom_reply_t, QScopedPointerPodDeleter> atom(xcb_intern_atom_reply(c, atomCookie, nullptr));
0149     if (!atom)
0150         return;
0151     
0152     if (m_enabled) {
0153         qreal devicePixelRatio = m_view->screen()->devicePixelRatio();
0154         QPainterPath path;
0155         path.addRoundedRect(QRect(QPoint(0, 0), m_view->size() * devicePixelRatio),
0156                             m_windowRadius * devicePixelRatio,
0157                             m_windowRadius * devicePixelRatio);
0158         QVector<uint32_t> data;
0159         foreach (const QPolygonF &polygon, path.toFillPolygons()) {
0160             QRegion region = polygon.toPolygon();
0161             for (auto i = region.begin(); i != region.end(); ++i) {
0162                 data << i->x() << i->y() << i->width() << i->height();
0163             }
0164         }
0165         
0166         xcb_change_property(c, XCB_PROP_MODE_REPLACE, m_view->winId(), atom->atom, XCB_ATOM_CARDINAL,
0167                             32, data.size(), data.constData());
0168         
0169     } else {
0170         xcb_delete_property(c, m_view->winId(), atom->atom);
0171     }
0172 #endif
0173 }