File indexing completed on 2024-04-28 05:47:17

0001 /*****************************************************************************
0002  *   Copyright 2010 Craig Drummond <craig.p.drummond@gmail.com>              *
0003  *   Copyright 2013 - 2015 Yichao Yu <yyc1992@gmail.com>                     *
0004  *                                                                           *
0005  *   This program is free software; you can redistribute it and/or modify    *
0006  *   it under the terms of the GNU Lesser General Public License as          *
0007  *   published by the Free Software Foundation; either version 2.1 of the    *
0008  *   License, or (at your option) version 3, or any later version accepted   *
0009  *   by the membership of KDE e.V. (or its successor approved by the         *
0010  *   membership of KDE e.V.), which shall act as a proxy defined in          *
0011  *   Section 6 of version 3 of the license.                                  *
0012  *                                                                           *
0013  *   This program is distributed in the hope that it will be useful,         *
0014  *   but WITHOUT ANY WARRANTY; without even the implied warranty of          *
0015  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU       *
0016  *   Lesser General Public License for more details.                         *
0017  *                                                                           *
0018  *   You should have received a copy of the GNU Lesser General Public        *
0019  *   License along with this library. If not,                                *
0020  *   see <http://www.gnu.org/licenses/>.                                     *
0021  *****************************************************************************/
0022 
0023 //////////////////////////////////////////////////////////////////////////////
0024 // blurhelper.cpp
0025 // handle regions passed to kwin for blurring
0026 // -------------------
0027 //
0028 // Copyright (c) 2010 Hugo Pereira Da Costa <hugo@oxygen-icons.org>
0029 //
0030 // Loosely inspired (and largely rewritten) from BeSpin style
0031 // Copyright (C) 2007 Thomas Luebking <thomas.luebking@web.de>
0032 //
0033 // Permission is hereby granted, free of charge, to any person obtaining a copy
0034 // of this software and associated documentation files (the "Software"), to
0035 // deal in the Software without restriction, including without limitation the
0036 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
0037 // sell copies of the Software, and to permit persons to whom the Software is
0038 // furnished to do so, subject to the following conditions:
0039 //
0040 // The above copyright notice and this permission notice shall be included in
0041 // all copies or substantial portions of the Software.
0042 //
0043 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0044 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0045 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
0046 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
0047 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
0048 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
0049 // IN THE SOFTWARE.
0050 //////////////////////////////////////////////////////////////////////////////
0051 
0052 #include "blurhelper.h"
0053 
0054 #include <QEvent>
0055 #include <QVector>
0056 #include <QDockWidget>
0057 #include <QMenu>
0058 #include <QProgressBar>
0059 #include <QPushButton>
0060 #include <QToolBar>
0061 #if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)
0062 #  include "private/qhighdpiscaling_p.h"
0063 #endif
0064 
0065 #include <qtcurve-utils/qtutils.h>
0066 #include <qtcurve-utils/x11blur.h>
0067 
0068 namespace QtCurve {
0069 BlurHelper::BlurHelper(QObject *parent):
0070     QObject(parent),
0071     _enabled(false)
0072 {
0073 }
0074 
0075 void
0076 BlurHelper::registerWidget(QWidget *widget)
0077 {
0078     widget->installEventFilter(this);
0079 }
0080 
0081 void
0082 BlurHelper::unregisterWidget(QWidget *widget)
0083 {
0084     widget->removeEventFilter(this);
0085     if (isTransparent(widget)) {
0086         clear(qtcGetWid(widget));
0087     }
0088 }
0089 
0090 bool
0091 BlurHelper::eventFilter(QObject *object, QEvent *event)
0092 {
0093     // do nothing if not enabled
0094     if (!enabled())
0095         return false;
0096 
0097     switch (event->type()) {
0098     case QEvent::Hide: {
0099         QWidget *widget = qtcToWidget(object);
0100         if (widget && isOpaque(widget)) {
0101             QWidget *window(widget->window());
0102             if (window && isTransparent(window) &&
0103                 !_pendingWidgets.contains(window)) {
0104                 _pendingWidgets.insert(window, window);
0105                 delayedUpdate();
0106             }
0107         }
0108         break;
0109     }
0110     case QEvent::Show:
0111     case QEvent::Resize: {
0112         // cast to widget and check
0113         QWidget *widget = qtcToWidget(object);
0114         if (!widget)
0115             break;
0116         if (isTransparent(widget)) {
0117             _pendingWidgets.insert(widget, widget);
0118             delayedUpdate();
0119         } else if (isOpaque(widget)) {
0120             QWidget *window(widget->window());
0121             if (isTransparent(window)) {
0122                 _pendingWidgets.insert(window, window);
0123                 delayedUpdate();
0124             }
0125         }
0126         break;
0127     }
0128     default:
0129         break;
0130     }
0131     // never eat events
0132     return false;
0133 }
0134 
0135 QRegion
0136 BlurHelper::blurRegion(QWidget *widget) const
0137 {
0138     if (!widget->isVisible())
0139         return QRegion();
0140     // get main region
0141     QRegion region = widget->mask().isEmpty() ? widget->rect() : widget->mask();
0142 
0143     // trim blur region to remove unnecessary areas
0144     trimBlurRegion(widget, widget, region);
0145     return region;
0146 }
0147 
0148 void
0149 BlurHelper::trimBlurRegion(QWidget *parent, QWidget *widget,
0150                            QRegion &region) const
0151 {
0152     // TODO:
0153     //     Maybe we should clip children with parent? In case we hit this[1] kind
0154     //     of bugs again.
0155     //     [1] https://bugs.kde.org/show_bug.cgi?id=306631
0156     // loop over children
0157     for (QObject *childObject: widget->children()) {
0158         QWidget *child = qtcToWidget(childObject);
0159         if (!(child && child->isVisible()))
0160             continue;
0161         if (isOpaque(child)) {
0162             const QPoint offset(child->mapTo(parent, QPoint(0, 0)));
0163             if (child->mask().isEmpty()) {
0164                 region -= child->rect().translated(offset);
0165             } else {
0166                 region -= child->mask().translated(offset);
0167             }
0168         } else {
0169             trimBlurRegion(parent, child, region);
0170         }
0171     }
0172     return;
0173 }
0174 
0175 void
0176 BlurHelper::update(QWidget *widget) const
0177 {
0178     // DO NOT condition compile on QTC_ENABLE_X11.
0179     // There's no direct linkage on X11 and the following code will just do
0180     // nothing if X11 is not enabled (either at compile time or at run time).
0181     QTC_RET_IF_FAIL(qtcX11Enabled());
0182     // Do not create native window if there isn't one yet.
0183     WId wid = qtcGetWid(widget);
0184     if (!wid) {
0185         return;
0186     }
0187     const QRegion region(blurRegion(widget));
0188     if (region.isEmpty()) {
0189         clear(wid);
0190     } else {
0191         QVector<uint32_t> data;
0192 #if QT_VERSION >= QT_VERSION_CHECK(5, 8, 0)
0193         const auto &rects = region;
0194 #else
0195         const auto &rects = region.rects();
0196 #endif
0197         for (const QRect &_rect: rects) {
0198 #if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)
0199             const auto &rect = QHighDpi::toNativePixels(_rect, widget->window()->windowHandle());
0200 #else
0201             const auto &rect = _rect;
0202 #endif
0203             data << rect.x() << rect.y() << rect.width() << rect.height();
0204         }
0205         qtcX11BlurTrigger(wid, true, data.size(), data.constData());
0206     }
0207     // force update
0208     if (widget->isVisible()) {
0209         widget->update();
0210     }
0211 }
0212 
0213 void
0214 BlurHelper::clear(WId wid) const
0215 {
0216     // DO NOT condition compile on QTC_ENABLE_X11.
0217     // There's no direct linkage on X11 and the following code will just do
0218     // nothing if X11 is not enabled (either at compile time or at run time).
0219     QTC_RET_IF_FAIL(qtcX11Enabled());
0220     qtcX11BlurTrigger(wid, false, 0, 0);
0221 }
0222 }