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 ®ion) 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 }