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 }